Prefix Caching 的原理是什么?它与普通 KV Cache 有什么区别?
简化版
普通 KV Cache 只在一次生成内复用当前请求已算过的历史 token,请求结束就释放;Prefix Caching(前缀缓存) 则把可复用前缀的 KV 块跨请求、跨轮保存下来——当新请求的开头与之前某请求完全相同时,直接跳过这段前缀的 Prefill、复用已算好的 KV。它只省「重复输入的 prefill 计算」,不加速未缓存的后缀和后续 Decode。命中条件很严格:模型、token 序列、以及所有影响 KV 的配置都必须完全一致。
详细版
系统按 token 块 + 其完整前缀计算哈希,映射到物理 KV 块。新请求从开头逐块查找:连续命中的块直接引用(跳过 prefill),第一个未命中块之后正常 prefill。块级 Copy-on-Write + 引用计数 让多请求安全共享只读前缀。
适用场景(前缀高度重复时收益大):
- 公共 System Prompt(所有请求共享同一段系统指令);
- 多轮对话(每轮都带着相同的历史前缀);
- 同一长文档被反复提问;
- 相同的 Few-shot 示例前缀。
失效场景:若每次 prompt 开头都插入动态时间戳、随机 ID、不同模板,缓存几乎无法命中。
完整版教学
一、两种缓存的范围区别
普通 KV Cache:自回归生成时,当前请求保存已处理 token 的 K、V,让下一步不必重算历史。它的生命周期随请求结束而释放,目标是加速同一序列的 Decode。
Prefix Cache:把 KV 的生命周期延长到跨请求,让以后的请求复用「相同输入前缀」产生的 KV。简要说——普通 KV Cache 是「一次回答内不重读前文」,Prefix Cache 是「以后遇到同一前缀也不重读」。
二、为什么必须是”完全相同的前缀”
这是理解前缀缓存的关键。Transformer 里,某位置的 K、V 依赖它之前的全部 token(通过多层注意力)。所以只有当前缀的 token、顺序、位置全部一致时,缓存的 KV 才能直接复用——哪怕只改了前缀里一个 token,它之后所有位置的 KV 都变了,不能复用。
几个容易忽略的命中条件:
- 相同自然语言,但 tokenization 不同 → 不是同一缓存键(比如多了个空格切法就变了);
- 模型权重、LoRA/Adapter、RoPE 配置、精度不同 → KV 不同,必须隔离;
- 多模态输入等任何影响前向结果的东西,都要纳入哈希键。
三、块级缓存与 PagedAttention 配合
为了高效,缓存按固定 token 数分块(如每 16 token 一块),和 PagedAttention 的分页机制天然配合:
System Prompt(512 token,32 个块)── 所有请求共享这 32 个物理块
请求A:[共享的32块] + [A独有的后缀块]
请求B:[共享的32块] + [B独有的后缀块]
完整块命中才能共享物理页;最后一个不完整块可能选择不缓存或单独处理。块大小是权衡:块越大元数据越少,但更难命中细小差异;块越小管理开销越高。
四、收益边界:只省 Prefill,不省别的
必须清楚前缀缓存的收益边界。命中 L 个前缀 token,主要省下的是这 L 个 token 的 prefill 计算:
省下的 ≈ L 个 token 的 prefill(TTFT 下降)
不省的 :新后缀的 prefill、全部输出的 Decode
所以它对 TTFT 影响大、对 TPOT 无影响。在这些场景收益很小:短 prompt(没多少可省)、一次性无重复请求、以及瓶颈在 Decode 的高并发场景。举例:一个 2K token 的公共 system prompt 被上万请求共享,每次省下 2K token 的 prefill,累积收益巨大;但若每个请求的 prompt 都独一无二,前缀缓存形同虚设。
五、显存竞争与淘汰
前缀缓存占用显存,且会和活跃请求的 KV Cache 竞争同一块显存。缓存太多前缀会挤占正在服务请求的空间。所以需要 LRU 等淘汰策略:优先保留高频命中的前缀(如公共 system prompt),淘汰久未命中的。这是一个「缓存收益 vs 显存占用」的动态平衡。
六、安全与隔离(易被忽略的坑)
跨请求共享缓存带来安全风险:
- 时序侧信道:攻击者可能通过「某前缀命中快、未命中慢」推断别人用过什么 prompt;
- 错误复用:不同租户若共享缓存,可能读到不该读的中间状态。
防护:租户命名空间隔离、缓存盐(salt)、访问控制。此外,更新模型、LoRA、prompt 模板后必须让旧缓存失效——否则会用错 KV 产生错误输出。缓存的是「中间 KV 状态」,不是「最终回答」,别搞混。
七、加强记忆
Prefix Caching 记「跨请求复用相同前缀的 KV」:普通 KV Cache 是「一次回答内不重读前文」,前缀缓存是「以后遇到同一前缀也不重读」,收益全在 Prefill(降 TTFT),命中要求前缀 token/顺序/位置及所有影响 KV 的配置完全一致。三个要点钉死:块级缓存配 PagedAttention 共享物理页、只省重复前缀的 prefill、不省后缀和 Decode、跨租户共享有侧信道风险需隔离+盐+失效策略。最适合公共 system prompt、多轮对话、同文档反复问这类高重复前缀场景。