分析Anthropic API缓存写入有1.25x~2x惩罚而读取仅0.1x,得出缓存命中率低于22%时账单反而增加,提供了可计算的决策框架。
几乎所有削减 LLM 成本的指南最终都会说同样的话:开启 Prompt Caching。但几乎没有人提到,缓存反而可能让你的账单变大。
它有一个盈亏平衡点,而且是可以算出来的,但大多数团队从来不检查自己到底站在平衡点的哪一边。
先解释两个词,因为整套论证都建立在这两个词之上。一个 token 大约等于 ¾ 个单词;模型的计费单位是每百万 token。Prompt 缓存把 Prompt 的前置部分——系统提示词、工具定义、你每次都重新发送的文档——存储起来,这样模型在下次请求时就不需要重新处理它。缓存按精确前缀匹配:只要开头附近的任何一个字节变了,之后的所有内容都算是未命中。
Cache writes cost more than plain tokens
这里是经常被忽略的部分。缓存不是一个价格,而是两个价格,其中一个还是惩罚。
在 Anthropic 的 API 上,相对于正常的 token 输入价格:
TTL 是存活时间:条目最后一次被访问之后还能存活多久。默认是 5 分钟。
所以缓存命中是 9 折,缓存未命中则是 1.25 倍的附加费。每个找不到热条目的请求都会写入新条目,并为此特权支付额外费用。缓存是一场赌局:你押注的是,你刚花了 1.25 倍价格创建的条目,在它过期之前至少会被读取几次。
The break-even hit rate
命中率是你从缓存提供服务的可缓存 token 所占的比例。设命中率为 h,写入乘数为 W,读取乘数为 R。当混合成本低于普通输入成本时,缓存就是划算的:
(1 − h)·W + h·R < 1
h > (W − 1) / (W − R)
5 分钟缓存:(1.25 − 1) / (1.25 − 0.1) = 21.7%
1 小时缓存:(2 − 1) / (2 − 0.1) = 52.6%
命中率大约低于 22% 时,5 分钟缓存就是在浪费钱。一小时 TTL 的写入成本翻倍,所以需要超过一半的请求命中才能回本——它的存在是为了应对间隔超过 5 分钟的突发流量,而不是作为默认升级选项。
来算个具体的。一个支持机器人使用 claude-sonnet-5(列表价每 1M 输入 token 2.00 美元),前缀 20K token,每天 200 次请求。无缓存输入:8.00 美元/天。90% 命中率:1.72 美元/天。15% 命中率——请求分散得足够开,以至于大多数条目在未被读取的情况下就过期了——8.62 美元/天。同样的代码,同样的功能开关,账单却往错误的方向移动了 8%。
「但我的流量很稳定」是一个合理的反驳,如果这是真的,你就没问题。被坑的团队通常是那些生产流量低、每个用户的前缀从不共享、或者将夜间批处理任务分散在一个小时内的情况。
Measure your actual hit rate
不要估计。每个响应都会报告命中率。用你真实的流量、按真实的顺序,跑一下这个:
import anthropic
client = anthropic.Anthropic()
created = read = fresh = 0
for prompt in prompts: # your real requests, in real order
r = client.messages.create(
model="claude-sonnet-5", max_tokens=512,
system=[{"type": "text", "text": SYSTEM,
"cache_control": {"type": "ephemeral"}}],
messages=[{"role": "user", "content": prompt}],
)
u = r.usage
created += u.cache_creation_input_tokens
read += u.cache_read_input_tokens
fresh += u.input_tokens
hit = read / (read + created)
billed = created * 1.25 + read * 0.10 + fresh
print(f"hit rate {hit:.0%} | billed {billed / (created + read + fresh):.2f}x uncached")
如果对带有相同前缀的重复请求,命中率返回 0%,说明有什么东西在悄悄使其失效——系统提示词里的时间戳、UUID、未排序的 json.dumps、以不同顺序组装工具列表。缓存 key 是精确的字节。
如果 cache_creation_input_tokens 也是 0,说明你的前缀低于最小可缓存长度。这个阈值因模型而异,而且跨代际并不单调:Claude Opus 5 是 512 token,Opus 4.8 和 Sonnet 5 是 1024 token,Opus 4.6 和 Haiku 4.5 是 4096 token。一个 3K token 的 Prompt 在一个模型上会缓存,在另一个模型上则静默地不缓存,两种情况都不会报错。
What this doesn't fix
好的命中率可以削减 token 数量。但它对另一个乘数——每个 token 的价格——毫无作用,而你的账单是两者的乘积。这里就轮到网关出场了:altrouter.ai 以低于厂商自身列表价 10–25% 的价格转售相同的模型(claude-sonnet-5 每 1M 输入 token 1.69 美元,而 Anthropic 是 2.00 美元),通过 OpenAI 兼容的 API,所以切换只是改一下 base_url。在这个话题上它诚实的差距是:我们的使用记录还没有细分缓存读取 token,所以上面的测量必须来自提供商响应体而不是我们的仪表盘。
The one number to take away
缓存不是白送的钱,它是一场固定赔率的赌局:5 分钟缓存需要 22% 的命中率,1 小时的需要 53%。在争论断点位置之前,先把你的命中率打印出来。如果在红线以下,今天你能做的最便宜的改动就是关掉缓存。