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>
16 KiB
Caching Strategies for AI Responses in APIM
Last updated: 2026-06-24 Status: GA Category: API Management & AI Gateway Type: reference Source: https://learn.microsoft.com/azure/api-management/caching-overview
Innhold
- Introduksjon
- Prompt-baserte caching-nokler
- Semantisk deduplisering
- TTL-konfigurasjon
- Cache-invalidering
- Kostnadsbesparelsesanalyse
- Caching-tjenester: Intern vs. Ekstern
- Referanser
- For arkitekten
Introduksjon
Caching er en av de mest effektive strategiene for a redusere kostnader og forbedre ytelse i AI-applikasjoner. Azure API Management tilbyr bade tradisjonell HTTP-caching og semantisk caching spesielt designet for LLM-API-er. Semantisk caching bruker embedding-vektorer for a identifisere prompts som er semantisk like -- ikke bare identiske -- og returnere cachede svar uten a kalle backend-modellen.
For norsk offentlig sektor kan caching-strategier gi vesentlige besparelser. En typisk offentlig virksomhet som bruker Azure OpenAI for chatbot-tjenester, intern dokumentanalyse eller innbyggerveiledning vil ofte motta mange lignende sporsmol. Semantisk caching kan redusere token-forbruket med 20-40% for slike workloads, med tilsvarende kostnadsbesparelse og forbedret responstid.
APIM stotter to hovedtyper caching: intern (innebygd) og ekstern (Redis-basert). For semantisk caching av AI-svar er ekstern cache via Azure Managed Redis med RediSearch-modulen pakrevd. Denne referansen dekker bade tradisjonell og semantisk caching, med fokus pa praktisk implementering for AI-workloads.
Prompt-baserte caching-nokler
Tradisjonell caching med eksakte matcher
For identiske prompts kan standard cache-lookup / cache-store policies brukes:
<policies>
<inbound>
<base />
<!-- Cache lookup based on exact request body hash -->
<cache-lookup vary-by-developer="false" vary-by-developer-groups="false">
<vary-by-header>x-tenant-id</vary-by-header>
<vary-by-query-parameter>model</vary-by-query-parameter>
</cache-lookup>
</inbound>
<outbound>
<base />
<!-- Store response in cache for 5 minutes -->
<cache-store duration="300" />
</outbound>
</policies>
Custom cache-nokler for AI-foresporsler
Bygg tilpassede cache-nokler basert pa prompt-innhold:
<policies>
<inbound>
<base />
<!-- Generate cache key from normalized prompt content -->
<set-variable name="cacheKey" value="@{
var body = context.Request.Body.As<JObject>(preserveContent: true);
var messages = (JArray)body?["messages"];
if (messages == null) return "";
// Build key from role+content pairs, normalized
var keyParts = new System.Collections.Generic.List<string>();
foreach (var msg in messages)
{
var role = msg["role"]?.ToString() ?? "";
var content = msg["content"]?.ToString()?.Trim().ToLower() ?? "";
keyParts.Add($"{role}:{content}");
}
var model = body["model"]?.ToString() ?? "default";
var combined = model + "|" + string.Join("|", keyParts);
// Generate SHA256 hash
using (var sha = System.Security.Cryptography.SHA256.Create())
{
var bytes = sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(combined));
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}" />
<!-- Lookup in cache -->
<cache-lookup-value key="@((string)context.Variables["cacheKey"])"
variable-name="cachedResponse" />
<choose>
<when condition="@(context.Variables.ContainsKey("cachedResponse"))">
<return-response>
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-header name="x-cache-hit" exists-action="override">
<value>true</value>
</set-header>
<set-body>@((string)context.Variables["cachedResponse"])</set-body>
</return-response>
</when>
</choose>
</inbound>
<outbound>
<base />
<!-- Store successful responses in cache -->
<choose>
<when condition="@(context.Response.StatusCode == 200)">
<cache-store-value key="@((string)context.Variables["cacheKey"])"
value="@(context.Response.Body.As<string>(preserveContent: true))"
duration="600" />
<set-header name="x-cache-hit" exists-action="override">
<value>false</value>
</set-header>
</when>
</choose>
</outbound>
</policies>
Semantisk deduplisering
Oversikt over semantisk caching i APIM
Semantisk caching bruker embeddings for a matche prompts basert pa meningsbetydning, ikke bare eksakt tekst. To prompts som "Hva er Microsoft Azure?" og "Kan du forklare hva Azure er?" vil ga i cache-treff selv om ordlyden er ulik.
Arkitektur
Klient --> APIM --> [Semantic Cache Lookup] --> Azure Managed Redis (RediSearch)
| |
| (cache miss) | (cache hit)
v v
[Embeddings API] [Returner cached svar]
|
v
[AI Backend (Chat)]
|
v
[Semantic Cache Store] --> Azure Managed Redis
Forutsetninger
| Komponent | Krav |
|---|---|
| Azure Managed Redis | RediSearch-modul aktivert (velges ved opprettelse) |
| Embeddings deployment | text-embedding-ada-002 eller nyere modell |
| APIM | Alle tiers stotter semantisk caching med ekstern cache |
| Autentisering | Managed Identity til bade OpenAI og Redis |
Konfigurering av semantisk caching
1. Opprett embeddings-backend
<!-- Backend for embeddings API -->
<set-backend-service backend-id="embeddings-backend" />
I Azure Portal:
- Type: Custom URL
- Runtime URL:
https://{aoai-name}.openai.azure.com/openai/deployments/{embedding-deployment}/embeddings - Managed Identity: System-assigned, Resource ID:
https://cognitiveservices.azure.com/
2. Konfigurer semantic cache lookup (inbound)
For Azure OpenAI API-er:
<policies>
<inbound>
<base />
<!-- Semantic cache lookup -->
<azure-openai-semantic-cache-lookup
score-threshold="0.15"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned"
ignore-system-messages="true"
max-message-count="10">
<vary-by>@(context.Subscription.Id)</vary-by>
</azure-openai-semantic-cache-lookup>
<!-- Rate limit as fallback if cache is unavailable -->
<rate-limit calls="20" renewal-period="60" />
</inbound>
</policies>
For andre LLM-API-er (ikke Azure OpenAI):
<policies>
<inbound>
<base />
<llm-semantic-cache-lookup
score-threshold="0.15"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned"
ignore-system-messages="true"
max-message-count="10">
<vary-by>@(context.Subscription.Id)</vary-by>
</llm-semantic-cache-lookup>
</inbound>
</policies>
3. Konfigurer semantic cache store (outbound)
<policies>
<outbound>
<base />
<!-- Store response for 60 seconds -->
<azure-openai-semantic-cache-store duration="60" />
</outbound>
</policies>
TTL-konfigurasjon
Strategier for Time-to-Live
Riktig TTL-konfigurasjon balanserer mellom kostnadsbesparelse og datakvalitet:
| Bruksscenario | Anbefalt TTL | Begrunnelse |
|---|---|---|
| FAQ/statisk veiledning | 3600s (1 time) | Innholdet endres sjelden |
| Generell chatbot | 300s (5 min) | Balanse mellom friskhet og kostnad |
| Dokumentanalyse | 600s (10 min) | Dokumenter endres sjelden innen sesjon |
| Sanntidsdata-sporring | 30-60s | Data kan endres raskt |
| Kodegenerering | 120s (2 min) | Brukere itererer raskt |
| Intern kunnskapssok | 1800s (30 min) | Intern kunnskap er relativt stabil |
Dynamisk TTL basert pa kontekst
<policies>
<outbound>
<base />
<!-- Dynamic TTL based on request type -->
<set-variable name="cacheDuration" value="@{
var body = context.Request.Body.As<JObject>(preserveContent: true);
var messages = (JArray)body?["messages"];
var lastMessage = messages?.Last?["content"]?.ToString() ?? "";
// Longer TTL for FAQ-like questions
if (lastMessage.Contains("hva er") || lastMessage.Contains("forklar"))
return 3600;
// Shorter TTL for data queries
if (lastMessage.Contains("status") || lastMessage.Contains("siste"))
return 60;
// Default TTL
return 300;
}" />
<azure-openai-semantic-cache-store
duration="@((int)context.Variables["cacheDuration"])" />
</outbound>
</policies>
Cache-invalidering
Manuell invalidering med cache-remove-value
<!-- Remove specific cached value -->
<cache-remove-value key="specific-cache-key" />
Automatisk invalidering ved modellbytte
<policies>
<inbound>
<base />
<!-- Include model version in cache key to auto-invalidate on model change -->
<azure-openai-semantic-cache-lookup
score-threshold="0.15"
embeddings-backend-id="embeddings-backend"
embeddings-backend-auth="system-assigned"
ignore-system-messages="true"
max-message-count="10">
<!-- Vary by model deployment to invalidate cache on model update -->
<vary-by>@(context.Subscription.Id)</vary-by>
<vary-by>@(context.Request.Headers.GetValueOrDefault("x-model-version", "default"))</vary-by>
</azure-openai-semantic-cache-lookup>
</inbound>
</policies>
Cache-invalidering via API-kall
Opprett en dedikert operasjon for administratorer:
<!-- Cache purge operation -->
<policies>
<inbound>
<base />
<!-- Verify admin access -->
<validate-jwt header-name="Authorization"
failed-validation-httpcode="401"
failed-validation-error-message="Unauthorized">
<required-claims>
<claim name="roles" match="any">
<value>CacheAdmin</value>
</claim>
</required-claims>
</validate-jwt>
<!-- Purge cache - requires external cache API call -->
<send-request mode="new" response-variable-name="purgeResult" timeout="10">
<set-url>@($"https://{cacheHost}:10000/FLUSHDB")</set-url>
<set-method>POST</set-method>
</send-request>
<return-response>
<set-status code="200" reason="Cache Purged" />
<set-body>{"status":"cache_purged","timestamp":"@(DateTime.UtcNow.ToString("o"))"}</set-body>
</return-response>
</inbound>
</policies>
Kostnadsbesparelsesanalyse
Beregningsmodell
| Parameter | Verdi |
|---|---|
| Gjennomsnittlig tokens per request | 2 000 (prompt) + 500 (completion) |
| GPT-4o pris per 1M input tokens | $2.50 |
| GPT-4o pris per 1M output tokens | $10.00 |
| Antall requests per dag | 10 000 |
| Gjennomsnittlig cache hit rate | 30% |
Kostnadsberegning
| Scenario | Daglig kostnad (NOK) | Manedlig kostnad (NOK) |
|---|---|---|
| Uten caching | ~750 | ~22 500 |
| Med 30% cache hit | ~525 | ~15 750 |
| Med 50% cache hit | ~375 | ~11 250 |
| Med 70% cache hit | ~225 | ~6 750 |
Tilleggskostnader for caching-infrastruktur
| Komponent | Manedlig kostnad (NOK) |
|---|---|
| Azure Managed Redis (Balanced B1) | ~2 500 |
| Embeddings API-kall (for semantisk caching) | ~150 |
| Total caching-overhead | ~2 650 |
Netto besparelse ved 30% hit rate
- Besparelse: 22 500 - 15 750 = 6 750 NOK/mnd
- Caching-kostnad: 2 650 NOK/mnd
- Netto besparelse: ~4 100 NOK/mnd (18% av total)
Score-threshold tuning
score-threshold i semantisk caching pavirker hit rate og kvalitet:
| Threshold | Hit Rate | Kvalitetsrisiko |
|---|---|---|
| 0.05 | Hoy (50-70%) | Hoy -- kan returnere irrelevante svar |
| 0.10 | Middels-hoy (30-50%) | Lav-middels |
| 0.15 (anbefalt) | Middels (20-35%) | Lav |
| 0.25 | Lav (10-15%) | Svart lav |
| 0.50 | Svart lav (<5%) | Neglisjerbar |
Caching-tjenester: Intern vs. Ekstern
| Egenskap | Intern cache | Ekstern (Redis) |
|---|---|---|
| Automatisk provisjonering | Ja | Nei |
| Tilleggskostnad | Nei | Ja |
| Semantisk caching | Nei | Ja |
| Tilgjengelig i alle tiers | Nei (ikke Consumption) | Ja |
| Persistent lagring | Ja (v2), Nei (classic) | Ja |
| Delt mellom instanser | Nei | Ja |
| Data preloading | Nei | Ja |
Referanser
- Caching overview in Azure API Management -- oversikt over caching-alternativer
- Enable semantic caching for LLM APIs -- trinnvis veiledning
- AI gateway capabilities - Semantic caching -- AI gateway-kontekst
- llm-semantic-cache-lookup policy -- policy-referanse
- llm-semantic-cache-store policy -- policy-referanse
- Set up an external cache in Azure API Management -- Redis-oppsett
- Application design for AI workloads - Caching strategies -- Well-Architected-anbefalinger
For arkitekten
- Bruk denne referansen nar kunden onsker a redusere AI-kostnader gjennom caching, eller nar de trenger a forbedre responstider for brukere som stiller lignende sporsmol.
- Start med
score-threshold="0.15"for semantisk caching -- dette gir god balanse. Juster ned til 0.10 for hoyere hit rate i FAQ-scenarier, eller opp til 0.25 for mer presise matcher i kritiske applikasjoner. - Husk at semantisk caching krever Azure Managed Redis med RediSearch-modulen -- denne modulen ma velges ved opprettelse av Redis-instansen og kan ikke legges til i ettertid.
- For norsk offentlig sektor med hoy grad av repetitive sporsmol (innbyggertjenester, veiledning), er semantisk caching en lavthengende frukt med typisk 20-40% kostnadsreduksjon.
- Inkluder alltid
<vary-by>@(context.Subscription.Id)</vary-by>for a forhindre at en leietakers svar returneres til en annen -- dette er kritisk for personvern og dataskille.