# Prompt Caching for Performance **Last updated:** 2026-06-19 **Status:** GA **Category:** Performance & Scalability **Type:** reference **Source:** https://learn.microsoft.com/azure/foundry/openai/concepts/provisioned-throughput --- ## Innhold - [Introduksjon](#introduksjon) - [Kjernekomponenter](#kjernekomponenter) - [Cache Eligibility Requirements](#cache-eligibility-requirements) - [Prefix Strategy Design](#prefix-strategy-design) - [Cost Reduction Calculation](#cost-reduction-calculation) - [Cache Invalidation](#cache-invalidation) - [Norsk offentlig sektor](#norsk-offentlig-sektor) - [Beslutningsrammeverk](#beslutningsrammeverk) - [Referanser](#referanser) - [For Cosmo](#for-cosmo) ## Introduksjon Azure OpenAI prompt caching er en innebygd mekanisme som reduserer latens og kostnad for forespørsler med identiske prefixer. Når de første 1024+ tokens i en prompt er identiske med en tidligere forespørsel, gjenbruker tjenesten de allerede beregnede token-representasjonene i stedet for å prosessere dem på nytt. Dette gir raskere time-to-first-token (TTFT) og lavere kostnad — cached tokens faktureres med rabatt for Standard deployments og opptil 100% rabatt for Provisioned (PTU) deployments. Prompt caching er automatisk aktivert for alle støttede modeller (GPT-4o og nyere) uten ekstra konfigurasjon. Cachen er basert på en hash av de første ~256 tokens og krever minimum 1024 identiske tokens for å trigge. Etter den initiale 1024-token terskelen caches ytterligere identiske tokens i blokker på 128. Cacher tømmes typisk innen 5-10 minutter uten aktivitet og alltid innen 24 timer. For norsk offentlig sektor der AI-applikasjoner ofte har lange, statiske system-prompts (inkludert regelverk, instruksjoner og eksempler), er prompt caching en svært effektiv optimaliseringsstrategi som kan gi 30-50% kostnadsreduksjon uten noen endring i output-kvalitet. ## Kjernekomponenter | Komponent | Formål | Teknologi | |-----------|--------|-----------| | Prompt Cache | Automatisk caching av identiske prefixer | Azure OpenAI | | prompt_cache_key | Valgfri parameter for å påvirke cache routing | Azure OpenAI API | | cached_tokens | API-respons felt som viser cache hits | prompt_tokens_details | | Semantic Cache | Ekstern cache for semantisk like forespørsler | Azure Cosmos DB | | Multi-layer Caching | Kombinert caching-strategi | Arkitektur-mønster | ## Cache Eligibility Requirements ### Tekniske krav for prompt caching ```python # Krav for at prompt caching skal fungere: CACHE_REQUIREMENTS = { "minimum_prefix_length": 1024, # Tokens "hash_prefix_length": 256, # Tokens brukt for routing-hash "subsequent_block_size": 128, # Etter 1024, cache i 128-blokker "cache_ttl_inactive": "5-10 min", "cache_ttl_max": "24 timer", "cross_subscription": False, # Cache deles IKKE mellom abonnement "supported_models": [ "gpt-4o-*", "gpt-4o-mini-*", "gpt-4.1-*", "gpt-4.1-mini-*", "gpt-4.1-nano-*", "o1-*", "o3-*", "o3-mini-*" ], "supported_operations": [ "chat-completions", "completions", "responses", "real-time" ] } # Sjekk om en prompt er cache-eligible def is_cache_eligible(messages: list[dict], model: str = "gpt-4o") -> dict: """Check if a prompt is eligible for caching.""" import tiktoken enc = tiktoken.encoding_for_model(model) # Beregn total tokens for alle meldinger total_tokens = 0 for msg in messages: total_tokens += len(enc.encode(msg["content"])) total_tokens += 4 # Role tokens overhead return { "total_tokens": total_tokens, "eligible": total_tokens >= 1024, "cacheable_tokens": max(0, (total_tokens // 128) * 128) if total_tokens >= 1024 else 0, "recommendation": ( "Eligible for caching" if total_tokens >= 1024 else f"Need {1024 - total_tokens} more tokens in prefix" ) } ``` ## Prefix Strategy Design ### Optimaliser prompt-struktur for caching ```python def design_cacheable_prompt( system_instructions: str, few_shot_examples: list[dict], reference_documents: str, user_query: str ) -> tuple[list[dict], dict]: """ Design prompt with optimal structure for caching. Prinsipp: Statisk innhold FØRST, dynamisk innhold SIST. Alt fra starten til det dynamiske innholdet caches. """ messages = [] # --- CACHEABLE PREFIX START --- # 1. System prompt (statisk per applikasjon) messages.append({ "role": "system", "content": system_instructions }) # 2. Few-shot eksempler (statisk per oppgave) for example in few_shot_examples: messages.append({"role": "user", "content": example["input"]}) messages.append({"role": "assistant", "content": example["output"]}) # 3. Referansedokumenter (statisk per sesjon) if reference_documents: messages.append({ "role": "user", "content": f"Referansemateriale:\n\n{reference_documents}" }) messages.append({ "role": "assistant", "content": "Forstått. Jeg vil bruke referansematerialet." }) # --- CACHEABLE PREFIX SLUTT --- # 4. Dynamisk brukerforespørsel (varierer — IKKE cached) messages.append({ "role": "user", "content": user_query }) # Beregn cache-statistikk import tiktoken enc = tiktoken.encoding_for_model("gpt-4o") static_tokens = sum( len(enc.encode(m["content"])) + 4 for m in messages[:-1] # Alt unntatt siste melding ) dynamic_tokens = len(enc.encode(user_query)) + 4 stats = { "static_prefix_tokens": static_tokens, "dynamic_tokens": dynamic_tokens, "cache_eligible": static_tokens >= 1024, "cache_hit_savings_pct": round( static_tokens / (static_tokens + dynamic_tokens) * 100, 1 ) if static_tokens >= 1024 else 0 } return messages, stats # Eksempel: Saksbehandler-assistent for Direktoratet for digital tjenesteutvikling messages, stats = design_cacheable_prompt( system_instructions="""Du er en AI-assistent for saksbehandlere i Direktoratet for digital tjenesteutvikling. Du hjelper med å analysere klager på vedtak om saksbehandling, vurdere om klagen har grunnlag, og foreslå svar. Regelverk du skal referere til: - Vegtrafikkloven § 24-34 - fagforskriften - Forvaltningsloven § 28-36 (klagebehandling) Format: Alltid bruk overskrifter, vurder hvert punkt separat, og avslutt med en samlet anbefaling.""", few_shot_examples=[ { "input": "Klage: Jeg fikk avslag på fornyelse...", "output": "## Vurdering\n### Regelverksvurdering..." }, { "input": "Klage: Mitt saksbehandling ble inndratt...", "output": "## Vurdering\n### Regelverksvurdering..." } ], reference_documents="Vedtaket av 15.01.2025 om avslag...", user_query="Analyser denne nye klagen: ..." ) print(f"Cacheable prefix: {stats['static_prefix_tokens']} tokens") print(f"Cache savings: ~{stats['cache_hit_savings_pct']}%") ``` ### prompt_cache_key for forbedret hit rate ```python from openai import AzureOpenAI client = AzureOpenAI( azure_endpoint="https://my-aoai.openai.azure.com", api_key="...", api_version="2024-12-01-preview" ) # Bruk prompt_cache_key for å forbedre routing # Forespørsler med samme key og prefix routes til samme cache response = client.chat.completions.create( model="gpt-4o", messages=messages, prompt_cache_key="ddt-complaint-handler-v2", # Gruppert caching max_tokens=1000 ) # Sjekk cache hit cached = response.usage.prompt_tokens_details.cached_tokens total_prompt = response.usage.prompt_tokens print(f"Cached tokens: {cached} / {total_prompt}") print(f"Cache hit rate: {cached / total_prompt * 100:.1f}%") # Advarsel: Mer enn ~15 RPM med samme prefix + cache_key # kan overflow til andre maskiner og redusere cache-effektivitet ``` ## Cost Reduction Calculation ### Beregn besparelser fra prompt caching ```python def calculate_caching_savings( monthly_requests: int, avg_total_input_tokens: int, avg_cached_tokens: int, # Tokens som treffer cache model: str = "gpt-4o", deployment_type: str = "standard" # "standard" eller "provisioned" ) -> dict: """Calculate cost savings from prompt caching.""" # Priser (USD per 1M tokens, estimater) pricing = { "gpt-4o": { "standard": {"input": 2.50, "cached_discount": 0.50}, "provisioned": {"input": 0, "cached_discount": 1.0} }, "gpt-4.1": { "standard": {"input": 2.00, "cached_discount": 0.50}, "provisioned": {"input": 0, "cached_discount": 1.0} }, "gpt-4o-mini": { "standard": {"input": 0.15, "cached_discount": 0.50}, "provisioned": {"input": 0, "cached_discount": 1.0} } } p = pricing.get(model, pricing["gpt-4o"]) dt = p.get(deployment_type, p["standard"]) non_cached_tokens = avg_total_input_tokens - avg_cached_tokens # Uten caching cost_without_cache = ( monthly_requests * avg_total_input_tokens / 1_000_000 * dt["input"]) # Med caching cached_cost = ( monthly_requests * avg_cached_tokens / 1_000_000 * dt["input"] * (1 - dt["cached_discount"])) non_cached_cost = ( monthly_requests * non_cached_tokens / 1_000_000 * dt["input"]) cost_with_cache = cached_cost + non_cached_cost savings = cost_without_cache - cost_with_cache return { "monthly_requests": monthly_requests, "cache_hit_rate": round( avg_cached_tokens / avg_total_input_tokens * 100, 1), "cost_without_cache_nok": round(cost_without_cache * 11, 2), "cost_with_cache_nok": round(cost_with_cache * 11, 2), "monthly_savings_nok": round(savings * 11, 2), "savings_pct": round(savings / max(cost_without_cache, 0.01) * 100, 1), "note": ( "PTU: cached tokens er 100% rabatt" if deployment_type == "provisioned" else "Standard: cached tokens er 50% rabatt") } # Eksempel: 50K forespørsler/mnd med RAG-pipeline savings = calculate_caching_savings( monthly_requests=50_000, avg_total_input_tokens=3000, avg_cached_tokens=2000, # System prompt + examples cached model="gpt-4o", deployment_type="standard" ) print(f"Månedlig besparelse: {savings['monthly_savings_nok']} NOK") print(f"Besparelse: {savings['savings_pct']}%") ``` ## Cache Invalidation ### Håndtering av cache-endringer ```python class CacheAwarePromptManager: """Manage prompts with cache invalidation awareness.""" def __init__(self, base_system_prompt: str, version: str = "v1"): self.base_system_prompt = base_system_prompt self.version = version self._prefix_hash = self._compute_hash(base_system_prompt) def _compute_hash(self, text: str) -> str: import hashlib return hashlib.sha256(text.encode()).hexdigest()[:16] def update_system_prompt(self, new_prompt: str): """ Oppdater system prompt. MERK: Dette invaliderer ALL cache for denne applikasjonen fordi prefix endres. Anbefaling: Gjør endringer i off-peak timer. """ new_hash = self._compute_hash(new_prompt) if new_hash != self._prefix_hash: print(f"WARNING: System prompt endret. " f"Cache invalideres for alle forespørsler.") print(f"Gammel hash: {self._prefix_hash}") print(f"Ny hash: {new_hash}") print(f"Anbefaling: Deploy endringen i off-peak timer " f"for å minimere cache miss-kostnaden.") self.base_system_prompt = new_prompt self._prefix_hash = new_hash def get_cache_key(self) -> str: """Get cache key for prompt_cache_key parameter.""" return f"app-{self.version}-{self._prefix_hash}" # Cache invalidation triggers: # 1. Endring i system prompt → Umiddelbar invalidering # 2. Endring i few-shot examples → Invalidering fra det punktet # 3. Inaktivitet > 5-10 min → Automatisk tømming # 4. > 24 timer siden siste bruk → Garantert tømming # 5. En eneste endret karakter i prefix → Full cache miss ``` ## Norsk offentlig sektor - **Kostnadseffektivitet**: Prompt caching er "gratis" optimalisering — ingen konfigurasjon nødvendig, bare riktig prompt-design. Spar 30-50% på input-token kostnader. - **PTU-deployments**: For PTU er cached tokens 100% gratis — dette betyr at riktig prefix-design kan doble effektiv throughput. - **Personvern**: Prompt caches er isolert per Azure-abonnement og deles ikke mellom kunder. Data i cache følger samme databehandling som vanlige forespørsler. - **Forutsigbarhet**: Cache hit rate kan monitoreres via `cached_tokens` i API-responsen — bygg dashboards for å spore cache-effektivitet over tid. ## Beslutningsrammeverk | Scenario | Anbefaling | Begrunnelse | |----------|------------|-------------| | Lang system prompt (>500 tokens) | Design for caching | Mest å vinne | | Mange few-shot examples | Flytt til prefix, bruk caching | Reduser input-kostnad | | RAG med statisk kontekst | Cache system + kontekst, varier spørsmål | Høy hit rate | | Unik prompt per forespørsel | Caching gir lite | Prefix endres for ofte | | PTU deployment | Maksimer caching | 100% rabatt på cached tokens | | Høy RPM (>15 per prefix) | Bruk prompt_cache_key | Forbedrer routing | ## Referanser - [Prompt caching](https://learn.microsoft.com/azure/foundry/openai/how-to/prompt-caching) — Offisiell guide - [Provisioned throughput](https://learn.microsoft.com/azure/foundry/openai/concepts/provisioned-throughput) — PTU caching-fordeler - [Semantic cache with Cosmos DB](https://learn.microsoft.com/azure/cosmos-db/gen-ai/semantic-cache) — Ekstern caching - [Application design for AI workloads](https://learn.microsoft.com/azure/well-architected/ai/application-design) — Multi-layer caching ## For Cosmo - **Bruk denne referansen** når kunden vil redusere kostnader eller latens for Azure OpenAI-workloads med repetitive prompt-strukturer. - Hovedregelen: Statisk innhold FØRST i prompten, dynamisk innhold SIST — alt statisk prefix caches automatisk. - Minimum 1024 tokens i identisk prefix for cache hit — legg til referansemateriale eller detaljerte instruksjoner for å nå terskelen. - For PTU: cached tokens teller 100% rabatt mot utilization — dette er den mest effektive optimaliseringen for PTU-deployments. - En eneste endret karakter i prefix gir full cache miss — vær forsiktig med dynamiske elementer (timestamps, request-IDs) i starten av prompts.