KV Cache 与推理性能优化

理解 KV Cache 如何减少自回归解码中的重复计算,并系统掌握延迟、吞吐、显存与服务调度之间的权衡。

难度

进阶

阅读时长

约 90 分钟

更新日期

2026/03/23

主题

推理优化 / KV Cache / 系统性能 / PagedAttention

先修知识

Transformer 基础GPU 显存常识

学习目标

读完这篇教程后,你应该能解释:

  1. 自回归生成为什么会天然变慢。
  2. KV Cache 到底缓存了什么,省掉了哪些重复计算。
  3. 为什么缓存会降低延迟,却会显著增加显存占用。
  4. PagedAttention、连续批处理、量化等系统优化分别解决什么瓶颈。

如果你已经读过 Transformer 注意力机制入门,这篇文章会帮你把“注意力公式”接到“线上推理系统”。

问题背景:为什么生成一个 token 会越来越贵

大模型推理通常是自回归的,也就是每次只生成一个新 token,然后把它接到上下文后面,再继续预测下一个 token。

如果没有任何缓存机制,第 t 步生成时,模型需要重新处理长度为 t 的整段前缀。这样做的问题是:

  • 历史 token 的 K/V 会被一遍遍重复计算。
  • 序列越长,单步推理成本越高。
  • 总体生成成本会随输出长度迅速增长。

从系统角度看,推理并不只是“跑一次前向传播”,而是“对同一段前缀做很多次高度重复的前向传播”。KV Cache 就是专门用来消除这部分浪费的。

KV Cache 到底缓存了什么

在自注意力里,每一层都会把隐藏状态投影成 QKV。对于已经生成过的历史 token 来说:

  • 这些 token 的 K/V 在后续步骤不会变化。
  • 真正变化的只有“当前新 token 的 query”和它对应的新 K/V

因此,我们可以把历史 token 在每一层产生的 K/V 保存下来。下一步生成时:

  1. 只对新 token 计算本层的 Q/K/V
  2. 把新产生的 K/V 追加到缓存里。
  3. 用新 token 的 Q 去和整段缓存里的 K 做注意力。
  4. 再根据权重读取缓存中的 V

这就是 KV Cache 的核心:历史信息不重算,只增量更新。

为什么它能大幅节省时间

如果没有 KV Cache,生成阶段每一步都要对整段前缀重新做投影和层内传播;如果有 KV Cache,历史 token 的大部分中间结果都能复用。

可以粗略理解为:

  • 无缓存:第 1 步算 1 个 token,第 2 步重算 2 个,第 3 步重算 3 个……
  • 有缓存:第 1 步算 1 个 token,第 2 步只新增算 1 个,第 3 步也只新增算 1 个……

当然,注意力分数的计算仍然需要让当前 query 看向所有历史 key,所以 decode 阶段的单步开销会随着序列变长而增长。但和“整段前缀完全重算”相比,缓存带来的节省仍然非常可观。

Prefill 和 Decode:推理有两个完全不同的阶段

理解 KV Cache 时,一定要区分两个阶段:

Prefill

模型第一次读入整段 prompt,把所有历史 token 的 K/V 建起来。这一阶段通常并行度高、吞吐高,但计算量大。

Decode

模型开始逐 token 生成,每一步只新增一个 token,并反复使用缓存。这一阶段计算粒度小、访存频繁,系统瓶颈与 prefill 很不一样。

现实服务里,很多优化都是分别针对这两个阶段设计的。例如:

  • Prefill 更关注大批量吞吐和长 prompt 处理效率。
  • Decode 更关注单 token 延迟、调度和缓存管理。

显存公式:缓存为什么会吃掉这么多内存

KV Cache 的速度收益并不是免费的,它会换来显著的显存开销。一个常见的粗略估算公式是:

memory_bytes ≈ 2 * layers * batch * seq_len * num_kv_heads * head_dim * bytes_per_element

这里的 2 表示要同时存储 key 和 value。

从这个公式可以直接看出,缓存成本会被以下因素线性放大:

  • 层数越多,缓存越大。
  • batch 越大,缓存越大。
  • 上下文越长,缓存越大。
  • 精度越高,例如 FP16 比 INT8 占更多空间。

所以推理系统里的很多工程问题,本质上都在问:如何在不明显损失效果的前提下,把这块缓存管理得更省、更稳、更灵活。

MHA、MQA、GQA 对缓存的影响

KV Cache 的体积和注意力头设计密切相关。

MHA

传统 Multi-Head Attention 中,每个头都有自己的 K/V,表达能力强,但缓存开销较大。

MQA

Multi-Query Attention 让多个 query head 共享同一组 K/V,可以明显减少缓存大小和访存开销,对推理很友好。

GQA

Grouped-Query Attention 介于两者之间:若干 query head 共享一组 K/V,在效果和效率之间做平衡。

这也是为什么今天很多面向部署优化的模型,会优先采用 GQA 或 MQA,而不是完全沿用原始 Transformer 的 MHA 设计。

PagedAttention:为什么“能放下缓存”还不够

只会缓存还不够,关键是怎么管理缓存。实际服务里,请求长度差异很大,如果直接为每个请求预留一整块连续显存,很容易出现:

  • 大量碎片
  • 已分配但未充分使用
  • 长短请求混跑时利用率低

PagedAttention 的核心思路,是把 KV Cache 拆成更小的页块来管理,而不是要求每个请求占据一整段连续大内存。这样做的好处是:

  • 显存分配更灵活
  • 碎片更少
  • 请求结束后更容易回收
  • 更适合多请求并发场景

这类优化不会改变模型输出逻辑,却能显著提高实际吞吐,是推理系统工程里非常典型的“底层改造换大收益”。

连续批处理:让 GPU 不要空等

静态 batch 有一个常见问题:你往往要等一批请求都凑齐才能一起算,或者一批里最长的请求拖住其他请求。

连续批处理(continuous batching)的思路是:

  • 有新请求进来时,不必等当前 batch 完整结束。
  • 已经完成的请求可以随时退出。
  • 空出来的计算槽位可以立刻被新请求填上。

这样做能明显提升 GPU 利用率,尤其适合在线服务。代价是调度实现更复杂,对缓存管理、序列状态维护和公平性策略要求更高。

量化为什么和 KV Cache 紧密相关

很多人把量化理解成“主要节省模型权重显存”,其实对长上下文推理来说,KV Cache 也同样重要。

因为当序列很长、并发很多时,瓶颈可能不是模型权重,而是缓存本身。此时对缓存做更低比特表示,或者采用更节省空间的头设计,都会直接影响:

  • 能容纳多少并发请求
  • 能支持多长上下文
  • 是否需要频繁换页或回收

当然,量化会带来精度和稳定性的权衡,因此通常要结合任务类型、模型架构和服务目标一起评估。

框架选择时该看什么

无论你最后用的是 vLLM、TGI、Ollama,还是自研服务,判断标准都不应只看“能不能跑起来”,而是看它在以下维度上的表现:

  • 是否支持高效的 KV Cache 管理
  • 是否具备连续批处理能力
  • 长上下文下吞吐和延迟是否稳定
  • 多模型、多租户场景下的资源隔离是否清晰
  • 监控、日志和回放能力是否足够

产品环境里的推理优化,本质上是一个系统问题,而不是单点算法问题。

线上需要重点观测的指标

如果你负责服务稳定性,建议长期盯住这些指标:

  • 首 token 延迟(TTFT)
  • 平均生成速度(tokens/s)
  • p95 / p99 延迟
  • 显存占用与碎片率
  • 请求排队时间
  • 长短 prompt 混跑时的吞吐变化

很多性能问题并不是模型太慢,而是缓存分配、batch 调度和请求形态共同作用的结果。

什么时候 KV Cache 反而会成为负担

KV Cache 并非无脑开启就完事。下面这些场景要特别小心:

  1. 上下文极长、并发极高,缓存显存先于权重成为瓶颈。
  2. 请求很短,缓存收益有限,但调度复杂度和内存管理开销上来了。
  3. 多轮对话 session 很多,如果缓存生命周期管理不好,显存会被历史会话长期占着。
  4. 某些边缘部署环境显存特别紧张,此时要优先考虑量化、裁剪上下文或分层卸载策略。

系统优化真正重要的不是“某个技术很先进”,而是“它是否解决了你当前最贵的瓶颈”。

推荐阅读顺序

如果你想把这部分知识串起来,建议按这个顺序继续:

  1. Transformer 注意力机制入门
  2. Attention Is All You Need
  3. Lost in the Middle
  4. RoPE Visualizer

这样你会同时理解三件事:注意力怎么工作、长上下文为什么昂贵、以及即便付出了高昂成本,模型也不一定真的会用好这些上下文。

练习题

  1. 为什么 KV Cache 能避免“重复投影历史 token”,却不能让 decode 阶段完全变成常数开销?
  2. 在长上下文在线服务里,为什么 GQA 往往比传统 MHA 更适合部署?
  3. 如果某个服务的 TTFT 正常,但 p99 延迟很差,你会优先排查哪些缓存或调度问题?
  4. 当显存瓶颈主要来自 KV Cache,而不是模型权重时,哪些优化优先级会提升?

延伸思考

推理优化最容易让人陷入“堆术语”的错觉,但真正有用的判断标准很简单:

你的系统瓶颈,究竟在算力、访存、显存,还是调度?

KV Cache 只是起点。理解了它,你才真正进入大模型系统工程的核心地带。

相关阅读

从相近主题继续深入,建立连续学习链路。