引言
如果你看过自己团队的大模型 Token 消耗看板,多半会注意到一个现象:主力模型的缓存命中率常年挂在 90% 上下,而且越是高频使用、跑得越久的模型,命中率越稳。
这不是某一家的"黑科技"。从 OpenAI、Anthropic 到 DeepSeek、Google,所有主流大模型 API 服务商都已将缓存作为基础设施。但缓存到底怎么命中?是不是只有前缀完全一样才行?语义相似能不能命中?为什么有人用 DeepSeek 10 块钱跑一整天,有人同样的调用量花了几百块?
本文从底层原理到工程实践,系统拆解大模型缓存的三层体系、各厂商实现差异,以及最大化命中率的实战策略。
一、缓存的三层体系
大模型缓存不是单一机制,而是三个层次协同工作:
| 层次 | 机制 | 匹配要求 | 省什么 | 代表实现 |
|---|---|---|---|---|
| L1 KV Cache | 单请求内复用已算 K/V | 同一次生成内自动生效 | 计算量(平方级→线性级) | 所有推理框架 |
| L2 Prefix Cache | 跨请求复用相同前缀的 KV | 从第一个 token 开始逐字节一致 | 输入 token 费用 + 首 token 延迟 | OpenAI / Anthropic / DeepSeek / vLLM |
| L3 Semantic Cache | 语义相似复用完整回答 | 向量相似度 > 阈值 | 全部 token 费用(含输出) | GPTCache / 自建网关 |
三层缓存严格程度递减:L1 对开发者完全透明,L2 要求前缀逐字节一致,L3 不要求文本一致但属于业务层优化而非模型原生能力。
二、L1:KV Cache — 一切的基础
2.1 为什么需要 KV Cache
大语言模型是自回归模型:每生成一个 token,都要"回头看"之前所有 token,通过注意力机制计算哪些位置更值得关注。如果没有优化,生成第 N 个 token 时要把前 N-1 个 token 重新前向计算一遍,总计算量随序列长度平方级增长。
关键观察是:每个位置的 Key(K)和 Value(V)只由该位置的输入 token 与模型权重决定,一旦算出就是常量,不会随后续 token 生成而改变。
KV Cache 的思路极其朴素:把每个 token 在每一层算出的 K、V 张量存下来,后续步骤直接复用。
2.2 两阶段推理
有了 KV Cache,一次推理分为两个阶段:
- Prefill(预填充):把整个 prompt 一次性喂入模型,并行算出所有位置的 K/V 写入缓存。这个阶段计算密集,但可以高度并行。
- Decode(解码):逐 token 生成,每来一个新 token 只计算它自己这一个位置的 Q/K/V,把新的 K/V 追加进缓存,再用它的 Q 去和缓存里全部 K/V 做注意力。每步增量计算量恒定。
整段生成的复杂度从平方级降到线性级。但 KV Cache 只在单次请求内生效,请求结束就释放。要跨请求复用,需要 Prefix Cache。
三、L2:Prefix Cache — 省钱的核心
3.1 工作原理
Prefix Cache 把 KV Cache 的复用范围从"单次请求内"扩展到"跨请求"。当多个请求共享相同的前缀时(比如相同的 system prompt、工具定义、知识库文档),这部分前缀的 K/V 只算一次,后续请求直接读取。
底层数据结构通常有两种实现:
- Radix Tree(前缀树):SGLang、TensorRT-LLM 使用。每个节点代表一个 token 序列片段,天然支持最长前缀匹配,查找效率高。
- 定长 Block + 哈希链:vLLM 的 Automatic Prefix Caching(APC)使用。把前缀切成定长 block,每个 block 的哈希由"父块哈希 + 本块内容"链式生成,这条哈希链天然表达了"完整前缀"。
两种路线殊途同归:让相同前缀的 KV 只算一次、被很多请求复用。
3.2 匹配规则:逐字节一致
这是最容易被误解的地方。Prefix Cache 是精确的 token 序列匹配,不是语义匹配:
- 多一个空格、少一个换行、改一个标点 → 后续全部失效
- 工具定义顺序变化 → 失效
- system prompt 里加了当前时间戳 → 失效
- 图片的
detail参数不同 → 失效 - 模型不同 → 缓存隔离,不共享
OpenAI 官方文档原话:"Cache hits are only possible for exact prefix matches within a prompt."
缓存从第一个 token 开始匹配,结构必须是:
[固定不变的内容][动态变化的内容]
↑ 缓存命中 ↑ 每次新算
如果动态内容插在中间,后面的静态内容也无法命中。
3.3 最小门槛与增量粒度
不是多长的前缀都能缓存。各厂商设置了最小 token 门槛:
| 厂商 | 最小缓存长度 | 增量粒度 |
|---|---|---|
| OpenAI | 1,024 tokens | 128 tokens 递增 |
| Anthropic Claude | 1,024 tokens(Sonnet/Opus);Haiku 2,048 | 按 cache_control 断点 |
| DeepSeek | 自动识别,无显式门槛 | 自动 |
| Google Gemini | 1,024 tokens | - |
| vLLM 自建 | ≥ 1 个 block(通常 16 tokens) | block 对齐 |
不满门槛的请求,cached_tokens 永远是 0。
3.4 缓存有效期
缓存不是永久的。当 GPU 显存不足时,系统按 LRU(最近最少使用)淘汰;即使显存充足,缓存也有 TTL:
| 厂商 | 默认 TTL | 最长 TTL |
|---|---|---|
| OpenAI(内存) | 5-10 分钟无活动,最长 1 小时 | 24 小时(Extended,KV offload 到 GPU 本地存储) |
| Anthropic | 5 分钟 | 1 小时(1 小时 TTL 写入价为 2x 输入价) |
| DeepSeek | 硬盘缓存,TTL 较长 | - |
实测数据显示:一个 11,561 token 的上下文,冷启动 prefill 耗时 4,109ms,缓存命中后仅 22ms——加速约 185 倍,99.9% 的前缀被复用。
四、各厂商实现对比
4.1 OpenAI:全自动 + Cache-Aware 路由
OpenAI 的 Prompt Caching 对开发者完全透明,无需改代码:
- Cache Routing:请求根据前缀哈希(通常前 256 tokens)路由到最近处理过相同前缀的机器
- Cache Lookup:在目标机器上检查前缀是否已缓存
- Cache Hit:命中则直接复用,
cached_tokens字段报告命中数 - Cache Miss:未命中则完整处理,处理完后写入缓存
支持 prompt_cache_key 参数手动影响路由,适合多请求共享长前缀的场景。但注意:同一 prefix + key 组合的请求超过约 15 次/分钟时,部分请求会溢出到其他机器,降低命中率。
2026 年,GPT-5.6 曾出现一个 bug:只匹配完全相同的完整 prompt,不支持部分前缀匹配(GPT-5.5 和 GPT-4o-mini 正常)。社区报告后已确认是 bug 而非预期行为。
4.2 Anthropic Claude:显式标记 + 多断点
Claude 的设计给了开发者更精细的控制。需要在请求中用 cache_control 标记缓存断点:
response = client.messages.create(
model="claude-sonnet-4-6",
system=[
{"type": "text", "text": "你是产品助手。"},
{"type": "text", "text": long_document, "cache_control": {"type": "ephemeral"}},
],
messages=messages,
)
Claude 支持最多 4 个 cache checkpoint,可以分层缓存:
[System Prompt + Tools] ← checkpoint 1(全局缓存,跨 session 共享)
[CLAUDE.md 项目上下文] ← checkpoint 2(项目级缓存)
[Session context] ← checkpoint 3(会话级缓存)
[Conversation messages] ← 动态部分,每次追加
这种分层设计让 Claude Code 这样的 Agent 产品能实现极高的命中率。Anthropic 官方甚至为缓存命中率设置了 SEV 级别告警——如果命中率太低,按生产事故处理。
Claude 的定价结构也反映了缓存的成本逻辑:
- 5 分钟 TTL 缓存写入:1.25x 输入价
- 1 小时 TTL 缓存写入:2x 输入价
- 缓存读取:0.1x 输入价(一折)
第一次写入反而更贵,真正的节省来自后续多次命中。
4.3 DeepSeek:全自动硬盘缓存 + 极致价差
DeepSeek 的方案最"无脑"——无需手动标记,系统自动识别重复前缀。最大的差异化在于 KV Cache 存在**硬盘(SSD)**上,而非仅在 GPU 显存中,因此缓存容量大、保留时间长。
价格差距极为悬殊:
| 模型 | 缓存命中输入 | 未命中输入 | 价差 | 输出 |
|---|---|---|---|---|
| V4 Flash | 0.02 元/百万 token | 1 元 | 50 倍 | 2 元 |
| V4 Pro | 0.025 元/百万 token | 3 元 | 120 倍 | 6 元 |
0.025 元的物理本质是 SSD 读取预存 KV Cache 的 I/O 成本(约 0.8-1.2ms),而 3 元对应的是加载全部权重、执行完整注意力计算的 GPU 成本。
2026 年 8 月 23 日起,DeepSeek 实施峰谷计费:周末全天低谷价,工作日高峰(9:00-12:00、14:00-18:00)为低谷 2 倍。缓存命中价在峰谷时段也有差异,但始终远低于未命中价。
真实案例:
- 半个月 8.5 亿 Token 仅花 101 元,输入缓存命中率 92%
- 充值 10 元从中午用到傍晚,Pro 模型缓存命中率 99.09%
- 22 个编程任务仅 2.5 元
4.4 Google Gemini:显式创建缓存
Gemini 采用类似 Claude 的显式模式,通过 cachedContent API 创建命名缓存,设置 TTL(默认 1 小时,可延长),在请求中引用缓存名称。缓存创建有固定费用,命中输入价约为正常价的 25%。
五、L3:语义缓存 — 突破前缀限制
5.1 为什么需要语义缓存
Prefix Cache 有两个硬约束:必须是前缀、必须逐字一致。这对客服 FAQ 这类场景很不友好——"怎么退款"和"我要退货"语义相同但 token 序列完全不同,前缀缓存帮不上忙。
语义缓存的思路完全不同:把用户问题向量化,在向量库中搜索相似度,超过阈值就直接返回缓存的完整回答。
用户提问 → embedding 向量化 → 向量库相似度搜索
├─ 相似度 > 0.92 → 直接返回缓存回答(< 50ms,几乎零成本)
└─ 相似度 < 阈值 → 调用 LLM → 结果写回缓存(设 TTL)
开源方案 GPTCache 支持 Redis、Milvus、FAISS 等向量后端,可以嵌入 API 网关层。
5.2 语义缓存的代价
语义缓存省的是全部 token 费用(含输出),但有明确的适用边界:
- 必须设 TTL:价格、库存、政策等时效性信息不能长期缓存
- 必须加业务 key:如
sku_id + policy_version,避免跨场景误命中 - 相似度阈值需调优:太高命中率低,太低返回错误答案。客服场景通常 0.90-0.95
- 不适合需要个性化的场景:返回的是固定答案,无法根据用户上下文调整
5.3 前沿研究:位置无关缓存
学术界正在攻克"非前缀位置缓存复用"的难题:
- Prompt Cache(MLSys 2024):用标记语言(PML)把可复用模块声明出来,无论出现在 prompt 哪个位置都能复用,首 token 延迟最高加速 8 倍(GPU)/ 60 倍(CPU)
- CacheBlend(EuroSys 2025 最佳论文):允许把非前缀位置的文档块缓存直接拼接,只对一小部分 token 做"选择性重算"来修正跨块注意力,TTFT 加速 2.2-3.3 倍
- EPIC(ICML 2025):系统性提出"位置无关缓存",把非前缀复用的主要障碍归因于 attention sink 现象并做针对性修正
这些方案目前多在研究阶段,尚未被主流 API 厂商商业化。
六、最大化缓存命中率的实战策略
策略 1:静态内容前置(最关键)
这是 Claude Code 团队的核心经验。正确的 prompt 结构:
1. System Prompt(永不改,一个字都不要动)
2. Tools 定义(顺序固定,不随机排序)
3. 长期上下文(CLAUDE.md / 知识库文档 / 业务规则)
4. 会话历史(append-only,只追加不修改)
5. 当前用户输入(每次变化)
Claude Code 曾因为多种原因破坏过这个顺序:在 system prompt 里放精细时间戳、以非确定性方式打乱工具定义顺序、修改 AgentTool 能调用的 agents 列表——每一次都导致缓存大面积失效。
策略 2:用消息更新替代修改前缀
当信息变化时(时间推移、文件被修改、状态更新),不要改 system prompt,而是通过下一条 message 传入:
❌ 错误:system prompt 里写 "现在时间是 2026-08-23 15:30"
→ 每分钟都在变,缓存永远命中不了
✅ 正确:system prompt 保持不变,在 user message 里追加
→ "<system-reminder>现在是周三 15:30</system-reminder>"
→ 前缀缓存完整保留
策略 3:同一会话持续追加
多轮对话天然形成前缀递增:第一轮 1000 tokens,第二轮 1200 tokens(前 1000 命中),第三轮 1400 tokens(前 1200 命中)。新建对话等于缓存从零开始。
不同话题用不同会话隔离——如果在一个对话里混多个不相关主题,上下文"污染"会导致公共前缀断裂。
策略 4:不要在会话中途切换模型
缓存按模型隔离。如果已经和一个模型对话到 100K tokens,这时切到另一个模型问简单问题,新模型的缓存是空的,全部要重新计算。
正确做法:简单问题用轻量模型开新会话;复杂问题留在原模型继续。
策略 5:RAG 场景的特殊处理
RAG 是前缀缓存的"天敌"——检索到的文档每次不同,又往往夹在中间。解决方案:
- 高频稳定文档前置:产品手册、FAQ、固定规则放在 system prompt 中作为固定前缀
- 动态检索结果后置:每次变化的检索片段放在用户消息之前、固定前缀之后
- 语义缓存兜底:对于高频相似问题,用 L3 语义缓存直接返回
- 文档分块缓存:对于稳定的大文档,用 Anthropic 的多 checkpoint 或 OpenAI 的 extended retention 单独缓存
策略 6:模型分级调度
- 高频简单任务(分类、翻译、摘要)用 V4 Flash / Haiku,缓存命中价极低
- 复杂推理任务用 V4 Pro / Opus / GPT-5
- 不要"一刀切"用最贵的模型
策略 7:错峰调用
DeepSeek 等厂商已实施峰谷定价。非实时批量任务(数据清洗、离线分析、报告生成)安排在夜间或周末运行,输出成本可降 50%。
策略 8:监控命中率
所有主流 API 都在响应中返回 cached_tokens 字段。应该:
- 按模型、功能、租户分别统计缓存命中率
- 设置命中率告警(Claude Code 团队按 SEV 级别处理)
- 命中率突然下降时,检查是否有人改了 system prompt、工具顺序或模型版本
命中率低的常见原因:
- 会话太短(3 轮以内命中率天然低)
- 请求被轮询路由到不同后端(非 cache-aware 网关)
- 前缀中有动态内容(时间戳、随机 ID、用户 ID)
- prompt 模板频繁变更
七、成本测算:缓存到底能省多少
以一个客服场景为例:每天 10,000 次请求,system prompt + 知识库 = 5,000 tokens,用户问题平均 50 tokens,回答平均 200 tokens,使用 DeepSeek V4 Flash:
| 方案 | 日输入成本 | 日输出成本 | 日总成本 |
|---|---|---|---|
| 无缓存 | 50.5 元 | 40 元 | 90.5 元 |
| 前缀缓存(命中率 90%) | ~5.5 元 | 40 元 | 45.5 元 |
| 前缀缓存 + 语义缓存(语义命中 30%) | ~4 元 | 28 元 | 32 元 |
如果用 DeepSeek V4 Pro 且缓存命中率达到 99%(Agent 编程场景的典型值),有用户实测半个月 8.5 亿 token 只花了 101 元,平均每百万 token 成本仅 0.12 元。
Claude Code 官方给出的数字更激进:对于被缓存的长篇系统指令或文档,输入 token 计费直接打一折。一份 10 万 token 的文档,首次提交后,后续所有针对它的交互请求,文档部分的成本几乎可以忽略。
八、常见误区
误区 1:缓存省输出 token。 错。KV Cache 和 Prefix Cache 只省输入 token 的计算,输出 token 逐字生成的过程完全不变。只有语义缓存(直接返回存好的回答)才省输出。
误区 2:语义相同就能命中前缀缓存。 错。"你好"和"您好"是不同的 token 序列,前缀缓存要求逐字节一致。语义相似走的是 L3 语义缓存,是完全不同的机制。
误区 3:缓存永久有效。 错。TTL 从 5 分钟到 24 小时不等,GPU 显存不足时 LRU 淘汰。需要长 TTL 的场景应使用 OpenAI Extended(24h)或 Anthropic 1 小时 TTL。
误区 4:缓存会影响回答质量。 错。KV Cache 只是复用已计算的中间张量,模型权重、采样参数、温度设置完全不变。同一个 prompt,有无缓存生成的结果在概率上完全一致。
误区 5:小 prompt 也能命中。 错。有最小 1,024 token 门槛(Claude Haiku 为 2,048),短请求不会被缓存。
误区 6:第一次调用就省钱。 错。缓存第一次写入时,Anthropic 收取 1.25-2x 的写入溢价;其他厂商虽然不额外收费,但第一次请求是完整计算。真正的节省从第二次命中开始。
结语
大模型缓存的内核始终是同一条原则:算过且不会变的东西不要重算。 按"变化频率从低到高"组织上下文,让可复用的前缀尽可能长,是所有缓存优化的根本。
三层缓存各有定位:KV Cache 解决单次推理的效率问题,Prefix Cache 解决跨请求的重复计算问题,语义缓存解决高频相似问题的复用问题。理解它们的边界和协同方式,就能在自己的系统里把延迟和成本压到最低。
对于开发者而言,当下最立竿见影的行动是:检查你的 prompt 结构,把静态内容前置、动态内容后置;在 API 网关层接入语义缓存;监控 cached_tokens 字段并设置命中率告警。这三步通常能将输入 token 成本降低 50-90%。
缓存不是锦上添花,而是大模型应用从"能用"到"用得起"的关键基础设施。
参考资料:
- OpenAI Prompt Caching 官方文档
- Anthropic Prompt Caching 官方文档与 Claude Code 工程实践
- DeepSeek API 定价与上下文硬盘缓存文档
- vLLM Automatic Prefix Caching 文档
- Google Gemini Caching 文档
- 《为什么大模型的缓存命中率能到 90%?》阿里技术,2026.07
- 《构建 Claude Code 的经验:Prompt Caching 是一切》Anthropic
- CacheBlend (EuroSys 2025 Best Paper)
- EPIC: Position-Independent Caching (ICML 2025)
- Prompt Cache (MLSys 2024)