Anthropic Prompt Caching в production: как да намалим Claude API разходите с 90% (2026)
Практическо ръководство за Anthropic prompt caching в production: как работят cache breakpoints, TTL опции (5 мин vs 1 час), break-even математика, стратегии за 80%+ hit rate и debugging на cache misses. С реални примери за агенти с tool use и RAG.
Anthropic prompt caching в production е механизъм, който запазва кодираното състояние на стабилен префикс от промпта и позволява следващите заявки да го четат на цена от само 10% от нормалната входна тарифа. Реалните икономии стигат 70–90% при правилно структурирани системни промпти, tool schemas и RAG контекст. Двете достъпни TTL опции (5 минути и 1 час) променят изцяло математиката за multi-turn чатботи и агенти, а грешно поставен cache breakpoint може да ви струва повече, отколкото ако изобщо не бяхте включили caching. Тази статия обяснява какво работи в production през 2026 г., какво се счупи през март и какви шаблони изравняват hit rate над 80%.
Cache read струва 0.1× базовата входна тарифа. Cache write е 1.25× за 5-минутен TTL и 2× за 1-часов TTL. 5-мин cache се изплаща след втората заявка, 1-час след третата.
Anthropic позволява до 4 cache_control breakpoints на заявка. Поставяйте ги ВЕДНАГА след най-дългите стабилни блокове (system prompt, tool schemas, RAG контекст), никога след динамично съдържание.
ProjectDiscovery повиши cache hit rate от 7% на 84% просто чрез преместване на динамичните части СЛЕД статичния префикс, спестявайки 59–70% от общия LLM бюджет.
През март 2026 г. Anthropic мълчаливо намали default TTL от 1 час на 5 минути. Workloads, които разчитаха на дълги cache lifetimes, отчетоха 17–26% ръст на сметките. Винаги задавайте TTL експлицитно.
1-часовият TTL е достъпен през Claude API, Amazon Bedrock, Google Cloud и Microsoft Foundry за Claude Sonnet 4.5/4.6, Haiku 4.5 и Opus 4.5.
Ако hit rate е под 40%, caching е нетна загуба. Оправете структурата на промптите, преди да превключвате доставчик.
Как работи prompt caching при Claude
Когато отбележите content block с cache_control, Anthropic запазва encoded state на всичко до тази точка на своите сървъри. Следващата заявка, която започва с точно същите байтове в префикса, чете от кеша вместо да пресмята attention върху хилядите токени от нула. Това не е semantic cache. Прилика в смисъла не помага. Един разместен интервал, различен timestamp или преподредени tool definitions правят prefix hash различен и водят до пълен cache miss.
Механизмът е особено ценен при три workload типа, които виждам постоянно при клиенти: multi-turn conversational агенти с дълги system prompts, RAG пайплайни, които препращат едно и също policy document на всяка заявка, и tool-heavy агенти с 20+ дефинирани функции. Във всички три случая огромен префикс се повтаря идентично, докато варира само последният message.
Важен нюанс: cache lookup работи само върху пълен prefix match от началото. Не можете да кеширате „средата" на промпта. Ако предположим system prompt (кеширано) → user message (динамично) → tool_result (искате да кеширате), tool_result-ът ще миссне, защото user message-а преди него е различен всеки път. Затова разпределението на кеш точките е inherently строго йерархично.
Ценообразуване, TTL и break-even математика
Anthropic таксува три различни ставки за кеширано съдържание. За Claude Sonnet 4.6 (при $3.00/M базова входна цена) числата изглеждат така:
Операция
Множител
Цена за 1M токена (Sonnet 4.6)
Кога плащате
Cache write (5-min TTL)
1.25×
$3.75
Първата заявка с новия префикс
Cache write (1-hour TTL)
2.00×
$6.00
Първата заявка с новия префикс
Cache read
0.10×
$0.30
Всяка следваща заявка в TTL прозореца
Стандартен вход (без cache)
1.00×
$3.00
Без cache_control
Изход (за референция)
N/A
$15.00
Без промяна
Break-even математиката е права линия. За 5-минутния TTL: 1 write (1.25×) + 1 read (0.1×) = 1.35× за две заявки, срещу 2.0× без cache. Спестявате 32.5% още от втория request. За 1-часовия TTL: 1 write (2×) + 2 reads (0.2×) = 2.2× за три заявки, срещу 3.0× без cache, което са 26.7% икономия от третия.
Реалният calculus: за workload с 10 000-токенов системен промпт, 2 000 заявки на ден и 75% hit rate, спестяванията са около $1 215/месец на Sonnet 4.6. За тежки агенти с 50k-токенов контекст (RAG bundle + tools + system) числата достигат пет цифри месечно. Виждал съм екип, който пусна caching за уикенда и в понеделник откри, че месечният им forecast е паднал със $47 000. Честно, това не е обичайният ми ден.
Cache breakpoints и правилното им разполагане
Anthropic позволява до 4 експлицитни cache_control breakpoints на заявка. Всеки breakpoint означава „запази cache checkpoint тук". Всичко ПРЕДИ последния маркер, което съвпада с предишна заявка в TTL прозореца, се таксува по cache-read тарифа.
Стратегията с 4 breakpoints работи най-добре при йерархично структурирани workloads. Ето типичната подредба, която препоръчвам (по горчив опит):
Breakpoint 1: в края на статичния system prompt (rarely changes, days-months)
Breakpoint 2: в края на tool definitions блока (changes при deploy)
Breakpoint 3: в края на голямото reference document / RAG context (per-session)
Breakpoint 4: в края на conversation history (turn-by-turn)
При тази структура нова user message в chat няма да събори първите три cache сегмента, само последният сегмент се преизчислява. Ако използвате един breakpoint само в края на system prompt, губите огромни спестявания при multi-turn разговори, защото history-то на всеки ход преизчислява attention върху всички предишни tool_results.
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-6-20260215",
max_tokens=1024,
system=[
{
"type": "text",
"text": LONG_SYSTEM_PROMPT, # ~8000 tokens
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{
"type": "text",
"text": COMPANY_POLICY_DOCUMENT, # ~15000 tokens
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}
],
tools=[...], # tool schemas cached automatically когато има breakpoint след тях
messages=[
{"role": "user", "content": [
{"type": "text", "text": PREVIOUS_TURNS},
{"type": "text", "text": "Cache stop here",
"cache_control": {"type": "ephemeral"}} # 5-min default
]},
{"role": "assistant", "content": "..."},
{"role": "user", "content": "New question"} # this часть без cache
]
)
# Инспектирайте usage за верификация
print(response.usage.cache_creation_input_tokens)
print(response.usage.cache_read_input_tokens)
print(response.usage.input_tokens) # само uncached частта
Как да структурираме промптите за максимален hit rate
Кеширането награждава стабилността на префикса, така че единственото правило, което трябва да интернализирате, е: всичко динамично отива в края. Звучи очевидно, ама го виждам грешно почти във всеки codebase, който ревизирам.
ProjectDiscovery публикува case study, в който hit rate им беше 7% при 200+ млн. токена дневно. Разследването показа, че включваха current timestamp в началото на system prompt („You are a security assistant. Current time is 2026-04-12T14:23:11Z..."). Всяка заявка правеше write, всяка заявка миссваше. След преместване на timestamp-а в user message и стабилизиране на system prefix, hit rate скочи на 84% и общите LLM разходи паднаха с 59–70%. Това е промяна от буквално 15 реда код.
Правила за стабилни префикси
Никакви timestamps или request IDs в system prompt. Ако имате нужда LLM да знае датата, подайте я в user message.
Стабилизирайте tool definitions ред. Ако генерирате tools списък от Set или Dict, използвайте sorted(). Промяна на реда счупва кеша.
Избягвайте personalization в system prompt. Ако имате user-specific instructions („The user's name is Alex, prefers Bulgarian"), сложете ги във втори system block БЕЗ breakpoint между тях, или в user message.
Замразете JSON schema whitespace. Различаващ се indent между json.dumps(x) и json.dumps(x, indent=2) прави различен hash.
Внимавайте с few-shot examples. Ако randomly семплирате примери от pool на всяка заявка, всяка заявка мисс. Или фиксирайте reservoir, или бачкайте с bucketing.
Минимални размери на кеширани сегменти
Cache write има минимална граница: 1024 токена за Sonnet 4.6 и Opus 4.5, 2048 за Haiku 4.5. По-малки блокове мълчаливо не се кешират, а вие плащате 1.25× write и не получавате нищо. Проверявайте response.usage.cache_creation_input_tokens. Ако е 0 при поставен breakpoint, префиксът ви е под прага.
Практически пример: агент с tool use и RAG
Тук е пълен, изпълним пример на support агент, който комбинира RAG контекст (продуктова документация), tool use (order lookup + refund) и multi-turn conversation history. Показва всичките 4 breakpoints и правилното инспектиране на usage. Използвам почти същата структура в свой current клиентски проект, само че с два допълнителни tool-а.
import os
from anthropic import Anthropic
from typing import Any
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
SYSTEM_PROMPT = """You are ACME Support, a customer service agent.
Rules:
- Be concise and empathetic.
- Never promise refunds without confirming via tools.
- Escalate anything involving legal or safety to human_handoff.
""".strip() # ~8k tokens в реалност
POLICY_DOC = load_file("policies/refund_policy_v12.md") # ~18k tokens
TOOLS = sorted([
{"name": "lookup_order", "description": "...", "input_schema": {...}},
{"name": "issue_refund", "description": "...", "input_schema": {...}},
{"name": "human_handoff", "description": "...", "input_schema": {...}},
], key=lambda t: t["name"]) # sort за стабилен hash
def build_request(conversation: list[dict], user_query: str) -> dict:
return {
"model": "claude-sonnet-4-6-20260215",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{
"type": "text",
"text": POLICY_DOC,
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}
],
"tools": TOOLS, # tools блок автоматично покрит от последния system breakpoint
"messages": [
*conversation,
{
"role": "user",
"content": [{
"type": "text",
"text": user_query
}]
}
]
}
def call_and_report(conversation, query):
req = build_request(conversation, query)
# Добавяме breakpoint след history-то (ако има >1024 токена)
if conversation and len(str(conversation)) > 4000:
req["messages"][-2]["content"][-1]["cache_control"] = \
{"type": "ephemeral"} # 5-min TTL за history
resp = client.messages.create(**req)
u = resp.usage
print(f"write={u.cache_creation_input_tokens} "
f"read={u.cache_read_input_tokens} "
f"uncached={u.input_tokens} out={u.output_tokens}")
# Estimated cost за проследяване
cost = (u.cache_creation_input_tokens * 6.00 + # 1h write = 2x
u.cache_read_input_tokens * 0.30 + # read = 0.1x
u.input_tokens * 3.00 +
u.output_tokens * 15.00) / 1_000_000
print(f"cost=${cost:.4f}")
return resp
# Първа заявка: пълен write
r1 = call_and_report([], "Where is my order 12345?")
# result: write=26000 read=0 uncached=15, плащаме full write
# Втора заявка веднага след: пълен hit
r2 = call_and_report(conversation_from(r1), "Actually, can you refund it?")
# result: write=0 read=26000 uncached=~200, 90% отстъпка!
За production ви препоръчвам да логвате cache_read_input_tokens / total_input ratio-то в Langfuse или еквивалентна LLM observability платформа. Ако ratio-то падне под 0.6 за workload, който би трябвало да е кеширан, това е сигнал за drift в префикса, вероятно някой е добавил timestamp или е разместил tool ред.
Debugging на cache misses в production
Три класически причини за misses, подредени по честота от моя опит:
1. Whitespace и newline drift
Най-коварният баг. Ако template engine-ът ви (Jinja, string.Template) добави trailing newline при промяна на template-а, всеки cached prefix от предната версия е dead. Решение: hash-нете кеширания блок при startup и логвайте hash-а при всяка заявка. Ако hash-ът се смени неочаквано, знаете точно кой deploy е счупил caching. Ударих се в тази конкретна греда преди месец, така че говоря от собствен опит.
import hashlib
def prefix_hash(text: str) -> str:
return hashlib.sha256(text.encode()).hexdigest()[:12]
# При startup
STARTUP_HASH = prefix_hash(SYSTEM_PROMPT + POLICY_DOC)
# При всяка заявка
current = prefix_hash(SYSTEM_PROMPT + POLICY_DOC)
if current != STARTUP_HASH:
logger.warning(f"prefix drift: {STARTUP_HASH} -> {current}")
2. Tool schema serialization
SDK-тата serializat tool schemas преди изпращане. Ако имате два деплоймента с различни Python версии (3.11 vs 3.12), dict ordering може да се различава и JSON изхода да е различен. Винаги serializat с sort_keys=True, ако правите client-side hashing, и стабилизирайте tool реда с sorted().
3. TTL истичане поради трафик pattern
Ако workload-ът ви има bursty pattern (10 заявки за 30 секунди, после 20 минути тишина), 5-минутният cache истича и следващият burst започва с write. За такива workloads 1-часовият TTL се изплаща бързо, дори при 2× write cost. Мерете inter-request interval distribution, а не средното време. Средното скрива дълги паузи.
Комбиниране с Batch API за максимални икономии
Anthropic Message Batches API обработва заявки асинхронно и връща резултати в рамките на 24 часа при 50% отстъпка от стандартните тарифи. Кеширането работи кумулативно с batch отстъпката: batch cache read = 0.5 × 0.1 × base = 5% от базовата цена. За nightly document processing pipelines това е разликата между $5 000 и $250 месечно.
Ограничение: batch заявките нямат гарантиран ред на изпълнение, така че първата заявка (write) може да пристигне при cold worker, а следващите могат да ударят различни workers. Cache е споделен между workers, но propagation latency е няколко секунди. Гарантирате hit чрез priming: изпратете една синхронна заявка с write първо, после stream-нете batch-а. Официалните Anthropic docs за batch processing покриват edge cases детайлно.
Чести грешки, които изяждат бюджета ви
Разчитане на default TTL
През март 2026 г. Anthropic мълчаливо смени default TTL от 1 час на 5 минути. Няма blog post, няма deprecation notice, няма API version bump. Просто в един ден workloads с 30-минутни паузи между заявките започнаха да пресмятат кешовете от нула. Няколко екипа отчетоха 17–26% ръст на месечните сметки. Пълната хронология на инцидента е в GitHub issue #46829. Урок: винаги задавайте ttl експлицитно, не разчитайте на default.
Кеширане на неща, които се променят
Не кеширайте current market prices, live sensor data, timestamps или user profile snapshots. За такива данни cache write е нетна загуба. Правилното решение е tool call, който извлича данните just-in-time, вместо да ги вграждате в статичния prefix.
Прескачане на минималния prefix размер
Ако системният промпт е под 1024 токена (Sonnet, Opus) или 2048 (Haiku), caching се игнорира мълчаливо. Проверявайте usage.cache_creation_input_tokens. Ако е 0 при поставен breakpoint, префиксът е под прага.
Кеширане при чести deploys
Ако правите 20 deploys дневно и всеки променя системния промпт (дори с един ред), плащате write cost 20 пъти на ден за нищо. Извадете prompt-ите от кода в config store (файл, S3, DB) и променяйте ги отделно от deploy pipeline-а.
Игнориране на cache metrics в observability
Ако не логвате cache hit ratio на request level, ще откриете regression чак когато счетоводството попита. Стандартен dashboard: cache_read_tokens / (cache_read + cache_write + input). Искате това число >0.7 за stable workloads. Официалните Anthropic prompt caching docs имат reference за всички usage полета. Също така Bedrock docs за prompt caching описват AWS-специфичните имена на полета, ако сте на този доставчик.
Често задавани въпроси
Колко пари реално се спестяват с prompt caching?
При типичен workload с 75% cache hit rate и 10 000-токенов система промпт, повторен 2 000 пъти дневно, спестяванията са около $1 215/месец на Claude Sonnet 4.6. За тежки агенти с 50k+ токенов контекст числата бързо стигат десетки хиляди долари месечно. Реалният фактор е hit rate. Под 40% caching е нетна загуба.
Кога да използвам 1-часовия TTL вместо 5-минутния?
Използвайте 1-час когато знаете, че префиксът се preизползва на всеки 10+ минути между заявките, например voice agents с дълги паузи, batch pipelines или evening/morning admin workflows. За чат приложения с активни разговори 5-минутният default е по-евтин. Break-even за 1-час е третата заявка в прозореца.
Работи ли prompt caching със streaming?
Да, напълно. Caching е server-side операция и не зависи от това дали response-а стрийма, или се връща наведнъж. Cache read и write полета се появяват в финалния message_delta event на stream-а, точно както при non-streaming call.
Може ли Anthropic prompt caching да се комбинира с Bedrock или Vertex AI?
Да. Amazon Bedrock поддържа 1-часовия TTL за Claude Sonnet 4.5/4.6, Haiku 4.5 и Opus 4.5 във всички commercial и GovCloud региони от януари 2026 г. Google Cloud Vertex AI и Microsoft Foundry също поддържат prompt caching, но параметрите донякъде се различават. Проверете съответните SDK docs за actual field names.
Как да разбера дали заявката ми е ударила кеша?
Проверете полетата cache_read_input_tokens и cache_creation_input_tokens в response.usage. Ако cache_read е ненулево, кешът е hit. Ако cache_creation е ненулево, това е write. Ако и двете са 0 при поставен cache_control, префиксът е под минималния размер (1024/2048 токена) или има prefix drift.
Има ли лимит колко cache breakpoints мога да имам?
Anthropic позволява максимум 4 експлицитни cache_control маркера на заявка. Всичко преди последния маркер, което съвпада с предишен request в TTL прозореца, се таксува по cache read тарифа. Йерархичната стратегия (system, tools, RAG context, history) използва точно 4 breakpoints и покрива повечето production workloads.
Marcus has been gluing systems together for twelve years - first as an integrations engineer at Tray.io, then four years at MuleSoft (post-Salesforce acquisition) leading a team that built connectors for regulated-industry customers. He moved full-time into LLM orchestration in 2023 after a side project - an n8n workflow that triaged his consulting firm's intake email - replaced an actual headcount.
He focuses on the boring middle layer: idempotent webhook receivers, dead-letter queues for tool-call failures, and getting Temporal to play nicely with OpenAI's Assistants API. He's published two open-source n8n community nodes (one for Pinecone hybrid search, one for Anthropic prompt caching) and contributed retry-backoff improvements to the LangChain JS repo.
Lives in Atlanta. Writes about what actually breaks in production agents, not what looks good in a demo.
Практически наръчник за structured outputs от LLM с Pydantic v2 и instructor — OpenAI strict mode, Claude tool use, шаблони за повторения и продукционна наблюдаемост, тествани в реални пайплайни.
Научете как да изградите MCP сървър с Python и FastMCP от нулата. Практическо ръководство с код за свързване на AI агенти с бази данни, API-та и външни инструменти чрез Model Context Protocol.
Практическо ръководство за function calling и tool use с LLM — от дефиниране на инструменти и Claude API, през Structured Outputs и паралелни извиквания, до MCP стандарта и продукционни практики за сигурност.