大模型缓存机制详解:原理、多模型策略与 Agent 端优化

核心:缓存命中 vs 未命中 — 处理流程与费用差异

什么是 Prompt Cache?

背景:为什么需要缓存?

大语言模型在处理每次请求时,都需要对输入的全部 Token 执行一遍 预填充(Prefill) 阶段——即逐层计算 Self-Attention,生成每一层的 Key 和 Value 向量(统称 KV Cache)。这个阶段的计算量与输入长度呈二次方关系(O(n²)),是整个推理过程中最耗资源、最耗时的环节。

在实际应用中,大量请求共享着相同的前缀内容:

  • System Prompt:定义模型角色、行为规则、输出格式等,通常数千 Token 且在整个会话中不变
  • Few-shot 示例:用于引导模型输出风格的参考样本,跨请求完全一致
  • RAG 检索上下文:同一轮对话中多次追问时,引用的文档片段往往相同
  • 多轮对话历史:随着对话推进,前面的轮次作为前缀被反复发送

如果每次都从头计算这些重复内容的 KV Cache,不仅是巨大的算力浪费,也直接转化为高昂的 API 费用。

核心机制:前缀匹配 + KV Cache 复用

Prompt Cache 的本质是一种 服务端侧的、基于严格前缀匹配的 KV Cache 复用机制。其工作流程如下:

  1. 首次请求:模型正常完成全量预填充,生成完整的 KV Cache。厂商在推理完成后,将这段 KV Cache 连同对应的 Token 序列指纹一起存入高速存储(通常为 GPU 显存或 NVMe SSD)
  2. 后续请求:当新请求到达时,系统从第一个 Token 开始,逐位比对输入序列与已缓存的前缀。只要连续匹配的 Token 数达到最低阈值(各厂商不同,通常为 1024~2048 Tokens),就判定为"缓存命中"
  3. 命中处理:已匹配部分的 KV Cache 直接从存储中加载到显存,跳过该区域的 Attention 计算;模型仅需对剩余未匹配的增量部分执行预填充
  4. 未命中处理:若前缀不匹配或匹配长度不足阈值,则退化为全量预填充,与无缓存时完全一致

关键约束

约束说明
严格前缀匹配必须从第一个 Token 开始连续一致,中间任何差异都会导致后续全部失效
最小长度阈值缓存有最低生效长度(如 Anthropic 要求 ≥1024 Tokens),过短的前缀不会被缓存
TTL 过期机制缓存有存活时间(通常 5 分钟 ~ 1 小时),超时未命中会自动清除
模型绑定KV Cache 是特定模型权重的计算产物,不同模型之间完全不兼容
厂商黑盒缓存的存储位置、淘汰策略、调度逻辑均由厂商控制,用户只能通过 API 参数和响应头感知命中状态

与传统缓存的区别

Prompt Cache 不同于传统的 HTTP 缓存或应用层语义缓存:

  • 不是结果缓存:它缓存的不是最终的文本输出,而是模型内部的中间计算状态(KV 向量)
  • 不是全文匹配:它只要求前缀一致,允许后缀任意变化
  • 不是客户端可控:缓存的创建、存储、淘汰完全由厂商服务端管理,开发者只能通过合理设计 Prompt 结构来提高命中率

两条路径的流程对比

✅ 缓存命中路径
前缀匹配校验
快速比对
接收 Prompt
读取已存 KV Cache
跳过重复计算
仅计算剩余部分
增量 Attention
逐 Token 生成输出
返回结果
❌ 缓存未命中路径
Tokenization
全量分词
接收完整 Prompt
Attention 计算
全量注意力矩阵
生成新 KV Cache
写入显存
逐 Token 生成输出
返回结果

关键差异:红色标注的步骤(全量 Attention + 生成 KV Cache)是未命中时的主要开销来源。命中路径通过绿色高亮的"读取已存 KV Cache"节点完全跳过了这两步,仅对新增内容做增量计算。

费用差异的本质

计费项未命中命中节省比例
输入 Token按全量计价按缓存折扣价(通常为原价 1/8 ~ 1/10)87.5% ~ 90%
输出 Token正常计价正常计价(无缓存概念)0%
首 Token 延迟高(需完成全量预填充)低(跳过预填充)50% ~ 80%

以 Anthropic Claude 为例:

模型输入(未命中)输入(命中缓存)输出
Opus$15/M tokens$1.875/M tokens$75/M tokens
Sonnet$3/M tokens$0.30/M tokens$15/M tokens

Agent 开发者的缓存实践思考

一、多模型切换对缓存命中率的影响

核心结论

在同一 Session 内切换不同模型,KV Cache 会完全失效。

KV Cache 是模型架构级别的产物——不同模型的权重矩阵、注意力头数、隐藏层维度均不相同,导致缓存数据互不兼容。即使 Prompt 文本完全相同,只要模型不同,厂商侧就是两套独立的 KV Cache 存储空间。

缓存兼容性示意

❌ 缓存完全不兼容
模型 B(如 Sonnet)
维度: 2048 · 头数: 32
KV Cache Shape: [32, T, 64]
✅ 自身请求可命中
模型 A(如 Opus)
维度: 4096 · 头数: 64
KV Cache Shape: [64, T, 128]
✅ 自身请求可命中

各场景缓存行为

场景缓存行为说明
连续用模型 A✅ 正常命中同模型、同前缀,完美复用
从 A 切到 B❌ 首次全部未命中B 需重新计算整个前缀的 KV Cache
从 B 切回 A⚠️ 取决于 TTL若 A 的缓存尚未过期(通常 5min~1h),仍可命中;否则重新计算
频繁交替 A↔B❌ 反复冷启动每次切换都触发重新计算,成本叠加

复杂开发场景下的优化建议

针对「前期设计/后期验证用高档位模型,实际开发用普通档位模型」的场景:

策略 1:按阶段隔离,而非按问题穿插

❌ 反面模式(频繁切换):
  Q1(Opus) → Q2(Sonnet) → Q3(Opus) → Q4(Sonnet)
  每次切换都丢失缓存,两边都付全价

✅ 推荐模式(阶段聚合):
  设计阶段: Q1→Q2→Q3 全用 Opus    ← 缓存连续命中
  开发阶段: Q4→Q5→Q6 全用 Sonnet   ← 缓存连续命中
  验证阶段: Q7→Q8→Q9 全用 Opus     ← 缓存连续命中

策略 2:System Prompt 保持字节级一致

无论使用哪个档位的模型,System Prompt 必须完全相同(包括换行符、空格、标点)。差异化指令放在 Prompt 最末尾的动态区域。

策略 3:为每个模型维护独立 Session

Agent 框架应为不同模型分别维护独立的会话上下文,两个 Session 各自积累自己的 KV Cache,互不干扰。

决策树

YES
NO
收到用户问题
需要深度推理 /
架构设计 / 最终验证?
当前在 Opus Session?
直接发送
✅ 缓存命中
切换到 Opus Session
⚠️ 接受一次冷启动
当前在 Sonnet Session?
直接发送
✅ 缓存命中
切换到 Sonnet Session
⚠️ 接受一次冷启动

一句话总结:不要让模型选择跟着"单个问题"走,而要跟着"工作阶段"走。阶段内用同一模型 + 同一 Prompt 模板,才能让缓存真正成为成本杠杆。


二、Agent 端加一层缓存的可行性

Agent 端能缓存什么?

Agent 端缓存 ≠ 替代厂商 KV Cache。它解决的是两个更实际的问题:相同问题不调 API(直接省钱)和 保证 Prompt 前缀稳定性(让厂商侧缓存更容易命中)。

❌ Agent 端无法缓存
KV Cache
(模型权重计算产物)
Attention 中间状态
Token 级概率分布
流式生成的
逐 Token 状态
✅ Agent 端可缓存
完整 Prompt 模板
(含变量槽位)
API 响应结果
(语义级去重)
中间推理产物
(工具调用结果等)
多轮对话的
拼接后文本

三层缓存架构

第 1 层:语义级响应缓存(难度 ⭐⭐)

相同或相似的问题直接返回历史结果,跳过 API 调用。

  • 缓存键:对 Prompt 做归一化后的 SHA-256 哈希
  • 存储:Redis / SQLite / 内存 LRU
  • TTL:按业务设定(知识类 24h,实时类 5min)
  • 实现难度:⭐⭐ 低,纯工程问题

第 2 层:Prompt 模板管理器(难度 ⭐⭐)

确保发给同一模型的 Prompt 前缀字节级一致,最大化厂商缓存命中。

  • 核心功能:模板编译、变量注入、版本锁定
  • 关键约束:System Prompt 从模板渲染,禁止运行时动态拼接
  • 实现难度:⭐⭐ 低,但需要团队纪律配合

这是多模型场景下最有价值的一层——它确保了无论切到哪个模型,该模型收到的前缀都是稳定的,厂商侧缓存才能在第二次请求就开始命中。

第 3 层:本地 KV Cache(难度 ⭐⭐⭐⭐⭐)

在 Agent 端自己跑推理,完全掌控 KV Cache。仅适用于开源模型 + 自有 GPU 场景。

  • 技术栈:vLLM / SGLang / llama.cpp
  • 优势:完全控制缓存生命周期、无厂商锁定
  • 劣势:需要 GPU 资源、运维成本高、闭源模型不可用

推荐架构:Agent 缓存层 + 模型路由

未命中
命中
用户请求入口
① 语义缓存层
Redis / SQLite
② Prompt 模板管理器
锁定前缀 + 注入变量 + 选择目标模型
直接返回
零成本 · 零延迟
Opus Session
设计 / 验证阶段
独立缓存空间
Sonnet Session
日常开发阶段
独立缓存空间
API Call
前缀稳定 → 厂商缓存易命中
API Call
前缀稳定 → 厂商缓存易命中

落地优先级

优先级动作预期收益工期
P0Prompt 模板管理器 + 版本锁定厂商缓存命中率从 ~30% → ~80%1-2 天
P1语义级响应缓存(精确匹配)重复问题零成本2-3 天
P2模型路由 + Session 隔离消除跨模型缓存抖动3-5 天
P3模糊语义缓存(Embedding)相似问题也能命中(有误返风险)1-2 周

实现难度总评

维度评估
技术难度第 1、2 层属于常规后端工程,不需要 AI 专业知识
最大挑战不是代码,而是 Prompt 治理纪律——团队必须接受"改 System Prompt 要走流程"
ROI极高。仅 P0+P1 就能在高频调用场景下节省 40%-70% 的 Token 费用
风险点缓存污染(过期数据被返回)、Prompt 模板僵化(过度锁定导致迭代慢)

一句话总结:Agent 端缓存的实现难度不高,但它真正的价值不在于替代厂商 KV Cache,而在于通过工程手段创造让厂商缓存高效工作的条件。对于多模型场景,把 Prompt 模板管理和 Session 隔离做好,比追求任何高级缓存算法都更有效。