sha256: 0c38c7d63adf7699687663b4a67f2e8b3fc1957060e778dda9a78677b586a36f --- title: "LLM 缓存原理与实践:从 KV Cache 到 Prefix Caching,为什么 Agent 命中率常挂 90%" source: wechat url: https://mp.weixin.qq.com/s/bsSBfvWyLUEdFHFZmFOckQ mp_name: 未知 publish_date: 2026-07-03 --- 这是2026年的第29篇文章 ( 本文阅读时间:约15分钟 ) ## 缘起:一个 90% 的观察 如果看过自己团队的大模型 token 消耗看板,我们多半会注意到一个现象:主力模型的缓存命中率常年挂在 90% 上下,而且越是高频使用、跑得越久的模型,命中率越稳。 这不是某一家的「黑科技」,实际上,这是一整套已经成为行业标配的推理优化技术,叠加上「agent 式调用」这种使用模式后的必然结果。 这篇文章想把这件事梳理清楚:缓存到底缓存了什么(KV Cache 原理);当前有哪些缓存技术方向;最先进的几个模型是怎么落地的;为什么命中率会这么高——以及它高,到底意味着什么。 ## 01 第一性原理:模型为什么需要缓存 ### KV Cache:把「回看」的中间结果存下来 大模型是「一个字一个字往外蹦」的。当前主流大模型都是自回归(autoregressive)生成:每次只预测下一个 token,把它接到已有文本后面,再预测再下一个。问题在于,Transformer 的注意力机制要求——预测每一个新 token,都要「回看」前面所有 token。 如果什么都不缓存,那就是一场灾难:生成第 100 个字时,要把前 99 个字重新计算一遍注意力;生成第 1000 个字时,把前 999 个字再算一遍……计算量随长度平方级膨胀。 注意力机制里,每个 token 都会被换算成三样东西:Query(查询)、Key(键)、Value(值)。预测新 token 时,用新 token 的 Query 去和所有历史 token 的 Key/Value 做运算。 关键洞察是:历史 token 的 Key/Value 一旦算出来就不再变了。那为什么每步都重算?把它们缓存下来,下一步直接读,新 token 只需要算自己那一份,就是 KV Cache。它把每步的计算从"重算整段历史"降到"只算新增的一个",是所有大模型推理的地基。 但 KV Cache 有个「先天局限」:它默认只在一次请求内部有效。请求一结束,这块缓存通常就被丢弃了。下一个请求哪怕开头一模一样,也得从头再算。真正决定"命中率"高低的,是能不能把缓存跨请求复用。 ## 02 从 KV Cache 到 Prefix Caching:跨请求复用 ### 核心思想:相同的前缀,只算一次 观察真实流量我们会发现:海量请求的开头是高度重复的。同一个 AI 助手,每个请求都带着同一份几千 token 的系统提示词(system prompt);同一段多轮对话,第 5 轮请求的开头就是第 4 轮的全部内容。 Prefix Caching(前缀缓存)就是把这部分"公共前缀"的 KV Cache 留下来、跨请求复用:新请求进来,先看它的前缀是不是已经被算过、缓存过;命中了就直接读,跳过最昂贵的"预填充(prefill)"环节。 ### 为什么必须「逐字完全一致」? 前缀从第一处不一致开始、往后就无法复用——分歧点之前的完整块仍然命中,之后的缓存才失效。原因在于现代模型用的位置编码(如 RoPE 旋转位置编码):每个 token 的 Key/Value 不仅取决于"它是什么词",还取决于"它排在第几位"。而且在多层注意力下,某个 token 的 K/V 还依赖它前面的整段上下文——前面一改,后面每个 token 的 K/V 都跟着变。 两个直接推论: 1. 稳定的内容要放在最前面(系统提示、工具定义),易变的内容(用户每次不同的问题、时间戳)放最后; 2. 只能追加(append),不能插改。在已缓存内容后面接新内容,前缀不变、缓存照命中;一旦改动前面的内容,缓存全废。 ## 03 当前缓存技术有哪些方向 ### 方向一/二:PagedAttention——让缓存「装得下、不浪费」 KV Cache 很吃显存:一条长序列就能占用数 GB(论文实测 OPT-13B 上单序列约 1.6GB)。早期系统因为要给每条序列预留连续显存,碎片化和冗余拷贝白白浪费了 60%–80% 的显存。 vLLM 的 PagedAttention 借鉴了操作系统管理内存的经典思路:把 KV Cache 切成固定大小的「页(block)」,像虚拟内存分页一样按需分配、灵活共享,把浪费压到 4% 以下,吞吐量提升 2–4 倍。 ### 方向三:跨请求复用的两条数据结构路线 **vLLM 的 Automatic Prefix Caching(APC)**:把前缀切成定长 block,每个 block 的哈希由「父块哈希 + 本块内容」链式生成——这条哈希链天然表达了「完整前缀」。所有块丢进一张哈希表,不维护树结构,块独立分配/释放,用 LRU 淘汰最久未用的。命中要求逐块精确匹配(只缓存写满的整块)。 **SGLang 的 RadixAttention**:用基数树(前缀树)显式建模请求间的前缀共享关系:树以 token 序列为路径,共享前缀的请求自然落在同一条分支上;用「递归淘汰叶子节点」的 LRU 管理,再配合「缓存感知调度」主动提高命中率。论文报告相比当时 SOTA 吞吐最高提升 6.4 倍。 ### 方向四:突破「必须是前缀、必须逐字一致」的限制 标准 prefix caching 有两个硬约束:必须是前缀、必须逐字一致。这对 RAG(检索增强)这类场景很不友好——检索到的文档每次都不同、又往往夹在中间而非开头。 - **Prompt Cache(MLSys 2024)**:让开发者用一套标记语言(PML)把系统提示、模板、常用文档声明成可复用模块,服务端预先算好它们的注意力状态,无论这个模块出现在 prompt 的哪个位置都能复用。首 token 延迟最高加速 8×(GPU)/ 60×(CPU)。 - **CacheBlend(EuroSys 2025 最佳论文)**:允许把非前缀位置的文档块缓存直接拼接,只对一小部分 token 做「选择性重算」来修正跨块的注意力,TTFT 加速 2.2–3.3×、吞吐提升 2.8–5×,且不掉生成质量。 - **EPIC(ICML 2025)**:系统性地提出「位置无关缓存(Position-Independent Caching)」,把非前缀复用的主要障碍归因于 attention sink(每个片段的首 token 过度吸走注意力),并据此做针对性修正。 这些还多在前沿研究/特定引擎阶段,但代表了缓存技术「从前缀走向任意片段」的演进方向。 ## 04 最先进的模型是怎么落地的 四家主流商用模型的缓存策略对比: | 维度 | Anthropic Claude | OpenAI | Google Gemini | DeepSeek | |------|-----------------|--------|--------------|----------| | 开启方式 | 手动打断点 cache_control(也可自动) | 全自动,无需改代码 | 隐式(自动) + 显式(手动建 CachedContent) | 全自动前缀缓存 | | 命中折扣 | 命中约 0.1× 原价 | 初版约 5 折;新口径"成本最高省 90%" | 隐式命中约 75% 折扣 | 命中价约为未命中的 1/10 | | 写入成本 | 5 分钟档 1.25×、1 小时档 2× | — | 显式缓存另收"按时长"的存储费 | 存储免费 | | TTL | 默认 5 分钟,每次命中自动续期 | 不活跃 5-10 分钟清除 | 默认 1 小时,可自定义 | 数小时至数天后自动清除 | | 最小可缓存 | 约 1024-4096 token | 1024 token 起,128 增量 | 隐式 1024-2048 | 最小 64 token | | 缓存存放 | 厂商侧 | 厂商侧 | 厂商侧 | 分布式硬盘阵列(靠 MLA 压缩 KV 体积) | 几个值得注意的落地细节: - Anthropic 在首发公告中称提示缓存可「降低成本最高 90%、降低延迟最高 85%」,缓存一本 10 万 token 的书后,响应延迟从 11.5 秒降到 2.4 秒。 - DeepSeek 的「硬盘缓存」很有代表性:常规 KV Cache 太大放不进内存,它靠 V2 的 MLA 架构把 KV 体积大幅压缩,才得以低成本地落到分布式硬盘上长期保留。 ## 05 为什么命中率会这么高 ### 关键:agent 对话是「只追加」的 回想第二节那条铁律:只追加、不插改,缓存就一直命中。而各类 AI agent 的多轮调用,正好就是这个形状:每一轮请求,都把整段历史原封不动重发一遍,再在末尾追加一点点新内容(上一步的工具输出 + 模型新回复)。于是除了最新追加的一小段,前面的巨大前缀全部命中缓存。会话越长,被反复重读的前缀越大,命中占比越高。 ### 简化模型:命中率 ≈ (T−1)/(T+1) 设一次会话共 T 轮,每轮新增的内容量大致相当(记为 d)。第 k 轮请求时,前面 (k−1) 段都已缓存、走「命中读」,只有最新 1 段是「写入」。 累计命中读 ≈ d·T(T−1)/2,累计新写入 ≈ d·T,命中率 ≈ (T−1)/(T+1)。 | 会话轮数 T | 理论命中率 | |-----------|-----------| | 10 | 81.8% | | 20 | 90.5% | | 40 | 95.1% | 一次典型的 agent 编码会话往往要跑十几到几十轮工具调用,命中率就容易落到 90% 上下。这大致解释了不同厂商主力模型的命中率为何都在这个区间——主要是「只追加对话 + 前缀缓存」这种工作负载的结果,而非某家模型的特殊能力。 ### TTL 短,为什么不掉链子 缓存默认只活 5 分钟,会话跑久了不会过期。因为每次命中都会刷新 TTL,且不额外收费。只要你在持续编码(隔几十秒就有一次工具往返),缓存被一次次"续命",整场会话几乎不过期。 ### 什么时候命中率会掉到 50% 凡是破坏「只追加 + 前缀一致」的场景,命中率立刻塌方: - 中途切换模型:缓存按模型隔离,换个模型等于全部冷启动 - 改动了工具集或系统提示:排在最前面,一动则后面全废 - 会话很短:T 很小时 (T−1)/(T+1) 本来就低(T=3 时正好约 50%) - 请求被分散路由到不同后端:若缓存按后端隔离、且路由不感知前缀(自建或非 cache-aware 网关常见),轮询会打散前缀的局部性 如果看板上看到某个「自动路由 / 多模型聚合」档位的命中率只有 ~50%,多半就是它在请求间不断切换模型/重置前缀,把有效会话深度压到了三五轮。 ## 06 一个反直觉的提醒 高命中率 ≠ 一定省钱、一定高效。命中率高,恰恰是「每一轮都把整段大上下文重发一遍」的副产物。命中读虽然只要 0.1× 价钱,但你的绝对输入量也被这种重发模式撑得很大。真实成本由命中读 + 写入 + 未缓存三部分的总和决定,单看命中率会误判。 命中率 90% 是好事,说明缓存机制在替用户省钱、降延迟;但真要压成本,杠杆往往在那掉到 50% 的少数流量上(让它们绑定单一模型、稳定工具集、复用前缀),而不是在已经 90% 的主力模型上抠。 把缓存当成一种「奖励只追加、惩罚乱插改」的契约——顺着它的脾气用,命中率自然就上去了。 ## 参考文献 文中引用了 15 篇论文和官方文档,涵盖: - KV Cache 原理:Pope et al. MLSys 2023 - PagedAttention:Kwon et al. SOSP 2023 - SGLang RadixAttention:Zheng et al. NeurIPS 2024 - Prompt Cache:Gim et al. MLSys 2024 - CacheBlend:Yao et al. EuroSys 2025 最佳论文 - EPIC:Hu et al. ICML 2025 - Anthropic/OpenAI/Google/DeepSeek 官方缓存文档及定价