C.W.K.
Stream
Lesson 05 of 06 · published

Prompt Caching for Real Dollar Savings

~16 min · prompt-caching, cache-control, ephemeral

Level 0Observer
0 XP0/64 lessons0/13 achievements
0/150 XP to next level150 XP to go0% complete

What prompt caching does

Mark a prefix of your prompt as cacheable and Anthropic stores the model state for it. Subsequent calls that send the same prefix read from cache instead of re-tokenizing — significantly cheaper and faster. Cache reads typically cost a fraction of base input tokens; cache writes cost more than base input tokens (the first call), so caching pays off when the prefix is reused.

Where to put cache_control

You attach cache_control: {"type": "ephemeral"} to a content block (system text, tools list, message content, or document). The cache breakpoint marks 'everything up to here is cacheable.' Anthropic supports up to 4 cache breakpoints per request — enough for system + tools + a stable history slice.

What invalidates the cache

Any change to the cached prefix invalidates the cache. That includes whitespace changes in the system prompt, tool definition changes, or shuffled message order. Stable prefixes are the engineering goal; if your prompt construction reorders or rewrites things, you will rarely see a cache hit.

Principle: Caching rewards stable prefixes. Make the front of your prompt boring on purpose.

Code

Cache the system prompt and the tools list·python
PIPPA_PERSONA = open("system_prompt.md").read()  # tens of KB of stable identity

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": PIPPA_PERSONA,
            "cache_control": {"type": "ephemeral"},  # breakpoint #1
        }
    ],
    tools=[
        # ... long tool definitions ...
        {"name": "last_tool", "description": "...", "input_schema": {...},
         "cache_control": {"type": "ephemeral"}},  # breakpoint #2
    ],
    messages=[{"role": "user", "content": "hi"}],
)

u = response.usage
print("cache_creation_input:", u.cache_creation_input_tokens)
print("cache_read_input:", u.cache_read_input_tokens)
print("input:", u.input_tokens, "output:", u.output_tokens)
Verify a cache hit·python
# Run the same call twice within the cache TTL (5 minutes default ephemeral).
for i in (1, 2):
    r = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=64,
        system=[{"type": "text", "text": LARGE_STABLE_TEXT, "cache_control": {"type": "ephemeral"}}],
        messages=[{"role": "user", "content": f"call {i}"}],
    )
    u = r.usage
    print(f"call {i}: write={u.cache_creation_input_tokens}, read={u.cache_read_input_tokens}")
# Expected: call 1 has write > 0, read = 0. Call 2 has write = 0, read > 0.

External links

Exercise

Take a prompt where you resend a stable preamble across 10 calls. Add a cache_control breakpoint at the preamble boundary. Compare total cost (read tokens at cache rate + write once) vs without caching.
Hint
Cache writes are more expensive than regular input tokens (~25% more) but reads are dramatically cheaper. Break-even is usually 2-3 calls.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.