# LLM 推理是怎么变快的：从 KV Cache 到投机解码的系统性拆解

> 面向工程师的推理优化全景图。读完你应该能回答三个问题：LLM 推理慢在哪？每种优化手段到底在优化什么？代价是什么？
>
> 文中的硬件数字以 NVIDIA A100/H100 公开规格为准，模型结构数字以 Llama 系列公开配置为准；标注「量级估算」的地方表示不必纠结个位数精度，抓住数量级即可。

---

## 0. 一个反直觉的事实：推理大部分时间 GPU 在「等数据」

很多人对 GPU 的直觉是「算力怪兽，瓶颈在计算」。但对 LLM 的**生成阶段**来说，这个直觉是错的：**大部分时间里，计算单元在空转，等着显存把数据搬过来**。

理解这一点，需要一个贯穿全文的分析工具：**算术强度（Arithmetic Intensity）**。

```
算术强度 = 计算量 (FLOPs) / 访存量 (Bytes)
```

任何一块 GPU 都有两个关键指标：

- **算力**：每秒能做多少次浮点运算。A100 的 FP16 Tensor Core 算力约 312 TFLOPS。
- **显存带宽**：每秒能从 HBM 搬多少数据。A100 80GB (SXM) 约 2039 GB/s，即约 2 TB/s。

两者相除得到一个「分界点」（Roofline 模型里的 ridge point）：

```
A100: 312 TFLOPS / 2039 GB/s ≈ 153 FLOPs/Byte
```

含义：**你的程序每从显存读 1 字节，至少要做约 153 次浮点运算，才能把算力吃满**。算术强度低于这个值，就是**内存带宽瓶颈（memory-bound）**——GPU 再强也快不起来，因为它在等数据；高于这个值才是**算力瓶颈（compute-bound）**。

H100 的这个比值更极端（FP16 约 989 TFLOPS / 3.35 TB/s ≈ 295 FLOPs/Byte）。硬件迭代中算力增长快于带宽增长，所以「喂饱 GPU」只会越来越难。

记住这个数字，下面所有优化手段的动机都从它出发。

---

## 1. Prefill 与 Decode：一次推理的两副面孔

一次 LLM 推理请求分两个阶段：

### 1.1 Prefill（预填充）：处理你的输入

用户发来一段 prompt（比如 2000 个 token），模型需要对这 2000 个 token 做一次完整的前向传播，产出第一个输出 token。

关键特点：**2000 个 token 可以并行处理**。它们组成一个 `[2000, hidden_dim]` 的大矩阵，与权重做矩阵乘。权重从显存读一次，被 2000 行输入复用——算术强度很高，是典型的 compute-bound。GPU 火力全开，这一阶段的耗时决定了**首 token 延迟（TTFT, Time To First Token）**。

### 1.2 Decode（解码）：逐个吐字

从第二个输出 token 开始，模型进入自回归循环：拿上一个 token，前向一次，得到下一个 token；再前向一次……每次**只处理 1 个 token**。

这就是灾难所在。做个粗略估算（量级估算）：

对参数量为 `P` 的稠密模型，生成 1 个 token 的计算量约为 `2P` FLOPs（每个参数参与一次乘加）。而访存量呢？**每生成一个 token，都必须把全部权重从显存完整读一遍**（权重太大，放不进片上缓存）。FP16 下权重占 `2P` 字节。于是：

```
decode (batch=1) 的算术强度 ≈ 2P FLOPs / 2P Bytes = 1 FLOP/Byte
```

1，对比分界点 153。**低了两个数量级**。此时 A100 的实际算力利用率只有 1% 左右，99% 的时间在等显存。

由此可以直接推出 batch=1 时生成速度的理论上限：

```
每 token 耗时 ≥ 权重字节数 / 显存带宽

例：7B 模型，FP16 权重 14 GB，A100 带宽 ~2 TB/s
    每 token ≥ 14 / 2039 ≈ 6.9 ms  →  上限约 145 token/s
```

实测 vLLM 等框架跑 7B 模型单请求能到 100+ token/s，正好是这个上限的七八成——**验证了 decode 就是在「用带宽换 token」**。

> **类比**：prefill 像一辆坐满 50 人的大巴跑一趟高速（油钱摊薄，效率高）；decode 像同一辆大巴每趟只载 1 个乘客，来回跑几百趟。车（算力）没变，浪费在「跑趟」（搬运权重）上了。

### 1.3 两阶段的优化目标不同

| | Prefill | Decode |
|---|---|---|
| 瓶颈 | 算力 (compute-bound) | 显存带宽 (memory-bound) |
| 用户感知指标 | 首 token 延迟 TTFT | 吐字速度 TPOT (Time Per Output Token) |
| 优化思路 | 减计算：FlashAttention、chunked prefill、prefix caching | 减访存：量化、batch、投机解码 |

后文的每个技术，都可以问一句：**它在优化哪个阶段的哪个瓶颈？**

---

## 2. KV Cache：一切的起点

### 2.1 为什么需要它

Transformer 的自注意力里，第 `t` 个 token 要和前面所有 token 的 Key/Value 做交互：

```
Attention(q_t, K_{1..t}, V_{1..t}) = softmax(q_t · K^T / √d) · V
```

关键观察：由于因果掩码（causal mask），**历史 token 的 K、V 一旦算出来就永远不变**。如果每生成一个新 token 都从头对整个序列重算一遍，生成第 `t` 个 token 的成本是 O(t)，生成长度为 `n` 的序列总成本 O(n²) 次完整前向——完全不可接受。

**KV Cache 就是把每层算出的 K、V 存下来**，decode 时每步只为新 token 算一份新的 K/V 追加进去，再和缓存做 attention。这样每步的前向就只处理 1 个 token，整体从 O(n²) 降到 O(n)。

它不是「锦上添花的优化」，而是**自回归推理能够实用的前提**。所有现代推理框架默认开启，后续一切优化（分页、量化、GQA、投机解码）都建立在它之上——所以说它是起点。

### 2.2 显存占用怎么算（这个公式值得背下来）

```
KV Cache 字节数 =
  2 (K 和 V)
  × num_layers（层数）
  × num_kv_heads（KV 头数）
  × head_dim（每头维度）
  × seq_len（序列长度）
  × dtype 字节数
  × batch_size
```

代入几个真实模型（FP16，即 2 字节）：

**Llama-2-7B**（32 层，32 个 KV 头，head_dim=128，标准多头注意力 MHA）：

```
每 token: 2 × 32 × 32 × 128 × 2 B = 512 KiB
4096 token 的一条序列: 512 KiB × 4096 = 2 GiB
```

一条 4K 上下文的对话就吃掉 **2 GB** 显存——而整个模型权重才 14 GB。如果想同时服务 32 个这样的请求，光 KV Cache 就要 64 GB，一张 A100 直接爆掉。

**Llama-3-8B**（32 层，但 KV 头从 32 降到 8，用了 GQA）：

```
每 token: 2 × 32 × 8 × 128 × 2 B = 128 KiB   （只有 Llama-2 的 1/4）
8K 上下文一条序列: 1 GiB
```

**Llama-3-70B**（80 层，8 个 KV 头）：

```
每 token: 2 × 80 × 8 × 128 × 2 B = 320 KiB
128K 上下文一条序列: 320 KiB × 131072 ≈ 40 GiB
```

看到问题了吗？**长上下文时代，KV Cache 不是权重的零头，而是和权重同量级甚至更大的显存消耗者**，而且它随并发数和上下文长度线性增长，权重却是固定的。

### 2.3 顺着这个公式做减法：MQA / GQA / MLA

公式里每一项都是优化的靶子：

- **MQA（Multi-Query Attention）**：所有 query 头共享 1 组 KV，`num_kv_heads = 1`，缓存缩小 32 倍。激进，但质量有损，需要训练时就这么设计。
- **GQA（Grouped-Query Attention）**：折中方案，若干 query 头共享一组 KV（如 32 个 Q 头配 8 个 KV 头，4:1）。质量几乎无损，已成开源模型标配（Llama 3、Qwen、Mistral 都用）。
- **MLA（Multi-head Latent Attention，DeepSeek-V2/V3）**：更进一步，把 K/V 投影到一个低秩潜向量再缓存，推理时只存潜向量。DeepSeek-V2 每层每 token 只缓存 576 个数（512 维压缩潜向量 + 64 维 RoPE 分量），相比同规模 MHA 缓存缩小一个数量级（量级估算），代价是解压时多一点计算——但 decode 本来就闲着算力，**用富余的计算换紧缺的带宽和显存，稳赚**。
- 还可以动 `dtype`：KV Cache 量化到 FP8/INT8/INT4（见第 4 节），以及动 `seq_len`：滑动窗口注意力只保留最近 N 个 token 的缓存（Mistral 的做法）。

> **一句话心智模型**：KV Cache 是「用显存换计算」的经典交易。后续所有 KV 相关优化，都是在讨价还价——能不能少付点显存，同时别把计算的账单加回去太多。

---

## 3. 显存与批处理：PagedAttention 和 Continuous Batching

第 1 节说 decode 是带宽瓶颈：读一遍 14 GB 权重只服务 1 个 token 太亏。最直接的解法是**批处理（batching）**：一次读权重，同时为 32 个请求各算 1 个 token——权重访存摊薄 32 倍，吞吐量接近提升 32 倍，而每个请求的延迟几乎不变（因为原本瓶颈就不在计算）。

**Batch size 是推理吞吐最重要的旋钮。** 而能开多大 batch，取决于显存里还能塞下多少 KV Cache。于是问题转化为：怎么高效管理 KV Cache 显存？2023 年之前的系统在这里浪费严重，两项技术改变了局面。

### 3.1 PagedAttention：给 KV Cache 上一套「虚拟内存」

**老方案的问题**：KV Cache 随生成逐 token 增长，但需要在显存里连续存放。系统不知道每个请求最终会生成多长，只好按「最大可能长度」（比如 2048 或 4096）**预分配一整块连续显存**。结果：

1. **内部碎片**：请求实际只生成了 200 个 token，剩下 3800 多个 token 的预留空间全程空置。
2. **外部碎片**：不同请求预留块大小不一，释放后在显存里留下无法利用的空洞。

vLLM 论文（Kwon et al., SOSP 2023）实测：在当时的主流系统里，**KV Cache 显存的实际利用率只有 20%~40%，也就是 60%~80% 被浪费**。

**PagedAttention 的解法**照抄了操作系统教科书：**分页**。

- 把 KV Cache 切成固定大小的**块（block）**，比如每块存 16 个 token 的 KV。
- 逻辑上连续的序列，物理上由分散在显存各处的块拼成，用一张**块表（block table）**维护「逻辑块 → 物理块」的映射——完全对应虚拟内存的页表。
- 请求生长时按需分配新块，结束时立刻归还；浪费被压缩到「最后一个块内不足 16 个 token」的零头，利用率提到 90% 以上。
- 额外红利：**块可以共享**。多个请求共享同一段系统 prompt 时，那部分物理块只存一份，配合 copy-on-write——这就是各框架 prefix caching / prompt caching 的基础机制之一。

代价很小：attention kernel 需要按块表做间接寻址，实现更复杂，有个位数百分比的 kernel 开销（量级估算），但换来的 batch size 提升让吞吐提高 2~4 倍（vLLM 论文对比 Orca 的数据）。

### 3.2 Continuous Batching：别让快的等慢的

有了显存，还要解决调度问题。**静态批处理**的做法是：攒 32 个请求组成一批，一起跑到全部结束。问题显而易见——有的请求生成 20 个 token 就完了，有的要生成 2000 个，**先完成的请求得陪跑到最后**，期间它占着的算力和显存全在空转。

**Continuous batching（连续批处理，源自 Orca 论文的 iteration-level scheduling，OSDI 2022）**把调度粒度从「整个请求」降到「单次迭代」：

- 每生成一步（一次前向）之后重新审视批次：完成的请求立即退出、返回结果、释放 KV 块；
- 等待队列里的新请求立即插进空位，先做它的 prefill，然后加入 decode 大军。

GPU 的 batch 因此始终保持饱满。它和 PagedAttention 是天作之合：一个保证「随时能插入新请求」在调度上可行，一个保证在显存上可行。这两项合起来，是 vLLM 相比朴素 HuggingFace 推理拿到 10 倍以上吞吐提升的主要来源。

再往下还有一个精细化问题：新请求的 prefill 是一大坨 compute-bound 计算，直接插进 decode 批次会让所有人卡一下（decode 延迟抖动）。**Chunked prefill** 把长 prefill 切成小段，和 decode 步混合执行，抹平抖动；更彻底的方案是 **P/D 分离（disaggregated prefill/decode）**——用不同的 GPU 池分别跑 prefill 和 decode，各自按自己的瓶颈配置硬件，KV Cache 通过高速互联传输（DeepSeek、Mooncake 等生产系统的做法）。

> **一句话心智模型**：这一节全部内容 = 操作系统课的复仇。PagedAttention 是虚拟内存分页，continuous batching 是抢占式调度，prefix caching 是共享内存页。

---

## 4. 量化：既省显存，又「直接」提速

### 4.1 为什么量化对 decode 特别有效

一般理解量化是「省显存的有损压缩」。这没错，但漏掉了对推理更关键的一点：**decode 的速度上限 = 权重字节数 / 带宽**（第 1 节的公式）。权重从 FP16 压到 INT4，字节数变成 1/4，**每 token 的访存量直接变成 1/4，理论生成速度提高近 4 倍**——不是靠算得快，是靠读得少。

这也解释了一个实践中的现象：**weight-only 量化（只压权重，计算时反量化回 FP16 再算）在小 batch 下就有实打实的加速**，尽管它增加了反量化的计算——因为 decode 本来就算力大量闲置，多算一点无所谓，省下的带宽才是真金白银。

### 4.2 主流方案与取舍

按「量化什么」分两大类：

**A. Weight-only（只量化权重）**——针对小 batch / decode 场景：

- **GPTQ**（INT4/INT3）：逐层用二阶信息（Hessian 近似）最小化量化误差，需要少量校准数据，量化过程逐列补偿。优点是精度好、生态成熟；4bit 下 perplexity 损失通常很小。
- **AWQ**（INT4）：观察到约 1% 的「显著权重通道」对精度影响极大，通过对激活值大的通道做等价缩放（scale 塞进前一层）来保护它们，不需要反向传播。精度与 GPTQ 相当，量化更快，对指令模型鲁棒性口碑较好。
- 两者都是 **W4A16**（权重 4bit、激活 FP16）：显存 ~1/4，小 batch 生成速度提升 2~3 倍（量级估算，取决于 kernel 质量）。

**B. Weight + Activation（权重和激活都量化）**——针对大 batch / prefill / 高吞吐场景：

- **INT8（W8A8）**：代表是 SmoothQuant。难点在激活值有少数极端离群通道（outlier），直接量化会炸精度；SmoothQuant 把激活的离群幅度「匀」一部分到权重上再量化。W8A8 能用上 INT8 Tensor Core，**计算本身也翻倍**，对 compute-bound 的 prefill 和大 batch decode 有效。
- **FP8（E4M3/E5M2）**：Hopper（H100）及之后的 GPU 原生支持。相比 INT8，浮点格式动态范围大，对离群值天然更宽容，**通常不需要复杂的校准手术**，精度损失普遍小于 1%（量级估算）。目前生产部署的事实趋势：有 H100 就优先 FP8。

**C. KV Cache 量化**：把缓存的 K/V 存成 FP8/INT8/INT4。同样显存直接省一半到 3/4，能开更大 batch 或更长上下文；FP8 KV 基本无损，INT4 KV 在长文本任务上需要实测把关。

### 4.3 决策表

| 方案 | 位宽 | 显存 | 加速场景 | 精度风险 | 适用 |
|---|---|---|---|---|---|
| FP16/BF16 | 16 | 1× | 基线 | 无 | 显存充裕、追求无损 |
| FP8 (W8A8) | 8 | ~0.5× | prefill + decode 都加速 | 很低 | 有 H100/H200，首选 |
| INT8 SmoothQuant | 8 | ~0.5× | 大 batch 吞吐 | 低，需校准 | A100 等无 FP8 硬件 |
| GPTQ / AWQ (W4A16) | 4 | ~0.3× | 小 batch decode | 中，4bit 需评测 | 单卡跑大模型、本地部署 |
| KV Cache FP8/INT8 | — | KV 减半+ | 更大 batch/更长上下文 | 低 | 与上述任意方案叠加 |

经验法则：**7B 以下的小模型对 4bit 更敏感，70B 级别的大模型 4bit 后往往仍强于同显存下能放的 FP16 小模型**——「大模型 + 低精度」通常优于「小模型 + 高精度」，但这是一条经验规律而非定理，上线前必须用自己的评测集验证，尤其是数学、代码这类对精度敏感的任务。

---

## 5. 投机解码：让「串行」也能并行

前面的手段都在「摊薄」访存（batch）或「减少」访存（量化），但没有动一个根本约束：**decode 是串行的，第 t+1 个 token 必须等第 t 个出来才能算**。投机解码（speculative decoding，Leviathan et al. 与 Chen et al. 于 2023 年分别提出）直接攻击这个约束。

### 5.1 核心思路：便宜地猜，昂贵地验

关键洞察有两个：

1. **验证比生成便宜**。让大模型「检查 5 个给定的 token 对不对」，只需一次前向（5 个 token 并行进网络，像一次 mini-prefill）；而「生成 5 个 token」需要 5 次串行前向。每次前向的主要成本是读一遍权重，所以验证 5 个 ≈ 1/5 的生成成本。
2. **很多 token 很好猜**。语言有大量低熵片段——代码的缩进和括号、`"United"` 后面的 `"States"`、格式化的模板文字。这些用小模型猜也八九不离十，何必让 70B 大模型逐个亲自写？

于是流程变成：

```
循环：
  1. 草稿模型（如 1B）快速串行生成 k 个候选 token（如 k=5）
  2. 目标模型（如 70B）一次前向，并行验证这 k 个 token
  3. 从左到右接受，遇到第一个「不合格」的 token 停下，
     由目标模型在该位置给出修正 token
  4. 回到 1
```

最好情况：一次大模型前向产出 k+1 个 token；最差情况：草稿全被拒，也能产出 1 个 token（大模型的修正）——**永远不会比不用投机更慢地产出 token**（不计草稿开销时；实际上草稿开销存在，见 5.3）。

### 5.2 为什么「完全不损失质量」——不是玄学，是数学

这是投机解码最漂亮的地方。它不是「小模型答案差不多就凑合用」，而是通过**投机采样（speculative sampling，一种修正的拒绝采样）**保证：**输出序列的概率分布与只用目标模型逐 token 采样完全一致**。

规则（对每个草稿 token `x`，草稿模型概率 `q(x)`，目标模型概率 `p(x)`）：

```
以 min(1, p(x)/q(x)) 的概率接受 x
若拒绝：从修正分布 norm(max(0, p - q)) 中重新采样一个 token
```

直觉：草稿模型比目标模型「更爱」这个 token（q > p）时，按比例打折接受，多出来的概率质量被拒绝路径上的修正分布精确补回。两条路径合起来，每个 token 的边际分布严格等于 `p`。这是可以三行代数验证的恒等式，不是近似。

所以投机解码是本文唯一一个**数学上零质量损失**的加速手段（贪心解码下则退化为简单规则：草稿 token 等于目标模型的 argmax 就接受）。

### 5.3 加速比与代价

设草稿 token 的平均接受率为 α，每轮草稿长度 k，则每次目标模型前向平均产出的 token 数约为：

```
E[tokens/轮] = (1 - α^(k+1)) / (1 - α)
```

α = 0.8、k = 5 时约 3.7 个 token/轮，扣掉草稿模型自身的开销（通常是目标模型的 5%~10%），端到端加速 2~3 倍是文献和生产中的典型区间（量级估算）。

代价与适用条件：

- **需要一个好草稿**。经典方案是同家族小模型（词表必须一致）；后来的变体消除了独立草稿模型：**Medusa** 给目标模型加多个预测头一次猜多步；**EAGLE** 用目标模型的隐层特征训练轻量草稿头（当前开源方案里加速比领先，EAGLE 系列论文报告 3~4 倍）；**prompt lookup / n-gram** 直接从上文里检索匹配片段当草稿，零训练成本，对「大量复述输入」的任务（改写、抽取、代码编辑）出奇地好。
- **吃闲置算力**。投机解码本质是「用富余算力换串行步数」，所以**小 batch 时收益最大**；batch 很大时 GPU 算力已经被填满，验证的并行前向不再是免费的，收益缩水甚至为负。低并发的本地部署和延迟敏感场景是它的主场。
- **接受率看任务**。代码、模板化文本 α 高；开放式创作、高温度采样 α 低，可能白忙。

> **类比**：资深工程师（大模型）审代码远快于自己写代码。让实习生（草稿模型）先写，工程师批量 review，通过的直接合入，不通过的从出错处自己改——只要实习生靠谱率够高，团队产出翻倍，且**代码质量标准丝毫未降**（每一行都经过了工程师之手）。

---

## 6. 三个专题：FlashAttention、MoE、长上下文

### 6.1 FlashAttention：不减少计算，只减少搬运

朴素 attention 实现的问题不在计算量，在**中间结果**：`S = QK^T` 是一个 `[n, n]` 矩阵，n=8192 时单头就是 8192² × 2 B = 128 MiB，必须写回 HBM，softmax 后再读回来乘 V。整个过程对 HBM 读写 O(n²) 的数据——又撞上带宽墙，且 n 越长越严重。

FlashAttention（Dao et al., 2022）的做法：

- **分块（tiling）**：把 Q、K、V 切成小块，装进 SRAM（A100 每 SM 192 KB，比 HBM 快一个数量级以上），在片上算完一块的 QK^T、softmax、乘 V，只把最终小结果写回。
- **Online softmax**：softmax 需要全行的 max 和 sum 才能归一化，看似必须先算完整行。技巧是分块流式处理时维护运行中的 max 和 sum，每来一块就用重缩放修正之前的部分结果——数学上严格等价，**结果精确，不是近似 attention**。
- 代价是反向传播时不存 n² 的中间矩阵而是重算（recompute），推理时无此负担。

效果：HBM 访存从 O(n²) 降到 O(n²/M)（M 为 SRAM 块大小相关因子），attention kernel 提速 2~4 倍，且 n² 的中间显存彻底消失——**长上下文的 prefill 因此才可行**。它是「IO-aware 算法设计」的教科书案例：算得一样多，搬得少得多。FlashAttention-2/3 进一步优化了并行划分和对 Hopper 硬件特性（TMA、FP8）的利用。

顺带一提，第 3 节的 PagedAttention 和这里是正交的：FlashAttention 管「片上怎么算」，PagedAttention 管「HBM 里怎么存」，现代框架两者同时用（如 FlashInfer、vLLM 的融合 kernel）。

### 6.2 MoE 推理：参数很多，干活的很少

MoE（Mixture of Experts）把 FFN 层换成 N 个「专家」，每个 token 由路由器选 top-k（通常 k=1~2，加共享专家）个专家处理。比如 Mixtral 8x7B：总参数 47B，每 token 激活约 13B。

推理特性因此很拧巴：

- **显存按总参数付费**：47B 参数一个不少都得在显存里（你不知道下个 token 路由到谁），FP16 要 ~94 GB——显存需求是 47B 稠密模型级别。
- **计算/带宽按激活参数付费**：每 token 只读约 13B 参数对应的权重（量级估算，batch=1 时），decode 速度接近 13B 稠密模型。

所以 MoE 的交易是：**用显存容量换「同等速度下更高的模型质量」**。这带来两个工程后果：

1. **小 batch 是甜点，大 batch 有摩擦**：batch 大了之后，不同 token 路由到不同专家，一个 batch 几乎会激活所有专家——权重访存的摊薄效果比稠密模型差；且专家负载不均衡时，最忙的专家决定整批的延迟。
2. **天然适合大规模专家并行**：把专家分散到多卡/多机（expert parallelism），token 通过 all-to-all 通信找自己的专家。DeepSeek-V3 这类细粒度 MoE（每层 256 个小专家激活 8 个）在大集群上反而能做出极低的单 token 成本——但这是「数据中心级」玩法，通信工程复杂度极高。

对单机部署者的实用结论：MoE 模型选型时，**显存按总参数算，速度按激活参数估**，两头都要过一遍。

### 6.3 长上下文的代价：一笔三重账

上下文从 4K 拉到 128K，付出的不是一种代价，是三种：

1. **Prefill 计算，O(n²)**：attention 计算量随长度平方增长。128K 是 4K 的 32 倍长，attention 计算量是 ~1000 倍。即使有 FlashAttention（它降访存不降计算量），128K 输入在单卡上的 TTFT 也是几十秒级（量级估算）——这就是长文档场景「转圈久」的根源，也是 prefix caching（缓存复用历史对话/文档的 KV，命中时跳过重算）成为多轮对话和 Agent 场景刚需的原因。
2. **KV Cache 显存，O(n)**：第 2 节算过，Llama-3-70B 一条 128K 序列的 KV Cache 约 40 GiB。长上下文直接吃掉并发度：显存装得下 100 个 4K 请求的 KV，只装得下 3 个 128K 请求。
3. **Decode 每步访存，O(n)**：decode 时每步除了读权重，还要读整个 KV Cache。当 KV Cache（40 GiB）超过权重分片大小时，**decode 瓶颈从「读权重」变成「读 KV」**，吐字速度随上下文变长显著下降。

所以长上下文优化是一个专门的军备竞赛方向：GQA/MLA 压 KV 体积、KV 量化、滑动窗口/稀疏 attention（如 NSA、MInference 类方法）砍 attention 范围、KV 卸载到 CPU/SSD 分层存储、prefix caching 避免重算。使用侧的朴素建议：**不要把 128K 窗口当免费午餐，RAG 检索出 4K 相关内容，往往比塞 100K 原文又快又好又便宜**。

---

## 7. 总结对照表

| 优化手段 | 攻击的瓶颈 | 核心思路 | 典型收益（量级） | 代价 / 局限 |
|---|---|---|---|---|
| **KV Cache** | decode 重复计算 | 缓存不变的历史 K/V，用显存换计算 | 使自回归生成从 O(n²) 前向降为 O(n)，是可用性前提 | 显存随上下文和并发线性增长，成为新瓶颈 |
| **GQA / MQA / MLA** | KV Cache 显存 + decode 读 KV 带宽 | 减少/压缩需要缓存的 KV | KV 缩小 4~30 倍 | 需训练时采用，无法给现成 MHA 模型后装；MLA 增加少量计算 |
| **PagedAttention** | KV 显存碎片浪费 | 分页 + 块表，按需分配、支持共享 | 显存利用率 20~40% → 90%+，batch 更大 | kernel 需间接寻址，实现复杂度高 |
| **Continuous batching** | GPU 空转（快请求陪跑慢请求） | 按「迭代」而非「请求」调度，随时进出 | 吞吐 2~10 倍（对比静态 batch） | 调度器复杂；prefill 插入引起 decode 抖动（需 chunked prefill 缓解） |
| **量化 (weight-only, INT4)** | decode 读权重带宽 + 显存 | 权重压到 1/4，读得少所以快 | 显存 ~1/4，小 batch 提速 2~3 倍 | 有损，需评测把关；大 batch 下反量化开销显现 |
| **量化 (FP8/INT8 W8A8)** | 算力 + 带宽 + 显存 | 用低精度 Tensor Core，算存双降 | 吞吐接近 2 倍 | FP8 需 Hopper+ 硬件；INT8 需离群值处理（校准） |
| **KV Cache 量化** | KV 显存 + decode 读 KV 带宽 | 缓存用 FP8/INT4 存 | KV 显存降 2~4 倍 → batch/上下文更大 | 低位宽下长文本精度需实测 |
| **投机解码** | decode 的串行性 | 小模型猜、大模型并行验，拒绝采样保分布 | 延迟降 2~3 倍，**数学上零质量损失** | 需草稿模型/额外头；吃闲置算力，大 batch 下收益消失；接受率看任务 |
| **FlashAttention** | attention 的 HBM 访存（尤其长序列 prefill） | tiling + online softmax，中间结果不落 HBM | attention kernel 快 2~4 倍，省 O(n²) 中间显存 | 精确无损；仅优化 attention 部分，kernel 与硬件强绑定 |
| **MoE 架构** | 「质量 vs 每 token 计算量」的根本权衡 | 参数多、激活少 | 同等速度下模型质量更高 | 显存按总参数付费；专家负载不均；大规模需专家并行+复杂通信 |
| **Prefix caching** | 重复 prefill 计算（多轮对话/共享 prompt） | 缓存并复用历史 KV | 命中时 TTFT 大幅下降 | 占显存/需分层存储；依赖前缀完全匹配 |
| **P/D 分离** | prefill 与 decode 瓶颈异质、互相干扰 | 两阶段分池部署，KV 跨机传输 | 消除干扰，两侧独立扩缩容 | 需高速互联传 KV，系统复杂度显著提高 |

---

## 8. 收尾：一个可复用的心智模型

把全文压缩成四条，以后遇到任何新的推理优化论文，都可以往这个框架里放：

1. **先问阶段**：它优化 prefill（compute-bound，TTFT）还是 decode（memory-bound，吐字速度）？两者的药方几乎不通用。
2. **decode 的一切围绕「每 token 搬多少字节」**：`每 token 耗时 ≈ (权重字节 + KV 字节) / 带宽 / batch摊薄`。量化减小分子，batching 摊薄分子，GQA/MLA/KV量化减小 KV 项，投机解码则减少「搬运的次数」。
3. **显存是吞吐的隐形上限**：batch 开多大取决于 KV Cache 塞得下多少，所以 PagedAttention 这种「不碰计算、只管内存」的工作能带来数倍吞吐提升。
4. **免费午餐分两种**：严格无损的（KV Cache、FlashAttention、PagedAttention、投机解码——数学等价，只是算得/搬得更聪明）和统计近似的（量化、稀疏 attention——通常没事，但上线前必须评测）。分清这两类，是判断一项优化能不能闭眼上的关键。

---

## 参考文献（关键结论的出处）

- Kwon et al., *Efficient Memory Management for Large Language Model Serving with PagedAttention* (vLLM), SOSP 2023 —— KV 显存浪费 60~80% 的实测与分页方案。
- Yu et al., *Orca: A Distributed Serving System for Transformer-Based Generative Models*, OSDI 2022 —— iteration-level scheduling（continuous batching 的源头）。
- Leviathan et al., *Fast Inference from Transformers via Speculative Decoding*, ICML 2023；Chen et al., *Accelerating Large Language Model Decoding with Speculative Sampling*, 2023 —— 投机采样及其分布一致性证明。
- Dao et al., *FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness*, NeurIPS 2022；及 FlashAttention-2 (2023)。
- Frantar et al., *GPTQ*, ICLR 2023；Lin et al., *AWQ*, MLSys 2024；Xiao et al., *SmoothQuant*, ICML 2023。
- Ainslie et al., *GQA: Training Generalized Multi-Query Transformer Models*, EMNLP 2023；DeepSeek-AI, *DeepSeek-V2* 技术报告（MLA）。
- Cai et al., *Medusa*, 2024；Li et al., *EAGLE* 系列, 2024。
- 硬件规格：NVIDIA A100 / H100 官方数据手册。

*本文由 AI 撰写。文中标注「量级估算」的数字用于建立直觉，工程决策请以目标硬件上的实测为准。*
