Mingyu's Library主页
深度学习 · 2026-08-21 Deep Dive · 2026-08-21

同一个 Agent,只挪了一行字,账单降了 59%

Same agent, one line moved, 59% off the bill

Prompt 缓存不是一个「打开就省钱」的开关,而是一门需要主动设计请求结构的手艺。厂商宣传的是「最高 90%」,跨三家 500+ 真实 agent 会话的实测区间是 41–80%,而多数团队的起点是 7%。这份文档讲清缓存到底怎么命中、怎么被打破、以及六步把命中率提上去。

Prompt caching is not a switch you flip to save money — it's a discipline that requires designing the shape of your requests. Vendors advertise "up to 90%." A measurement across 500+ real agent sessions on three providers found 41–80% in practice. Most teams start at 7%. This guide covers how a cache hit actually happens, what breaks it, and six steps to fix your hit rate.

调研时间:2026-08-21 · 阅读约 20 分钟 · 全文含 3 张图解 · 所有关键数字附来源

Researched 2026-08-21 · ~20 min read · 3 diagrams · Every key number is sourced

0030 秒速览

00The 30-second version

如果你只读一段,读这段。

If you read only one paragraph, read this one.

Prompt 缓存(prompt caching)的原理很朴素:模型把你请求开头那一段一模一样、一字不差的内容的计算结果存起来,下次同样的开头直接复用,只算新增的部分。省钱和省延迟都来自这里。关键词是前缀(prefix)——它只从头开始匹配,遇到第一个不同的 token 就停止,后面全部重算。

Prompt caching works on a plain idea: the model stores the computed state for the opening stretch of your request — byte-for-byte identical — and reuses it next time, computing only what's new. Both the cost savings and the latency savings come from that. The operative word is prefix: matching starts at position zero and stops at the first token that differs. Everything after that point is recomputed.

这就带来了整件事最反直觉的一点:缓存是否命中,取决于你把动态内容放在哪里,而不取决于动态内容有多少。一个 4,000 token 的系统提示里塞了一个每次都变的会话 ID,如果它在中间,那 4,000 token 每次全额重算;把它挪到末尾,前面 3,900 多个 token 全部命中。有实测记录的一个安全情报 Agent,做的正是这一个改动:命中率 7% → 74%,月度推理账单降 59%(来源 [2])

Which leads to the least intuitive fact in the whole topic: whether you get a cache hit depends on where the dynamic content sits, not on how much of it there is. A 4,000-token system instruction with one per-request session ID buried in the middle recomputes all 4,000 tokens every time. Move that ID to the end and roughly 3,900 of them hit cache. A documented security-intelligence agent made exactly that one change: hit rate went 7% → 74% and the monthly inference bill dropped 59%. (Source [2])

0.1×
Anthropic 缓存读取价 / 基础输入价
1.25×
缓存写入价 / 基础输入价
41–80%
500+ 真实会话实测的节省区间
13–31%
首 token 时间(TTFT)缩短幅度
0.1×
Anthropic cache read vs. base input price
1.25×
Cache write vs. base input price
41–80%
Measured savings across 500+ real sessions
13–31%
Reduction in time-to-first-token
一句话判断你有没有这个问题 A one-line test for whether this applies to you

打开你的用量面板,看 cache read token 占总输入 token 的比例。如果这个数低于 50%,而你的 Agent 每轮都发同一份系统提示和工具定义,那你几乎肯定在为已经算过的东西重复付钱。

Open your usage dashboard and look at cache-read tokens as a share of total input tokens. If that number is under 50% while your agent sends the same system prompt and tool definitions every turn, you are almost certainly paying twice for work the model already did.

01Agent 为什么特别吃缓存

01Why agents live or die on cache

聊天应用里缓存是锦上添花;在 Agent 循环里它是成本结构的主导项。

In a chat app, caching is a nice-to-have. In an agent loop, it dominates the cost structure.

单轮问答的成本模型很简单:发一份 prompt,收一份回答。Agent 不是这样。一个 Agent 完成一个任务要跑十几轮甚至上百轮,每一轮都要把完整的历史重新发一遍——系统提示、工具定义、之前所有的思考与工具结果。第 20 轮发送的输入,可能是第 1 轮的十几倍。

Single-turn Q&A has a simple cost model: send a prompt, get an answer. Agents don't work that way. Completing one task takes a dozen turns, sometimes a hundred, and every turn resends the entire history — system prompt, tool definitions, all prior reasoning and tool results. The input on turn 20 can be an order of magnitude larger than on turn 1.

这正是缓存的理想场景:每一轮的输入都是上一轮输入的严格前缀延长(append-only)。理论上,第 N 轮只需要为「第 N−1 轮之后新增的那点内容」付全价,前面全部按 0.1× 计费。理论上。

That is the ideal case for caching: each turn's input is a strict append-only extension of the previous turn's. In theory, turn N pays full price only for what was added since turn N−1, and everything before it bills at 0.1×. In theory.

打个比方

把模型想成一个每天早上都要重读一遍项目背景才能开工的同事。缓存等于让他「昨天读到哪、今天从哪接着读」。但他有个怪癖:只要你在文档开头改了一个字——哪怕只是把日期从 8 月 20 日改成 8 月 21 日——他就会从第一页重新读起。

An analogy

Think of the model as a colleague who has to re-read the whole project background every morning before starting work. Caching means he picks up where he stopped yesterday. But he has a quirk: change one character near the front of the document — even just the date, from Aug 20 to Aug 21 — and he starts over from page one.

Agent 循环把这个怪癖放大了。因为历史很长,前缀失效的惩罚不是「多算一点」,而是「把已经积累的整个上下文全额重算」。一个 100k token 的 Agent 会话,前缀被破坏一次,这一轮就要按全价重付 100k 输入 token,而不是 0.1× 的 10k 等效价。这就是为什么一份实践分析把它称作「Agent 循环打破缓存并抽干你的预算」。(来源 [8])

The agent loop amplifies that quirk. Because the history is long, a prefix miss doesn't mean "a bit of extra compute" — it means recomputing the entire accumulated context at full price. In a 100k-token agent session, one broken prefix costs you 100k input tokens at full rate rather than the 10k-equivalent you'd have paid at 0.1×. Hence the framing in one production analysis: agent loops break caching and drain your budget. (Source [8])

本文假设你已经知道:token 是什么、system prompt 与 tool definitions 会被一起发给模型、以及 Agent 是「模型调工具 → 拿结果 → 再想」的循环。不需要任何缓存的前置知识。
Assumed background: what a token is, that the system prompt and tool definitions are sent to the model along with the conversation, and that an agent is a loop of "model calls a tool → gets a result → thinks again." No prior knowledge of caching is needed.

02前缀缓存到底怎么工作

02How prefix caching actually works

三个概念:前缀匹配、断点、TTL。理解这三个,后面全是推论。

Three concepts: prefix matching, breakpoints, TTL. Everything else follows from them.

前缀匹配(prefix matching)

缓存查找只从请求的第 0 个 token 开始,逐 token 比对,遇到第一个不同就停。停下来的位置之前算命中,之后全部重算。它不做「中间那段一样」的模糊匹配——不是搜索,是精确的开头比对。

Prefix matching

Cache lookup starts at token 0 of the request and compares token by token until the first difference. Everything before that point is a hit; everything after is recomputed. There is no fuzzy "the middle section is the same" matching — it isn't search, it's an exact comparison from the front.

缓存断点(cache breakpoint)

你在请求里显式标记「到这里为止的内容请存下来」的位置。Anthropic 用 cache_control 参数标记,每个请求最多 4 个断点。OpenAI 走的是自动前缀缓存,不需要你标记。

Cache breakpoint

An explicit marker saying "store everything up to here." Anthropic marks these with the cache_control parameter, with up to 4 breakpoints per request. OpenAI uses automatic prefix caching instead, requiring no markers from you.

TTL(存活时间)

缓存条目多久过期。Anthropic 的每个断点有 ephemeral TTL,默认 5 分钟(每次命中刷新),也可选 1 小时——1 小时档的写入价是基础输入价的 2×。同一请求里两种 TTL 可以混用,但 1 小时的条目必须排在 5 分钟的前面。

TTL (time to live)

How long an entry survives. Each Anthropic breakpoint carries an ephemeral TTL: 5 minutes by default, refreshed on every hit, or 1 hour as an option — the 1-hour tier writes at 2× base input price. You can mix both TTLs in one request, but 1-hour entries must appear before 5-minute ones.

情况 A · 动态内容在中间 系统提示 2,000 token · 静态 会话 ID 12 token · 每次变 工具定义 1,800 token · 静态 对话历史 追加增长 命中 2,000 全额重算 · 剩下全部 情况 B · 动态内容挪到末尾 系统提示 2,000 token · 静态 工具定义 1,800 token · 静态 对话历史 追加增长 会话 ID 12 token 命中 3,800 + 历史 只重算 12 同样的内容、同样的 token 总量,只改了顺序。 实测案例:命中率 7% → 74%,月度推理账单降 59%(来源 [2])

图 1 · 前缀缓存只从头匹配。一个 12 token 的动态字段放在中间,就让它后面的 3,800 个静态 token 全部作废;挪到末尾,损失降到 12 个 token。这不是优化技巧,这是缓存机制的直接推论。

Case A · dynamic field in the middle System prompt 2,000 tokens · static Session ID 12 tokens · varies Tool definitions 1,800 tokens · static Conversation append-only 2,000 hit full recompute · everything after Case B · dynamic field moved to the end System prompt 2,000 tokens · static Tool definitions 1,800 tokens · static Conversation append-only Session ID 12 tokens 3,800 + history hit 12 recomputed Same content, same token count. Only the order changed. Documented case: hit rate 7% → 74%, monthly inference bill down 59% (Source [2])

Figure 1 · Prefix caching matches from position zero. A 12-token dynamic field in the middle invalidates the 3,800 static tokens behind it; moved to the end, the loss shrinks to 12 tokens. This isn't a clever trick — it falls straight out of how the mechanism works.

03三家机制与定价对比

03Three vendors compared

手动 vs 自动、折扣多少、什么时候值得。

Manual vs. automatic, how big the discount is, and when it pays off.

维度Anthropic ClaudeOpenAIGoogle Gemini
触发方式自动缓存 + 可选 cache_control 显式断点(每请求最多 4 个)自动前缀缓存,零代码改动隐式 + 显式两种
缓存读取折扣0.1× 基础输入价(约省 90%)约省 50%约 90% 折扣(2.5 系列)
缓存写入成本1.25× 基础输入价(5 分钟档);1 小时档 2×不额外收写入费另有存储计费维度
TTL5 分钟(命中即刷新)或 1 小时由平台管理可配置
最小可缓存长度按模型不同,如 1,024 / 2,048 token 起有最小长度门槛有最小长度门槛
DimensionAnthropic ClaudeOpenAIGoogle Gemini
How it triggersAutomatic caching plus optional explicit cache_control breakpoints (max 4 per request)Automatic prefix caching, zero code changesBoth implicit and explicit modes
Cache read discount0.1× base input price (~90% off)Roughly 50% savings~90% discount on 2.5-series models
Cache write cost1.25× base input (5-min tier); 2× for the 1-hour tierNo separate write chargeSeparate storage billing dimension
TTL5 minutes (refreshed on hit) or 1 hourPlatform-managedConfigurable
Minimum cacheable lengthModel-dependent, e.g. from 1,024 / 2,048 tokensHas a minimum-length thresholdHas a minimum-length threshold

来源 [1][3][4]。定价与门槛数字随模型代际变化,落地前请以各家当前官方文档为准。

Sources [1][3][4]. Pricing and thresholds shift between model generations; check each vendor's current docs before you build on these numbers.

5 分钟还是 1 小时?一个可以直接套的判据

Five minutes or one hour? A rule you can apply directly

因为 1 小时档的写入价是 2×(而 5 分钟档是 1.25×),你需要在这一小时内至少读 3 次才能比 5 分钟档划算;5 分钟档只需要读 2 次就回本。实践建议是:交互式、流量稳定 → 用默认 5 分钟;流量突发或请求之间间隔长 → 考虑 1 小时,批处理是典型场景(一个批次跑完往往超过 5 分钟)。如果流量尖峰且不可预测,5 分钟是更安全的默认值。(来源 [3])

Because the 1-hour tier writes at 2× (against 1.25× for the 5-minute tier), you need at least three reads within that hour to come out ahead; the 5-minute tier breaks even at two reads. The practical guidance: interactive workloads with steady traffic → stay on the 5-minute default; bursty or widely spaced requests → consider the hour, with batch processing as the obvious case (a batch often takes longer than five minutes to work through). If your traffic is spiky and unpredictable, 5 minutes is the safer default. (Source [3])

先自动,后手动 Automatic first, manual second

官方建议是从自动缓存开始——它以最小成本覆盖了大多数用例;只有当你确实需要细粒度控制(比如想把工具定义和系统提示分成两个独立的缓存段,让工具集变化时不牵连系统提示)时,才切到显式断点。过早手动标断点是常见的过度工程。

The documented recommendation is to start with automatic caching — it covers the majority of use cases with minimal effort. Switch to explicit breakpoints only when you genuinely need fine-grained control, e.g. splitting tool definitions and system prompt into separate cache segments so a change to the tool set doesn't invalidate the prompt. Reaching for manual breakpoints too early is a classic case of over-engineering.

04提高命中率的六步

04Six steps to a higher hit rate

按顺序做,前两步通常就能拿走大部分收益。

Do them in order. The first two usually capture most of the win.

  1. 先测,别先改把 cache read token / 总 input token 这个比值打进你的可观测面板,按会话统计。没有基线,后面所有改动都是盲改。一份行业分析的判断是:大多数 Agent 的真实命中率大约在 7% 左右,而团队普遍以为自己在 90%。
  2. 前缀重排:静态在前,动态在后把系统提示、工具定义、少样本示例、政策文本这些「永远不变」的内容全部推到最前面;把时间戳、会话 ID、用户 ID、当前日期这些每次都变的东西推到最后。这一步不需要改 API 调用方式、不引入延迟风险,是收益/成本比最高的一步。
  3. 让更新变成 append-onlyAgent 的历史应该只往后追加,不要回头重写。任何「重新生成一遍系统提示」「把摘要插回开头」的操作都会摧毁前缀。如果框架帮你自动做了这类事,先把它关掉。
  4. 把缓存边界划在实时数据之前工具返回的实时数据(股价、天气、库存)不要落进缓存段。缓存边界应该停在任何实时工具输出之前,否则后续请求会基于陈旧数据推理——这是正确性问题,不只是成本问题。
  5. 稳定工具定义与顺序工具定义被包含在 prompt 里,工具集一变、甚至只是顺序随机化,前缀就作废。把工具列表排序固定下来;动态工具加载要放在缓存边界之后,或者索性用 tool-search 这类模式,避免每轮工具集抖动。
  6. 控制压缩(compaction)频率会话压缩会重写历史开头,等于主动作废整个缓存。压缩阈值设得越激进,缓存被砸得越频繁。把压缩当成一次性的昂贵操作来安排,而不是每 N 轮自动触发。
  1. Measure before you change anythingPut the ratio of cache-read tokens to total input tokens on your observability dashboard, per session. Without a baseline every subsequent change is a guess. One industry analysis puts the typical real-world agent hit rate at around 7%, while teams generally assume they're near 90%.
  2. Restructure the prefix: static first, dynamic lastPush everything that never changes — system prompt, tool definitions, few-shot examples, policy text — to the very front. Push everything that changes per request — timestamps, session IDs, user IDs, today's date — to the very end. This step requires no API changes and carries no latency risk, which makes it the best return on effort available.
  3. Make updates append-onlyAgent history should only grow at the tail; never rewrite what came before. Anything that regenerates the system prompt or splices a summary back into the opening destroys the prefix. If your framework does this automatically, turn it off first.
  4. Put the cache boundary before any live dataLive tool output — stock prices, weather, inventory — must not land inside a cached segment. The boundary belongs before live results, otherwise later requests reason over stale data. That's a correctness problem, not just a cost one.
  5. Stabilise tool definitions and their orderTool definitions travel inside the prompt. Change the tool set — or merely randomise its order — and the prefix is void. Fix a deterministic ordering for your tool list. Dynamic tool loading belongs after the cache boundary, or should be replaced with a tool-search pattern so the tool set stops jittering every turn.
  6. Control how often you compactCompaction rewrites the head of the conversation, which deliberately voids the entire cache. The more aggressive your compaction threshold, the more often the cache gets smashed. Treat compaction as an expensive one-off you schedule, not something that fires automatically every N turns.
推荐排布:按「变化频率」从低到高排序 ① 系统提示 / 角色定义 / 政策文本 变化频率:几乎从不 · 断点 1 · 建议 1 小时 TTL BP1 ② 工具定义(顺序固定)/ 少样本示例 变化频率:发版时 · 断点 2 BP2 ③ 检索到的文档 / 长期记忆(本会话内不变的部分) 变化频率:每会话 · 断点 3 BP3 ④ 对话历史(只追加,不回改) 变化频率:每轮追加 · 断点 4 滚动前移 BP4 ⑤ 时间戳 / 会话 ID / 用户上下文 / 实时工具结果 变化频率:每次请求 · 绝不放进缓存段 越靠上越稳定 · 缓存收益越大;越靠下越易变 · 重算代价越小

图 2 · 一个可以照抄的请求排布。核心规则只有一条:按「变化频率」从低到高排,让最稳定的内容占据最长的前缀。Anthropic 每请求最多 4 个断点,把它们放在变化频率的边界上。

Recommended layout: order by how often each part changes ① System prompt / role definition / policy text Changes: almost never · breakpoint 1 · consider 1-hour TTL BP1 ② Tool definitions (fixed order) / few-shot examples Changes: on release · breakpoint 2 BP2 ③ Retrieved documents / long-term memory (stable within a session) Changes: per session · breakpoint 3 BP3 ④ Conversation history (append-only, never rewritten) Changes: appended each turn · breakpoint 4 rolls forward BP4 ⑤ Timestamps / session ID / user context / live tool results Changes: every request · never inside a cached segment Higher = more stable = bigger caching win. Lower = more volatile = cheaper to recompute.

Figure 2 · A layout you can copy. One rule drives it: sort by change frequency, lowest first, so the most stable content occupies the longest possible prefix. Anthropic allows four breakpoints per request — place them on the change-frequency boundaries.

代码长什么样

What this looks like in code

# ❌ 反模式:动态内容混在静态内容中间
system = f"""你是一个代码审查助手。
当前时间:{datetime.now()}          # ← 每次都变,毁掉后面全部
会话:{session_id}                   # ← 同上
{3000_tokens_of_review_guidelines}   # ← 静态,但已经缓存不到了
"""

# ✅ 正确:静态在前,动态压到最后
system = [
    {
        "type": "text",
        "text": REVIEW_GUIDELINES,        # 3000 token,永不变
        "cache_control": {"type": "ephemeral", "ttl": "1h"},
    },
    {
        "type": "text",
        "text": TOOL_USAGE_NOTES,          # 变化频率:发版时
        "cache_control": {"type": "ephemeral"},   # 默认 5 分钟
    },
    {
        "type": "text",
        "text": f"当前时间:{now}\n会话:{session_id}",  # 动态,断点之后
    },
]
# 注意:1 小时 TTL 的段必须排在 5 分钟 TTL 的段之前
# ❌ Anti-pattern: dynamic content buried among static content
system = f"""You are a code review assistant.
Current time: {datetime.now()}       # ← changes every call, voids everything below
Session: {session_id}                # ← same problem
{3000_tokens_of_review_guidelines}   # ← static, but now uncacheable
"""

# ✅ Correct: static first, dynamic pushed to the tail
system = [
    {
        "type": "text",
        "text": REVIEW_GUIDELINES,        # 3,000 tokens, never changes
        "cache_control": {"type": "ephemeral", "ttl": "1h"},
    },
    {
        "type": "text",
        "text": TOOL_USAGE_NOTES,          # changes only on release
        "cache_control": {"type": "ephemeral"},   # 5-minute default
    },
    {
        "type": "text",
        "text": f"Current time: {now}\nSession: {session_id}",  # dynamic, after the breakpoint
    },
]
# Note: 1-hour TTL segments must come before 5-minute TTL segments

写法依据 Anthropic 官方 prompt caching 文档 [1];具体字段名与可选值请以当前文档为准。

Structure follows Anthropic's prompt caching documentation [1]; verify field names and accepted values against the current docs.

05真实数字与边界

05Real numbers, real limits

宣传值、实测值、和你大概率会拿到的值。

The advertised number, the measured number, and the one you'll probably get.

先说结论:各家宣传的「最高 90%」是理论上限,不是你的预期值。一份 2026 年 1 月的研究在 OpenAI、Anthropic 与 Google 上测量了 500+ 个真实 agent 会话,得出的实际节省区间是 41–80%。这个差距不是厂商在夸大——90% 指的是「缓存读 vs 全价输入」的单价折扣,而 41–80% 是「一整个会话的实际账单差异」,中间隔着写入成本、未命中的部分和 output token。(来源 [2])

The headline first: the "up to 90%" every lab markets is a theoretical ceiling, not your expected value. A January 2026 study measured caching across 500+ real agent sessions on OpenAI, Anthropic and Google and found actual savings of 41–80%. That gap isn't vendors exaggerating — 90% describes the unit-price discount on a cache read versus full-price input, while 41–80% describes the difference in a whole session's bill, with write costs, unhit segments and output tokens sitting in between. (Source [2])

7% → 74%
安全情报 Agent:仅移动一个动态标识符
−59%
同一改动带来的月度推理账单下降
45–80%
缓存对 Agent API 成本的削减幅度
2–3 次
同一前缀至少被读这么多次才回本
7% → 74%
Security-intelligence agent: one identifier moved
−59%
Monthly inference bill drop from that same change
45–80%
Range of API cost reduction attributed to caching
2–3×
Reads of the same prefix needed to break even

延迟收益比成本收益小但真实:多份实践报告给出的首 token 时间(TTFT)缩短 13–31%。对交互式产品,这个数量级足以被用户感知到。(来源 [2][6])

The latency win is smaller than the cost win but real: practice reports converge on a 13–31% reduction in time-to-first-token. For interactive products that magnitude is perceptible to users. (Sources [2][6])

2026 年被反复提到的「成本优化三件套」是:为静态结构做前缀缓存为增长中的上下文做对话压缩把语义缓存或计划缓存作为上层优化。这三层解决的是不同的问题,不能互相替代——前缀缓存省的是重复计算,压缩省的是上下文体积,语义缓存省的是「同样的问题被问了第二遍」。(来源 [5])

The stack most often described for 2026 cost optimisation has three layers: prefix caching for static structure, conversation compression for a growing context window, and semantic or plan caching as an optimisation layer on top. They solve different problems and don't substitute for each other — prefix caching saves repeated computation, compression saves context volume, semantic caching saves you from answering the same question twice. (Source [5])

缓存不是无条件划算 Caching is not unconditionally cheaper

写缓存比普通输入 token 贵 25%(Anthropic 5 分钟档)。如果一个前缀只被用一次,开缓存是净亏损。回本点在同一前缀被读 2–3 次。一次性的批量分类、单轮的分类接口、每次 prompt 都不同的场景,不要开。

A cache write costs 25% more than an ordinary input token (Anthropic's 5-minute tier). If a prefix is used only once, caching is a net loss. Break-even is 2–3 reads of the same prefix. One-shot bulk classification, single-turn classifier endpoints, and workloads where every prompt differs should leave it off.

学术侧也在跟进:arXiv 上有一篇《Don't Break the Cache: An Evaluation of Prompt Caching for Long-Horizon Agentic Tasks》专门评测长时程 agent 任务下的缓存行为,标题本身就点明了这个领域的核心矛盾。(来源 [7])

Academia is catching up too: an arXiv paper titled Don't Break the Cache: An Evaluation of Prompt Caching for Long-Horizon Agentic Tasks evaluates cache behaviour specifically under long-horizon agent workloads — the title alone names the central tension in this area. (Source [7])

06常见坑

06Common traps

这些都是有据可查、反复出现的失败模式,不是假想的。

Documented, recurring failure modes — not hypotheticals.

坑 1:框架偷偷往系统提示里注时间戳

Trap 1: your framework quietly injects a timestamp

很多 agent 框架会在运行时把时间戳、用户 ID、会话配置直接注入系统提示。系统提示里差一个字符,整个前缀缓存就作废,每一步都被迫全量重算。这是最隐蔽的一类,因为你的业务代码看起来完全正确。定位方法:抓两次相邻请求的完整 payload,做逐字节 diff。

Many agent frameworks inject timestamps, user IDs, or session configuration straight into the system prompt at runtime. A single character of difference in the system prompt invalidates the prefix cache entirely, forcing a full recompute at every step. This is the sneakiest failure because your own code looks perfectly correct. How to find it: capture the full payload of two consecutive requests and diff them byte for byte.

坑 2:压缩之后时间戳变了

Trap 2: the timestamp changes after compaction

有一个公开记录的 bug 类型是:自动注入的上下文每 N 轮重建一次系统提示,在任何做前缀缓存的后端上都会导致 KV 缓存整体失效。这类问题的共同特征是「周期性的账单尖峰」——每 N 轮就有一轮特别贵。(来源 [8])

One publicly documented bug class: auto-injected context rebuilds the cached system prompt every N turns, invalidating the KV cache on every prefix-caching backend. The signature of this family of problems is a periodic billing spike — one turn in every N costs far more than its neighbours. (Source [8])

坑 3:把实时工具结果缓存进去了

Trap 3: caching live tool results

如果一个工具抓的是股价或天气,而你把包含这些结果的完整上下文一起缓存了,后续请求会基于过期数据推理。这条比其他几条更严重,因为它是正确性 bug 而不是成本 bug——账单看起来很漂亮,答案却是错的。规则:缓存边界必须停在任何实时工具输出之前,而不是之后。

If a tool fetches stock prices or weather and you cache the full context including those results, later requests reason over stale data. This one is more serious than the others because it's a correctness bug rather than a cost bug — the bill looks great and the answers are wrong. The rule: the cache boundary belongs before any live tool output, never after.

坑 4:工具集在轮次之间抖动

Trap 4: the tool set jitters between turns

动态函数调用会在工具定义变化时打破缓存。工具定义包含在 prompt 里,可用工具集的任何变化都会作废前缀。常见诱因包括:工具顺序被随机化、MCP 频繁重连导致工具列表重建、按上下文动态增删工具。修法是把工具列表排序固定、把动态工具装载移到缓存边界之后。

Dynamic function calling breaks the cache whenever tool definitions change. Tool definitions live inside the prompt, so any change to the available tool set invalidates the prefix. Common causes: randomised tool ordering, frequent MCP reconnection rebuilding the tool list, and context-dependent addition or removal of tools. The fix is a deterministic tool ordering plus moving dynamic tool loading past the cache boundary.

坑 5:网关或代理层悄悄关掉了缓存

Trap 5: a gateway or proxy silently disables caching

这一条在 2026-08-20 有了一个具体的公开例证:Claude Code v2.1.237 修复了「使用 LLM gateway 或自定义 base URL 的会话中 prompt caching 失效」的问题。中间层是缓存最容易悄无声息失效的地方——它可能重写 header、规范化 payload、或者干脆不透传 cache_control。如果你在自建网关后面跑 Agent,把缓存命中率作为网关的一项回归测试(来源 [9])

This one got a concrete public example on 2026-08-20: Claude Code v2.1.237 shipped a fix for prompt caching being broken in sessions that go through an LLM gateway or a custom base URL. Middle layers are where caching most often dies silently — they may rewrite headers, normalise payloads, or simply fail to pass cache_control through. If you run agents behind your own gateway, make cache hit rate a regression test on the gateway itself. (Source [9])

一个 Agent 会话里的缓存生命周期 轮次 1 轮次 8 · 压缩触发 轮次 16 前缀稳定 · 缓存持续增长 每轮读价 0.1× 压缩重写历史开头 整段缓存作废,归零重建 重新积累 · 但起点更低 这次压缩的净收益要减去重建成本 缓存覆盖长度 ↑ ↓ 归零

图 3 · 缓存覆盖长度随轮次增长,直到某个操作重写了历史开头。压缩、时间戳注入、工具集变化都会造成同一个形状的断崖。评估「要不要压缩」时,别只算省下的上下文,要减去缓存重建的成本。

Cache lifecycle across one agent session Turn 1 Turn 8 · compaction fires Turn 16 Prefix stable · cache keeps growing reads bill at 0.1× each turn Compaction rewrites the head whole cache voided, rebuilt from zero Rebuilding · from a lower base net gain must cover the rebuild cost Cached prefix length ↑ ↓ zero

Figure 3 · Cached prefix length grows turn over turn until something rewrites the head of the conversation. Compaction, timestamp injection and tool-set changes all produce the same cliff. When deciding whether to compact, subtract the cost of rebuilding the cache from the context you save.

07什么时候不该用

07When not to bother

诚实的边界:这不是万能优化。

The honest boundary: this is not a universal optimisation.

收尾的一句话 The closing thought

缓存命中率工程之所以值得单独当成一件事来做,是因为它不需要牺牲任何东西:不降低模型能力、不减少上下文、不改变输出质量。它唯一要求的是你对「请求里每一段内容变化多快」有一个清晰的认识,然后按这个认识排序。在所有 LLM 成本优化手段里,这大概是唯一一个纯粹的免费午餐。

Cache hit-rate engineering earns its own name because it costs you nothing in return: no reduction in model capability, no context removed, no change in output quality. All it asks is that you know how fast each part of your request changes, and then order them accordingly. Among LLM cost optimisations, it's about the only genuinely free lunch on the menu.

08术语表

08Glossary

prefix caching(前缀缓存)
从请求第一个 token 开始逐 token 匹配、复用已计算状态的机制。遇到第一处不同即停止复用。
cache hit rate(缓存命中率)
命中缓存的输入 token 占总输入 token 的比例。这是本文所有优化的唯一目标指标。
cache_control / breakpoint(缓存断点)
Anthropic API 里显式标记「缓存到此为止」的参数,每请求最多 4 个。
TTL(time to live,存活时间)
缓存条目的过期时长。Anthropic 提供 5 分钟(命中刷新)与 1 小时两档。
cache write / cache read(缓存写 / 读)
两类独立计费的 token。写贵于普通输入(Anthropic 5 分钟档 1.25×),读远便宜于普通输入(0.1×)。
TTFT(time to first token,首 token 时间)
从发出请求到收到第一个输出 token 的延迟。缓存命中会显著降低它。
append-only(只追加)
一种更新纪律:新内容只加在末尾,已有内容永不回改。这是保持前缀稳定的前提。
compaction(压缩)
把长对话历史摘要化以节省上下文的操作。副作用是重写历史开头,从而作废缓存。
semantic cache(语义缓存)
更上层的缓存:对语义相近的查询直接复用之前的答案。与前缀缓存解决的是不同问题。
prefix caching
Reusing precomputed state by matching token by token from position zero, stopping at the first difference.
cache hit rate
The share of input tokens served from cache. It is the single target metric for everything in this guide.
cache_control / breakpoint
The Anthropic API parameter that explicitly marks "cache up to here," with a maximum of four per request.
TTL (time to live)
How long a cache entry survives. Anthropic offers 5 minutes (refreshed on hit) and 1 hour.
cache write / cache read
Two separately billed token classes. Writes cost more than ordinary input (1.25× on Anthropic's 5-minute tier); reads cost far less (0.1×).
TTFT (time to first token)
Latency from sending the request to receiving the first output token. Cache hits reduce it noticeably.
append-only
An update discipline: new content is added only at the tail and existing content is never rewritten. It's the precondition for a stable prefix.
compaction
Summarising a long conversation history to save context. Its side effect is rewriting the head of the conversation, which voids the cache.
semantic cache
A higher layer of caching that reuses a previous answer for a semantically similar query. It solves a different problem than prefix caching.

09来源清单

09Sources

标记说明:官方=厂商文档或发布说明;二手=第三方实践文章、聚合站或媒体报道,数字可能未经独立复核。

Tags: Official = vendor documentation or release notes; Secondary = third-party practice write-ups, aggregators or press, whose figures are not independently verified here.

  1. 官方Prompt caching — Claude Platform Docs · 断点数量、TTL 选项、定价倍率、最小长度门槛的一手依据。
  2. 二手Prompt Caching in Practice: From 7% to 74% Hit Rate — DigitalOcean · 7%→74%、−59% 账单、41–80% 实测区间、13–31% TTFT 的出处。
  3. 二手The 2026 Caching Playbook for Agents — Galileo · TTL 选择判据(3 次读 vs 2 次读回本)与三层缓存栈。
  4. 二手Prompt Caching in 2026: Anthropic, OpenAI, Azure Compared · 跨厂商折扣对比。
  5. 二手Prompt Cache Hit Rate Engineering — AgentMarketCap · 45–80% 成本削减、前缀重排的零风险论述。
  6. 二手Prompt Caching in 2026: Cut LLM Costs, Keep Quality · 各家折扣与实施要点。
  7. 二手Don't Break the Cache: An Evaluation of Prompt Caching for Long-Horizon Agentic Tasks — arXiv · 长时程 agent 任务下的缓存评测。
  8. 二手How LLM Agent Loops Break Caching and Drain Your Budget — Tensormesh · Agent 循环中的失效模式与周期性账单尖峰。
  9. 官方Claude Code changelog · v2.1.237(2026-08-20)修复 LLM gateway / 自定义 base URL 下的 prompt caching 失效。
  10. 二手Prompt Caching in Codex CLI: How the Agent Loop Stays Linear — Codex Knowledge Base · 另一家 CLI 侧的线性 agent 循环与命中率实践。
  1. OfficialPrompt caching — Claude Platform Docs · Primary source for breakpoint counts, TTL options, price multipliers and minimum-length thresholds.
  2. SecondaryPrompt Caching in Practice: From 7% to 74% Hit Rate — DigitalOcean · Source of the 7%→74%, −59% bill, 41–80% measured range and 13–31% TTFT figures.
  3. SecondaryThe 2026 Caching Playbook for Agents — Galileo · TTL selection rule (3 reads vs 2 reads to break even) and the three-layer caching stack.
  4. SecondaryPrompt Caching in 2026: Anthropic, OpenAI, Azure Compared · Cross-vendor discount comparison.
  5. SecondaryPrompt Cache Hit Rate Engineering — AgentMarketCap · The 45–80% cost reduction figure and the zero-risk argument for prefix restructuring.
  6. SecondaryPrompt Caching in 2026: Cut LLM Costs, Keep Quality · Vendor discounts and implementation notes.
  7. SecondaryDon't Break the Cache: An Evaluation of Prompt Caching for Long-Horizon Agentic Tasks — arXiv · Cache evaluation under long-horizon agent workloads.
  8. SecondaryHow LLM Agent Loops Break Caching and Drain Your Budget — Tensormesh · Failure modes inside agent loops and the periodic billing spike signature.
  9. OfficialClaude Code changelog · v2.1.237 (2026-08-20) fixed prompt caching for sessions using an LLM gateway or custom base URL.
  10. SecondaryPrompt Caching in Codex CLI: How the Agent Loop Stays Linear — Codex Knowledge Base · A different CLI's take on keeping the agent loop linear for cache hits.