最大化大模型缓存命中率的实战方法
核心铁律:缓存只在"前缀完全一致"时命中,哪怕前缀里改一个字符,从那个字符开始往后全部失效。 所有优化技巧都是围绕这条铁律展开的。
一、Prompt 结构设计:把"稳定的"放前面,"变化的"放后面
这是最关键、收益最大的一条原则。Prompt 的结构应该像一座金字塔:越稳定的内容越靠下(靠前),越易变的内容越靠上(靠后)。
1.1 推荐的标准结构(从前到后)
| 层级 | 内容 | 变化频率 | 缓存友好度 |
|---|---|---|---|
| 1. 系统提示词 | 角色设定、规则、输出格式约束 | 几乎不变 | ⭐⭐⭐⭐⭐ |
| 2. 工具/函数定义 | Function Calling 的 schema | 偶尔更新 | ⭐⭐⭐⭐⭐ |
| 3. Few-shot 示例 | 示范输入输出 | 偶尔调整 | ⭐⭐⭐⭐⭐ |
| 4. 知识库/参考文档 | RAG 检索到的长文档 | 按会话变化 | ⭐⭐⭐⭐ |
| 5. 对话历史 | 多轮对话的前几轮 | 每轮追加 | ⭐⭐⭐ |
| 6. 当前用户问题 | 本次提问 | 每次变化 | ⭐ |
1.2 反例(典型踩坑)
❌ 错误写法:
"现在是 2026-05-23 22:57:13,用户 ID 是 7027738,
你是一个专业助手,请遵循以下规则……(5000 字规则)"
→ 把时间戳和用户 ID 放在最前面,导致后面 5000 字规则永远无法命中缓存✅ 正确写法:
"你是一个专业助手,请遵循以下规则……(5000 字规则)
---
用户上下文:ID=7027738,当前时间=2026-05-23 22:57:13
问题:……"
→ 5000 字规则固定在前,每次都能命中缓存二、消除"看不见的随机扰动"
很多时候 prompt 看起来一样,但隐藏着导致缓存失效的"暗雷"。
2.1 常见暗雷清单
| 暗雷 | 影响 | 解决方法 |
|---|---|---|
| 时间戳("今天是 X 月 X 日") | 每秒都变,缓存永远不命中 | 移出系统提示,放到 prompt 末尾 |
| 随机 UUID / Trace ID | 每次请求都不同 | 不要写进 prompt,用 metadata 传递 |
| 用户 ID / Session ID 在开头 | 每个用户都不同 | 放到 prompt 末尾的用户上下文段 |
| 浮点数轻微差异(如温度参数被写进 prompt) | 0.7 vs 0.70 也算不同 | 统一格式化 |
| 空格 / 换行符不一致 | " " 和 " " 视为不同 | 用模板引擎统一渲染 |
| JSON 字段顺序不固定 | {"a":1,"b":2} ≠ {"b":2,"a":1} | 序列化时按字母排序 key |
2.2 工程实践:用模板引擎统一渲染
python
# 推荐做法:把 prompt 拆成"静态模板 + 动态变量"
STATIC_SYSTEM_PROMPT = """你是一个专业助手……
(5000 字稳定内容)"""
def build_prompt(user_question, user_ctx):
return [
{"role": "system", "content": STATIC_SYSTEM_PROMPT}, # 这部分稳定命中
{"role": "user", "content": f"上下文:{user_ctx}\n问题:{user_question}"}
]三、多轮对话的缓存优化
多轮对话是缓存收益最大的场景,但也最容易因为不当操作让缓存失效。
3.1 保持历史"只追加,不修改"
- ✅ 追加新消息:第 N 轮在第 N-1 轮历史末尾追加,前面全部命中。
- ❌ 修改历史消息:哪怕只是"压缩前几轮",从修改点往后全部失效。
- ❌ 重排消息顺序:调换两条消息位置,整段历史失效。
3.2 长对话的"截断 vs 摘要"权衡
当对话过长接近上下文窗口时,有两种处理方式:
| 策略 | 缓存影响 | 适用场景 |
|---|---|---|
| 滑动窗口截断(丢掉最早 N 条) | 截断点之后的内容失效一次,之后保持命中 | 对话信息密度均匀 |
| 摘要压缩(把前 10 轮压成 1 段摘要) | 每次摘要内容都不同,缓存大面积失效 | 谨慎使用,最好定期固化摘要 |
实战建议:优先用截断,必要时做摘要后长期固定该摘要,不要每轮都重新生成摘要。
四、RAG 场景的特殊技巧
RAG(检索增强生成)每次检索结果可能不同,对缓存非常不友好。需要专门优化。
4.1 检索结果排序要稳定
- ❌ 按相似度分数排序:每次分数微小波动会导致顺序变化。
- ✅ 检索后按文档 ID 排序:同样几篇文档,顺序固定,命中概率大增。
4.2 文档块大小固定化
- 把文档切成固定 size 的 chunk(比如每块 512 tokens),而不是按句子或段落切。
- 这样相同文档每次切出来的块完全一致,提升命中率。
4.3 热点文档预热
- 对高频查询的文档(FAQ、产品手册),可以**定时发送"假请求"**保持缓存活跃,避免过期。
- 注意:厂商缓存通常有 TTL(5 分钟到 1 小时不等),过期就要重算。
五、批量任务的缓存优化
如果你要处理"基于同一模板的 1000 个任务",正确的姿势能让成本降一个量级。
5.1 同模板任务要"集中、连续"发送
✅ 推荐:把 1000 个同模板任务在 5 分钟内连续发送
→ 第 1 次缓存模板,后 999 次全部命中
❌ 不推荐:分散在一天内零散发送
→ 缓存可能多次过期,反复重算5.2 利用厂商的 Batch API
- OpenAI、Anthropic 都提供 Batch API(异步批量接口),通常额外打 5 折。
- 缓存折扣 + Batch 折扣可以叠加,组合优惠极大。
六、跨用户共享缓存的设计模式
如果你做的是 SaaS 产品,多个用户共用一套系统提示,缓存可以跨用户复用。
6.1 让"公共部分"完全一致
- 系统提示、产品介绍、规则说明:所有用户使用同一份,不要因用户身份做微调。
- 用户个性化内容:集中放在 prompt 末尾的一个"用户上下文"段。
6.2 多租户场景的分层缓存
[全局公共系统提示] ← 所有用户命中
↓
[租户级配置] ← 同租户用户命中
↓
[用户个性化上下文] ← 仅当前用户
↓
[当前问题] ← 每次不同七、Function Calling / Tool Use 的优化
Agent 应用经常带几十个工具定义,每个工具的 JSON schema 都很长。
7.1 工具列表要稳定
- ❌ 根据用户权限动态过滤工具列表 → 每个用户的工具集不同,缓存难命中。
- ✅ 全量发送所有工具,在系统提示里说明权限规则 → 工具列表稳定,命中率高。
- 权衡:多发的 token 成本 vs 失去缓存的成本,前者通常更划算。
7.2 工具 schema 序列化要确定性
- 工具的 JSON schema 按固定 key 顺序输出。
- 描述文本里不要塞动态内容(时间、版本号等)。
八、监控和度量:知道自己省了多少
光做优化不够,得知道实际命中率才能持续改进。
8.1 关注厂商返回的 usage 字段
主流厂商的 API 响应里都会返回缓存命中详情,例如:
json
{
"usage": {
"prompt_tokens": 8200,
"cached_tokens": 7800, // 命中缓存的 token 数
"completion_tokens": 800,
"cache_hit_rate": 0.95 // 命中率
}
}8.2 设定优化目标
| 应用类型 | 健康命中率目标 |
|---|---|
| 单轮问答 | > 60%(主要靠系统提示) |
| 多轮对话 | > 85%(历史累积) |
| Agent / RAG | > 90%(长前缀 + 模板化) |
| 批量任务 | > 95%(同模板高频复用) |
如果命中率低于目标,回头检查前面 1–7 条是否有踩坑。
九、不同厂商的缓存机制差异(避坑提示)
不同厂商的缓存策略略有不同,迁移模型时要重新评估。
| 厂商 | 触发方式 | 最小缓存长度 | TTL | 折扣力度 |
|---|---|---|---|---|
| OpenAI | 自动(≥1024 token 前缀) | 1024 token | 5–10 分钟 | 5 折 |
| Anthropic | 手动标记 cache_control | 1024 token | 5 分钟(可延长到 1 小时) | 1 折读 / 1.25 倍写 |
| DeepSeek | 自动 | 64 token | 数小时 | 1 折 |
| Google Gemini | 显式创建 cached content 对象 | 32K token | 自定义 | 按存储 + 命中分别计费 |
注意 Anthropic 的特殊性:它的缓存写入要加价 25%,但读取只要 10% 价格。所以只有重复使用超过 2 次才划算,一次性请求不要乱标 cache_control。
十、一张实战 Checklist
部署前自查:
- [ ] 系统提示、工具定义放在 prompt 最前面
- [ ] 时间戳、UUID、用户 ID 移到 prompt 末尾或 metadata
- [ ] JSON 序列化按固定 key 顺序
- [ ] 模板用统一渲染函数,避免空格/换行差异
- [ ] 多轮对话只追加不修改历史
- [ ] RAG 检索结果按文档 ID 排序
- [ ] 批量任务集中连续发送
- [ ] 监控
cached_tokens指标,设定命中率目标 - [ ] 针对所用厂商确认其缓存机制(自动/手动、TTL、最小长度)
十一、一句话收尾
优化缓存命中率的本质,就是把 prompt 当作一份"分层契约"来设计:底层是亘古不变的规则,顶层是瞬息万变的输入。层次越清晰、变化点越靠后,省下的钱就越多。
对中等规模的 Agent 应用,认真做完上面这些优化,月度账单降低 40%–70% 是非常常见的结果。