一切都没坏。这正是让人困惑的地方。没有部署失败,没有延迟报警,错误率也没有上升。有人合并了一个只有一行的 PR,在系统提示词(system prompt)末尾添加了一句话——一个新工具的描述、一条政策提醒,或者是“今天的日期是”的页眉——结果第二天早上,推理账单就高出了三到五倍。流量平稳,模型没变,代码也完全按照预期运行。
改变的是那一行代码放错了位置,导致你集群中所有的缓存前缀(cached prefix)瞬间失效。你的缓存命中率在一个请求周期内从 90% 降到了零,原本几乎免费的每个 token 开始按全价计费。这就是 Prompt 缓存悬崖(prompt-cache cliff),它是生产环境下 LLM 系统中最昂贵的故障模式,而且没人会对它进行威胁建模,因为它看起来根本不像故障。
它之所以难以察觉,是因为 Prompt 缓存是一种你从未显式开启的折扣。当供应商识别出重复的前缀时,会自动应用它,所以你的系统便宜地运行了几个月,而你从未在意过。接着,折扣悄无声息地消失了,“新”价格其实只是没有了你甚至不知道自己在依赖的折扣后的原价。如果你没有针对缓存命中率设置报警,你收到的第一个信号就是发票——而那时,你已经按悬崖价支付了一个完整的计费周期。
缓存即前缀匹配,这就是全部逻辑
每个主流供应商的 Prompt 缓存底层工作原理都一样:它是对你请求中渲染后的字节进行的精确前缀匹配。模型逐个 token 地处理你的提示词,而最昂贵的部分——构建键值(KV)注意状态——如果新请求的开头与已经计算过的内容字节完全一致,就可以复用。供应商会将你的提示词哈希处理到特定的检查点,如果命中,就加载预先计算好的状态,而不是重新计算。
结论显而易见:**前缀中任何位置的任何变动都会使之后的所有内容失效。**失效的不只是改变的那个 token,而是它下游的所有内容。缓存键(cache key)是根据每个检查点之前的精确字节生成的,因此在位置 N 处的一个字节差异就会使位置 ≥ N 的所有检查点失效。一个尾随空格、一个重新排序的 JSON 键、一个重新格式化的日期,或者系统提示词中多出的一句话:所有这些都会导致后续前缀的彻底失效。
这就是为什么提示词的顺序 是一个成本决策,而不仅仅是风格问题。供应商按固定顺序渲染请求——在 Anthropic 上,顺序是工具(tools)、系统提示词(system prompt),然后是消息(messages)。你放在前面的任何内容都排在其他所有内容之前。插入到系统提示词页眉的时间戳不仅自身无法被缓存,还会导致其后的整个系统提示词和每个工具定义都无法缓存,因为它们现在位于一个随每个请求变化的值的下游。
由于这个原因,“不断增长的系统提示词”和 Prompt 缓存正处于冲突之中。系统提示词在不断增长。每一次事故都会产生一条新的“永远记住……”行,每一个功能都会增加一个工具,每一个边缘案例都会增加一条告警。这些修改都位于前缀的前部。你构建的稳定前缀越大,你押注在上面的筹码就越多——这意味着触碰它的波及范围(blast radius)随着时间的推移而扩大,而不是缩小。
写入的经济学:为什么悬崖如此致命
要理解为什么失效不仅是麻烦,而且极其昂贵,你必须查看价格结构。供应商对输入 token 收取三种不同的费率:
缓存读取(Cache reads) —— 从现有缓存项中提供的 token。在 Anthropic 上,其成本约为基础输入费率的 0.1 倍,即 9 折优惠。对于 Claude Opus 4.8,每百万 token 的读取费用为 0.50 美元,而未缓存时为 5.00 美元。
缓存写入(Cache writes) —— 缓存未命中时写入缓存的 token。在 Anthropic 上,这些费用比基础输入更高 :默认 5 分钟 TTL 为 1.25 倍,1 小时 TTL 为 2 倍。
未缓存输入(Uncached input) —— 全价,不涉及缓存。
在稳定状态下,你的大部分提示词 token 都是 0.1 倍的缓存读取,这就是为什么缓存良好的系统很便宜。当有人修改前缀时,两件事会同时发生。首先,每个缓存路径上的下一个请求现在都是一次完整的缓存写入 ——你支付 1.25 倍的溢价来重建缓存项。其次,在重建完成之前,这些 token 按完整的未缓存费率计费。稳定状态下的费率是基础价格的 0.1 倍;悬崖费率是基础价格的 1 到 1.25 倍。这就是 3 到 5 倍的跳升,并且它会同时应用于所有并发路径,因为它们共享了你刚刚修改的前缀。
损益平衡计算让写入溢价变得具体。在 5 分钟 TTL 下,只需两次请求缓存就能回本(1.25 倍写入 + 0.1 倍读取 = 1.35 倍,而两次未缓存调用为 2 倍)。1 小时 TTL 使写入成本翻倍,因此至少需要三次请求才能回本,但它在突发流量的较长间隔中表现更好。无论哪种方式,模型都假设你会多次复用 前缀。强行导致重建的修改会丢弃你积累的所有摊销收益,让计费表重新开始。
其他供应商虽然在细节上有所修饰,但核心逻辑是一致的。OpenAI 的缓存是全自动的——它对超过 1,024 个 token 的提示词生效,以 128 个 token 为增量匹配之前见过的最长前缀,且不收取写入溢价,仅对缓存读取提供 50% 的折扣。Google 的 Gemini 同时提供隐式缓存(默认开启,约 90% 优惠,哈希处理请求的开头)和显式缓存(你创建一个带 TTL 的命名缓存,支付少量的写入费用,然后支付每小时的存储 租金——Pro 级模型每百万 token 每小时 4.50 美元)。调节旋钮(knobs)各不相同,但规律是一致的:移动前缀最前面的内容,你就会失去其后的折扣。
针对“缓存悬崖”进行架构设计:上层稳定,底层易变 这种防御是结构性的,且在每个供应商处都是通用的:按照从最稳定到最不稳定的顺序排列你的 Prompt,永远不要让易变的值排在稳定值之前。
具体来说,易于缓存的布局应该是:首先是工具定义(它们在 position 0 处渲染,并且在不同请求之间必须保持字节一致——请按名称排序进行确定性序列化),接着是系统 Prompt 的固定核心部分,然后是每个会话的上下文,接着是对话历史,最后才是结尾处的实时用户查询。缓存检查点(Cache checkpoint)应设置在共享内容与变化内容的分界线上。
最常见的一个错误是将动态数据放在系统 Prompt 中。“当前日期:2026-07-04”、“登录用户:alice”、“模式:加急”——每一个被插入到系统头部的此类变量都会导致每次请求时整个 Prompt 失效。无论你设置多少个 cache-control 标记都无济于事,因为字节内容确实发生了变化。解决方法是将这些内容移至最后一个检查点 之后 。在消息数组末尾注入日期不会使之前的任何内容失效。有一个团队报告称,通过将动态工作内存从系统 Prompt 移至尾部的用户消息中,他们的缓存命中率一夜之间提高到 84%,账单也相应大幅下降。
对于针对特定租户或用户的上下文,同样的逻辑也适用于更细的粒度:将真正的全局前缀(所有租户共享)放在顶部并设置其自身的检查点,并将特定租户的片段放在该分界线下方,并设置第二个检查点。这样,全局 Prompt 的更新和租户特定的值就会独立失效,而不会互相干扰。供应商会提供断点配额——Anthropic 允许每个请求有四个 cache_control 标记——正是为了让你能将它们放置在这些稳定性缝隙中。
还有两个更微妙的陷阱值得内化。分叉操作(Fork operations)——如摘要生成、压缩处理、运行中途派生的子智能体(sub-agent)——必须重用父级 完全一致 的系统 Prompt、工具和模型,否则它们将完全错过父级的缓存并支付冷启动成本。在长轮次的智能体交互中,某些供应商只会回溯有限的窗口(Anthropic 最多回溯 20 个内容块)来查找先前的缓存条目;如果一个轮次追加了超过这个数量的工具调用块,即使没有任何内容“发生改变”,它也可能由于超出回溯范围而无法命中缓存。如果你的智能体循环在一个轮次中塞入了 40 个工具结果,请每隔约 15 个块放置一个中间检查点。
你真正需要的告警 如果你看不见即将到来的悬崖,所有这些架构设计都将毫无价值。好消息是,信号已经存在于你的 API 响应中了。每个供应商都会在 usage 对象中报告缓存活动:在 Anthropic 中,它是 cache_creation_input_tokens(本次请求写入缓存的)和 cache_read_input_tokens(从缓存读取的)。读取量与总输入量的比例就是你的缓存命中率,它是你拥有的最灵敏的早期预警指标。
FinOps 的做法是将缓存命中率作为一级 SLO(服务水平目标)进行告警,而不是在一个月后根据发票来推导。一个带有大型共享前缀的健康生产系统,其缓存读取占比应在 80–95% 的范围内。如果该数值在多次具有相同前缀的请求中急剧下降并保持低位,说明有“静默失效因素”在起作用——这几乎总是可以追溯到最近对前缀输入内容的更改。当告警触发时,诊断过程是机械化的:对比两个连续请求中渲染后的 Prompt 字节,找到它们开始出现差异的首个位置。那就是你的失效因素。
这重新定义了整个问题。Prompt 缓存悬崖本质上不是一个缓存 Bug,而是一个 变更管理 的缺失。系统 Prompt 是承载成本的基础设施,而目前大多数团队将其编辑视为琐碎的内容修改,任何人无需审核即可合并。事实并非如此。在前缀顶部追加一行内容,其对全系统的影响范围与更改速率限制器的配置一样大——只是它不会主动宣布。
因此,要把护栏设在风险所在之处。将可缓存前缀的编辑置于了解缓存成本的审核机制之下。将缓存命中率检查接入监控延迟和错误率的同一个仪表盘,并对回退进行告警。结构化 Prompt,让人们真正需要更改的内容位于缓存分界线 下方 ,从而使编辑操作在设计上就是廉价且安全的。这样做,下一个出于好意的单行 PR 就会落在它该去的易变部分——而你的账单将纹丝不动。
会员专享
余下内容仅对会员开放。 会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。
— 完整文章,包含未公开存档的部分 — 可落地的工作框架,附带权衡与决策依据 — 新文章抢先看,先于公开发布 登录以继续阅读→ 随时取消 · 一次订阅,畅读全部