跳到正文
动手理解 · CONCEPT LAB

生成越长,KV Cache 为什么越像一本变厚的笔记?

每层都会保存历史 token 的 K/V,避免下一轮重新计算旧 token。缓存随层数、上下文、KV 头数、head dim、位宽和并发共同增长。

已经发生 正在观察 接下来
01 / 04

完整前缀在 Layer 1…L 中逐层重跑

HIST 完整前缀 X[1:t]
REPEAT 逐层重算 每层:QKV + Attention + MLP
LAST 最终层取位置 t
NEXT 生成新 Token

中间节点表示“在每一层内对完整前缀执行 QKV、attention 与 MLP”,不是先跑完所有层再统一生成 QKV。

观察点 01

每生成一个词,都把整段历史重新算一遍

若不保存历史 K/V,第 t 步要重新让完整前缀经过各个 Transformer 层,包括旧位置的投影、attention 与 MLP。随着序列增长,重复计算越来越多。

历史重复计算非常多
缓存占用几乎没有
此刻要记住

KV Cache 用显存换重复计算,是自回归服务的核心状态。

算法工程 · KV Cache / Serving

KV Cache:长上下文为什么吃显存,PagedAttention 怎么救

大模型生成不是一次性吐完,而是一个 token 一个 token往外写。KV Cache 让模型不用反复重算历史,是推理加速的命门;但它也会随着上下文和并发线性膨胀,成为长上下文服务最容易爆的显存账。

KV Cache 与 PagedAttention 总览:请求队列进入调度器,块表把逻辑 token 块映射到 GPU 显存中的 KV cache blocks,continuous batching 持续输出
一图看懂:每条活跃序列都有自己的逻辑 KV 状态;PagedAttention 把历史 token 按固定大小 block 编组,再用块表映射到不连续的 GPU 显存块;调度器动态组成 batch,让一次 decode step 服务更多序列。图中的“分页”只借鉴地址映射思想,并不表示一定存在操作系统式缺页或磁盘换页。查看原图 ↗
00 · 先抓住

KV Cache 是模型生成时的“历史笔记本”

生活类比
写长邮件时,你不会每打一个字都从头重读全部资料,而会把要点放在旁边。KV Cache 就是每一层 attention 的旁边笔记:省重读,但笔记本会越写越厚。
小例子
同一个 70B 模型,权重可能能放进多卡,但如果每个用户都带 128K 上下文,KV Cache 会按用户数和上下文长度线性膨胀,服务端显存很快被“历史笔记”吃掉。
先分两段Prefill 是读题并生成笔记,Decode 是每写一个新 token 都翻笔记。
PagedAttention借鉴操作系统分页:笔记本不要求连续摆放,用块表把逻辑顺序映射到显存块。
核心权衡保留所需历史能避免重算;可见历史越长,KV 的容量与读取压力通常越大,可承载并发越少。
01 · 为什么要缓存

没有 KV Cache,大模型会一遍遍重读整篇历史

在标准因果全注意力中,第 t 个位置要看 1...t。如果每个 decode step 都把完整前缀重新过一遍 Transformer,就会重复计算旧位置。KV Cache 的作用很简单:把历史 token 在每层 attention 里的 Key / Value 存下来;下一步只让新增位置经过各层,产生自己的 Query / Key / Value,追加新 K/V 后查询历史缓存。

new token attention:qtK1:tsoftmax()V1:t\text{new token attention:}\quad q_t K_{1:t}^{\top} \rightarrow \mathrm{softmax}(\cdot)V_{1:t}

新位置的 q_t 仍要和允许访问的 K[1:t] 做注意力;旧 K/V 不再重算,新 k_t/v_t 会写入本层缓存。滑窗或稀疏注意力只读取其中的子集。

← 左右滑动查看完整链路 · 打开原图

有缓存以后,旧位置不必再次经过各层的投影、attention 与 MLP;但历史状态仍要读取:当前 Q(t)K[1:t] 形成权重,再读 V[1:t] 得到输出,新 K(t)/V(t) 在逐层 QKV 路径追加。
Prefill 读题

并行处理 prompt,并给每层建好历史 K/V。在排队、网络与预处理受控时,长 prompt 的 prefill 计算通常是 TTFT 的主要组成之一。

Decode 答题

常规自回归每步为每条活跃序列新增一个 token,并读取权重和所需历史 KV;低 batch 等形状下常受带宽限制,具体仍看模型、硬件与 kernel。

Cache 历史笔记

缓存所需历史可避免重算;但上下文越长、并发越高,逻辑容量和读取量通常越大。

一句话直觉
KV Cache 像给每层 attention 做“读书笔记”:读过的段落不再重读,只把笔记摊在桌上让新 token 查。但笔记本越写越厚,桌面空间也会被吃光。
手算:先声明计数口径
把 BOS / 起始 token 视为第 1 个位置,只数 4 个逐步增长前缀中的因果 query-key 配对,不把 MLP、投影和采样混进来。若每轮重算完整前缀,配对数为 1+(1+2)+(1+2+3)+(1+2+3+4)=20;有 KV Cache 时,每轮只新增一个 query,配对数为 1+2+3+4=10。推广到长度 T:朴素重跑的 attention 累计是 Θ(T³),缓存后的 dense 增量 attention 累计仍是 Θ(T²),并非 O(1)
02 · 显存公式

KV Cache 的账:层数 × 上下文 × KV 头数 × head dim

这条公式是理解长上下文推理的钥匙。它解释了为什么 GQA/MQA/MLA 会流行,也解释了为什么 128K/1M 上下文真正贵在服务端。

logical KV cache bytesB×L×S×Hkv×D×2×bytes\text{logical KV cache bytes} \approx B \times L \times S \times H_{kv} \times D \times 2 \times \text{bytes}

B=等长活跃序列数,L=层数,S=每条序列缓存 token 数,H_kv=KV 头数,D=每头维度,乘 2 是 K 和 V。这是标准 MHA/GQA 的逻辑、分片前容量:变长 batch 应改为对各序列 S_i 求和;张量/上下文/流水并行会改变单 rank 驻留量,prefix sharing 会改变物理去重,block 对齐、量化 scale、元数据和临时 buffer 又会增加实现开销。MLA 也不能直接套用。

场景粗略 KV Cache为什么重要
Mistral-7B-v0.3, 32K32×32768×8×128×2×2 bytes = 4GiB/sequence官方配置为 32 层、8 KV 头、hidden size 4096 / 32 query heads,因此 head_dim 128;按 BF16/FP16 2 bytes 粗算。这里尚未扣分片或 prefix sharing。
Llama 3.1 70B, 128K80×131072×8×128×2×2 bytes = 40GiB/sequence发布配置为 80 层、64 query heads、8 KV 头、hidden size 8192,因此 head_dim 128;按 BF16/FP16 粗算,未计运行时开销。
同一 70B,1 Mi token1,048,576 = 8×131,072,逻辑 KV 约 320GiB/sequence只说明架构与 dtype 不变时的线性外推;模型是否支持该窗口、如何分片,以及 MLA、KV quant、滑窗等都要另算。

这里故意用“量级”而非固定数字,因为真实模型的 L/H_kv/D 差异很大。判断方法是看模型配置:层数、query head 数、KV head 数、head_dim 和 KV dtype。

为什么 GQA 一下子能省很多

KV heads matter
KV cacheGQAKV cacheMHA=HkvHq\frac{\text{KV cache}_{\mathrm{GQA}}}{\text{KV cache}_{\mathrm{MHA}}}=\frac{H_{kv}}{H_q}
若一个模型有 32 个 Query 头,但只有 8 个 KV 头,在层数、序列长度、head_dim 和 dtype 相同的前提下,KV Cache 是对应 MHA 的 1/4。GQA 因而被 Llama 3 等模型采用来改善推理扩展性;具体质量/速度权衡仍取决于训练与实现。
03 · 怎么省 KV

减少每 token 状态,有“共享 KV 头”和“低秩压缩”两条路线

MHA、MQA、GQA 的主要区别是一个 KV 头服务多少 Query 头;DeepSeek-V2 的 MLA 则把内容相关的 K/V 联合压到低维 latent,并把 RoPE(Rotary Position Embedding,旋转位置编码)分量解耦。它们都缩窄每 token 缓存,但机制并不相同。

方法怎么省代价 / 代表
MHAMulti-Head Attention通常每个 Query 头对应自己的 K/V 头KV 头最多;不是“表达力一定更强”的保证,而是容量/带宽成本最高的基线。
MQAMulti-Query Attention所有 Query 头共享 1 组 K/V在 MHA/MQA/GQA 且其余维度相同的比较中缓存最小;原论文报告降低增量解码的 KV 带宽,并观察到轻微质量退化,不能外推到所有训练配方。
GQAGrouped-Query AttentionQuery 头分组,每组共享一组 K/V介于 MHA 与 MQA;GQA 论文的 uptraining 实验达到接近 MHA 的质量和接近 MQA 的速度,不是对所有模型的无条件保证。
MLAMulti-head Latent Attention缓存压缩的内容 latent 与较小的解耦 RoPE key;用矩阵吸收/等价变换消费 latent,无须显式物化完整每头 K/VDeepSeek-V2 的特定设计;论文相对 DeepSeek 67B 报告 KV Cache 降低 93.3%,实现和 kernel 更复杂,不能把比例泛化到所有 MLA。
KV Quant把 KV 从 FP16/BF16 降到 INT8/INT4/更低直接降低元素位宽与潜在流量;scale/元数据、反量化 kernel、硬件支持和精度损失都要计入。
Sliding / Sparse让某些层或位置只保留/读取历史子集这些路径不再执行完整全局注意力;不同层可能仍保留全局窗口,容量、流量和远程召回要按具体模式算。
和 FlashAttention 的边界
FlashAttention 主要优化一次 attention 算子内部的 IO;KV Cache 主题处理推理阶段历史状态怎么存、分页、复用与调度。这是职责区分,不是互斥实现:官方 FlashAttention 接口也能在 decode 时更新 KV cache,并通过 block table 读取 paged KV。
04 · PagedAttention

像操作系统分页一样管理 KV Cache

PagedAttention 论文针对当时要求 KV tensor 连续、并按潜在最大输出长度预留的服务方案:请求长度和生命周期未知,会带来未用预留、末尾内部碎片与 allocator 外部碎片。PagedAttention 把 KV Cache 切成固定大小 block,用块表把“逻辑 token 块”映射到“不连续物理显存块”,随序列增长按需分配。

连续预留与 PagedAttention 块表映射对比 左侧三条请求分别显示已用前缀和预留尾部;右侧块表把 A 映射到物理块 1、4、8,把 B 映射到 2、5,把 C 映射到 3、7、9,其余编号块空闲,因此逻辑连续的 KV 可以分散存放。 论文对照:连续预留方案 request A · usedreserved B · usedreserved request C · usedreserved 浪费:未用预留 / 末尾内部碎片 / allocator 外部碎片 结果:可用于真实 token 状态的空间减少,并发受限 PagedAttention:块表 + KV blocks block table A → 1,4,8 B → 2,5 C → 3,7,9 free list 1234 5678 9101112 好处:按需分配;每条序列仅尾部未满 block 有内部碎片 块级引用可支持前缀共享和 copy-on-write

这是一张机制示意,不是操作系统虚拟内存的逐项复刻:block table 提供地址间接层,但 PagedAttention 本身不等同于 demand paging、page fault 或磁盘换页;抢占时选择重算、CPU swap 或远端 KV transfer 是服务系统的另一层策略。

PagedAttention 解决什么

  • 减少 KV Cache 的碎片浪费,提高同一张卡能塞的请求数。
  • 支持不同请求长度共存,不必为最大输出长度预留整段连续空间。
  • block 映射使 copy-on-write 和前缀 KV 共享更容易实现;是否启用及命中规则仍取决于服务引擎。

它不解决什么

  • 对 dense attention,它不改变每条序列逻辑 KV 随上下文线性增长的事实。
  • 分页本身不减少一次 dense decode 逻辑上需要访问的历史 K/V 元素;实际 HBM 流量还取决于 kernel、缓存命中、共享与并行布局。
  • 它不是缩窄单 token 状态的模型架构优化;GQA/MLA/KV quant 等才直接改变元素数或位宽。
真实收益口径
原论文报告的是基于 PagedAttention 构建的 vLLM 整体系统:在其模型、A100 硬件、trace / 解码工作负载和同延迟口径下,相比 FasterTransformer / Orca 等基线,吞吐约提高 2–4×,长序列、大模型和复杂解码时更明显。这不是单个 kernel 或任意部署的固定倍数;收益同时涉及 block-level 管理、调度与 KV 共享。
05 · Continuous Batching

Decode 阶段,把多个用户一起“凑一锅炒”

常规自回归 decode 中,每条活跃序列每轮通常推进 1 个 token;投机解码等实现可以一次接受多个。若活跃序列太少,GPU 容易受权重与 KV 搬运限制。Continuous batching(连续批处理,也叫 iteration-level scheduling)在迭代边界动态组成 batch:完成的序列移出,符合准入条件的新工作补入。

decode throughputbatch tokens per steptime per decode step\text{decode throughput} \approx \frac{\text{batch tokens per step}}{\text{time per decode step}}
关键不是让单条序列的 attention 数学变少,而是让一次昂贵的 decode step 推进更多序列。批内 token 可摊销权重流量、kernel 启动等成本;各序列仍逻辑访问自己的 KV,共享前缀可以去重物理存储,但读流量能否复用还取决于 kernel 与 cache 命中。吞吐、TTFT 与 TPOT 需要一起按 SLO 调参。
调度方式问题连续批处理怎么改
静态 batch等一批请求全部结束再换下一批;短请求会等长请求。每个 iteration 都能插入/移除请求。
只看吞吐batch 太大时 TTFT/TPOT 可能恶化。按 SLO 控 batch、prefill chunk 和队列优先级。
忽略 KV请求塞太多导致 KV Cache 爆显存。PagedAttention + admission control 一起决定能塞多少。
类比
普通 decode 像厨师只给一桌炒菜;continuous batching 像把每桌下一口菜合并成一锅小炒。锅热一次、油烧一次,多桌都前进一步。但桌太多也会排队,所以要调度。
06 · Prefill 相关优化

Prefix cache、Chunked Prefill、PD 分离:解决“读题”和“答题”互相打架

KV Cache 不是只有 decode 才重要。RAG、多轮对话、Agent 常有大量共享前缀或超长 prompt,prefill 会抢算力并阻塞 decode。现代推理系统会专门拆这块。

技术解决什么机制
Prefix Cache同一长文档、多轮历史或 few-shot 前缀反复 prefill缓存完整 KV block;新请求在 token IDs、前缀父 hash 和引擎要求的模型/adapter/多模态等附加身份一致时复用。它跳过命中部分的 prefill,不改变后续新 token 的 dense decode 数学。
Chunked Prefill一个超长 prompt 占住 GPU,短 decode 被饿死把 prefill 切成小块,与 decode iteration 混批或交错;chunk / token budget 会在 TTFT、TPOT 与吞吐之间取舍。
Prefill/Decode 分离prefill 常更偏算力、decode 在低 batch 时常更偏带宽,混跑会互相干扰把 prefill worker 和 decode worker 分开并独立扩缩容;需要额外传 KV,未必对所有负载更快。
KV TransferPD 分离后,KV 要跨 GPU/节点搬用高速互联和调度策略减少 KV 传输成为新瓶颈。
长文档 / RAG 场景

若模板把同一长文档放在查询之前,使多个请求拥有相同 token ID 前缀,Prefix cache 命中后可跳过已缓存的完整 block;未满末块、文档顺序、空格、工具列表或查询插入位置变化都可能减少命中。

Agent 场景

长任务会反复带着系统提示、工具说明、历史轨迹调用模型。KV 复用和上下文压缩都会直接影响成本。

07 · 常见误区

别把 KV Cache、FlashAttention、长上下文混成一件事

误区 1:有缓存后每步就是 O(1)

错。KV Cache 相比重算完整前缀确实大幅降低总计算,但第 t 个新 token 的 query 仍要读约 t 个历史 K/V;标准全注意力的累计增量 attention 仍是二次量级。

误区 2:PagedAttention 会让逻辑 KV 变小

不会。它主要减少预留、碎片和可共享前缀的重复物理副本;每 token 元素数或位宽要靠 GQA/MLA/KV quant 等改变。

误区 3:FlashAttention 等于 KV Cache 优化

FlashAttention 优化一次 attention 算子的 IO;KV Cache 处理历史状态生命周期。两者职责不同,但可以组合在同一个 KV-aware / paged decode kernel 中。

误区 4:上下文越长一定越好

窗口变长不等于召回变好;长上下文还会提高 KV 成本、调度难度和延迟。

误区 5:吞吐越高体验越好

吞吐高可能靠大 batch 换来,但 TTFT/TPOT 可能变差。服务要看 SLO,不只看 tokens/s。

误区 6:prefix cache 永远命中

可复用块需要相同 token 前缀,并满足模型、adapter、多模态输入等引擎校验条件;模板、空格、工具列表顺序变化都可能影响命中。

速查

一句话总结

Cheat sheet
KV Cache 是什么每层 attention 缓存历史 token 的 K/V,避免每步重算历史。
为什么爆显存随 batch、层数、上下文长度、KV 头数、head_dim、dtype 线性增长。
PagedAttention 是什么用固定大小 block 与块表管理 KV,减少预留与碎片,并为块级共享提供机制;不是完整复刻 OS demand paging。
Continuous batching在 iteration 边界动态组 batch,让一次 decode step 推进更多活跃序列。
真正减少 KV 状态GQA/MQA/MLA 改元素数,KV quant 改位宽,滑窗/稀疏改变保留或访问范围;上下文压缩则会改变输入历史本身。
下一层专题量化MoE、分布式训练都会继续围绕“容量、带宽、通信”展开。
资料来源

主要参考

核查日期:2026-07-14。显存手算采用二进制 KiB/GiB;实际占用还受 KV dtype、张量/上下文/流水并行布局、prefix sharing、block 大小、对齐、元数据、缓存实现和同时驻留序列长度分布影响。