Skip to content
DWKD

Tool note

Claude: Prompt Caching for the Person Paying

A defeated cache never throws an error — it returns the right answer at full price, so the only place you can see it is the token counter.

Your system sends a large block of identical bytes on every request: instructions, tool definitions, reference material, examples. Then it sends the one short thing the user asked. Prompt caching lets the provider keep that stable block prepared so repeat sends are billed at a discount, and it is the only cost lever that has no quality cost at all.

The interesting part is not that caching exists. It is that failing to hit it is completely invisible. Nothing errors, nothing degrades, and the only symptom arrives on the invoice weeks later.

Why this exists

Caching works on a prefix, and a prefix is all-or-nothing from the first byte that differs. One changed character near the top invalidates everything after it and you get no benefit whatsoever — while still returning a correct answer, at full price, with no warning anywhere in the response your code looks at.

The ordering mistake behind it is always mundane. A current date at the top of the system prompt. A request ID added for logging. A user’s name placed above the shared instructions instead of below. Retrieved documents in whatever order the search returned them.

The nastiest version is this one: tool definitions serialized by iterating a map whose order is not guaranteed across processes. Inside one worker the order is stable, so the cache hits and everything looks fine in development, where there is a single process and a warm cache. In production, across restarts and a pool of workers, each process builds a different prefix and the hit rate collapses. The code is identical in both places. That is why this one survives review.

How to use it

Measure the overlap before you write anything. Print the full payload for two consecutive real requests and diff them byte for byte. The identical portion is what you are currently paying full price to resend. That number is the size of the prize, and you have it before writing any code.

Order strictly from stable to variable — system instructions, tool definitions, reference material, examples, conversation history, then the current question — and put the cache boundary at the last byte that is identical across requests, not at a section break that feels tidy.

Sort everything that arrives from somewhere else. Retrieval results, tool lists, key order in any serialized structure. Determinism is the whole requirement.

Then make the regression impossible to merge. Write a test that builds the payload for two different inputs and asserts the first N bytes are identical. This is the step most teams skip and the one that matters, because the change that breaks a cache — a field added near the top — looks harmless in review in every respect except this one. Then log the cached-token count beside the regular input count, put the ratio next to spend, and alert when it falls.

One consequence worth using: once the prefix is cached, longer and clearer instructions become the cheap option. Teams trim prompts to save money and pay for it in quality; with caching in place, that trade largely disappears.

Where it goes wrong

Output is not cached. On Claude Opus 5, output is billed at five times input; on Fable 5.1, the same five-to-one. If your responses are long, caching will not touch that, and a tighter output format will.

Low volume can lose. Cache entries expire. If your requests arrive further apart than the entry lives, you pay to write the cache repeatedly and never read it. Check whether your provider bills a cache write above the base input rate — if it does, caching an occasional-use system can cost more than not caching it at all.

Unique input has no prefix to share. If every request carries a different large document, only the instructions above it benefit.

And caching makes waste affordable, which is not the same as removing it. A bloated prompt that now costs less is still bloated, and human review time — usually the largest cost in the whole system — is unaffected by any of this.

Copy and Clear become available when the worksheet is ready.

PROMPT CACHE AUDIT — MEASURE, ORDER, INSTRUMENT, DEFEND

Run top to bottom. Steps 1-2 need no code changes.

STEP 1 — SIZE THE PRIZE (30 minutes, no code changes)

Raw bytes as sent, not a pretty-printed summary.

total input tokens, request A .........

total input tokens, request B .........

byte-identical leading prefix ......... tokens

identical prefix as % of input ........ %

caching is not your cost problem.

STEP 2 — FIND WHAT BREAKS THE PREFIX

Walk the first 500 bytes of the payload and mark anything that varies:

  • "today you are helping " style personalization

For each hit, decide: move it below the boundary, sort it, or drop it.

Most timestamps and request IDs do not need to be in the prompt at all.

STEP 3 — THE ORDER (stable to variable, always)

  1. system instructions stable <- cache this
  2. tool definitions stable <- cache this (SORT THEM)
  3. reference material stable <- cache this
  4. worked examples stable <- cache this
  5. --------- CACHE BOUNDARY: last byte identical across requests ---
  6. conversation history grows by append only
  7. retrieved context for this request
  8. the user's actual question

Rules:

  • Boundary goes at the last identical byte, not at a tidy section break.
  • Append to history; never rewrite or re-summarize earlier turns in place.
  • Sort retrieved context by a stable key (id, then score), never by

whatever the search returned.

STEP 4 — THE TEST THAT KEEPS IT WORKING

Pseudocode. Put it in CI next to your other tests.

def test_prompt_prefix_is_stable():

a = build_payload(user="", question="")

b = build_payload(user="", question="")

n = expected stable prefix length in bytes

assert a[:n] == b[:n], first_difference(a, b)

def test_tool_definitions_are_sorted():

names = [t["name"] for t in build_tool_definitions()]

assert names == sorted(names)

Run build_payload in a fresh process twice and compare, too — that is

the check that catches map-iteration order.

STEP 5 — INSTRUMENTATION (log on every call)

model

input_tokens_uncached

input_tokens_cache_read

input_tokens_cache_write

output_tokens

cache_read_ratio cache_read / (cache_read + uncached)

prompt_build_version hash of the stable prefix

Dashboard: cache_read_ratio over time, on the same screen as spend.

Alert: ratio drops more than 20 points day over day.

The prompt_build_version hash tells you which deploy did it.

STEP 6 — WHAT CACHING WILL NOT FIX

Fix with a tighter output format instead.

still waste. Delete it, then cache what remains.

you pay writes and never read. Check whether a write is billed

above base input before you model any saving.

COST LEVERS, CHEAPEST FIRST

  1. caching no quality cost
  2. input hygiene remove context you cannot justify
  3. output discipline ask for a tighter format
  4. effort setting real trade-off, measure it
  5. model tier biggest trade-off, do it last

Most teams start at 5 and never do 1 and 2.