提示缓存与上下文优化:LLM降本的隐藏大招
提示缓存能省一半以上token成本,但很多人不会用。讲清缓存原理、命中条件、失效策略和上下文压缩技巧。
被低估的降本利器
在所有 LLM 优化手段里,提示缓存(Prompt Caching)是投入产出比最高的一个,但很多团队根本没认真用。
原因很简单:它不够”性感”。大家更爱聊新模型、新架构,却忽略了——你每次请求里那一大段重复的 system prompt 和文档,本可以只算一次钱。
提示缓存是什么
大多数 LLM 请求里,前缀部分是高度重复的:
- 固定的 system prompt(角色、规则、格式要求)
- 一大段工具定义
- RAG 里同一篇文档被反复提问
- 多轮对话的历史
如果每次都重新计算这些 token,就是在烧钱。
提示缓存把这些前缀的中间计算结果存下来,下次命中就直接复用:
[缓存前缀: system prompt + 工具定义 + 文档] ← 命中,便宜
[变化的: 用户这轮的问题] ← 全价
命中部分通常便宜 50%–90%,首 token 延迟也大幅降低。
命中条件:为什么你经常不命中
缓存只对”稳定前缀”生效,最常见的失败原因:
- 前缀里有动态内容:比如把时间戳、随机 ID、用户数据放在 system prompt 前面 → 每次都不一样,永远不命中
- 前缀顺序乱:把稳定内容放在变化内容之后 → 缓存从第一个变化点就断了
- 差一个字符:多一个空格、换个措辞,前缀就变了
黄金法则:把最稳定、最长的内容放最前面,把最易变的内容放最后。
正确的内容组织顺序
1. system prompt(几乎不变) ← 缓存
2. 工具/函数定义(很少变) ← 缓存
3. 长文档 / 知识库(一整个会话不变)← 缓存
4. 对话历史(缓慢增长) ← 部分缓存
5. 用户当前问题(每次都变) ← 不缓存
只要 1–3 稳定,命中率就能很高。
失效与一致性
缓存不是永久的,要设计好策略:
- 设 TTL:过期的缓存自动失效,避免陈旧内容
- 内容变了要主动失效:文档更新后,旧缓存必须作废,否则答案自相矛盾
- 版本标识:给缓存的 prompt 加版本号,便于切换和回滚
矛盾点:缓存越久越省钱,但越久越可能过时。按内容的”变化频率”分别设置 TTL。
上下文压缩:另一条战线
即使不缓存,缩短上下文本身也能省钱、提速、提升准确率(模型在长上下文里容易”失焦”)。
常用手段:
- 摘要历史:把早期多轮对话压缩成摘要,而不是原文堆着
- 按相关性截断:只带和当前问题相关的历史/文档块
- 检索代替全塞:别把整个知识库塞进 prompt,用 RAG 只取相关部分
- 结构化精简:用表格/JSON 代替啰嗦的自然语言说明
- 去重:多轮里重复的内容剔除
别踩的坑
- 动态内容污染前缀:时间戳、随机数放前面 = 缓存全废
- 缓存没失效机制:文档改了还在用旧缓存,答案错得离谱
- 过度压缩丢关键信息:压得太狠,模型没上下文了,答非所问
- 不测命中率:不知道缓存命中多少,等于没优化
- 所有内容都缓存:只出现一次的内容缓存了也没用,还占空间
落地清单
- 统计当前请求的前缀重复率
- 把稳定内容前置、易变内容后置
- 开启提示缓存并监控命中率
- 按变化频率给不同内容设 TTL
- 内容更新时主动失效缓存
- 用摘要/检索压缩长上下文
- 对比优化前后的成本和延迟
结语
提示缓存是”不用改业务逻辑就能省钱”的少数手段之一。核心就一条:让重复的内容真正重复,让变化的内容留在最后。 配合上下文压缩,你往往能在不动模型的前提下,把成本和延迟同时砍下来。