Study guides / CCDV-F / Domain 1

Applications & Integration · Lesson 4 of 11

1.4 - Prompt Caching for Cost and Latency

Place cache breakpoints where they actually save money: on the large, stable prefix, not the part that changes every call.

Prompt caching lets you mark a point in your request — via a cache_control field of type ephemeral on a content block — after which everything before it can be reused on a later call instead of reprocessed from scratch. The response's usage object reports cache_creation_input_tokens (written to the cache this call, billed at a premium over a normal input token) and cache_read_input_tokens (served from cache on a later call, billed at a steep discount versus a fresh read — roughly a tenth of the normal input-token price). You can place up to four cache breakpoints in a single request, which matters when a request has more than one genuinely independent stable segment — for example a large tool-definitions block and a large reference document that both repeat, but not in lockstep with each other.

Where to put the breakpoint

The win only materialises if the cached prefix is large and genuinely repeated across calls — a long system prompt, a big document the user is asking multiple questions about, a large tool definitions block. Put the breakpoint after that stable content and before the part that changes every turn (the latest user message). A cache breakpoint placed after content that changes every call caches nothing useful and just adds the overhead of writing a cache entry that will never be read. Anthropic also imposes a minimum token count for a segment to be cacheable at all — a very short stable prefix isn't worth a breakpoint even if it's technically stable.

Cache lifetime and exact-prefix matching

A cache entry has a short default TTL (around five minutes from last use, refreshed on each cache hit), with a longer-lived option available for workloads with a bigger gap between calls. Caching works on an exact-prefix match: everything up to and including the cache-controlled block must be byte-identical to what was cached, or the cache misses entirely and that segment is reprocessed as a normal (uncached) read — it doesn't partially hit. This is why caching pairs naturally with stable ordering: tool definitions and system prompt first (rarely changing), then any large shared document, then the per-turn conversation, with the breakpoint placed right after the last block you want covered.

Common exam distractor

An answer suggesting caching speeds up token generation is wrong. Caching only cuts the cost and latency of re-processing input the model has already seen; it has no effect on how fast output tokens are produced once generation starts. A cached request can still take just as long to generate a long answer as an uncached one.

Caching inside an agentic loop

In a multi-turn tool-use loop, each new call resends the growing conversation, and that growing prefix is exactly what benefits most from caching as the loop goes on — the first several turns of a long agentic session are the ones repeated, unmodified, on every subsequent call. A common pattern is to move the breakpoint forward as the conversation grows, so the cached prefix always covers everything except the most recent one or two turns. Getting this wrong — leaving the breakpoint at its original position from turn one as the conversation grows past it — still caches something, just a shrinking fraction of an ever-larger request, which quietly erodes the savings the technique is supposed to provide.

Caching interacts with tools and system content too

A cache breakpoint isn't limited to the system block — it can sit on the last block of a tools array, on a document block, or on any content block in the message history. Because caching matches an exact prefix, the entire preceding structure of the request counts, including tool definitions: if your application sometimes sends a request with three tools and sometimes with four (say, a feature flag toggling one tool on or off), those are two different prefixes as far as the cache is concerned, and traffic split between them halves the effective cache hit rate for each variant. Keeping tool definitions stable and ordered identically across calls is part of getting real caching benefit in practice, not just an implementation detail.

The premium-to-discount trade

Writing to the cache costs more per token than an ordinary input token would — the first call that establishes a cache entry is more expensive than the same call without caching at all. The economics only work out because a cache write is meant to be read many times afterward at the steep discount; a cache breakpoint on content that will realistically only be sent once (a one-off request with no expected repeat) is a net loss, not a savings. The technique pays off specifically under repetition — the same stable prefix reused across several calls in quick succession — which is the scenario worth checking for before adding a breakpoint at all.

Exam traps

Practice question

An application sends the same 4,000-token set of tool definitions and a 2,000-token system prompt on every call, followed by a short, different user question each time. Where should the cache_control breakpoint go for maximum benefit?

  • A On the user's question block, since that's the newest content.

    The question changes every call, so caching it caches nothing reusable - the opposite of where the benefit lives.

  • B Immediately after the tool definitions and system prompt, before the user's question. Correct

    This caches the large, stable 6,000-token prefix that repeats on every call, while the short per-call question stays outside the cache as it should.

  • C There's no benefit to caching unless the entire conversation history is identical across calls.

    Caching works on a shared prefix, not an all-or-nothing identical request - this scenario is a textbook caching win.

  • D At the very start of the system prompt only, leaving the tool definitions uncached.

    This needlessly excludes 4,000 stable tokens from the cache, leaving most of the available savings on the table.

Build exercise: Measure the token-usage difference caching makes

Intermediate · 25 minutes

You'll practice:

  1. Send the same large system prompt (at least a few hundred tokens) with cache_control set on it, twice in a row with a different short user message each time.

    The second call is where you should actually see the cache pay off.

    You should see: The first call reports cache_creation_input_tokens; the second call reports cache_read_input_tokens instead, for roughly the same amount.

    Hints
    1. Which field in the content block, not the top-level request, is where cache_control actually goes?
    2. cache_control goes inside the content block object itself (e.g. on the system block or the last tool definition), not as a top-level request field. The cache has a short TTL - don't wait too long between the two calls or it may expire.
    3. system: [{ type: "text", text: longSystemPrompt, cache_control: { type: "ephemeral" } }]
  2. Now change one word in the cached system prompt and resend, comparing usage against the previous cached call.

    This demonstrates the exact-prefix-match rule directly instead of leaving it as an abstract claim.

    You should see: cache_read_input_tokens drops to zero or near-zero, and cache_creation_input_tokens appears again - a full cache miss and rewrite, not a partial hit.

    Hints
    1. If caching matched on similarity rather than an exact prefix, what would you expect instead of this result?
    2. Because the match is exact-prefix, any change before or at the breakpoint invalidates the whole cached segment - there's no partial credit for "almost the same".
    3. // After editing one word in the system prompt:
      console.log(response.usage.cache_read_input_tokens); // expect ~0
      console.log(response.usage.cache_creation_input_tokens); // expect a fresh write
  3. Simulate a growing multi-turn agentic conversation (append a few more turns each call) and move the cache_control breakpoint forward each time to always sit right before the newest one or two turns.

    This is the pattern a real agentic loop needs, and it's where a fixed, never-moving breakpoint quietly loses value as the conversation grows.

    You should see: cache_read_input_tokens grows call over call, tracking the growing stable prefix, rather than staying flat while the uncached remainder grows.

    Hints
    1. As the conversation grows, does the amount of content before your original fixed breakpoint change relative to the whole request?
    2. Move the cache_control marker onto the content block that is now second-to-last each time you send a new call, so the cached region always expands to just before the freshest turn.
    3. // Turn N: breakpoint on messages[messages.length - 2]
      messages[messages.length - 2].content[0].cache_control = { type: "ephemeral" };

Sources