重要提示:如需以 Markdown 形式查看本页,请在 URL 后追加 `.md`。 完整文档索引见 llms.txt
跳到主要内容
完整文档索引见 llms.txt。 在任意 URL 后追加 `.md` 即可查看该页面的 Markdown 版本。

前缀缓存

前缀缓存(也称为提示词缓存或上下文缓存)是在 LLM 推理中降低延迟和成本最有效的技术之一。它尤其适用于存在重复提示词结构的生产工作负载,例如聊天系统、AI agent 和 RAG 流水线。

其思路很简单:通过缓存现有查询的 KV 缓存,新的查询如果共享相同前缀,就可以跳过这部分提示词的重复计算,而是直接复用缓存结果。

前缀缓存不同于简单的语义缓存。后者会把完整输入和输出文本存储在数据库中,只有完全匹配(或相似查询)时才能命中缓存并立即返回。

前缀缓存如何工作?

前缀缓存会复用模型已经计算过的注意力状态。

  1. 在预填充阶段,模型对输入 token 执行一次前向传播,并逐步构建键值(KV)缓存。
  2. 在解码阶段,模型使用预填充阶段缓存的状态逐个生成输出 token。注意力机制会计算一个 token 间交互矩阵。每个 token 对应生成的 KV 对会被存储在 GPU 内存中。
  3. 当新的请求到达时,模型会找到与该请求起始部分匹配的最长已缓存 token 序列。它加载这些 KV 状态,并只对剩余 token 执行预填充。

这只有在前缀完全一致时才有效,包括空白字符和格式也必须一致。哪怕只差一个字符,缓存都会失效。考虑下面三个提示词:

Prompt 1: Summarize this incident report in one paragraph.
Prompt 2: Summarize this incident report in three bullet points.
Prompt 3: Write a one-paragraph summary of this incident report.

Prompt 2 可以复用共享起始部分 Summarize this incident report in 的 KV 状态。模型只需要处理两个提示词发生分叉后的后缀。Prompt 3 虽然请求的结果相似,并且与 Prompt 1 包含许多相同词语,但它并不是从相同 token 序列开始。因此,它无法从头复用 Prompt 1 的缓存。

这也是前缀缓存不同于语义缓存的原因。两个提示词即使语义相同,也可能无法命中前缀缓存;而两个最终问题不同的请求,也可能共享大部分已缓存计算。

下面是前缀缓存的两个常见用例:

复用静态系统提示词

一个常见的可缓存前缀,是许多请求共享的系统提示词:

You are a helpful AI writer. Please write in a professional manner.

如果这段提示词及其序列化形式保持不变,模型就可以只计算一次 KV 状态,并在多个对话之间复用。这样每个请求只需对其后跟随的用户特定内容执行预填充。

复用不断增长的聊天历史

多轮聊天中,这种收益会更明显。假设第一轮是:

User: Why did the checkout API slow down after deployment?
Assistant: Trace data shows that repeated inventory database lookups added most of the latency.

然后用户继续提问:

User: Which lookup should we optimize first?

模型接收到的并不只是最新问题。应用会把先前消息作为 上下文窗口 的一部分重新发送,以便模型知道用户说的是哪些 lookup。因此,第二次请求的序列化结果大致如下:

User: Why did the checkout API slow down after deployment?
Assistant: Trace data shows that repeated inventory database lookups added most of the latency.
User: Which lookup should we optimize first?

前两条消息构成了模型已经处理过的精确前缀。如果它们对应的 KV 状态仍然可用,模型就可以复用它们,只对新的用户消息执行预填充。没有前缀缓存时,它必须再次处理整段对话。

随着对话增长,可复用前缀也会随之增长。避免重复预填充可以减少 GPU 计算,并防止 TTFT 在多轮对话中增长得过快。请注意,缓存命中仍然取决于服务引擎是否保留该条目、是否能够 将请求路由到可访问该缓存的 worker,以及此前消息是否以完全相同的方式序列化。

KV caching 和前缀缓存有什么区别?

KV caching 用于把每个 token 的中间注意力状态存储在 GPU 内存中。它最初用于描述单个推理请求内部的缓存,对加速解码阶段尤其关键。

LLM 在解码期间以自回归方式工作,会根据先前已生成的 token 输出下一个新 token(也就是复用它们的 KV 缓存)。如果没有 KV 缓存,模型在每一个解码步骤都必须重新计算之前所有 token 的内容(而且上下文会在每一步继续增长),这会极大浪费资源。

当把这种缓存概念扩展到多个请求之间时,更准确的叫法是前缀缓存。由于 KV 缓存的计算只依赖于所有先前 token,不同请求只要拥有相同前缀,就可以复用这部分前缀 token 的缓存,避免重复计算。

如何组织提示词以获得更多缓存命中

只有在提示词保持一致时,前缀缓存才会有帮助。下面是一些能最大化缓存命中率的最佳实践:

  • 把静态内容前置:把任何固定不变或很少变化的信息放在提示词开头。这可以包括系统消息、上下文或多次查询间保持不变的指令。把动态内容或用户特定内容移到提示词末尾。
  • 对相似请求做批处理:把共享相同前缀的查询放在一起处理(尤其是在为多个用户或多个 agent 提供服务时),这样缓存结果可以更高效地复用。
  • 避免在前缀中放入动态元素:不要在提示词前部插入时间戳、请求 ID 或其他按请求变化的变量。这些都会降低缓存命中率。
  • 使用确定性的序列化:确保你的上下文或记忆序列化(例如 JSON)在键顺序和结构上是稳定的。非确定性序列化即使在逻辑内容相同的情况下,也会导致缓存未命中。
  • 监控并分析缓存命中率:定期检查缓存性能,以识别可优化空间。

采用情况与性能收益

前缀缓存可以在某些用例中把计算量和延迟降低一个数量级。

  • Anthropic Claude Sonnet 提供 prompt caching,对长提示词可实现最高 90% 成本节省和 85% 延迟下降。
  • Google Gemini 对 已缓存 token 提供折扣计费,并单独收取存储费用。
  • vLLM、TensorRT-LLM 和 SGLang 等框架支持针对不同开源 LLM 的自动前缀缓存。

在 agent 工作流中,这种收益更为明显。有些用例的输入输出 token 比可以达到 100:1,因此重复处理大提示词的成本会显得格外高。

局限性

对于具有长且重复提示词的应用,前缀缓存可以显著降低延迟和成本。但随着时间推移,KV 缓存规模也可能变得很大。GPU 内存是有限的,在许多用户之间存储长前缀会迅速占用空间。你需要缓存驱逐策略或内存分层。

开源社区正在积极探索分布式服务策略。详见 推理路由

另一个实际限制是特性组合。当前缀缓存只面对一个标准的全注意力 KV 缓存时,它很容易理解;但较新的服务栈可能需要同时管理多种类似缓存的状态:用于 推测解码 的 draft model 和 target model 缓存、VLM 的图像编码器状态、量化 KV 缓存的缩放元数据,或者混合注意力层的独立缓存。

对于这些模型,共享文本前缀并不总意味着每种缓存状态都能以相同方式复用。例如,sliding-window attention 只保留一个有界的最近窗口,因此缓存管理器必须知道哪些 token 仍然有效。在生产中,应把前缀缓存命中率视为按工作负载区分的指标,而不是一个统一的全局数值,并验证你的推理框架是否能够把前缀缓存与其他已启用优化组合使用。


优化 LLM 前缀缓存,要求你的 LLM 服务和基础设施栈具备灵活的可定制能力。我们致力于提供专用且可定制的 LLM 部署基础设施,支持快速自动扩缩容和 scale-to-zero,以确保资源效率。