Ordre 20260912T193441Z-7358817909. Steg 1 var ikke transformen, men å rette
roadmapens R13-gate og få den ratifisert. Gaten `grep -rl "Cosmo"
skills/*/references -> 0` var usann på to uavhengige måter:
1. Ordren fanget den første: 451 av forekomstene er Azure Cosmos DB, ekte
produktinnhold. Diskriminatoren er ikke bokstaven «s» — `Cosmos <norsk
substantiv>` er genitiv av personaen (`### Cosmos tonalitet`), mens
`Cosmos DB`/`CosmosClient`/`cosmos_ru` er produkt.
2. Denne økten fant den andre: 132 persona-forekomster ligger i prosa,
tabeller, dialog-replikker og proveniens-linjer. Heading-nøytralisering
kan ikke nå dem, så «0 persona» er uoppnåelig også under den ratifiserte
formen. Operatøren ratifiserte alternativ A: gaten speiler formen, og de
132 bokføres til R13b/R14.
Tre korreksjoner av premisser som sto i ordren og STATE:
«ca 320 produkt» -> 451 (case-sensitivt nett manglet 327 lowercase
TOC-ankre + 99 identifikatorer; sann nevner 1 638)
«169 headinger» -> 401. 169 var `^## For Cosmo`-prefikset (168) og var
internt inkonsistent med sin egen topp-variant (204)
«417 matcher ingen
populasjon» -> 417 er cosmo-headinger utenfor kodefences; briefens
nevner var reell hele tiden
Fence-bevissthet er målt skadelig, ikke nødvendig: begge toggle-regler er
gale på dette korpuset (naiv toggle skjuler en ekte heading i
chain-of-thought-prompting.md, CommonMark-regelen ubalanserer
service-level-documentation-dr.md). Fence-agnostisk deteksjon finner 401
heading-linjer i nøyaktig de samme 40 variantene som fence-bevisst finner
400 i — ingen kodeblokk-linje er byte-identisk til en persona-heading. Derfor
nøkles transformen på 40 enumererte heading-tekster og ignorerer fences. En
ukjent variant kaster; en slug-kollisjon kaster. Ingenting auto-fikses.
TOC-en regenereres ikke, den rettes kirurgisk: alle 327 persona-lenker hadde
lenketekst lik én av de 40 heading-tekstene og anker lik slugify av den
(327/327, 0 avvik), så heading og TOC-entry skrives i samme operasjon og
ingen mellomtilstand etterlater en død lenke.
Ratifisert målform: `For Cosmo`, `For Cosmo Skyberg` og `For arkitekten
(Cosmo)` konvergerer på `For arkitekten`. To filer kolliderte og er adjudisert
ved å lese dem, ikke ved regel.
Verifisering (alle 7 kriterier fra ordren):
G1 persona på heading-linjer 401 -> 0
G2 døde fragmentlenker 1 -> 1 (pre-eksisterende, unntatt)
G3 produkt-forekomster 451 -> 451; `Cosmos DB|Azure Cosmos` 308 = 308
de 3 kun-produkt-filene byte-identiske
nettet validert begge veier injisert persona feller G1; genitiv feller G1;
produkt-heading og de 3 filene passerer
hele diffen 802 heading-linjer + 654 TOC-linjer, ANNET = 0
linjeantall 728 lagt til = 728 slettet
suite 1120/1120 (1097 + 23 nye)
validate-plugin 250 PASS / 0 FAIL
stikkprøve 10 filer, alle 5 skills, inkl. de 3 mest
produkt-tunge (26/20/19) — kun heading+TOC
Utenfor scope, urørt: de 4 SKILL.md, de 23 commands, CLAUDE.md, README.md,
NOTICE.md, docs/ (alt R14).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
19 KiB
Circuit Breaker Patterns for AI Models
Last updated: 2026-02 Status: GA Category: API Management & AI Gateway Type: reference
Innhold
- Introduksjon
- Circuit Breaker State Machine
- Konfigurasjon
- Failure Threshold Tuning
- Fallback-policies
- Recovery-mekanismer
- Timeout-konfigurasjon
- Avanserte mønstre
- Anti-mønstre
- Komplett resiliens-policy
- For arkitekten
Introduksjon
Circuit breaker-mønsteret er en grunnleggende resiliensmekanisme for AI-applikasjoner som kommuniserer med Azure OpenAI og andre LLM-backends. Når en backend-tjeneste blir overbelastet eller utilgjengelig, forhindrer circuit breaker at applikasjonen fortsetter å sende forespørsler som uansett vil feile. I stedet "bryter kretsen" og returnerer en feilmelding umiddelbart, slik at backend-tjenesten får tid til å gjenopprette seg.
For Azure AI-tjenester er circuit breaker spesielt viktig fordi Azure OpenAI returnerer 429 (Too Many Requests) med en Retry-After-header som kan ha verdier opp til 24 timer. Uten circuit breaker vil applikasjoner fortsette å hamre på en throttlet tjeneste, noe som forverrer situasjonen og kaster bort gateway-ressurser. APIMsintegrerte circuit breaker håndterer dette automatisk ved å respektere Retry-After-headeren.
I kombinasjon med backend pools og lastbalansering utgjør circuit breaker selve nervesystemet i en intelligent AI-gateway: den detekterer problemer, isolerer feilende backends, ruter trafikk til friske alternativer, og gjenoppretter normal drift automatisk når backend er tilbake.
Circuit Breaker State Machine
Tre tilstander
Circuit breaker opererer som en tilstandsmaskin med tre tilstander:
Feil > threshold
┌─────────┐ ───────────────► ┌──────────┐
│ CLOSED │ │ OPEN │
│ (normal)│ ◄────────────── │ (trip) │
└─────────┘ Alle OK i └──────────┘
│ half-open │
│ │ Trip duration
│ │ utløpt
│ ┌──────────────┐ │
│ │ HALF-OPEN │◄───┘
│ │ (test) │
│ └──────────────┘
│ │
│ Suksess │ Feil
◄──────────────┘───────────► OPEN
| Tilstand | Oppførsel | Varighet |
|---|---|---|
| Closed | Normal drift, alle requests videresendes til backend | Ubegrenset (til feilbetingelse oppstår) |
| Open | Alle requests avvises umiddelbart med 503 | Trip duration (konfigurerbar, eller fra Retry-After) |
| Half-Open | Et begrenset antall test-requests sendes til backend | Til nok suksesser ELLER ny feil |
APIM-spesifikk oppførsel
APIMcircuit breaker har noen viktige forskjeller fra den generelle circuit breaker-mønsteret:
| Egenskap | APIM Circuit Breaker |
|---|---|
| Konfigurasjons-scope | Per backend (ikke per API eller policy) |
| Antall regler | Kun én regel per backend (p.t.) |
| Synkronisering | Ingen mellom gateway-instanser (approksimasjon) |
| Retry-After respekt | Ja, dynamisk trip duration basert på backend-respons |
| Støttede tiers | Alle unntatt Consumption |
| Respons ved Open | 503 Service Unavailable |
Konfigurasjon
Grunnleggende circuit breaker for Azure OpenAI
resource openaiBackend 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
parent: apim
name: 'openai-norwayeast'
properties: {
url: 'https://aoai-norwayeast.openai.azure.com/openai'
protocol: 'http'
circuitBreaker: {
rules: [
{
name: 'ai-resilience-rule'
failureCondition: {
count: 3
interval: 'PT1M'
statusCodeRanges: [
{ min: 429, max: 429 }
{ min: 500, max: 599 }
]
}
tripDuration: 'PT10S'
acceptRetryAfter: true
}
]
}
}
}
Attributter forklart
| Attributt | Type | Beskrivelse | Anbefalt verdi for AI |
|---|---|---|---|
failureCondition.count |
int | Antall feil som trigger trip | 3-5 |
failureCondition.interval |
duration | Tidsvindu for feil-telling | PT1M (1 minutt) |
failureCondition.statusCodeRanges |
array | HTTP-koder som teller som feil | 429 + 500-599 |
tripDuration |
duration | Hvor lenge circuit er åpent | PT10S - PT1M |
acceptRetryAfter |
bool | Bruk Retry-After header som trip duration | true (alltid for AI) |
Prosentbasert vs. count-basert triggering
APIM støtter to modeller for feil-deteksjon:
Count-basert (anbefalt for AI):
{
"failureCondition": {
"count": 3,
"interval": "PT1M",
"statusCodeRanges": [{"min": 429, "max": 429}]
}
}
Trigger: 3 eller flere 429-responser innen 1 minutt.
Prosentbasert:
{
"failureCondition": {
"percentage": 50,
"interval": "PT1M",
"statusCodeRanges": [{"min": 429, "max": 429}]
}
}
Trigger: 50% eller mer av requests feiler innen 1 minutt.
Anbefaling: Count-basert er mer forutsigbar for AI-workloads. Prosentbasert kan gi falske positiver ved lav trafikk (2 av 3 requests feiler = 66%).
Failure Threshold Tuning
Faktorene som påvirker threshold
| Faktor | Lav threshold (1-2) | Høy threshold (5-10) |
|---|---|---|
| Reaksjonstid | Rask, reagerer umiddelbart | Tregere, tolererer noen feil |
| Falske positiver | Høy risiko | Lav risiko |
| Backend-beskyttelse | Sterk, minimal ekstra belastning | Svakere, flere feil-requests |
| Anbefalt for | Kritiske, kapasitetsbegrensede backends | Robuste backends med transiente feil |
Anbefalte innstillinger per scenario
| Scenario | count | interval | tripDuration | acceptRetryAfter |
|---|---|---|---|---|
| PTU-instans (high priority) | 3 | PT1M | PT10S | true |
| PAYGO-instans (fallback) | 5 | PT2M | PT30S | true |
| Dev/test | 2 | PT30S | PT5S | true |
| Business-critical | 3 | PT1M | PT10S | true |
| Batch processing | 10 | PT5M | PT1M | true |
Dynamisk trip duration med Retry-After
Når acceptRetryAfter: true er satt, overstyrer Azure OpenAIs Retry-After-header den konfigurerte tripDuration:
Scenario: OpenAI returnerer 429 med Retry-After: 30
→ Circuit breaker åpner i 30 sekunder (ikke konfiguert tripDuration)
→ Etter 30 sekunder: half-open → test request
→ Suksess: circuit lukkes
→ Feil: circuit åpner igjen med ny Retry-After
Scenario: OpenAI returnerer 429 med Retry-After: 86400 (1 dag!)
→ Circuit breaker åpner i 24 timer
→ All trafikk rutes til andre backends i poolen
Viktig advarsel: Azure OpenAI kan returnere Retry-After verdier opp til 1 dag (86400 sekunder). Med
acceptRetryAfter: truevil dette bety at backend er utilgjengelig i 24 timer. Sørg for at backend-poolen har nok kapasitet i andre backends til å håndtere dette.
Fallback-policies
Mønster 1: Backend Pool med automatisk failover
Den enkleste og mest robuste tilnærmingen:
<policies>
<inbound>
<!-- Backend pool håndterer failover automatisk -->
<set-backend-service backend-id="openai-pool-priority" />
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</inbound>
</policies>
Når circuit breaker utløses på Priority 1-backends, ruter APIM automatisk til Priority 2, osv.
Mønster 2: Retry med backend-bytte
Eksplisitt retry-logikk som bytter backend ved 429:
<policies>
<backend>
<retry condition="@(context.Response.StatusCode == 429)"
count="3"
interval="0"
first-fast-retry="true">
<set-backend-service backend-id="openai-pool-priority" />
</retry>
</backend>
</policies>
Viktig: interval="0" betyr umiddelbar retry til neste backend, IKKE ventetid. Server-side retries bør aldri ha delay — det holder opp klienten og bruker gateway-ressurser.
Mønster 3: Graceful Degradation med cache-fallback
<policies>
<inbound>
<!-- Prøv semantic cache først -->
<azure-openai-semantic-cache-lookup
score-threshold="0.20"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned" />
<set-backend-service backend-id="openai-pool-priority" />
</inbound>
<on-error>
<choose>
<!-- Alle backends utilgjengelige -->
<when condition="@(context.Response.StatusCode == 503)">
<return-response>
<set-status code="503" reason="AI Service Temporarily Unavailable" />
<set-header name="Retry-After" exists-action="override">
<value>60</value>
</set-header>
<set-body>@{
return new JObject(
new JProperty("error", new JObject(
new JProperty("code", "service_unavailable"),
new JProperty("message", "AI-tjenesten er midlertidig utilgjengelig. Prøv igjen om 60 sekunder."),
new JProperty("type", "circuit_breaker_open")
))
).ToString();
}</set-body>
</return-response>
</when>
</choose>
</on-error>
</policies>
Mønster 4: Fallback til enklere modell
<policies>
<backend>
<retry condition="@(context.Response.StatusCode == 429 || context.Response.StatusCode == 503)"
count="1"
interval="0"
first-fast-retry="true">
<!-- Fallback til mindre modell -->
<set-backend-service backend-id="openai-gpt4o-mini-backend" />
<rewrite-uri template="/deployments/gpt-4o-mini/chat/completions" />
</retry>
</backend>
</policies>
Recovery-mekanismer
Automatisk recovery
Circuit breaker håndterer recovery automatisk:
1. Trip: Circuit åpner (503 til klienter)
2. Wait: tripDuration utløper (eller Retry-After)
3. Half-Open: Test-request sendes til backend
4. Success: Circuit lukkes, normal drift gjenopptas
5. Failure: Circuit åpner igjen, ny tripDuration starter
Recovery-timing
| Kilde | Prioritet | Typisk verdi |
|---|---|---|
Retry-After header (når acceptRetryAfter: true) |
Høyest | 1-86400 sekunder |
Konfigurert tripDuration |
Fallback | PT10S - PT1M |
| Default (uten konfigurasjon) | Lavest | PT1M |
Overvåking av circuit breaker-tilstand
<outbound>
<!-- Log circuit breaker state -->
<trace source="circuit-breaker" severity="information">
<message>@{
var backendId = context.Backend?.Id ?? "unknown";
var statusCode = context.Response.StatusCode;
return $"Backend: {backendId}, Status: {statusCode}";
}</message>
</trace>
</outbound>
KQL for circuit breaker-hendelser:
ApiManagementGatewayLogs
| where ResponseCode == 503
| extend backendId = tostring(parse_json(BackendResponseBody).backendId)
| summarize CircuitBreakerTrips = count() by backendId, bin(TimeGenerated, 5m)
| render timechart
Timeout-konfigurasjon
Forward-request timeout
Kontroller hvor lenge APIM venter på backend-respons:
<policies>
<backend>
<forward-request timeout="120" />
</backend>
</policies>
Anbefalte timeouts for AI-workloads:
| Operasjon | Anbefalt timeout | Begrunnelse |
|---|---|---|
| Chat Completion (standard) | 60-120 sek | GPT-4o kan bruke tid på komplekse prompts |
| Chat Completion (streaming) | 120-180 sek | Streaming starter raskt, men kan vare lenge |
| Embeddings | 30-60 sek | Raskere operasjon, typisk < 10 sek |
| Image Generation (DALL-E) | 120-180 sek | Bildegenerering er CPU-intensivt |
| Assistants API | 180-300 sek | Multi-step agent workflows |
| Batch API | 300-600 sek | Store batch-operasjoner |
Timeout + Circuit Breaker interaksjon
Timeout utløper (120 sek)
→ APIM registrerer det som feil
→ Teller mot circuit breaker threshold
→ Etter N timeouts → Circuit breaker trip
→ Backend fjernes fra pool → Trafikk til alternativer
Best practice: Sett timeout lavere enn det du tror er nødvendig. Bedre å få rask feil og retry til annen backend enn å vente 120 sekunder på en hengende request.
Avanserte mønstre
Mønster: Cascading Circuit Breakers
For multi-tier arkitekturer der APIM ruter til mellomtjenester som igjen kaller Azure OpenAI:
Client → APIM [CB-1] → Custom Service [CB-2] → Azure OpenAI
// CB-1: APIM → Custom Service
resource customServiceBackend 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
properties: {
circuitBreaker: {
rules: [{
failureCondition: {
count: 5
interval: 'PT2M'
statusCodeRanges: [
{ min: 502, max: 504 }
]
}
tripDuration: 'PT30S'
}]
}
}
}
Applikasjons-nivå CB-2 implementeres med Polly (.NET), resilience4j (Java), eller tilsvarende.
Mønster: Health Endpoint Monitoring
Kombiner circuit breaker med aktiv health checking:
<policies>
<inbound>
<!-- Sjekk health endpoint før ruting -->
<send-request mode="new"
response-variable-name="healthCheck"
timeout="5"
ignore-error="true">
<set-url>@("https://aoai-norwayeast.openai.azure.com/openai/models?api-version=2024-10-21")</set-url>
<set-method>GET</set-method>
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</send-request>
<choose>
<when condition="@(((IResponse)context.Variables["healthCheck"]).StatusCode != 200)">
<!-- Backend er nede, bruk fallback direkte -->
<set-backend-service backend-id="openai-fallback-pool" />
</when>
<otherwise>
<set-backend-service backend-id="openai-primary-pool" />
</otherwise>
</choose>
</inbound>
</policies>
Merk: Health endpoint monitoring legger til latens og backend-belastning. Bruk det kun for scenarier der circuit breaker alene ikke gir rask nok failover.
Anti-mønstre
| Anti-mønster | Problem | Løsning |
|---|---|---|
| Ingen circuit breaker | Backend overbelastes, cascading failure | Aktiver circuit breaker på alle AI-backends |
| For lav threshold (count=1) | Falske positiver ved transiente feil | Bruk count=3-5 for produksjon |
| For lang tripDuration | Backend er unødvendig utilgjengelig | Bruk acceptRetryAfter: true |
| Ignorere Retry-After | Hammer backend som eksplisitt ber om pause | Sett acceptRetryAfter: true alltid |
| Server-side delay | Retry med sleep/delay holder opp klienter | Bruk interval="0" med backend pool failover |
| Timeout for lang | Gateway-ressurser brukt opp på hengende requests | Sett realistiske timeouts per operasjonstype |
| Mangle monitoring | Ingen innsikt i circuit breaker-oppførsel | Emit metrikk + KQL dashboards |
Komplett resiliens-policy
<policies>
<inbound>
<!-- 1. Token rate limiting -->
<llm-token-limit
counter-key="@(context.Subscription.Id)"
tokens-per-minute="50000"
estimate-prompt-tokens="true" />
<!-- 2. Backend pool med circuit breaker -->
<set-backend-service backend-id="openai-pool-priority" />
<!-- 3. Managed Identity auth -->
<authentication-managed-identity
resource="https://cognitiveservices.azure.com/" />
</inbound>
<backend>
<!-- 4. Retry til annen backend ved 429 -->
<retry condition="@(context.Response.StatusCode == 429)"
count="3"
interval="0"
first-fast-retry="true">
<set-backend-service backend-id="openai-pool-priority" />
</retry>
<!-- 5. Timeout -->
<forward-request timeout="120" />
</backend>
<outbound>
<!-- 6. Token metrikk -->
<llm-emit-token-metric namespace="ai-gateway">
<dimension name="Backend" value="@(context.Backend?.Id ?? "unknown")" />
<dimension name="StatusCode" value="@(context.Response.StatusCode.ToString())" />
</llm-emit-token-metric>
</outbound>
<on-error>
<!-- 7. Graceful degradation -->
<choose>
<when condition="@(context.Response.StatusCode == 503)">
<return-response>
<set-status code="503" reason="AI Service Unavailable" />
<set-header name="Retry-After" exists-action="override">
<value>60</value>
</set-header>
<set-body>{"error":{"code":"all_backends_unavailable","message":"Alle AI-backends er midlertidig utilgjengelige"}}</set-body>
</return-response>
</when>
</choose>
</on-error>
</policies>
For arkitekten
- Circuit breaker er obligatorisk for alle Azure OpenAI backends i produksjon -- uten det risikerer du cascading failures og bortkastet gateway-kapasitet mot throttlede backends.
- Sett ALLTID
acceptRetryAfter: truefor Azure OpenAI backends. Azure OpenAI returnerer presise Retry-After verdier som gir optimal recovery-timing. Uten dette bruker du den statiske tripDuration som kan være for kort eller for lang. - Anbefalt baseline:
count: 3,interval: PT1M,tripDuration: PT10S,acceptRetryAfter: true. Juster count opp for PAYGO-backends med mer toleranse. - Kombiner circuit breaker med backend pools for automatisk failover: når PTU-backend tripper, ruter APIM automatisk til PAYGO-backends uten klient-endringer.
- Advarsler: Azure OpenAI kan returnere Retry-After opp til 86400 sekunder (1 dag). Sørg for at arkitekturen har nok alternative backends til å håndtere langvarige circuit breaks.