Prompt Caching cu Claude și OpenAI în Python: Ghid Practic pentru Reducerea Costurilor LLM (2026)
Cum activezi prompt caching cu Claude și OpenAI în Python: cod complet, reguli de invalidare, benchmark real cu numere din producție și când NU merită.
Prompt caching este un mecanism nativ al API-urilor Claude și OpenAI care refolosește tokenii statici dintr-un prompt între cereri consecutive, reducând costul input-ului cu până la 90% și latența primului token cu 50–80%. În loc să retrimiți sistem prompt-ul de 8000 de tokeni la fiecare apel, îl marchezi (sau lași API-ul să-l detecteze automat) și plătești doar pentru tokenii noi. În ghidul ăsta îți arăt exact cum se activează în Python pentru ambele providere, cât costă operațiunea de scriere în cache, care sunt regulile de invalidare pe care le uită toată lumea și un benchmark cu numere reale din producție.
Claude folosește cache explicit, prin marker-ul cache_control, cu TTL de 5 minute (default) sau 1 oră. OpenAI face caching automat pentru prompturi peste 1024 de tokeni, dacă au prefix comun.
Cache read costă 10% din prețul standard de input la Anthropic și aproximativ 50% la OpenAI. Cache write la Anthropic costă însă 1.25× (5 min) sau 2× (1 oră) prețul de input.
Minimul de tokeni pentru cache: 1024 la Sonnet/Opus, 2048 la Haiku pentru Anthropic; 1024 pentru OpenAI (gpt-4o și mai noi).
Ordinea contează foarte mult: pune conținutul static (tools, system, few-shot exemple) la începutul promptului și partea dinamică la coadă. Altfel cache-ul e invalidat la fiecare cerere.
Tool use e cache-abil. Definițiile de tools sunt printre primele candidate pentru caching când ai zeci de tool-uri complexe.
Metrica de urmărit e cache hit rate raportat la costul total, nu doar volumul de tokeni salvați. Un cache scris fără hit-uri e pierdere netă.
Ce este prompt caching și cum funcționează?
Prompt caching e o optimizare la nivel de infrastructură prin care providerul de LLM stochează reprezentarea internă (KV cache-ul) a unei porțiuni de prompt după prima cerere, ca apoi să o refolosească pentru cereri ulterioare care încep cu exact același prefix de tokeni. Practic, nu mai recalculezi atenția peste 8000 de tokeni de system prompt de fiecare dată. Modelul reia calculul de acolo de unde s-a oprit.
Mecanismul funcționează pentru că transformerele autoregresive procesează secvențial. Dacă primul token diferă, tot restul trebuie recalculat. De asta ordinea în prompt este critică. Un exemplu clasic pe care l-am văzut de zeci de ori: cineva pune un timestamp la începutul system prompt-ului („e ora 15:04, ajută utilizatorul...”), iar cache-ul se invalidează la fiecare cerere. Mută timestamp-ul la sfârșit, în ultimul user message, și restul devine cache-abil.
Sunt două modele de UX: explicit (Anthropic, unde tu marchezi punctele de breakpoint) și automat (OpenAI, unde infrastructura detectează prefixele comune). Ambele produc aceleași economii când sunt folosite corect, dar modelul explicit îți dă control mai fin, inclusiv posibilitatea unui TTL mai lung. În experiența mea cu workload-uri agentice, caching-ul explicit e mai previzibil când ai multe branchi conversaționale paralele.
Anthropic vs OpenAI: comparație directă
Cele două implementări diferă în locurile care contează: cine controlează cache-ul, cât costă scrierea și cât timp trăiește. Tabelul de mai jos rezumă exact ce trebuie să știi înainte să alegi provider-ul pentru un workload cu prompturi lungi și repetitive.
Caracteristică
Anthropic (Claude)
OpenAI (GPT-4o+)
Model de activare
Explicit, prin marker cache_control
Automat, prin detectare prefix
TTL cache
5 minute (default) sau 1 oră (opt-in)
5–10 minute, până la 1h off-peak
Preț cache write
1.25× input (5min) / 2× input (1h)
Fără taxă suplimentară
Preț cache read
0.1× input (economie 90%)
0.5× input (economie 50%)
Prag minim tokeni
1024 (Sonnet/Opus) / 2048 (Haiku)
1024 tokeni
Număr breakpoints
Până la 4 per cerere
N/A (automat)
Suport pentru tools
Da, tools se pot marca separat
Da, incluse în prefix
Vizibilitate metrici
cache_read_input_tokens în usage
cached_tokens în prompt_tokens_details
Diferența strategică e simplă: Anthropic te obligă să iei o decizie conștientă (plătești mai mult pe primul apel pentru economie mare pe apeluri repetate), în timp ce OpenAI oferă economie mai modestă, dar „gratuită”. Pentru cereri unice sau prompt-uri sub 1024 tokeni, OpenAI e mai puțin riscant. Pentru sisteme agentice cu context lung și multe iterații, Anthropic cu TTL de 1 oră devine dramatic mai ieftin, iar documentația oficială Anthropic despre prompt caching arată reduceri de 90% pe workload-uri de conversație lungă.
Cum implementezi prompt caching cu Claude în Python
Cache-ul se activează adăugând obiectul cache_control unui bloc din system, tools sau messages. Marker-ul înseamnă „cache-uiește totul de la începutul cererii până aici (inclusiv)”. Un exemplu complet, cu SDK-ul oficial anthropic (versiunea 0.40+):
import anthropic
client = anthropic.Anthropic()
# Prompt static de ~5000 de tokeni (documentație, ghid stil etc.)
KNOWLEDGE_BASE = open("company_handbook.md").read()
def ask_with_cache(user_question: str) -> str:
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
system=[
{
"type": "text",
"text": "Ești un asistent intern pentru echipa de suport."
},
{
"type": "text",
"text": KNOWLEDGE_BASE,
# Marker-ul: totul până aici e cache-abil, TTL 5 min
"cache_control": {"type": "ephemeral"}
}
],
messages=[{"role": "user", "content": user_question}]
)
usage = response.usage
print(f"Cache write: {usage.cache_creation_input_tokens} tokens")
print(f"Cache read: {usage.cache_read_input_tokens} tokens")
print(f"Input nou: {usage.input_tokens} tokens")
return response.content[0].text
# Primul apel scrie cache-ul (plătești 1.25× pentru KNOWLEDGE_BASE)
ask_with_cache("Care e politica de concediu?")
# Al doilea apel în 5 min citește din cache (plătești 0.1×)
ask_with_cache("Cum aplic pentru work-from-home?")
Pentru TTL de 1 oră, adaugă "ttl": "1h" în obiectul cache_control. Reține că poți combina breakpoints. De exemplu, un breakpoint la finalul tools și altul la finalul unui assistant message care conține exemple few-shot. Fiecare breakpoint activ înseamnă un cost separat de scriere, așa că nu împrăștia mai mult de 2–3 pe cerere decât dacă ai măsurat hit rate-ul.
Cum activezi prompt caching cu OpenAI în Python
Sincer, la OpenAI nu prea ai ce activa. Caching-ul e automat pentru orice prompt de peste 1024 tokeni, dacă începe cu un prefix comun cu o cerere anterioară din ultimele 5–10 minute (până la 1 oră off-peak). Ce trebuie să faci tu e să structurezi promptul astfel încât partea statică să vină prima. Un pattern corect arată așa:
from openai import OpenAI
client = OpenAI()
SYSTEM_PROMPT = open("system_instructions.md").read() # ~3000 tokeni
FEW_SHOT_EXAMPLES = open("examples.jsonl").read() # ~2500 tokeni
def ask(user_question: str) -> dict:
response = client.chat.completions.create(
model="gpt-4o-2024-11-20",
messages=[
# 1. Partea STATICĂ vine prima, devine cache-abilă
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "system", "content": FEW_SHOT_EXAMPLES},
# 2. Partea DINAMICĂ vine ultima
{"role": "user", "content": user_question}
]
)
details = response.usage.prompt_tokens_details
print(f"Cached tokens: {details.cached_tokens}")
print(f"Non-cached: {response.usage.prompt_tokens - details.cached_tokens}")
return response.choices[0].message.content
# Primul apel: 0 cached_tokens
ask("Rezumă ultimele modificări la politica de retur.")
# Al doilea apel în ~5 min: cached_tokens ≈ 5500 (system + exemple)
ask("Care e procedura pentru retur după 30 de zile?")
Cheia stă în ce nu faci. Nu concatena user input în system prompt. Nu strica ordinea mesajelor între cereri. Nu insera timestamp-uri sau ID-uri de request în prefix. Ghidul oficial OpenAI pentru prompt caching confirmă că cached_tokens raportat în răspuns e sursa singură de adevăr. Verifică-l în CI ca să prinzi regresiile.
Prompt caching cu tool use și function calling
Dacă ai un agent cu 15–20 de tools bine documentate, definițiile lor probabil ocupă 2000–4000 de tokeni. Sunt candidate perfecte pentru caching pentru că se schimbă rar și sunt trimise la fiecare iterație a agentului. La Anthropic, aplici marker-ul pe ultimul element din array-ul tools:
tools = [
{"name": "search_docs", "description": "...", "input_schema": {...}},
{"name": "run_sql", "description": "...", "input_schema": {...}},
# ... alte 13 tools ...
{
"name": "send_email",
"description": "...",
"input_schema": {...},
"cache_control": {"type": "ephemeral"} # Cache-uiește TOATE tools de mai sus
}
]
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2048,
tools=tools,
messages=conversation_history,
)
Un pattern puternic pentru agenți multi-turn: pune un breakpoint la finalul tools și un al doilea la finalul ultimului assistant message. Astfel, întreaga istorie a conversației (inclusiv tool_use și tool_result-urile intermediare) devine cache-abilă la următoarea iterație. Pentru un agent cu 10 pași care apelează tools, economia poate ajunge la 85% din costul total de input.
Am scris mai multe despre orchestrarea unor astfel de agenți în articolul despre context engineering pentru aplicații AI de producție. Caching-ul e stratul care face economics-ul viabil atunci când context window-ul crește la 100k+ tokeni pe iterație.
Cât economisești real: benchmark cu numere din producție
Cifrele din documentație („90% reducere”) sunt marketing. Ce contează în producție e cost per cerere amortizat peste toate hit-urile și miss-urile. Iată un benchmark real dintr-un chatbot intern pe care l-am ajutat să-l optimizez, care primește ~5000 de cereri/zi cu un system prompt de 6000 de tokeni:
Observație importantă: TTL-ul de 1 oră devine profitabil doar la volum. Sub ~500 cereri/zi cu același prefix, plătești mai mult pe scrierile duplicate decât economisești pe read-uri. Fă întotdeauna calculul cu numerele tale reale înainte să activezi 1h. Pentru workload-uri sub 500 req/zi, TTL-ul de 5 minute e aproape întotdeauna alegerea corectă.
Latența e a doua metrică relevantă. Pe același benchmark, TTFB (time to first token) a scăzut de la 1.8s la 0.4s pentru cache hit-uri. Când construiești un UX conversațional, cei 1.4s conștientizabili fac diferența între „instant” și „așteaptă”.
Când NU merită să folosești prompt caching
Prompt caching nu e universal profitabil. Sunt scenarii unde adaugă complexitate fără beneficiu, sau chiar pierdere netă:
Prompt-uri sub 1024 tokeni: nu se califică. Fără excepții. Consolidează sau nu te obosi.
Cereri unice (one-shot): plătești write premium fără să faci hit. Batch API-ul OpenAI e mai potrivit aici (50% reducere pentru latency-tolerant).
Prompt-uri unde partea dinamică e mare relativ la cea statică: dacă din 5000 tokeni doar 800 sunt statici, economia e marginală și overhead-ul de management (mai ales la Anthropic cu breakpoints) nu se justifică.
Sisteme cu multe variante de system prompt (A/B testing): fiecare variantă are propriul cache. Testezi 8 variante, ai 8 cache-uri de scris.
Când folosești sampling cu temperature ridicat și seed diferit: output-ul variază, dar input-ul cache-uit rămâne valid, deci aici chiar merită. Excepția e când modifici tools sau system între cereri.
Măsurarea cache hit rate în producție
Ce nu măsori, nu poți optimiza. Fiecare cerere returnează câmpuri detaliate de usage pe care trebuie să le agregi într-o metrică observabilă. Iată un wrapper minimal pe care l-am folosit personal în două proiecte și se integrează cu orice sistem de monitoring (Prometheus, DataDog, OpenTelemetry):
import time
from dataclasses import dataclass, field
@dataclass
class CacheStats:
total_requests: int = 0
total_cache_read: int = 0
total_cache_write: int = 0
total_input_new: int = 0
total_cost_usd: float = 0.0
def record(self, usage, model_pricing):
self.total_requests += 1
cache_read = getattr(usage, "cache_read_input_tokens", 0) or 0
cache_write = getattr(usage, "cache_creation_input_tokens", 0) or 0
input_new = usage.input_tokens - cache_read - cache_write
self.total_cache_read += cache_read
self.total_cache_write += cache_write
self.total_input_new += input_new
self.total_cost_usd += (
cache_read * model_pricing["cache_read"] +
cache_write * model_pricing["cache_write"] +
input_new * model_pricing["input"]
) / 1_000_000
@property
def hit_rate(self) -> float:
cacheable = self.total_cache_read + self.total_cache_write
return self.total_cache_read / cacheable if cacheable else 0.0
# Preț Claude Sonnet 5 (per 1M tokens)
SONNET_PRICING = {"input": 3.0, "cache_write": 3.75, "cache_read": 0.30}
Un hit rate sănătos începe pe la 60% după prima oră de trafic. Dacă stai sub 40% după o zi, ai o problemă de invalidare, cel mai probabil un câmp dinamic strecurat în prefix. Alarmează pe hit rate, nu pe cost absolut. Costul crește liniar cu traficul, în timp ce hit rate-ul te avertizează la regresii de calitate.
Pentru validarea end-to-end a agenților care se bazează pe caching, integrează metricile într-o pipeline de evaluare, un pattern pe care l-am detaliat în ghidul despre evaluarea agenților AI cu DeepEval în Python. Nu accepta niciodată un deployment care schimbă system prompt-ul fără să reverifice hit rate-ul pe un sample reprezentativ.
Pentru ceva mai practic pe partea de output, dacă generezi JSON structurat din răspunsuri cache-uite, combinația e imbatabilă. Vezi ghidul despre structured outputs cu OpenAI și Pydantic pentru cum să validezi consistent output-ul la scară.
Ce urmează: caching semantic și cache-ul la nivel de aplicație
Prompt caching-ul nativ e limitat la potrivire exactă de prefix. Următorul strat de optimizare, semantic caching, indexează cererile prin embeddings și returnează răspunsuri gata generate pentru întrebări similare semantic. Redis (cu RediSearch), pgvector și integrările de cache din LangChain oferă implementări gata de producție. Trade-off-ul: risc de a servi răspunsuri stale sau greșite pentru interogări care doar par similare. Onest, îl folosesc doar pentru FAQ-uri clare, niciodată pentru agenți multi-turn.
Pentru cele mai multe workload-uri, prompt caching-ul nativ acoperă 80% din economii. Semantic caching-ul e stratul al doilea, opțional, cu overhead operațional non-trivial. Începe cu ce e nativ, măsoară, și abia apoi decide dacă merită adăugat un strat de complexitate.
Întrebări frecvente
Cât timp durează un cache Anthropic?
Default 5 minute de la ultima accesare (nu de la creare), fiecare hit resetează cronometrul. Opțional 1 oră cu "ttl": "1h" în cache_control, dar cu preț de scriere 2× în loc de 1.25×. Alege 1h doar dacă hit rate-ul justifică costul superior de scriere.
Pot combina prompt caching cu tool use?
Da. La Anthropic pui cache_control pe ultimul tool din array și totul devine cache-abil (tools + system). La OpenAI e automat dacă tools și system prompt depășesc împreună 1024 tokeni și rămân neschimbate între cereri.
De ce nu am cache hits deși prompt-ul pare identic?
Cauza numărul unu: un câmp dinamic (timestamp, user ID, session ID, cookie) strecurat înainte de marker. Cauza numărul doi: whitespace-uri diferite (tab vs space, newline la sfârșit). Cauza numărul trei: modelul a fost schimbat între cereri, cache-ul e per model și per versiune.
Cache-ul e izolat între utilizatori sau se poate scurge date?
Cache-ul e izolat per organizație/API key. Anthropic și OpenAI confirmă în documentație că nu există partajare între conturi și nu se folosește la training. Totuși, pentru workload-uri cu date PII, revizuiește politica de retenție cu provider-ul.
Merită să implementez și cache aplicativ pe lângă cel nativ?
Doar dacă ai identificat un pattern clar de interogări repetitive (FAQ, autocompletări) care se pretează la potrivire exactă sau semantică. Pentru agenți cu răspunsuri contextuale, cache-ul nativ e suficient și mai puțin riscant. Nu suprapune două straturi de cache decât dacă ai măsurat că primul nu e destul.
LiteLLM abstrahează 100+ furnizori de LLM într-un singur API compatibil OpenAI. Vezi cum îl integrezi în Python cu fallback automat, load balancing, cost tracking și proxy server pentru echipe.
Ghid practic pentru Structured Outputs cu OpenAI și Pydantic în Python: JSON garantat, exemple de cod și comparație cu Claude tool use, plus capcanele întâlnite în producție.
Ghid practic pentru testarea agenților AI cu DeepEval în Python. Acoperă metrici LLM, tool correctness, tracing cu @observe, integrare pytest și CI/CD — cu cod funcțional verificat.