开启提示词缓存(prompt caching)对我来说毫无节省——事实上,我的 OpenAI-API 账单反而增加了约四分之一。罪魁祸首是每一条请求都会改变的一行代码:嵌入在系统提示词中的时间戳。
LLM 提供商允许开发者缓存提示词片段,以降低 token 处理成本。缓存读取(“命中”,hit)的成本仅为常规费率的十分之一,而缓存写入(“未命中”,miss)的成本大约是正常价格的 1.25 倍。如果发生了写入但缓存片段从未被读取,那么这额外的 25% 费用就白白浪费了。当时间戳导致提示词无法匹配任何现有的缓存条目时,情况正是如此。
为什么缓存可能会适得其反
提示词缓存的工作原理是匹配缓存部分的精确字节序列。提供商会对输入进行哈希处理;如果哈希值与存储的条目匹配,系统就会重用之前的计算结果并应用低廉的读取费率。任何变化——哪怕只是一个字符——都会破坏匹配,从而强制进行新的计算,并按较高的写入费率计费。
在我的案例中,系统提示词以如下内容开头:
Current session started: 2026-07-14T09:41:07Z
由于时间戳在每次 API 调用时都会更新,请求的前几个字节从未完全相同。提供商将每次调用都视为一个新的缓存条目,收取了写入溢价,且从未记录过读取。结果是 cache_creation_input_tokens 稳步上升,而 cache_read_input_tokens 始终为零,这清楚地表明缓存从未被命中。
如何发现缓存失效
API 提供的使用日志提供了两个关键计数器:
- cache_creation_input_tokens – 触发写入的 token。
- cache_read_input_tokens – 受益于读取的 token。
当前者上升而后者保持平稳时,说明缓存没有被重用。一个快速的检查方法是重复发送完全相同的请求两次;如果缓存正常工作,第二次调用应该显示读取 token 的激增。
解决问题
解决方法很简单:确保缓存区域在调用过程中是静态的。遵循以下两条规则:
- 将不可变内容放在最前面。 系统提示词、工具定义或任何永不改变的指令应占据请求的前导字节。
- 将可变内容放在最后面。 时间戳、用户生成文本、请求 ID 或任何随调用而变化的数据必须放在缓存片段之后。
哪怕只有一个字符发生偏移,哈希值就会改变,导致缓存未命中持续发生。通过重新排列提示词,将时间戳放在末尾,可以恢复缓存命中率,并将账单降回预期的低成本水平。
缓存何时真正有效
在相同的指令集被多次重用的场景中,提示词缓存表现出色:
- Agent 循环:AI 反复调用一组固定的工具。
- 对话会话:引用一份长篇且静态的文档,而只有用户的最新查询在变化。
- 批量数据提取:将相同的解析提示词应用于大量记录。
对于每次都包含全新上下文的一次性调用(例如带有独特前言的一次性问题),缓存不会带来任何好处,如果请求无意中触发了写入,甚至可能增加成本。
隐藏的陷阱
即使提示词本身是静态的,请求在下游也可能被更改:
- 代理或聚合器:重新排序或注入空格可能会破坏字节级匹配。
- 网关服务:在前面添加身份验证标头或修改 JSON 格式可能会无意中改变缓存片段。
通过网关进行测试,发送两次完全相同的请求并检查读取计数器,有助于验证缓存路径是否保持完整。
更广泛的成本图景
写入时收取的 25% 附加费并不是对使用缓存的惩罚;它反映了为了存储该片段以供将来重用所需的额外计算量。当发生缓存命中时,成本会大幅下降——通常仅为常规费率的一小部分。关键在于让系统真正命中缓存。否则,你支付了溢价却没有任何节省。
反论:缓存并未过时
一些开发者认为,管理静态与动态提示词部分的复杂性超过了其带来的节省。这种观点忽视了一个事实:许多生产流水线已经将配置(静态)与用户数据(动态)分离开来。通过相应地构建提示词,无需额外努力即可利用为该 API 原生开发者节省成本的相同缓存机制。这种权衡仅仅是提示词设计上需要一点规范,而非技术本身的根本缺陷。
后续关注事项
- 每周在您的使用仪表板中监控两个缓存计数器。
- 审计提示词构建过程,以确认任何变量元素都位于缓存块之后。
- 在具有代表性的工作负载上进行 A/B 测试(对比开启与关闭缓存的情况),以量化实际节省的成本。
- 通过比较经过代理前后的原始请求负载来验证网关。
要点总结
提示词缓存可以大幅削减 LLM API 的成本,但前提是缓存片段在多次调用中必须完全一致。提示词开头出现一个随机的时间戳或任何其他动态 Token,都会导致每次都进行昂贵的写入操作,从而推高账单。通过将静态指令前置,并将变化的数据置于末尾,您可以让缓存发挥作用,并有效控制支出。
