跳转至

Prefix Caching

前缀缓存复用相同提示前缀的 KV Cache,减少重复 prefill。多个请求共享同一段前缀(如系统提示、文档片段)时,只计算一次该前缀的 KV,后续请求直接复用。

前缀缓存的由来是服务负载中的前缀重复性:在多轮对话、检索增强生成 (Retrieval-Augmented Generation, RAG) 与 agent 场景里,系统提示、few-shot 示例、检索到的文档片段会在大量请求中逐 token 一致地重复出现,而 prefill 恰恰要为这些 token 重新算一遍 KV。既然 KV 只由前缀 token 决定,命中相同前缀时即可跳过这段 prefill,直接把已缓存的 KV 拼接到后续新 token 上,从而显著降低 TTFT 与 prefill 计算量。主流的两种组织方式分别是 SGLang 的前缀树 RadixAttention 与 vLLM 的 automatic prefix caching,前者按 token 序列组织成树并做 LRU 逐出,后者按 block 做哈希匹配并自动复用。

快速开始

只缓存稳定且可共享的前缀,设计租户和权限隔离;监控命中率、节省 token 和显存占用。

  1. 识别前缀:确认负载中存在稳定重复的前缀,如统一系统提示、共享文档头部。
  2. 启用并隔离:在支持前缀缓存的运行时启用,并保证不同租户/权限的数据不会交叉命中。vLLM 在启用 --enable-prefix-caching 的同时还要校验多租户配置,SGLang 的 RadixAttention 默认开启。
  3. 监控:记录缓存命中率、由此节省的 prefill token 数与缓存占用的显存。

验证成功的关键是命中率与节省量可观,同时显存占用可控、无越权复用。若命中率低,检查请求的前缀是否真的逐 token 一致,以及缓存是否被频繁失效。

风险

不同用户的私有上下文不能被跨租户复用。缓存按「前缀」而非「用户」组织,若实现不当,租户 A 的前缀可能被租户 B 的请求命中,造成信息泄露,必须做显式的租户与权限隔离。

缓存键必须包含模型、Tokenizer、模板和精确 token 序列。同一段文本在不同模型或分词器下 token 序列不同,模板差异也会改变前缀;任一项变化都意味着 KV 不再等价,必须视作不同缓存项。哈希式缓存(如 vLLM)以「父 block 哈希 + 本 block token」逐块计算指纹来识别前缀,键设计不严谨会导致「看似相同、实则不同」的错误命中;前缀树方式(如 SGLang)则天然按 token 序列对齐,但树的维护与逐出策略更复杂。

此外,前缀缓存占用显存,与活跃请求的 KV 争抢空间,需要淘汰策略(如 LRU)在命中率与显存之间平衡。

案例

多个请求共享长系统提示和文档前缀时,缓存命中可显著降低 TTFT。模型版本切换后必须失效旧条目。

以「知识库问答 + 固定系统提示」为例,系统提示和检索到的文档片段构成每个请求的共同前缀,命中缓存后这部分 prefill 被跳过,TTFT 明显下降,尤其在前缀很长时收益更大。

代价是缓存占用显存,且内容一旦变化(文档更新、提示调整)该前缀即失效。模型版本切换后权重与分词都可能不同,旧条目的 KV 不再有效,必须整体失效,否则会产生错误结果。

常见失败点是命中率虚高或越权复用,排查时核对缓存键是否含全部必要维度,并审计是否存在跨租户命中。

相关主题