第一次接触 LLM 推理优化时,大家会先听到一个词:

KV Cache

它听起来很玄乎,但本质是非常朴素的一件事:

不要把已经算过的东西重复算。把可复用的“中间结果”先记下来。

本篇用最少公式、尽量白话,解释它是什么、为什么有用、什么时候会“掉速”。

1. 先把问题说清楚:大模型推理为什么慢?

给模型发一句话,模型在第一个 token 出来之前,会做两个阶段:

  • prefill(预填充):把完整输入(prompt)一次性喂进去,计算每一层每个 token 的注意力。
  • decode(解码):逐 token 继续生成。

慢主要不在“会不会算”,而在“有多少重复计算”。

如果你每次都把相同上下文从头算一遍,长上下文下开销会很快膨胀。

2. Transformer 注意力里,真正复用的是什么?

在解码每一步,模型会用到历史 token 之间的注意力信息。

这部分历史相关信息里,核心可以拆成两类:

  • Key(K)
  • Value(V)

每层每个头都会算一堆 K/V。它们本身不依赖“当前要预测的新 token”,而是依赖历史上下文。也就是说,前面已经算出来的 K/V 可以继续用。KV Cache 就是在这一步做“缓存”。

3. 一个“可视化”理解

把一次解码想成“接力”:

  • 第 1 次生成 token 时,你要把所有上下文都处理一遍;
  • 第 2 次生成 token 时,如果不缓存,就又要处理一次前面的上下文。

有了 KV Cache:

  • 本轮新算出来的 K/V 只加到缓存末尾;
  • 已有的旧 K/V 直接复用;
  • 每步计算规模基本从“越来越大”变成“基本稳定增长”。

这就是为什么 decode 阶段可以明显提速、稳定 throughput 的核心机制之一。

4. 一个很重要的边界:Prompt Cache 和 KV Cache 不是一回事

  • KV Cache每层注意力 中间结果的缓存,核心在解码时复用历史 token。
  • Prompt Cache(不同系统里叫法不同):更偏“请求级”或“会话级”对同一段 prompt 的额外命中优化。

它们可能协同,但职责不同:

  • KV Cache 解决“时间序列上重复用历史”。
  • Prompt 类优化解决“多个请求共享同一段上下文”。

5. 为什么有时候还是慢?

KV Cache 能加速,但不是所有情况下都神奇:

  • 并发高且长度长:缓存本身要占显存,内存压力会限制 batch 与序列长度。
  • 上下文频繁变化:一旦上下文切换频繁,缓存命中率下降。
  • 参数配置不合适:一些调度器在高并发场景下为了公平与延迟可能触发频繁切片。

这也是很多服务里要做 batch/scheduler/分页策略的原因:

你优化的不是单一算子,而是“算力利用 + 显存 + 延迟”三者的平衡。

6. PagedAttention 和 KV Cache 的关系(入门版)

很多同学在看 vLLM 时会看到 PagedAttention

它可以理解为对 KV Cache 的“内存管理增强”:

  • 把传统连续 KV 存储改为“分页”组织;
  • 提升显存碎片利用率;
  • 在高并发下更容易回收与扩缩。

你可以把它想成:KV Cache 是概念,PagedAttention 是“把这个概念跑快、跑稳”的工程实现策略。

7. 工程上如何判断你“真的用了”KV Cache?

观察这几类指标:

  • 单 token 的 decode time 是否随上下文长度线性持续变慢;
  • GPU 利用率是否因为反复算 K/V 下降;
  • 相同 batch/sequence 下,第一轮与后续轮次的耗时差异。

如果你看到后续轮次显著更低,说明缓存链路在发挥作用。

8. 小结

如果你只记一条:

KV Cache 的价值,不在于“算法技巧”,而在于“减少重复计算的工程认知”。

对 AI Infra 来说,后面你会很快接触到:

  • Scheduler 如何打包请求
  • 连续解码如何影响吞吐
  • 显存页管理如何影响稳定性
  • 什么时候 tradeoff 延迟,什么时候 tradeoff 吞吐

这些问题的入口,几乎都从 KV Cache 能否被有效维护开始。

我会在下一篇把它和 PagedAttention 的内存块组织细节再往下打磨一版,尽量用一张图配清晰的例子来讲。