# Token-Based Rate Limiting & Quota Policies **Last updated:** 2026-02 **Status:** GA **Category:** API Management & AI Gateway --- ## Introduksjon Token-basert rate limiting er den viktigste mekanismen for å kontrollere forbruk av AI-tjenester i Azure API Management. I motsetning til tradisjonell request-basert throttling, teller APIM faktisk antall tokens som konsumeres av hver LLM-forespørsel og håndhever grenser basert på dette. Dette er essensielt for norsk offentlig sektor der flere etater og prosjekter deler Azure OpenAI-ressurser og trenger presis kostnadskontroll. APIM tilbyr to parallelle sett med token-policies: ett spesifikt for Azure OpenAI (`azure-openai-token-limit`) og ett generelt for alle LLM-er (`llm-token-limit`). Begge fungerer likt, men det generelle settet støtter også tredjeparts LLM-endepunkter som er kompatible med OpenAI API-formatet. For de fleste scenarier anbefales `llm-token-limit` da det gir størst fleksibilitet. I tillegg til tokens per minutt (TPM) rate limits, støtter APIM token-kvoter over lengre perioder (time, dag, uke, måned, år). Kombinasjonen av rate limits og kvoter gir finkornet kontroll: rate limits beskytter mot plutselige spikes, mens kvoter sikrer rettferdig fordeling over tid. --- ## Token-telling i APIM ### Hvordan APIM teller tokens APIM bruker to metoder for token-telling: | Metode | Tidspunkt | Nøyaktighet | Konfigurasjon | |--------|-----------|-------------|---------------| | **Estimert (prompt)** | Før request sendes til backend | Omtrentlig, basert på tegnantall | `estimate-prompt-tokens="true"` | | **Faktisk (completion)** | Etter respons fra backend | Eksakt, fra `usage`-feltet i respons | Alltid aktiv for completions | **Estimering av prompt tokens:** Når `estimate-prompt-tokens="true"` er satt, beregner APIM et estimat av prompt-tokens basert på innholdet i forespørselen. Dette muliggjør pre-validering: hvis estimatet allerede overskrider kvoten, avvises forespørselen umiddelbart uten å bruke backend-ressurser. ``` Token-estimat = f(antall tegn i prompt, modelltype) ``` > **Viktig:** Token-estimatet er en tilnærming. Det faktiske tokenforbruket kan avvike, spesielt for ikke-engelske tekster (norsk bruker typisk 20-40% flere tokens enn engelsk for tilsvarende tekst). ### Token-flyt i APIM ``` 1. Request mottas av APIM gateway 2. IF estimate-prompt-tokens=true: Estimer prompt tokens IF estimat > gjenstående kvote: RETURNER 429 umiddelbart (ingen backend-kall) 3. Send request til Azure OpenAI backend 4. Motta respons med usage-data: { "usage": { "prompt_tokens": 127, "completion_tokens": 350, "total_tokens": 477 } } 5. Oppdater token-teller med faktiske verdier 6. Emit metrikk til Application Insights ``` --- ## Policy-referanse ### llm-token-limit (anbefalt for nye implementasjoner) ```xml ``` **Attributter:** | Attributt | Påkrevd | Beskrivelse | Eksempel | |-----------|---------|-------------|---------| | `counter-key` | Ja | Nøkkel for å identifisere konsumenten | `@(context.Subscription.Id)` | | `tokens-per-minute` | Ja | Maks tokens per minutt (TPM) | `50000` | | `token-quota` | Nei | Total tokenkvote for perioden | `1000000` | | `token-quota-period` | Nei | Kvoteperiode | `hourly`, `daily`, `weekly`, `monthly`, `yearly` | | `estimate-prompt-tokens` | Nei | Pre-estimer prompt tokens | `true` / `false` | | `remaining-tokens-variable-name` | Nei | Variabel for gjenstående TPM | `remainingTokens` | | `remaining-token-quota-variable-name` | Nei | Variabel for gjenstående kvote | `remainingQuota` | | `tokens-consumed-variable-name` | Nei | Variabel for brukte tokens | `tokensConsumed` | | `retry-after-variable-name` | Nei | Variabel for retry-after sekunder | `retryAfter` | ### azure-openai-token-limit (Azure OpenAI-spesifikk) ```xml ``` > **Merk:** `azure-openai-token-limit` støtter kun TPM rate limiting, ikke token-kvoter over lengre perioder. Bruk `llm-token-limit` for full kvotestøtte. --- ## Counter-key-strategier Valg av `counter-key` bestemmer granulariteten av rate limiting: ### Strategi 1: Per subscription (standard) ```xml ``` **Bruk:** Standard for de fleste scenarier. Hvert team/prosjekt får egen APIM subscription med dedikert kvote. ### Strategi 2: Per IP-adresse ```xml ``` **Bruk:** Beskyttelse mot individuelle klienter som overforbruker. Nyttig for interne applikasjoner. ### Strategi 3: Per avdeling/etat (custom header) ```xml ``` **Bruk:** Offentlig sektor der flere etater deler infrastruktur. Krever at klienter sender header. ### Strategi 4: Per bruker (JWT claim) ```xml ``` **Bruk:** Individuell brukerbegrensning. Krever JWT-token med brukeridentitet. ### Strategi 5: Kombinert (subscription + bruker) ```xml ``` **Bruk:** Finkornet kontroll der hvert team har en total kvote, men individuelle brukere innen teamet også begrenses. --- ## Rate Limit-algoritmer ### Classic tiers: Sliding Window I Classic tiers (Developer, Basic, Standard, Premium) bruker APIM en sliding window-algoritme: ``` Tidslinje: [────────── 60 sek vindu ──────────] ^-- request evalueres her Tokens brukt i vinduet: 45 000 av 50 000 TPM Ny request med estimert 6 000 tokens → AVVIST (429) Ny request med estimert 4 000 tokens → GODKJENT ``` **Egenskaper:** - Jevn fordeling over tid - Kan gi uventede 429-svar ved burst-trafikk - Teller akkumuleres over glidende 60-sekunders vindu ### V2 tiers: Token Bucket V2 tiers (Basic v2, Standard v2, Premium v2) bruker en token bucket-algoritme: ``` Bucket-kapasitet: 50 000 tokens Refill rate: 50 000 tokens / 60 sek = 833 tokens/sek Tidspunkt 0: Bucket = 50 000 (full) Request A: -10 000 → Bucket = 40 000 Request B: -15 000 → Bucket = 25 000 ... 10 sek ... Refill: +8 330 → Bucket = 33 330 Request C: -35 000 → AVVIST (overstiger bucket) ``` **Egenskaper:** - Tillater korte bursts opp til bucket-kapasiteten - Jevnere throttling-opplevelse - Mer effektiv for ujevn trafikk (typisk for AI-workloads) --- ## Kvoter over lengre perioder ### Kvote vs. Rate Limit | Egenskap | Rate Limit (TPM) | Kvote | |----------|-------------------|-------| | **Tidshorisont** | Per minutt | Time, dag, uke, måned, år | | **Formål** | Beskytt mot spikes | Rettferdig fordeling over tid | | **Counter scope** | Per gateway-instans (regional) | Globalt (på tvers av regioner) | | **HTTP-kode ved overskridelse** | 429 Too Many Requests | 403 Forbidden | | **Retry-After header** | Ja | Ja | ### Eksempel: Månedlig kvote med daglig rate limit ```xml ``` ### Kvoteberegning for offentlig sektor Eksempel for en etat med 50 ansatte som bruker AI-tjenester: | Brukerkategori | Antall | TPM per bruker | Månedlig kvote per bruker | Total månedlig | |----------------|--------|----------------|---------------------------|----------------| | Power users | 5 | 10 000 | 500 000 | 2 500 000 | | Standard users | 30 | 3 000 | 100 000 | 3 000 000 | | Light users | 15 | 1 000 | 30 000 | 450 000 | | **Totalt** | **50** | - | - | **5 950 000** | **Buffer-anbefaling:** Legg til 20-30% buffer for uforutsette topper. --- ## Multi-region-hensyn ### Rate limits er regionale ``` APIM Gateway (Norway East) → Rate limit counter: 50 000 TPM APIM Gateway (Sweden Central) → Rate limit counter: 50 000 TPM (separate tellere!) ``` **Viktig:** I multi-region deployments har hver regional gateway sin egen rate limit-teller. En konsument kan potensielt bruke 50 000 TPM i Norway East OG 50 000 TPM i Sweden Central = 100 000 TPM totalt. ### Kvoter er globale ``` APIM Instance (global) ├── Gateway (Norway East) ─┐ └── Gateway (Sweden Central) ─┤── Delt kvote-teller: 2 000 000/mnd └── (synkronisert globalt) ``` **Anbefaling for offentlig sektor:** Bruk kvoter for total kostnadskontroll, og rate limits for burst-beskyttelse. Vurder å justere regionale rate limits basert på forventet trafikkfordeling. --- ## Feilhåndtering og respons-headers ### HTTP-responser ved overskridelse | Scenario | HTTP-kode | Response header | Body | |----------|-----------|-----------------|------| | TPM rate limit nådd | 429 | `Retry-After: ` | Feilmelding med gjenstående tokens | | Kvote brukt opp | 403 | `Retry-After: ` | Feilmelding med kvoteinformasjon | | Prompt estimat overskrider | 429 | `Retry-After: ` | Avvist uten backend-kall | ### Bruk av context-variabler ```xml @(context.Variables.GetValueOrDefault("remainingTokens").ToString()) @(context.Variables.GetValueOrDefault("tokensConsumed").ToString()) ``` --- ## Burst Allowances og Concurrency Control ### Kombinere token limit med concurrency limit For å beskytte mot mange samtidige store requests: ```xml ``` ### Burst-håndtering med Token Bucket (V2 tiers) Token bucket-algoritmen i V2 tiers tillater naturlig burst-kapasitet: | Konfigurasjon | Effektiv burst | Sustained rate | |---------------|----------------|----------------| | TPM=50 000 | Opp til 50 000 tokens i enkelt-request | ~833 tokens/sek | | TPM=100 000 | Opp til 100 000 tokens i enkelt-request | ~1 667 tokens/sek | | TPM=200 000 | Opp til 200 000 tokens i enkelt-request | ~3 333 tokens/sek | --- ## Monitorering av token-forbruk ### Token-metrikk policy ```xml ``` ### KQL-spørring for token-forbruk ```kusto customMetrics | where name == "Total Tokens" | extend etat = tostring(customDimensions["Etat"]) | summarize TotalTokens = sum(value) by etat, bin(timestamp, 1h) | order by timestamp desc | render timechart ``` ### Azure Monitor Alert for kvote-overskridelse ```json { "type": "Microsoft.Insights/metricAlerts", "properties": { "criteria": { "metricName": "Total Tokens", "metricNamespace": "ai-token-usage", "operator": "GreaterThan", "threshold": 4000000, "timeAggregation": "Total", "dimensions": [ { "name": "Subscription", "operator": "Include", "values": ["*"] } ] }, "windowSize": "P1D", "evaluationFrequency": "PT1H" } } ``` --- ## Tier-kompatibilitet | Policy | Classic | V2 | Consumption | Self-hosted | Workspace | |--------|---------|----|-----------|----------- |-----------| | `azure-openai-token-limit` | Ja | Ja | Nei | Ja | Ja | | `llm-token-limit` | Ja | Ja | Nei | Ja | Ja | | `azure-openai-emit-token-metric` | Ja | Ja | Nei | Ja | Ja | | `llm-emit-token-metric` | Ja | Ja | Nei | Ja | Ja | | `rate-limit-by-key` | Ja | Ja | Nei | Ja | Ja | | `quota-by-key` | Ja | Nei | Nei | Ja | Ja | > **Merk:** Token-policies er IKKE tilgjengelige i Consumption tier. For AI-workloads, bruk minimum Basic v2 eller Standard v2. --- ## Best Practices ### Anbefalt oppsett for norsk offentlig sektor 1. **Bruk `llm-token-limit`** fremfor `azure-openai-token-limit` for fremtidig fleksibilitet 2. **Aktiver `estimate-prompt-tokens`** for å avvise for store requests tidlig 3. **Kombiner TPM rate limit med månedlig kvote** for dobbel beskyttelse 4. **Bruk subscription-basert counter-key** som primær granularitet 5. **Legg til custom header-dimensjoner** for kostnadsrapportering per etat/prosjekt 6. **Sett opp Azure Monitor Alerts** ved 80% kvotebruk 7. **Dokumenter kvoteallokeringer** i tjenestekataloger og SLA-er 8. **Test med GenAI Gateway Toolkit** for å verifisere policy-oppførsel under last --- ## For Cosmo - Token rate limiting er den viktigste AI gateway-policyen -- alltid start her når du setter opp APIM for Azure OpenAI. Bruk `llm-token-limit` som standard, med `estimate-prompt-tokens="true"` for tidlig avvisning. - Counter-key-strategien bestemmer granulariteten: subscription-basert for team-nivå, custom headers for etat/prosjekt, JWT claims for bruker-nivå. For offentlig sektor anbefales subscription per team + custom header for kostnadsrapportering. - V2 tiers bruker token bucket-algoritme som håndterer bursts bedre enn sliding window i Classic tiers -- anbefal Standard v2 for nye deployments. - Rate limits er regionale (per gateway-instans), men kvoter er globale. I multi-region oppsett må du dimensjonere rate limits per region, men bruke kvoter for total kostnadskontroll. - Kombiner alltid `llm-token-limit` med `llm-emit-token-metric` for full observabilitet, og sett opp alerts ved 80% kvotebruk for proaktiv kapasitetsstyring.