Back to Insights
21 Jun 20265 min readAI & LLMs

Your Claude Agent Re-Reads Its Whole Prompt Every Turn. Here's the 10× You're Leaving On the Table.

Every turn your agent takes, it re-sends the same thing: a big system prompt, a frozen tool list, a growing transcript. A 10,000-token system prompt that doesn't change between turns gets re-processed, at full price, on turn 1, turn 2, turn 20. Prompt caching exists to stop exactly that — and on a repeated prefix it makes the repeat cost one tenth of full price. Most teams have it switched on and still pay nearly full freight, because one byte in the wrong place silently turns it off. This is the whole game, and the part nobody measures.

One invariant, and three numbers

Prompt caching is a prefix match. Any change anywhere in the prefix invalidates everything after it. The cache key is the exact bytes of the rendered prompt up to each cache_control breakpoint. The render order is fixed: tools → system → messages. A single differing byte at position N kills the cache for everything at or after N.

The economics are three multipliers of a model's base input price:

multiplierwhen
uncached input1.00×every token, every request
cache write1.25×first request (5-minute TTL; 2.00× for 1-hour)
cache read0.10×every later request that hits

So on a cached prefix you pay a 25% premium once, then 90% off forever after. Break-even is the second request: 1.25 + 0.10 = 1.35× for two cached requests versus 2.00× uncached. Everything past that is gravy. For a 1-hour TTL the write is doubled, so you need three requests to come out ahead — worth it only when traffic is bursty enough that the longer-lived entry survives the gaps.

The field everyone reads wrong

The response usage object tells you what actually happened:

  • cache_creation_input_tokens — tokens written this request (you paid 1.25×)
  • cache_read_input_tokens — tokens served from cache (you paid 0.10×)
  • input_tokens — tokens processed at full price

The trap: input_tokens is only the uncached remainder. Total prompt size is input_tokens + cache_creation_input_tokens + cache_read_input_tokens. We've watched people conclude "caching isn't doing anything, input_tokens is still 4,000" — while 60,000 tokens quietly flowed through cache_read_input_tokens next to it. Read the sum, not the one field. And if cache_read_input_tokens is zero across repeated requests with the "same" prefix, you don't have a pricing problem — you have a silent invalidator.

The silent invalidators (grep your prompt-building code for these)

This is the actionable part. Every one of these sits in the prefix and changes its bytes per request, so nothing after it ever caches:

PatternWhy it kills caching
datetime.now() / Date.now() in the system promptthe prefix changes every request
uuid4() / request IDs early in contentevery request is byte-unique
json.dumps(d) without sort_keys=True, or iterating a setnon-deterministic serialization
f-stringing a session/user ID into the system promptper-user prefix; zero cross-user sharing
if flag: system += "..." conditional system sectionsevery flag combo is a distinct prefix
tools=build_tools(user) where the set variestools render at position 0 — nothing caches across users

The fix is always the same shape: keep the system prompt and tool list frozen, and move anything volatile to the end, after the last breakpoint. A "current date: …" line belongs in a user message at turn 5, not in the system header where it poisons everything downstream. Serialize tools deterministically (sort by name). A message at turn 5 invalidates nothing before turn 5; a byte in the system header invalidates the entire conversation.

Two gotchas that look like bugs

Minimum cacheable prefix is model-dependent — and bigger than you think. Below the floor, the marker is silently ignored: no error, just cache_creation_input_tokens: 0.

ModelMinimum
Opus 4.8 / 4.7 / 4.6, Haiku 4.54096 tokens
Sonnet 4.62048 tokens
Sonnet 4.51024 tokens

A 3,000-token preamble caches fine on Sonnet 4.5 and silently won't on Opus 4.8. If you switched models and your hit rate cratered, this is why.

The 20-block lookback. Each breakpoint walks back at most 20 content blocks to find a prior entry. An agentic turn that appends 30 tool_use/tool_result blocks pushes the previous cache out of range, and the next request misses silently. Fix: drop an intermediate breakpoint every ~15 blocks in long turns. (Related: on a fan-out, send one request, await its first streamed token, then fire the rest — a cache entry only becomes readable once the first response starts streaming, so N parallel requests all pay full price.)

Putting a number on it

We wrote a tiny, dependency-free tool, cachecost, that reads a usage object and tells you what caching did — in model-agnostic base-input-token units, so the answer doesn't depend on today's price sheet. On a cache read of a ~10,000-token prefix:

$ cachecost explain read-usage.json
  cache state : READ (served from cache at 0.10x)
  uncached    : 30 tok
  cache write : 0 tok  x1.25
  cache read  : 10,000 tok  x0.1
  cacheable prefix this request: 10,000 tok
  ---
  input cost (eq tokens)     : 1,030
  same prompt, caching OFF   : 10,030
  >> saved 9,000 eq-tokens on this request (89.7% off the input).

And amortized the way agents actually run — one write, then many reads:

$ cachecost amortize write-usage.json read-usage.json --reads 10
  cached  : 1 write (12,500) + 9 reads (1,000 each) = 21,500 eq-tok
  uncached: 10 x 10,000 = 100,000 eq-tok
  >> 78.5% cheaper on the prefix across 10 requests (78,500 eq-tokens saved).

The cost arithmetic is locked down with tests (11/11). The multipliers above are the published ones; to see your real token counts, point measure-cache.sh at a funded API key — it fires two identical-prefix calls and prints the cache_creation/cache_read split so you can confirm the cache actually engaged before trusting any savings estimate.

The real lesson

Prompt caching isn't a feature you turn on; it's a property of how you assemble the prefix. Get the ordering right — frozen system, deterministic tools, volatile content last — and the 90% is automatic. Get one datetime.now() in the system header and no quantity of cache_control markers will save you. The single highest-leverage thing you can do for an agent's bill is grep the six patterns above out of your prompt-building path, then watch cache_read_input_tokens climb.

We build and run autonomous agent fleets on Claude in production. If you're hardening — or trying to afford — a multi-agent setup, talk to us.


Get the tool → cachecost in agent-ops — open source (MIT), a single dependency-free script, part of our toolkit for running coding agents in production.

AI agentsprompt cachingcosteconomicsClaude

Found this useful?