我们的文档问答服务每次请求都要带 30K token 的规范文档做上下文。上线一个月账单出来,老板问了一句"这个能不能便宜点"。这篇是把成本打下来 60% 的完整过程。
可复现前提: 使用 Anthropic Messages API,cache_control 参数。测试脚本 bench/cache-test.py 在附件里,跑一轮约 5 分钟、花费不到 ¥2。
一、缓存到底省的是什么
先说清楚原理,不然调优就是瞎试:缓存命中的部分按大幅折扣计费,写入缓存时则比普通输入略贵。所以:
- 同一段前缀被复用得越多,越划算
- 只用一次的内容放进缓存反而亏钱
我们的场景是典型的高复用:30K 规范文档 + 每次不同的用户问题。
二、关键:把稳定的部分放最前面
缓存按前缀匹配,前缀一变整段全失效。所以消息结构必须是:
messages = [
{
"role": "user",
"content": [
# 1. 最稳定:系统规范文档,打上缓存标记
{
"type": "text",
"text": SPEC_DOCUMENT,
"cache_control": {"type": "ephemeral"},
},
# 2. 每次都变的用户问题,放在缓存点之后
{"type": "text", "text": user_question},
],
}
]我第一版把当前时间戳写进了 system prompt 开头,结果命中率恒等于 0,排查了半天。任何随请求变化的内容都不能出现在缓存点之前——时间、请求 ID、用户名,全都不行。
三、实测数据
连续 500 次真实请求:
| 指标 | 启用前 | 启用后 |
|---|---|---|
| 平均输入成本 | ¥0.096 | ¥0.038 |
| 缓存命中率 | — | 94.2% |
| 首字延迟 P50 | 1.9s | 0.8s |
| 日成本 | ¥48 | ¥19 |
降幅 60.4%,而且延迟也降了一半——这是意外之喜,缓存命中时不需要重新处理那 30K token。
四、两个坑
坑一:缓存有效期。 缓存是有生存时间的,低频场景可能每次都是冷的。我们凌晨请求稀疏,命中率只有 40%。解法是加了个每 4 分钟的保活请求,一天成本不到 1 毛钱,把凌晨命中率拉到了 91%。
坑二:多个缓存点的顺序。 可以打多个缓存标记,但要从最稳定到最易变排列。我们现在的顺序是:规范文档 → 团队术语表 → 最近对话历史 → 当前问题。
五、复现
pip install anthropic
export ANTHROPIC_API_KEY=...
python bench/cache-test.py --rounds 20
# 输出:每轮的 cache_read_input_tokens 与实际计费对比表看 usage.cache_read_input_tokens 字段就知道有没有命中,别靠猜。
评论与复现反馈 2
补充一个后续数据:保活请求跑了三周,凌晨命中率稳定在 90% 以上,月成本增加不到 3 元。
这句话值 60% 的成本。我们也是把请求 ID 写在了最前面,命中率一直是 0,看到这篇才反应过来。已改,命中率 89%。