“Claude Sonnet 5.5 Prompt Cache Reads 降价 50%”这个消息传出来之后,我看到的第一个反应,是群里一堆人兴奋地算账:“这回不得省一大半?” 结果真把账单拉出来一核对,不少人懵了:缓存命中量明明很高,账单下降的幅度却远没有 50%。这个落差,恰恰说明很多人对 Prompt Cache 的计费结构理解得不够细。
这篇不聊营销解读,也不去争论这个版本到底算不算“史诗级升级”,就讲清楚一件事:这次降价到底让你的真实成本降了多少,以及这笔账应该怎么算才靠谱。目标读者是正在用 Claude API 做多轮对话、批量文档处理、Agent 编排,并且已经被 API 账单折磨过的开发者。读完你至少能拿到一套可直接复用的核算公式,以及判断自己业务“该不该高兴”的方法。
1. 这次降价真正改的是哪一环节:提示缓存的三级计价结构
1.1 read、write、base 三档价格,差在“对 token 做了什么”
Prompt Cache(提示缓存)的计价不是一档,而是三档。很多人只看公告里的“Input/Output”两个数字,忽略了真正的计价维度,导致后续怎么算都是糊涂账。
以 Claude 系列 API 的通用计价规则来看,输入侧存在三种价格:基础输入价(base)、缓存写入价(cache write)、缓存读取价(cache read)。它们的相对关系大致是:
- base:按正常输入价格计费,模型需要完整处理这些 token;
- cache write:通常是 base 的 1.25 倍,因为模型不仅要处理,还要把计算好的状态保存到缓存层;
- cache read:通常是 base 的 0.1 倍左右,因为模型直接从缓存把已经计算好的状态取出来用,不需要重新跑一遍完整的前向计算。
这次公告把 cache read 的价格下调 50%,也就是把原本已经很低的那档费用再砍一半。为了便于后文统一算账,我采用一组常见比例做演示:
| 计费类型 | 相对输入基准价 | 降价前的 cache read 假设 |
|---|---|---|
| base input | 1.0×P | — |
| cache write | 1.25×P | — |
| cache read(降价前) | 0.1×P | — |
| cache read(降价后) | 0.05×P | 下降 50% |
具体每百万 token 的绝对价格以你账户所在区域的官方定价页为准,这里只用相对倍数讲清楚机制。因为这次降价的动作发生在“读缓存”这个环节,所以它对账单的影响,完全取决于你原本的账单里 cache read 费用占了多大比重。
1.2 50% 只是针对 read:对账单全局的影响取决于 read 费用占比
这是全文最关键的一个认知。很多人听到“Prompt Cache Reads 降价 50%”,下意识认为“API 总成本能降 50%”,其实完全不是一回事。
我们做一个简单的数学推演:假设你上一个月的 API 账单里,cache read 的计费金额占总账单的 20%,那么 cache read 降价 50% 之后,总账单的降幅就是 20% × 50% = 10%。这一点换算关系极其重要,但也是最容易被忽略的。
换句话说,只有当你账单里的 read 计费占比足够高,这次降价才对你构成实质性利好。如果 read 费用只占 5%,那整体账单降幅只有 2.5%,几乎感觉不到。先记住这个结论,后面所有算例都建立在这个逻辑之上。
2. 别直接看总账单:先给“等效无缓存成本”建立基准
2.1 加缓存后 App 调用模式也会变,总账单对比不可靠
核算真实节省时,最容易犯的错误是:这个月加了缓存优化,下个月看总额,发现只省了 10%,于是得出结论“缓存没用”。这个对比本身就有问题。
加了缓存之后,业务代码往往会跟着调整。以前不敢在每次请求里塞大量历史上下文,现在敢了;以前每轮对话都做截断,现在为了质量会把完整历史都发过去。结果就是:虽然单位 token 价格变低了,但总 token 消耗量变大了,两个变量混在一起,总账单自然无法说明任何问题。
正确做法是建立一个“等效无缓存成本”基准:还是同一批请求,还是同样的 token 消耗,假设一个缓存都没有开,按全价计算要花多少钱;再按开了缓存的实际计费规则计算要花多少钱。两者相减,才是缓存带来的真实节省。
2.2 四类 token 计数与一套可复用的核算公式
要做上述对比,需要从每条请求里拿到四个数字。Claude API 响应中的 usage 结构一般包含:
input_tokens:本次请求中没有命中缓存的输入 token 数;cache_creation_input_tokens:本次请求写入缓存的 token 数;cache_read_input_tokens:本次请求从缓存读到的 token 数;output_tokens:输出 token 数。
有同事第一次看usage会困惑:“为什么input_tokens这么小?我明明发了好几千 token 过去。” 原因是:被缓存覆盖的前缀部分,被统计到了cache_read_input_tokens或cache_creation_input_tokens里,而不是input_tokens里。这三个输入侧数字加起来,才是你真实发送的物理 token 总量。
有了这四个数字,核算公式就非常清晰。设输入基准价为 P,输出价为 P_out,cache write 价为 P_write,cache read 价为 P_read,则:
- 等效无缓存成本 = (input_tokens + cache_creation_input_tokens + cache_read_input_tokens) × P + output_tokens × P_out
- 实际缓存成本 = input_tokens × P + cache_creation_input_tokens × P_write + cache_read_input_tokens × P_read + output_tokens × P_out
这两个数字一对比,“缓存帮我省了多少钱”就水落石出了。注意 price 单位必须一致,建议统一换算成“每百万 token”价格再乘。
2.3 从 usage 字段到每日看板:最小采集示例
核算不能靠手工复制粘贴日志,应该做成一条自动链路。下面这段 Python 代码不依赖任何特定 SDK,逻辑就是累加每天的四类 token 数量,然后代入计价公式。你只需要把自己的请求日志解析成下面的Usage结构即可。
from dataclasses import dataclass @dataclass class Usage: input_tokens: int = 0 cache_creation_input_tokens: int = 0 cache_read_input_tokens: int = 0 output_tokens: int = 0 def calculate_bill(records, p_input, p_output, p_write, p_read): """ records: 一天内所有请求的 Usage 列表 p_input / p_output / p_write / p_read: 每百万 token 价格 返回 (等效无缓存成本, 实际缓存成本) """ base_tok = creation_tok = read_tok = out_tok = 0 for r in records: base_tok += r.input_tokens creation_tok += r.cache_creation_input_tokens read_tok += r.cache_read_input_tokens out_tok += r.output_tokens cost_without_cache = ( (base_tok + creation_tok + read_tok) * p_input + out_tok * p_output ) cost_with_cache = ( base_tok * p_input + creation_tok * p_write + read_tok * p_read + out_tok * p_output ) return cost_without_cache, cost_with_cache实际落地时,把每条请求的usage写入日志系统,然后用这类聚合函数按小时、按天、按业务线统计即可。成本优化的前提是可观测,这一步无论如何都值得先做。
3. 三种典型流量下的真实节省测算(附完整算例)
有了核算基准,下面看三类最典型的调用模式。你会直观感受到同一个利好消息,在不同业务上带来的收益差距能有多大。
3.1 多轮对话:write 占大头,read 降价帮不上太多忙
假设一个客服机器人,固定 system prompt 有 6000 token,每轮用户提问 500 token,助手回复 800 token,连续对话 10 轮。为简化,假设每轮都发送完整历史,且缓存命中一切正常。
| 指标 | 无缓存 | 缓存(降价前 read=0.1P) | 缓存(降价后 read=0.05P) |
|---|---|---|---|
| 输入计费 token | 123.5k | 18.2k write + 105.3k read | 同左 |
| 输出计费 token | 8k | 8k | 8k |
| 总成本 | 163.5P | 73.28P | 68.02P |
| 相对无缓存的节省 | — | 55.2% | 58.4% |
这里有个很反直觉的现象:多轮对话的缓存命中 token 量其实巨大,105.3k 的 read 比 18.2k 的 write 多得多,但 read 降价只让总成本从 73.28P 降到 68.02P,降幅只有 7.2%。原因很简单,read 单价本来就只有 base 的 0.1 倍,即使再降 50%,在总账单里的分量也不高。真正压住成本的是 write 和 output。
3.2 固定前缀高频复用:read 占比接近满格,降价收益最明显
再来看另一种场景:某个批量任务,每次请求都携带 20k 的固定前缀(比如同一份规则说明、同一个知识库片段),每次只追加 200 token 的动态问题,输出 200 token,总共执行 1000 次。
| 指标 | 无缓存 | 缓存(降价前 read=0.1P) | 缓存(降价后 read=0.05P) |
|---|---|---|---|
| 输入计费部分 | 20.2M base | 20.2k write + 0.2M base + 19.98M read | 同左 |
| 总成本 | 21.2P | 3.22P | 2.22P |
| 相对无缓存的节省 | — | 84.8% | 89.5% |
这个场景下的 read 费用占了旧账单接近 62%,所以 read 降价 50% 后,总账单直接又下降了约 31%。这才是这次降价真正的“甜区”:大量请求重复消费同一段长前缀,而且动态部分很短。
3.3 长文档增量分析:介于两者之间,取决于追加节奏
第三类是长文档增量分析。比如把一份 30k 的文档作为主前缀,每隔一段时间追加一小段分析指令。这类业务的特点和 3.1 有些重叠,但又有区别:如果追加的节奏快、间隔短,前缀会持续命中,read 费用会慢慢爬升;如果每次追加很长时间间隔很长,缓存过期重建反而让 write 费用剧增。
实操层面我建议这类业务不要认死账,直接把每天的 usage 统计跑出来,看三件事:write 费用占比、read 费用占比、output 费用占比。架构上它往往是三类业务的混合体,必须用数据说话。
3.4 一张表快速预判:read 费用占比与整体降幅的关系
把前面所有算例抽象成通用规律,就是这一张表:
| 旧账单中 read 费用占比 | 本次 read 降价 50% 后整体账单降幅 |
|---|---|
| 10% | 约 5% |
| 30% | 约 15% |
| 50% | 约 25% |
| 70% | 约 35% |
| 90% | 约 45% |
下次再看到“降价 50%”这类消息,先别激动,打开看板看一眼 read 费用占比,就能立刻知道这次降价对你是毛毛雨还是及时雨。
4. 四个让核算失真、让缓存失效的隐形因素
算账方法清晰了,但实际操作中有四个坑,任何一个都会让前面的公式失真,甚至让缓存完全失效。
4.1 缓存命中不是免单,而是按低价续费
最常见的误解是“既然命中缓存,这些 token 是不是就免费了”。不是。缓存命中后的 token 仍然按 cache read 计费,只不过单价很低。如果你把它当成免费,核算时就会高估节省,决策时也会误判性价比。
拿 3.1 的多轮对话算例来说,105.3k 的缓存命中 token 在降价后仍然产生 5.27P 的费用。对大体量业务,这个数字并不小。
4.2 前缀中混入动态内容:双倍成本的产生过程
Prompt Cache 是按前缀精确匹配的。只有当两次请求的开头 token 序列完全一致时,缓存才能命中。如果你的 system prompt 里拼了时间戳、随机数、用户 ID、会话元数据,并且这些内容放在非常靠前的位置,那么每次请求的前缀都不一样,缓存永远无法命中。
最糟糕的情况下,成本反而会翻倍:一方面旧缓存由于前缀变化无法复用,需要重新按全价处理;另一方面如果代码里声明了 cache_control 块,还会额外产生一次 write 计费。等于钱没省,还多花了。
提示:固定信息放前面,动态信息放后面。这是所有缓存类接口的第一设计铁律。动态用户 ID、trace ID 之类的内容,要么放到请求末尾,要么放到不被 cache 标记控制的区域。
在 Anthropic 新版本的自动缓存策略下,系统提示词和工具定义如果超过一定长度,会被自动纳入缓存。但“自动”不意味着“万能”,如果你的 system prompt 里嵌入了每次都在变的内容,它照样会被排除在可命中范围之外。
4.3 TTL 过期、网关改写与跨会话复用
缓存不会永久保留。早期版本的提示缓存是固定 5 分钟 TTL,后来的版本演进为动态过期策略,核心逻辑都是:如果一段时间内没有再次命中,缓存就可能被淘汰。上一轮多轮对话如果间隔太久,下一次恢复时所有上下文都得重新 write,那一刻的账单会非常难看。
另一个隐蔽的坑在网关层。不少团队会在 API 前面套一层自己的代理网关,用来做鉴权、限流、日志注入。如果网关在转发请求时,往 system prompt 前面插入了一段统一的元数据,或者对请求做了重写,原本匹配的好好的前缀就会被打乱,缓存命中率骤降。
跨会话复用同样值得留意:从平台的设计逻辑来看,只要前缀完全一致,不同业务线之间的请求理论上也可能命中同一份缓存。所以千万不要把带敏感信息的动态内容编进可被缓存的前缀里,这是一条隐私边界问题,不只是性能问题。
4.4 output 和思考 token 不因 read 降价而变便宜
最后别忘了,read 降价只管输入侧的缓存命中部分,输出 token 依然按原价计算。如果业务大量使用长输出、又开了 extended thinking(扩展思考),这部分费用可能才是账单真正的大头。我在前面的算例里一直把输出单独列出来,就是这个原因。
很多团队反复调参后觉得“账单怎么没降”,最后拉明细一看,原来是输出 token 金额占了 60% 以上。这种情况下,把注意力集中在压缩输出、缩短回答长度上,比研究 cache read 降价有效得多。
5. 降价之后值得做的事:清理缓存设计,而不是追加缓存
看到降价后的第一反应不该是“赶紧把所有东西都丢进缓存”,而是重新检查现有缓存设计是否合理,让每一分命中率都花在刀刃上。
5.1 重新审视 Prompt 布局,把固定前缀尽量向前提
拿一个典型的 RAG 应用举例。多数人写的 prompt 是:
- 动态用户问题;
- 动态检索到的知识片段;
- 固定指令;
- 固定输出格式。
这样的布局对缓存极不友好。固定指令放在最后,意味着前缀始终在变化,缓存命中率会非常难看。更好的布局是:
- 固定指令;
- 固定输出格式;
- 动态知识片段;
- 动态用户问题。
前面两块完全恒定,可以被稳定缓存;后面两块是请求差异的来源,不参与缓存或者只参与小范围缓存。很多人做完这个调整,命中率从 20% 涨到 80%,而代码逻辑一行没变,只是换了一下拼接顺序。
5.2 按 read 占比给业务分档,决定优化优先级
把监控先做起来,然后按业务线或按请求类型统计 read 费用占比,分成三档:
- read 占比超过 60%:本次降价让你的这类业务直接受益,可以进一步扩大固定前缀的数量和长度;
- read 占比在 20%~60%:有受益但有限,优先优化 write 费和 output 费,比如压缩历史上下文、精简 system prompt;
- read 占比低于 20%:这次降价基本和你无关,不要为了追热点盲目增加缓存标记,把精力放回业务本身。
这个分类方法比“大家都说缓存好所以我全都要开”要靠谱得多。
5.3 上线前用“三连发”验证缓存生命周期行为
最终上线前,建议做一个最简单的冒烟测试:连续调用三次完全相同的请求,观察 usage 字段的四个数字。
- 第一次:cache_creation_input_tokens 应该很大,因为缓存被创建;
- 第二次和第三次:cache_read_input_tokens 应该对应增大,input_tokens 明显变小;
- 如果三次都显示 cache_creation 很大而 read 接近 0,说明你的前缀里有动态内容,或者请求被网关改写了。
这个测试耗时五分钟,却能避免“上线后才发现缓存从未命中”的灾难。每次升级模型版本或调整网关逻辑后,都值得重跑一遍。
回到账面本身,这次下调 50% 的意义,在于把“读缓存”这个动作的边际成本压到了极低。对固定前缀高频复用的业务来说,这是一次实打实的红利;对多轮对话型业务来说,影响有限,重点还是压 write 和 output。我个人体会是,不要把希望寄托在某一次降价上,而是把 usage 四字段的采集、核算、看板做扎实,之后任何价格变动、任何模型升级,你都能在十分钟内算出它对账单的真实影响。这套能力,比追某一个版本的新闻有用得多。