AI

Azure API Management AI gateway : diagnostiquer un 429 token limit avant d'augmenter le quota

Un runbook de production pour séparer compteur APIM, portée, estimation des tokens, backend et retries clients avant d'élargir une limite de tokens IA.

26 sept. 2026 azureapi-managementapimai-gatewayllm-token-limitmicrosoft-foundryrate-limitingtokensobservabilityguardrailsrunbookrollbackproduction

Une API IA exposée par Azure API Management commence à retourner des 429 après le déploiement d’une policy llm-token-limit. Le backend Microsoft Foundry dispose encore de capacité, mais certains tenants sont bloqués tandis que d’autres passent. Augmenter tokens-per-minute semble être le correctif le plus rapide.

Ce geste peut masquer un compteur mal isolé, une clé vide partagée par tous les consommateurs, une policy appliquée deux fois, une différence entre gateways ou une boucle de retry qui transforme une limitation saine en incident. Le cas fil rouge est une API POST /responses mutualisée entre plusieurs applications. Ce runbook établit l’origine du 429, reconstruit le budget effectif, teste une correction en canari puis décide entre promotion, attente et rollback.

Figer une requête refusée et le contrat de trafic

Conservez un exemple complet avant de modifier la policy : heure UTC, gateway, région, API, opération, identité du consommateur, modèle demandé, statut, Retry-After, identifiant de corrélation et taille approximative du prompt. Ne journalisez ni prompt brut, ni secret, ni donnée personnelle pour faciliter le diagnostic.

Décrivez ensuite le budget attendu. Une limite par tenant, une limite par application et une protection globale ne répondent pas au même risque.

yaml ai-token-limit-contract.yml
gateway: apim-ai-prod
api: assistant-v1
operation: POST /responses
consumer_key_source: validated tenant_id claim
rate_budget:
tokens_per_minute: 30000
quota_budget:
tokens: 500000
period: Daily
client_contract:
honors_retry_after: true
max_attempts: 2
jitter: true
promotion_requires:
- one-counter-per-tenant
- gateway-429-distinguished-from-backend-429
- no-empty-counter-key
- canary-within-budget
rollback:
restore: apim-policy-before.xml
verify: previous-counter-behavior-and-backend-traffic

Le nombre ci-dessus illustre le contrat du cas, pas une recommandation universelle. Il doit dériver de la capacité backend, du coût acceptable, du nombre de consommateurs et de la taille réelle des requêtes.

Prouver qui a produit le 429

Un 429 visible par le client peut provenir de la policy APIM, du backend de modèle ou d’une autre limite dans la chaîne. Comparez la présence des headers configurés par la policy, les traces gateway et les logs du backend sur le même identifiant de corrélation.

Ajoutez des noms de headers explicites dans la policy afin de rendre la décision observable sans exposer le compteur interne.

xml llm-token-limit-policy.xml
<llm-token-limit
counter-key="@(context.Principal?.Claims.GetValueOrDefault(&quot;tenant_id&quot;, &quot;&quot;))"
tokens-per-minute="30000"
token-quota="500000"
token-quota-period="Daily"
estimate-prompt-tokens="true"
retry-after-header-name="x-ai-retry-after"
remaining-tokens-header-name="x-ai-tokens-remaining"
remaining-quota-tokens-header-name="x-ai-quota-remaining" />

Si APIM rejette la requête avant l’appel backend, le backend ne doit pas montrer de requête correspondante. S’il retourne lui-même 429, la policy n’est pas nécessairement en cause : examinez capacité, quota du déploiement, pool et circuit breaker. Ne cumulez pas les deux limites dans un seul graphique intitulé « throttling ».

Auditer la portée et l’ordre des policies

La même policy peut être héritée aux scopes global, workspace, product, API ou operation. Reconstituez la policy effective, y compris les balises base, avant de conclure qu’une seule limite s’applique. Deux limites légitimes peuvent coexister, mais leur objectif, leur clé et leur budget doivent être distincts.

Cherchez notamment :

  1. une limite globale et une limite API utilisant la même clé sans convention de scope ;
  2. des valeurs tokens-per-minute incohérentes pour une même clé sur des tiers v2 ;
  3. une policy ajoutée dans le portail alors qu’elle existe déjà dans le dépôt IaC ;
  4. une policy placée avant la validation de l’identité dont dépend counter-key ;
  5. une expression qui retourne une chaîne vide en l’absence du claim attendu.

Une clé vide est un incident d’isolation : plusieurs tenants alimentent le même compteur. Refusez la requête avant la policy si l’identifiant validé manque, au lieu d’utiliser silencieusement une valeur partagée comme unknown.

xml reject-missing-tenant-before-counter.xml
<choose>
<when condition="@(string.IsNullOrWhiteSpace(context.Principal?.Claims.GetValueOrDefault(&quot;tenant_id&quot;, &quot;&quot;)))">
  <return-response>
    <set-status code="401" reason="Validated tenant identity required" />
  </return-response>
</when>
</choose>

Recalculer le budget réellement consommé

Une limite en tokens ne se comporte pas comme une simple limite de requêtes. Deux appels identiques en nombre peuvent consommer des volumes très différents. La policy s’appuie sur l’usage retourné par le modèle et peut estimer les tokens du prompt en amont pour éviter un appel backend déjà hors budget. Les valeurs de tokens restants demeurent des estimations : ne les traitez pas comme une comptabilité financière exacte.

Regroupez les preuves par tenant, modèle, opération et gateway, avec une cardinalité bornée. Évitez les dimensions request_id, conversation ou utilisateur individuel : elles rendent les métriques coûteuses et finissent par masquer de nouvelles séries.

Pour les réponses en streaming, vérifiez que l’usage est réellement renvoyé. Une interruption ou un backend qui omet les compteurs rend la mesure incomplète ; absence de métrique ne signifie pas consommation nulle. Testez séparément streaming et non-streaming avec une charge contrôlée.

xml emit-bounded-token-metrics.xml
<llm-emit-token-metric namespace="NaxayaAIGateway">
<dimension name="API ID" />
<dimension name="Operation ID" />
<dimension name="Gateway ID" />
<dimension name="ConsumerTier" value="@(context.Request.Headers.GetValueOrDefault(&quot;x-consumer-tier&quot;, &quot;unknown&quot;))" />
</llm-emit-token-metric>

Le header de tier doit provenir d’une identité ou d’un mapping maîtrisé, pas d’une valeur libre fournie par le client.

Tenir compte des gateways et des régions

Les compteurs sont suivis indépendamment par gateway. Une instance multirégion, une workspace gateway et une self-hosted gateway ne constituent donc pas un compteur global unique. Un tenant peut être accepté dans une région et limité dans une autre selon son trafic local.

Ventilez les 429, tokens et requêtes par gateway avant d’augmenter une limite. Vérifiez aussi les changements de routage : un failover, une affinité perdue ou une reprise régionale peut concentrer soudainement le trafic sur un compteur différent. Si l’exigence métier porte sur un budget global strict, documentez que la policy locale ne suffit pas à elle seule et placez le contrôle agrégé dans une couche adaptée.

Vérifier que Retry-After ne crée pas une tempête

Une limitation correcte peut devenir une panne si SDK, gateway et agent retentent chacun. Capturez le nombre d’appels initiaux, de retries et de tokens par action métier. Le client doit respecter Retry-After, ajouter du jitter et borner le nombre total de tentatives sur toute la chaîne.

Ne retentez pas automatiquement une requête non idempotente qui peut déclencher un outil ou une écriture. Pour un agent, conservez l’identifiant de l’action et l’état du tool call afin qu’un retry ne rejoue pas une opération déjà acceptée.

text retry-decision.txt
Gateway 429 with Retry-After
wait once with jitter
keep the same business action id
stop when the end-to-end retry budget is exhausted

Backend 429
inspect deployment capacity and gateway routing
do not raise the APIM token budget as a substitute

Missing tenant identity
fail authentication
never fall back to a shared counter

Write-capable agent action
verify prior tool-call state before any retry

Canaryer une correction sans réinitialiser le diagnostic

Créez une route ou un produit canari avec une clé de compteur explicitement distincte, par exemple en suffixant la version de policy. Envoyez un seul tenant de test et rejouez trois profils : petits prompts réguliers, rafale sous contrôle et requête qui dépasse volontairement le budget.

Le canari doit prouver que :

  1. le tenant A ne consomme pas le budget du tenant B ;
  2. le 429 apparaît au seuil attendu avec un Retry-After exploitable ;
  3. APIM n’appelle pas le backend lorsqu’il bloque en amont ;
  4. le trafic autorisé produit des métriques cohérentes ;
  5. le client s’arrête dans son budget de retry ;
  6. les actions d’agent avec effets restent protégées contre le rejeu.

N’utilisez pas un nouveau counter-key sur tout le trafic pour faire disparaître les 429 : cela réinitialise de fait les compteurs et efface la preuve. Réservez-le au canari borné.

Décider : corriger, augmenter ou rollbacker

Corrigez la policy lorsque les tenants partagent une clé, que la portée est dupliquée, que l’identité n’est pas validée avant le compteur ou que les valeurs diffèrent pour une même clé. La capacité backend n’autorise pas à conserver une isolation incorrecte.

Augmentez le budget seulement lorsque la clé et la portée sont prouvées, que les métriques montrent une demande légitime, que le backend peut absorber la charge et que le coût est accepté. Déployez le changement par paliers et gardez un seuil d’arrêt sur les 429 backend, la latence, les erreurs et la consommation.

Rollbackez si le canari mélange les consommateurs, si les métriques deviennent incomplètes, si les retries s’amplifient ou si la correction déplace les refus vers le backend. Restaurez la policy exportée, vérifiez la policy effective à chaque scope, puis rejouez un test positif et un test limité. Le rollback est terminé lorsque le comportement des compteurs, le trafic backend et les headers clients correspondent de nouveau au contrat connu.

Conclusion

Un 429 après l’ajout de llm-token-limit n’est pas automatiquement la preuve d’un quota trop bas. Il peut signaler une clé partagée, une policy héritée deux fois, une différence entre gateways, une estimation incomplète ou des retries qui amplifient la demande.

La décision devient exploitable lorsque l’équipe sait qui a produit le refus, quel compteur a été touché et pourquoi. Corrigez d’abord l’isolation et la preuve ; n’augmentez le budget qu’avec une capacité backend et un coût assumés ; rollbackez dès que le canari ne permet plus d’attribuer précisément consommation et refus.