为什么推理加速值得做:两大根本矛盾
过去做后端,我们优化的是 QPS、RT、连接池与缓存;转到 AI Infra 后,优化对象变成了大模型推理(Inference) 本身。训练是“一次性把题算完”,而推理是 7×24 小时在线、要同时服务海量用户、且逐字(token)生成 的过程。它决定了两件最花钱的事:用户的等待时延 与GPU 的持有成本 。
从成本结构看,训练是一次性的大额投入 ,而推理成本随请求量线性增长、永不停机 ——在一个模型服务的整个生命周期里,推理的累计算力开销往往远超训练;同一张 GPU 卡能同时服务多少用户、每个 token 摊多少成本,全部取决于推理层的效率。这就是推理加速“值得做”的定量理由:每一点吞吐与时延的改善,都会直接折算进 GPU 账单 。
大模型推理慢、贵,根子上是两个绕不开的矛盾:
矛盾一:自回归的串行依赖(算法层面)。 第 $N$ 个 token 必须等前 $N-1$ 个 token 全部生成后才能计算。哪怕 GPU 有上万个并行核心,原生解码也只能“一个一个往外蹦”,并行度天然为 1。
矛盾二:重复计算 + 显存墙(系统层面)。 每生成一个新词都要把全部历史重新参与注意力计算(重复算力浪费);而真正算的时候,GPU 算力又远快于显存搬运速度,计算单元大部分时间在“等数据”——这就是显存墙(Memory Wall) 。
两大矛盾对所有业务都成立,但不同业务痛的点不一样 :在线聊天最在意 TTFT 与 ITL;IDE 代码补全输出短、追求极低 ITL,是投机解码的最佳猎场;RAG 与长文档问答痛在长 Prefill 的 TTFT;Agent 多轮调用共享大量 system prompt,前缀命中率决定成本;离线批处理没有时延约束,只看吞吐与每 token 成本。读后面每章都可以带着这个问题:我的业务属于哪一类,这项优化为我解决什么?
生成的 token(以问答「北京今天天气怎么样?」为例)
今天
北京
天气
晴朗
适合
前向 #1 读全部权重
前向 #2 读全部权重
前向 #3 读全部权重
前向 #4 读全部权重
前向 #5 读全部权重
单次前向的时间构成(Decode)
≈23ms ≈23ms
≈23ms ≈23ms
≈23ms
橙色 = 有效计算(<5%);灰色 = 等待权重 / KV 从显存搬到计算单元(>95%)。7B FP16 权重约 14 GiB,每步都要完整读一遍
5 次前向 × 读 14 GiB 权重 ≈ 搬运 70 GiB 数据,有效产出只有 5 个 token —— 算术强度仅 1–2 FLOPs/B,A10 脊点约 208,远落在带宽斜坡上
GPU 算力利用率
个位数~12%
串行依赖 + 等显存,算力大量闲置
优化点① KV Cache:不重复算历史(03 章)
优化点② 拼 batch:摊薄权重读取(04 章)
优化点③ 投机解码:一次出多个(05 章)
图 3 原生自回归解码:5 个 token 触发 5 次串行 前向;每步时间几乎全花在等待权重 / KV 搬运上,GPU 算力利用率长期只有个位数。底部三个优化点对应后续第 03、04、05 章的优化主线。
本文的一条主线
沿着输入→输出的流水线,每个环节都有各自的优化抓手:输入侧 识别公共前缀(RadixAttention);主干计算侧 用 KV Cache 消除重复计算、FlashAttention 减少访存、量化与 KV 压缩减少搬运字节;并发侧 用 Continuous Batching、分页与 PD 分离把 GPU 喂满;采样侧 用投机解码一次前向产出多个 token、用约束解码保证格式。它们大多无损、可叠加。
01
输入与 Tokenizer:文字和图片变成 ID TOKENIZER
旅程第一站,是把人能看懂的输入变成模型能处理的整数序号(token ID) 。这一站不占 GPU、却决定了后续所有计算的粒度:同一个意思,切出来的 token 越少,算得越快、KV Cache 也越小。
流水线位置导航 · POSITION 输入 Tokenizer 文本转序号 Embedding ID 转向量 Transformer 主干计算 ×L Sampling 挑选序号 Detokenizer 序号转文本 输出 当前环节 · Tokenizer(文本转序号)
Tokenizer:文本怎样切成序号
主流大模型使用 BPE(Byte-Pair Encoding,字节对编码) 类分词器:它在语料上预先统计“哪两个相邻片段最常一起出现”,把它们逐步合并成一个子词,最终形成一张 3–15 万大小的词表。分词时把句子从左到右 greedily 匹配词表,输出一串 ID;遇到没见过的词,就拆成已知的更小片段(极端情况退到字节),因此不会出现 OOV。
对中文业务还有一个容易忽略的量化事实:不同词表对中文的切分粒度差异很大 。早期以英文为主的词表里一个汉字可能要拆成 2–3 个 token,而面向中文扩容过的词表(Qwen、GLM 等)通常在 1 个汉字 1 个 token 上下——同一句话的 token 数可以差到 1.5–2×。token 数直接决定 Prefill 算力、KV Cache 体积和按 token 计费的账单,所以评估一个模型是否适合自己的业务,用真实业务语料实测“每千字 token 数”,是比看参数量更实在的口径 。
原始文本
unbelievable idea
un believ able Ġidea
812 3051 619 1842
BPE 分词要点
① 从最小的字符 / 字节单元开始
② 每轮合并语料中频率最高的相邻对
③ 重复合并,直到词表上限
④ 未登录词拆成已知子词,不会 OOV
特殊 token(如 <|im_start|>)整体保留
中文多按单字 / 子字切,数字常逐位切
图 4 BPE 把文本切成子词序列、再查成 ID(ID 为示例值)。前缀 Ġ 表示词前空格,是字节级 BPE 的特殊标记。分词在 CPU 上完成,不占 GPU。
图片怎样进来:视觉编码器与图像 token
多模态模型里,图片不是直接进入 Transformer :它先被切成小块(patch),由一个视觉编码器(ViT) 编码、再经投影层对齐维度,变成一组图像 embedding,与文本 token 的向量拼接成同一条序列 ,之后走的是完全相同的推理路径。分辨率越高、图像 token 越多(常见一张图数百到上千 token),算力与 KV Cache 开销随之增长。
图像 token 的数量是可以自己算出来的:以 Qwen2-VL 式的动态分辨率为例,ViT 按 14×14 像素切 patch、再经 2×2 合并,图像 token 数约为 $\frac{H}{28}\times\frac{W}{28}$(不同模型的 patch 与合并参数不同)——一张 1024×1024 的图约 1300 token,4K 分辨率则上万。视频则是“帧采样 × 每帧 token ”,几秒视频轻松吃掉数千 token。多模态场景的显存规划,第一步就是把这条公式代进第 3 章的 KV 公式里。
图片
像素输入
切 patch
视觉编码器
ViT + 投影层
输出图像向量
图 图 图
文 文
拼接为统一序列
图像 embedding 与文本向量拼接后,进入同一套 Transformer ,没有第二条推理路径
图像 token 越多,算力与 KV Cache 开销越大:多模态场景的成本主要来自这里
图 5 图片接入路径:像素 → patch 网格 → ViT + 投影 → 图像 embedding,与文本 token 拼接。之后的 KV Cache、批处理、采样等优化对图像 token 同样生效。
这一环节怎么优化
① 分词在 CPU 异步执行、与 GPU 前向重叠,别让字符串处理阻塞推理;② 公共前缀(system prompt、多轮历史)在分词阶段即可识别,为 RadixAttention 的前缀复用铺路(第 6 章);③ 为结构化输出 / 工具调用预留的特殊 token 应加进词表,避免在采样阶段被拆碎(第 4 章)。
还有一个常踩的坑在分词之前:对话模板(Chat Template) 。多轮对话并不是直接拼接文本,而是按模型约定的模板(如 <|im_start|>user … <|im_end|>)拼成一条带角色标记的字符串再分词——模板用错(换模型没换模板、系统提示位置拼错),模型不会报错、只会静默变笨 ;模板不一致还会让前缀缓存完全失效。上线前拿官方模板逐字节比对,是零成本的质量保险。
02
Embedding:ID 转向量,位置编码就位 EMBEDDING
第二站很短,但它是“离散符号”进入“连续计算世界”的入口:ID 序列被查成一批浮点数向量,之后 GPU 才能大展拳脚。
流水线位置导航 · POSITION 输入 Tokenizer 文本转序号 Embedding ID 转向量 Transformer 主干计算 ×L Sampling 挑选序号 Detokenizer 序号转文本 输出 当前环节 · Embedding(ID 转向量)
Embedding:一次近乎免费的查表
模型自带一张 Embedding 矩阵 (词表大小 × 隐藏维度,如 15 万 × 4096),每个 ID 对应矩阵的一行;所谓 embedding,就是按 ID 把对应行取出来、拼成向量序列,再乘一个缩放系数。它是显存 gather 操作、没有矩阵乘 ,开销在整条路径中几乎可以忽略。图像 embedding 也在这一站与文本向量汇合。
ID
152 8873 619
Embedding 矩阵(查找表)
token 向量(一批浮点数)
位置信息(RoPE 旋转位置编码)在进入注意力前作用于 Q/K;图像 embedding 在此与文本向量汇合
Embedding 常与输出投影 lm_head 共享权重(weight tying);lm_head 是采样前的一次大矩阵乘,与本站的“免费查表”形成对比
图 6 Embedding 就是按 ID 从权重矩阵取行、拼成向量序列;自注意力本身对位置无感,因此还要叠加位置编码(RoPE)。这一站是 gather、不是 GEMM,开销极小。
位置编码:给向量装上“坐标”
自注意力只看内容相关性、对 token 的先后顺序天然无感 (打乱输入,注意力照样能算)。因此必须显式注入位置信息:主流做法是 RoPE(旋转位置编码) ,在每个注意力层对 Q、K 按位置做一次与相对距离相关的“旋转”,让注意力打分天然带有相对位置信息,且能外推到训练时没见过的长度。RoPE 之外还有 ALiBi 等替代方案(不给向量做旋转,而是给注意力打分直接加上与距离线性相关的偏置,外推性好但表达力略弱),不过当前主流模型几乎清一色采用 RoPE。
长上下文外推:PI、NTK 与 YaRN。 RoPE 的“外推”其实有限——拿按 4K 训练的模型直接跑 128K,注意力打分会迅速退化。工程上靠三类位置编码改造把窗口拉长:位置插值(PI) 把超长位置线性压缩回训练范围,配合少量微调即可;NTK-aware 插值 改为非均匀缩放旋转频率、压低频保高频,短文本几乎无损;YaRN 在此基础上按维度分频段处理并引入注意力温度校正,成为长上下文模型(Qwen、GLM 等)的主流配置。它们的共同点:不改模型结构、只动 RoPE 的“坐标系” ,是部署长上下文时成本最低的改造。
RoPE 与 KV Cache 的耦合。 旋转是施加在 Q、K 上的,因此缓存进 KV Cache 的 K 已经带上了位置信息 ——这带来两个直接后果:① 前缀复用(6.2 RadixAttention)要求命中的前缀位置编号完全一致,否则缓存的 K 与新请求的坐标系对不上;② DeepSeek MLA(3.2)之所以要在潜向量之外单独缓存一份 RoPE 部分 ,正是因为位置分量无法和内容一起被低秩压缩。同理,用 PI / YaRN 改坐标系扩上下文时,存量 KV 也必须一并重算。
这一环节怎么优化 Embedding 本身没有提速空间,关键是别让它阻塞串行路径 :查表可与前一步的采样 / 分词在流水线上重叠,RoPE 可融合进 QKV 投影算子。需要记住的是反方向的事实——采样前的 lm_head 输出投影是词表维度的大矩阵乘 ,在大 batch、大词表下开销可观,是第 4 章要面对的对象。
03
Transformer 主干计算:KV Cache、FlashAttention、量化 TRANSFORMER · KERNEL 向量序列进入模型主体——$L$ 个结构相同的 Transformer Block,这是整条路径上算力、显存带宽与优化手段最密集的一环。本章先用 3.1 建立背景、诊断 Decode 为什么慢;再沿三条优化主线展开:3.2 KV Cache 家族(少算、放得下、装得少,能复用见 6.2)、3.3 FlashAttention、3.4 量化。
流水线位置导航 · POSITION 输入 Tokenizer 文本转序号 Embedding ID 转向量 Transformer 主干计算 ×L Sampling 挑选序号 Detokenizer 序号转文本 输出 当前环节 · Transformer 主干计算 ×L
03 Transformer 主干计算 · 先诊断瓶颈,再沿三条优化主线开方
3.1 背景与
瓶颈诊断
推理只有前向
QKV 结构
Prefill/Decode 两节拍
显存账
GPU 存储层级
显存墙
Roofline 诊断
→ 结论:Decode 落在带宽斜坡(Memory-Bound),提速不能靠堆算力
诊断顺序:前向数据流 → 两节拍 → 显存账 / 存储层级 → Roofline 落点
3.2 KV Cache
家族
围绕「历史 K/V」
的三层手段
① 少算
历史 K/V 只算一次
注意力 O(n²)→O(n)
KV Cache 本体
② 放得下
PagedAttention
切 block + 页表映射
碎片 60–80%→个位数
③ 装得少
GQA/MQA 减头 · MLA 降维
H2O/SnapKV 逐出
KIVI 位宽量化见 3.4
3.3 Flash
Attention
分块 HBM→SRAM,片上融合
N×N 中间矩阵不落地,HBM 访存 O(N²)→O(N)
3.4 量化
BF16→FP8 / INT8 / INT4
搬运字节减半 ~ 1/4(有损,需校准)
主线分工:3.2 让历史 K/V 不重算、好摆放、体积小;3.3 让注意力中间矩阵不落地;3.4 让每个字节更便宜——彼此正交、可叠加。
另一条思路是减少前向「次数」(一次前向出多个 token):投机解码家族,见第 04 章。
图 7 03 章结构地图 :3.1 背景与瓶颈诊断(两节拍 + 显存账 + Roofline);3.2 KV Cache 家族三层手段(少算 / 放得下 / 装得少;跨请求前缀复用属于并发请求一章,不在本图);3.3 FlashAttention;3.4 量化。
背景:推理只有前向,Decode 为什么慢 推理只有前向:权重固定,不断预测下一个 token 前向传播(Forward) 是数据从 Embedding 一路算到 logits 的过程,训练和推理都有;反向传播(Backward) 从损失 Loss 倒推梯度、更新权重,只在训练中存在。推理阶段权重固定、只有前向、不断预测下一个 token ,不更新任何参数——这也是为什么推理优化的抓手集中在“怎么搬数据、怎么调度”,而不需要保存反向用的中间状态。
30 秒回顾 Transformer 与 QKV 向量序列流过 $L$ 个结构相同的 Transformer Block (多头自注意力 MHA + 前馈网络 MLP/FFN,配 LayerNorm 与残差),最后由输出 Linear 层投影成词表维度的 logits。注意力做的事,是让当前 token 的 Query 与所有历史 token 的 Key 打分、再按权重取 Value:
$$\mathrm{Attention}(Q,K,V)=\mathrm{softmax}\!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V$$
其中 $Q$ 是当前 token 在“问什么”,$K$ 是每个历史 token 的“标签”,$V$ 是每个历史 token 的“内容”。多头(Multi-Head)只是把 Q/K/V 切成多组并行计算后拼回。
容易被忽略的是另一半参数:MLP/FFN 。每个 Block 里注意力只占约 1/3 参数,剩下约 2/3 在两层(或 SwiGLU 三层)的前馈网络里——Decode 每步“搬权重”,大头其实是搬 MLP。现代模型的主流做法是把 MLP 换成 MoE(Mixture of Experts,混合专家) :把一个大 FFN 拆成数十到数百个“专家”,每个 token 由路由器只激活其中少数几个(如 Qwen3-30B-A3B 总参 30.5B、每 token 仅激活 3.3B)。MoE 对推理的含义是显存按总参数装、带宽与算力按激活参数算 :模型必须完整常驻显存,但每个 token 只需读取被激活专家的权重——Decode 访存大减、TPS 天花板抬高(6.1 会按此修正口径),代价是专家路由引入 All-to-All 通信与负载均衡问题(见 7.3 趋势)。
每个 token 独立过路由器
token 向量 token 向量 token 向量
Router 路由器
对全部专家打分,选 top-k
专家池(全部常驻显存)
E1
E2 ✓
E3
E4
E5
E6
E7 ✓
E8
橙色:本 token 激活的专家(如 128 选 8)
显存:全部专家常驻 → 按总参数装
带宽 / 算力:只读激活专家 → 按激活参数算
不同 token 可激活不同专家;注意力层不受影响,KV Cache 照常
图 8 MoE 路由:每个 token 经 Router 打分只激活少数专家(橙),其余专家(灰)本轮不读取;模型按总参数占显存、按激活参数耗带宽与算力——Qwen3-30B-A3B 为 128 专家选 8,DeepSeek-V3 为 256 选 8。
两个节拍:Prefill 与 Decode
Prompt
L 个 token
① Prefill
一次性并行前向
算全部 K/V 并缓存
Compute-Bound
KV Cache
逐层 K / V 缓存
随生成不断追加 ↓
② Decode
输入 1 个新 token
读 KV,出下一个 token
Memory-Bound
循环:每步追加 K/V,直到结束
token
流式输出
图 9 推理两阶段:Prefill 一次性并行处理整个 prompt 并生成 KV Cache(算力受限);Decode 逐 token 自回归生成、反复读取 KV(带宽受限),每步把新 K/V 追加进缓存。
为什么 Decode 每次只输入 1 个 token? 不是硬件强制,而是自回归逻辑 + KV Cache 设计 的自然结果:Prefill 已把全部历史 K/V 存好,Decode 时“新信息”只有刚生成的那 1 个 token,所以本轮的 Q 只有 1 个;它用这 1 个 Q 去和缓存里全部历史 K/V 打分,采样出下一个 token,再把这 1 个 token 的 K/V 追加进缓存。第 $N$ 个 token 无法提前知道第 $N+1$ 个,只能逐步进行。
关键认知 Prefill 和 Decode 的瓶颈完全不同——一个拼算力、一个拼带宽 。这是后面所有优化(包括 PD 分离)成立的根本原因。
显存占用:模型权重、KV Cache 与激活 $$\text{GPU 显存总占用}\ \approx\ \underbrace{P\times b}_{\text{模型权重}}+\underbrace{\mathrm{KV}_{\text{bytes}}}_{\text{KV Cache}}+\underbrace{A}_{\text{激活/中间张量}}+\text{碎片}$$
$$\mathrm{KV}_{\text{bytes}}=2\times n_{\text{kv}}\times d_{\text{head}}\times L\times s\times b_{\text{size}}\times \underbrace{b}_{\text{每元素字节}}$$
模型权重 :参数量 $P$ × 每参数字节。BF16/FP16 = 2B/参数,FP8 = 1B,INT4 ≈ 0.5B。如 7B BF16 ≈ 14 GiB ,70B BF16 ≈ 140 GiB ——这部分常驻、不随上下文变化。
KV Cache :随并发数与序列长度线性增长 ,是长上下文、高并发场景下最容易爆显存的部分,也是调度要重点管理的对象。
激活 $A$ :推理时主要是 Prefill 的中间张量,相对权重小得多,Decode 阶段几乎可忽略。
先看清 GPU 的存储层级 GPU 不是一块“均匀的大内存”,而是一个越靠近计算核心越快、但容量越小 的层级结构。硬件细节不是本文重点,只需记住结论:数据在不同层级之间搬运的速度,往往才是推理的真正瓶颈。
寄存器 Register
数十 TB/s · 256KB/SM
片上 SRAM(L1 / Shared Memory)
TB/s 级 · ~228KB/SM
HBM3 / GDDR6 显存
H100 HBM3 3.35TB/s · 80GB | A10 GDDR6 600GB/s · 24GB
主机 DRAM(DDR5)
~50 GB/s(0.05 TB/s)· 数百 GB–2TB
NVMe SSD / 远端存储
~7 GB/s · 数 TB(需经 CPU/PCIe 搬运)
快 / 小
慢 / 大
离计算核心越近
离计算核心越远
图 10 GPU 存储层级:片上寄存器/SRAM 带宽极高但以 KB 计;HBM / GDDR6 是模型权重与 KV Cache 的主阵地(H100 HBM3 3.35TB/s、80GB,A10 GDDR6 600GB/s、24GB);再往下到主机 DRAM、SSD,带宽断崖式下降。
显存墙:算得快,搬得慢 当一次计算的算术强度(Arithmetic Intensity,每搬运 1 字节能做多少次浮点运算,FLOPs/Byte)很低 时,计算单元会大量空转等数据,这就是 Memory-Bound。Decode 阶段每个 token 要把全部权重 + 全部 KV Cache 从 HBM 读一遍,却只做约 2 倍参数量的运算 ,算术强度极低,因此被显存带宽死死卡住。
Roofline:一张图判断瓶颈在算力还是带宽
1 10 100 1000
1 10 100 1000
算术强度 I(FLOPs / Byte,对数轴)
性能(TFLOPS,对数)
算力屋顶 989 TFLOPS
带宽屋顶 = 3.35 TB/s × I
脊点 I*≈295
Decode I≈1.5
落在斜坡:带宽受限
Prefill I 大
贴近屋顶:算力受限
图 11 Roofline 模型(Williams et al., 2009):斜屋顶由显存带宽决定(性能 = β·I),平屋顶由峰值算力决定,二者交点为“脊点”。H100 脊点 ≈ 989/3.35 ≈ 295 FLOPs/B。Decode 落在斜坡(带宽受限,约 5 TF/s 量级),Prefill 贴近平顶(算力受限)。
A10 口径:FP16 Tensor Core 稠密峰值约 125 TFLOPS、GDDR6 带宽 600 GB/s,脊点 ≈ 125 / 0.6 ≈ 208 FLOPs/B——Decode 同样落在斜坡,结论不变;A10 无 FP8 硬件,FP8 屋顶不适用。 用 Roofline 指导优化 Decode 想提速,要么减少搬运字节 (量化、压缩/驱逐 KV、减 KV 头);要么提高算术强度 (多请求拼 batch,让一次搬运服务更多 token,第 6 章);Prefill 想提速则靠 FlashAttention、张量并行与低精度。
KV Cache 家族:少算、分页、压缩与逐出 如果只记住一个推理优化,那就是 KV Cache。本节把所有围绕 KV Cache 的手段收为一个家族,按四个问题展开:① 少算 ——历史 K/V 只算一次;② 放得下 ——PagedAttention 分页管理;③ 装得少 ——GQA/MQA、MLA 与运行时逐出(KIVI 位宽量化见 3.4);④ 能复用 ——RadixAttention 前缀树(见 6.2)。
① 少算:把历史 K/V 存起来,注意力计算 O(n²) → O(n) 它的思想极其朴素:把已经算过的历史 token 的 K、V 存起来,新 token 只算自己的 Q,直接复用旧 K/V ,从而把每步“重算全部历史”的开销砍掉。
无 KV Cache:每步重算全部历史
O(n²)
1
2
3
4
5
第 $k$ 步要算 $k$ 个 token,总量 $1+2+\dots+n$
有 KV Cache:每步只算 1 个新 token
O(n)
1
1
1
1
1
历史 K/V 直接复用,每步恒定只算新 Q
图 12 KV Cache 把单请求解码的注意力计算量从 $O(n^2)$ 降到 $O(n)$:左图每步计算量随序列线性增长,右图每步恒定。代价是要用显存存放历史 K/V,序列越长占用越高。
KV Cache 的数据流动:HBM、SRAM 与一次写入 把 KV Cache 放到硬件层面看,它改变的是「数据在 HBM 与片上 SRAM 之间怎么流动」。没有缓存时,每生成一个新 token,都要把它之前所有 token 的 K/V 重新算一遍 (生成第 k+1 个 token 时,重算的是之前的 1~k 个):权重反复从 HBM 读进 SRAM、算出的 K/V 用完即弃,下一步全部重来。有了缓存,Prefill 阶段权重只需流式读一遍,算出的 K/V 作为结果写回 HBM 的 KV Cache 区、只写一次;Decode 每生成一个 token,只算自己的 Q/K/V,把之前已缓存 token 的 KV 块从 HBM 读进 SRAM,在片上完成 $QK^\top$、softmax、乘 V,再把新 token 的 K/V 作为增量追加写回。另外要严格区分两层含义:「缓存随生成变长」说的是已缓存的有效内容逐步增多;而物理显存是按块管理的 ——旧式方案按最大生成长度连续预留一整段,PagedAttention(②)则切成固定页、按需分配、写满再取新页,空间总是先备好、内容再逐步写入。
无 KV Cache:每步重算全部历史
每生成一个新 token,都把它之前所有 token 的 K/V 重算一遍
北京
重算:
今天
天气
重算:
今天
北京
晴朗
重算:
今天
北京
天气
生成 n 个 token 共重算 n(n−1)/2 次 K/V → O(n²);
每步还要把全部权重重新从 HBM 搬进 SRAM
有 KV Cache:一次写入,反复读取
每个 token 的 K/V 只算一次、只写一次;之后每步只读缓存
Prefill
今天
北京
天气
并行算好,写缓存
Decode
晴朗
只算自己的 Q/K/V;读缓存 3 个
(之前的 1~3 个),追加写 1 个
Decode
…
读缓存 4 个,再追加写 1 个
历史 K/V 永不重算
n 个 token 共写 n 次 → 计算 O(n);
代价是 HBM 上要常驻这份缓存
HBM 上的 KV Cache 区:「变长」的是有效内容,物理空间按块管理
今天
北京
天气
晴朗
…
空闲
空闲
空闲
已写入:随 Decode 只增不改(只追加、不重算)
空闲块:按需分配,写满再取新页
旧式方案按最大生成长度连续预留(碎片 60–80%);PagedAttention 切成固定页、按需分配——空间先备好,内容逐步写入
图 13 以「今天、北京、天气、晴朗」为例看 KV Cache 的数据流:无缓存时,每生成一个新 token 都要重算它之前所有 token 的 K/V(生成第 k+1 个时,重算之前的 1~k 个);有缓存时,Prefill 把已有 token 的 K/V 一次写入 HBM 的 KV Cache 区,Decode 每步只读缓存、并把新 token 的 K/V 追加写入。注意「缓存随生成变长」指有效内容逐步增多;物理显存按块管理——旧式方案按最大长度连续预留,PagedAttention 按需分页。它与 FlashAttention 正交:一个让历史「不重算」,一个让中间矩阵「不落地」。
注意区分两件正交的事:KV Cache 让历史 K/V「不重算」 (省计算,代价是占用 HBM);FlashAttention(3.3)让注意力的中间矩阵「不落地」 ——读进 SRAM 的 KV 块在片上算完、结果只写回一次(省访存)。二者叠加,才构成 Decode 的完整数据流。
为什么只缓存 K、V,从不缓存 Q? 这来自注意力结构的根本不对称 :
$K$、$V$ 是历史 token 的表示 ,一旦算好就不再改变,后续每一步都要反复使用——天然值得缓存。
$Q$ 是“当前这一步”的查询 ,只在当前位置、当前这一次注意力里使用,用完即弃;下一步的新 token 会产生全新的 Q。缓存 Q 没有复用价值,反而白占显存。
一句话:K/V 面向过去、可复用;Q 面向当下、一次性 。所以 KV Cache 里永远只有 K 和 V。
KV Cache 显存,一个公式算清 $$\mathrm{KV}_{\text{bytes}}=2\times n_{\text{kv}}\times d_{\text{head}}\times L\times s\times b_{\text{size}}\times \underbrace{b}_{\text{每元素字节}}$$
$2$ :K 和 V 两份,最容易漏;
$n_{\text{kv}}$ :KV 头数 (GQA/MQA 用它,不是 Query 头数!Q 头再多也不影响 KV 大小);
$d_{\text{head}}$ :单头维度,Llama/Qwen 系列一般为 $128$;
$L$ :模型层数;$s$ :序列总长度(prompt + 生成);$b_{\text{size}}$ :并发 batch;
$b$ :每元素字节,BF16/FP16 = 2,FP8/INT8 = 1。
② 放得下:PagedAttention,像操作系统管内存一样管 KV 缓存本身该怎么在显存里摆放?传统做法给每个请求按最大生成长度连续预留一整段显存 。但请求实际生成长度未知,预留多了形成内部碎片 、预留少了直接 OOM;再加上预留的显存无法在请求间灵活共享,浪费惊人(vLLM 论文测得浪费 60–80%)。
PagedAttention 借鉴 OS 虚拟内存分页 :把 KV Cache 切成固定大小的 Block(页,如每块 16 个 token) ;逻辑上连续的 KV,物理上可以分散存放,由页表 记录映射;按需分配、用完即回收。更进一步,相同前缀(系统提示、公共 few-shot、beam/采样分叉)的 KV 块可以在多个请求间共享(写时复制) ,几乎消灭碎片。
传统:连续预留
红色=内部碎片
浪费 60–80%
分页:逻辑连续 / 物理分散
共享前缀块
物理块池(按需分配)
图 14 上:连续预留产生大量内部碎片;下:PagedAttention 把 KV 切成固定块、页表映射,物理块按需分散分配,相同前缀块(橙)跨请求共享。显存浪费从 60–80% 降到个位数。
vLLM Efficient Memory Management for Large Language Model Serving with PagedAttention
Kwon et al. · UC Berkeley · SOSP 2023 · PagedAttention 与 vLLM,吞吐较 HF/传统方案数倍提升
arXiv:2309.06180 ③ 装得少(结构侧):减头 GQA / MQA 先从模型结构入手,减少每个 token 要缓存的 K/V。
KV Cache 大小正比于 KV 头数,于是模型侧最直接的演进就是减少 KV 头、让多个 Q 头共享同一组 K/V :
MHA · 每 Q 独享 KV
GQA · 多 Q 共享(主流)
MQA · 全局共享 1 组
Q Q Q Q
Q Q Q Q
Q Q Q Q
KV KV KV KV
KV KV KV
KV Cache 最大(基准 1.0×)
Llama3-70B:Q 64 / KV 8,缓存降至 1/8
KV 最小,质量略损
图 15 MHA 中每个 Q 头有专属 K/V;GQA 将多个 Q 头分组共享 K/V(Llama2/3、Qwen 主流);MQA 所有 Q 头全局共用 1 组 K/V。KV Cache 只与 KV 头数有关。
MQA Fast Transformer Decoding: One Write-Head is All You Need
Noam Shazeer · 2019 · 首次提出多查询注意力,所有 Q 共享一组 K/V
arXiv:1911.02150 GQA GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
Ainslie et al. · Google · EMNLP 2023 · 分组查询注意力,质量与 MHA 接近、KV 按组数缩减,可从 MHA 检查点低成本转换,现为 Llama/Qwen 等主流标配
arXiv:2305.13245 易错三连 ① GQA 必须用 KV 头数 而非 Q 头数;② 不要漏 K+V 的系数 2 ;③ KV Cache 显存 ≠ 模型权重显存,二者要分开估算再相加。
③ 装得少(维度侧):MLA 多头潜在注意力 GQA/MQA 减的是 KV 头的数量 ;DeepSeek 提出的 MLA(Multi-head Latent Attention) 走另一条路——把 K、V 向量本身通过低秩投影压缩成更小的潜向量(latent),缓存里只存这个潜向量,Decode 时再投影还原 。KV 头数量不变,但每个 token 缓存体积大幅下降。
原始高维 K/V
每头 128 维
GQA:直接存这一份
压缩 Down
潜向量 c_KV
低维(如 128 → 更小)
↑ KV Cache 实际只存这一份
还原 Up
投影还原 K/V
Decode 时算注意力
精度近无损
不同模型实测(BF16):
Qwen3-30B GQA ≈ 96KB/字
V2 MLA:较 MHA −93.3%
128K 上下文 KV ≈ 8.4GB
图 16 MLA:Prefill 用可学习投影把高维 K/V 编码为低维潜向量,缓存只存潜向量;Decode 再投影还原。压缩/还原矩阵随模型一起训练,注意力精度近无损(DeepSeek-V2/V3)。
MLA DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model
DeepSeek-AI · 2024 · 首次提出 MLA 多头潜在注意力,配合 MLA 大幅压缩 KV Cache
arXiv:2405.04434 同属“结构侧装得少”的前沿方向还有稀疏注意力 :DeepSeek 的 NSA 与月之暗面的 MoBA 让注意力只计算被选中的 KV 块、而非全部历史,把长上下文的注意力开销从 $O(n^2)$ 压到近线性,且设计为可训练、近无损 ——可以理解为“把 KV 驱逐(3.2)直接做进模型结构”的版本,二者均已进入新一代长上下文模型(趋势见 7.3,论文见参考文献)。工程上还有一个更温和的中间档:滑窗注意力(SWA) 及其与全局注意力的层间混合——大部分层只看最近 W 个 token、每隔几层插一层全局注意力(Mistral 首开,Gemma 2/3 的 5:1 局部/全局交替即此路线;Qwen3-Next 等则把部分层换成线性注意力),KV 占用随窗口封顶、实现简单,是中长上下文模型的实用默认。
三个主流模型,代入公式实算 口径:KiB/GiB 按 1024 换算;KV 为单请求、单并发,线上还要乘以并发 batch。Qwen3-30B 为 MoE(总参 30.5B、单 token 激活 3.3B),但 KV Cache 只与注意力结构有关,与 MoE 无关。 ③ 装得少(运行时):KV 逐出 H2O 与 SnapKV 结构改动需要重新训练模型;不训练模型,也能在运行时主动丢 KV——这就是逐出(eviction)。
KV Cache 随序列线性膨胀,长上下文下甚至超过权重。但注意力本身是高度稀疏 的:实证表明,生成时 95% 以上的历史 token 几乎从未被高权重关注 ,真正反复被“看”的只有少数“关键 token”(Heavy Hitters)加上最近的一小段。这给了我们主动丢弃低价值 KV 的空间(属有损压缩,需控制比例以保质量)。
注意力权重(生成某 token 时对历史的关注)
少数关键 token
>95% 历史 token 注意力权重接近 0,驱逐它们对结果影响很小
H2O:边生成、边驱逐
Heavy Hitters 保留
Recent 窗口
每步按累计注意力淘汰低分 KV
KV 显存恒定(bounded),适合长生成
训练免费、即插即用
SnapKV:Prefill 末一次压缩
Prefill
观察窗口投票
压缩
Decode
长 prompt 一次瘦身,近无损
适合 RAG / 长文档,可配合 prompt 缓存
图 17 上:注意力稀疏、只有少数关键 token 被反复关注;左下 H2O 在生成中持续保留 Heavy Hitter + 最近窗口、KV 总量恒定;右下 SnapKV 用 prefill 末尾观察窗口投票、在生成前一次性压缩。
H2O:Heavy-Hitter Oracle · 边生成边驱逐。
H2O 观察到一个规律:历史贡献(累计注意力得分)高的 token,未来也更可能被需要 。它在每步维护一个固定大小的 KV 池,保留“累计注意力最高的 Heavy Hitter”加“最近窗口”,其余直接驱逐,从而把 KV Cache 变成有上界 的滚动窗口,训练免费、可直接嵌入任意引擎。
H2O H2O: Heavy-Hitter Oracle for Efficient Generative Inference of Large Language Models
Zhang, Zhang, Mirzadeh et al. · NeurIPS 2023 · 边生成边驱逐,KV 显存大幅下降、质量可控
arXiv:2306.14048 SnapKV:生成前「一次看对眼」。
SnapKV 利用 prefill 末尾若干 query 位置(观察窗口)对各历史 KV 的注意力作为投票 ,选出对当前任务真正重要的 KV 位置,在 Decode 开始前一次性批量压缩 。它特别契合长 prompt / RAG 场景——大量无关文档块可以在生成前就被丢掉,且因为依据的是真实任务相关的投票,压缩近无损。
SnapKV SnapKV: LLM Knows What You Are Looking for Before Generation
Li et al. · NeurIPS 2024 · 观察窗口加权投票 + 生成前一次压缩
arXiv:2404.14469 Attention Sink:为什么开头几个 token 永远丢不得。 驱逐类方法有一个共同的实证基础:softmax 要求注意力权重归一,模型会把大量“无处安放”的注意力倾倒给序列最开始的几个 token (Attention Sink)——它们被关注的强度远超其语义重要性,一旦被驱逐,输出立刻崩坏。StreamingLLM 利用这一点给出极简方案:只保留最前 4 个 sink token + 最近滑动窗口 ,KV 有界、无需微调,即可在远超训练长度的流式输入上稳定生成。它既是所有驱逐策略“特殊照顾开头”的物理直觉,也是无限流式对话(直播字幕、持续监控等场景)的经典解法。
StrLLM Efficient Streaming Language Models with Attention Sinks
Xiao et al. · MIT · ICLR 2024 · Attention Sink 现象 + 滑动窗口,KV 有界的无限流式生成
arXiv:2309.17453 KV Cache 家族一览 少算(缓存复用)→ 放得下(PagedAttention)→ 装得少(GQA/MQA、MLA、H2O/SnapKV;位宽量化 KIVI 见 3.4)→ 能复用(RadixAttention 见 6.2)。现代引擎里这几件事通常同时开启,且与 3.3/3.4 正交可叠加。
FlashAttention:用分块把 N×N 矩阵“焊”在片上 先把标准注意力的完整计算写全(与 3.1 的公式一致):
$$\mathrm{Attention}(Q,K,V)=\mathrm{softmax}\!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V$$
拆成三步看:$S=\dfrac{QK^{\top}}{\sqrt{d_k}}$(打分,别忘了除以 $\sqrt{d_k}$ 做缩放 ,防止分数随维度变大把 softmax 推进饱和区)、$P=\mathrm{softmax}(S)$(归一化成注意力权重)、$O=PV$(按权重加权求和 Value)。标准实现要把 $S$、$P$ 这些 $N\times N$ 中间矩阵反复写回 HBM 再读出 ,访存量是 $O(N^2)$。FlashAttention 的做法是算子融合 + 分块(Tiling)+ 在线 Softmax(Online Softmax) :把 Q/K/V 分块搬进片上 SRAM,在片上连续完成 $QK^\top$、softmax、乘 V,用流式方式逐块更新 softmax 归一化因子,最终输出 $O$ 只写回 HBM 一次,HBM 访存降到 $O(N)$。
HBM · 慢、容量大
Q
K
V
O(写一次)
softmax 归一化因子
不落地 HBM,片上流式更新
分块读入
O 仅写回一次
SRAM · 快、容量小
Q 块
K 块 / V 块 循环遍历
片上算 QKᵀ · softmax · PV
online softmax 逐块累积
数学结果与标准注意力完全一致(exact / 无损) ,只改变计算顺序与访存路径;HBM 访存由 O(N²) 降为 O(N)
图 18 FlashAttention 的 Tiling:Q/K/V 分块载入 SRAM,片上融合完成注意力与在线 softmax,避免 N×N 矩阵落地 HBM。它与 KV Cache 正交——一个优化 Prefill 的算子访存,一个优化 Decode 的重复计算。
FA1 FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness
Dao et al. · NeurIPS 2022 · IO 感知、分块 + 在线 softmax
arXiv:2205.14135
FA2 FlashAttention-2: Better Parallelism and Work Partitioning
Tri Dao · 2023 · 约 2× FA1,减少非 matmul 开销
arXiv:2307.08691
FA3 FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision
Shah, Bikshandi, Zhang, Thakkar, Ramani, Dao · NeurIPS 2024 · Hopper TMA 异步、Warp 特化、FP8
arXiv:2407.08608 同层的另一件武器:CUDA Graph 消除启动开销
FlashAttention 优化的是单个算子内部 的访存;Decode 还有一层更“机械”的开销——每步前向要发起成百上千次 kernel launch,每次 launch 本身有数微秒的 CPU→GPU 开销,而 Decode 的每个 kernel 只算几十微秒,小 batch 下 launch 开销能占单步耗时的两三成 (这正是 6.1 实测低于理论天花板的原因之一)。CUDA Graph 把 Decode 的整条计算图一次性“录制”下来,之后每步整体回放 :CPU 只发一次启动指令,launch 开销几乎归零,vLLM、SGLang、TensorRT-LLM 均已默认对 Decode 开启。它与 FlashAttention、量化正交,是“不改算法、只改执行方式”的纯系统优化——代价是计算图形状(batch、序列长度档位)必须固定,引擎需要按档位预录多份。
量化:直接减少要搬运的字节 Decode 是 Memory-Bound,把权重/KV 从 BF16 降到 FP8/INT8/INT4,直接把搬运字节减半甚至减到 1/4 ,提速立竿见影;代价是引入微小精度损失(属有损 优化,需校准或少量微调)。
AWQ AWQ: Activation-aware Weight Quantization for On-Device LLM Compression
Lin et al. · MLSys 2024
arXiv:2306.00978
KIVI KIVI: A Tuning-Free Asymmetric 2bit Quantization for KV Cache
Zhang et al. · ICML 2024
arXiv:2402.02750
A10 等 Ampere 卡没有 FP8 硬件 ,优先选择 INT8(SmoothQuant,A10 INT8 Tensor Core 可直接加速)或 W4(AWQ / GPTQ);FP8 仅在 Hopper / Blackwell 上可用。 量化的两条边界 ① W4A16 只省搬运、不省计算 :权重以 4bit 存储、计算前反量化回 FP16,只有配套专用 kernel(Marlin、ExLlamaV2 等)才能把“省带宽”兑现为真实加速,且 batch 调大、负载转入 Compute-Bound 后收益递减;② 只有激活也量化(W8A8 / FP8)才能吃到低精度 Tensor Core 的计算加速 ——A10 上的 SmoothQuant INT8 即属此类,而纯 W4 方案的价值主要在省显存与带宽。先用 Roofline(3.1)判瓶颈,再决定量化谁。
04
采样:从 logits 到下一个 ID SAMPLING Transformer 最后一层输出的隐藏向量,先经 lm_head 输出投影变成词表维度的一批浮点数(logits),采样环节要回答:这批浮点数对应哪个 token ID。本章先在 4.1 建立 logits→ID 的完整背景(采样旋钮),再讲两个优化方向:限制候选的约束解码(4.2),以及把「一次前向只出一个 ID」变成「一次前向出多个 ID」的投机解码家族(4.3)。
流水线位置导航 · POSITION 输入 Tokenizer 文本转序号 Embedding ID 转向量 Transformer 主干计算 ×L Sampling 挑选序号 Detokenizer 序号转文本 输出 当前环节 · Sampling(logits 选 ID) 背景:logits 怎样变成一个 ID 确定性方法(贪心)直接取 logit 最大的 ID;随机方法先做 softmax 得到概率分布再按分布采样,并用一组旋钮调节随机性与重复度。
先补一笔容易被低估的账:lm_head 本身是词表维度的大矩阵乘 (隐藏维 × 词表,如 4096 × 15 万)。Decode 阶段每个 token、每个请求都要过一次,大词表模型在 batch 较大时 lm_head 可占单步耗时的 10–30%。工程上的应对包括:词表维度做张量并行、lm_head 与采样融合为一个 kernel。这也回答了 02 章留下的悬念——同一张矩阵,Embedding 查表几乎免费,lm_head 全量投影却不便宜 。
温度 T:改变分布尖锐度
T=0.5 集中 T=1 原始 T=2 平坦
Top-K / Top-P:截断候选
Top-K=3
Top-P≈0.9(前4个累计)
候选按概率排序,截断后重新归一化再采样
图 19 左:温度对 softmax 的影响,$p_i\propto e^{z_i/T}$,T 越低越确定、越高越发散;右:Top-K 固定只在前 K 个候选采样,Top-P(nucleus)按累计概率动态截断——候选少而尖时少取、多而平时多取。
惩罚项在 softmax 之前加到 logit 上(取值常为 −2~2,正值抑制、负值鼓励);代码生成场景一般关闭频率惩罚,以免合法的重复变量名被误伤。 约束解码:把非法 ID 提前屏蔽 做后端最常需要模型输出 JSON、代码、函数调用参数等有严格格式 的结果。但自由采样可能在任意位置混入非法字符(缺括号、多余逗号、枚举值乱写),下游解析直接失败。约束解码(Constrained / Guided Decoding) 在每一步采样前,根据目标文法(JSON Schema、正则、BNF)判断当前状态下哪些 token 合法 ,把非法 token 的 logit 屏蔽为 $-\infty$,只在合法集合里采样,从机制上保证输出 100% 可解析。
文法编译为状态机(FSM / PDA)
START 状态0
{
key "..."
: value
}
{ 合法key : 合法value
下一步 logit:非法 token 屏蔽为 −∞
合法
合法
非法 token:logit = −∞,概率 0
图 20 约束解码:文法先编译成状态机(上),每步根据当前状态确定合法 token 集合;在 logit 层把非法位置屏蔽(下),采样只在合法集合中进行。输出从“概率上像”升级为“机制上必然合法”。
OUTLINES Efficient Guided Generation for Large Language Models
Willard & Louf · 2023 · Outlines 的状态机 / 正则引导生成
arXiv:2307.09702
XGrammar XGrammar: Flexible and Efficient Structured Generation Engine for LLMs
Dong et al · 2024 · 高效文法编译与掩码执行
arXiv:2411.15100
GCD Grammar-Constrained Decoding for Structured NLP Tasks without Finetuning
Geng et al. · EMNLP 2023 · 文法约束解码早期系统工作
arXiv:2305.13971 两个工程提醒 ① 当合法 token 恰好是模型很不想要的 token 时,约束会“硬逼”模型走低概率路径,可能导致重复或质量下降——应让提示词与目标格式对齐、并设置合理停止条件;② 约束解码与投机解码、连续批处理不冲突 ,但需要在验证阶段同样施加约束掩码。
投机解码:一次前向,确认多个 Token 前面的优化都在“喂饱”串行解码;投机解码家族更激进——先让一个便宜的“猜测者”一口气写出多个候选 ID,再让大模型用一次并行前向统一验证 ,对的直接采纳、错的丢弃重算。如果猜测足够准,就相当于用一次前向的时间换出了多个 token ,且输出分布与大模型完全一致(无损)。
两阶段:Draft 猜测 → Target 验证
猜测者 Draft
小模型 / 头 / 自身
快速、连续写 k 个
The ✓
cat ✓
sat ✓
on ✗
k 个候选(单链或树)
大模型 Target
一次并行前向验证全部
逐位置接受 / 拒绝
采纳前缀
拒绝处重采样后重来
关键:验证是并行 的(一次前向处理 k 个候选),成本≈一次普通 decode,却可能一次确认多个 token
图 21 Draft→Verify:猜测者快速连续写出 k 个候选,大模型用一次并行前向逐位置校验;接受最长正确前缀,在第一个错误位置按目标分布重采样,然后进入下一轮。
为什么能“无损”:拒绝采样的数学保证 设目标模型分布为 $p(x)$、猜测者分布为 $q(x)$。对候选 token $x$,以概率
$$P(\text{接受}\,x)=\min\!\left(1,\frac{p(x)}{q(x)}\right)$$
决定接受;若被拒绝,则从修正分布 $r(x)\propto\max\big(0,\,p(x)-q(x)\big)$ 中重采样。可以证明:无论 $q$ 准不准,最终被接受的 token 分布严格等于目标分布 $p$ 。直觉上:猜测者认为概率不低于目标的 token($q\ge p$)必然被接受;猜测者高估的 token 会以相应概率被拒、并“修正”回目标分布。猜测越准,接受长度越长、加速越多;猜得再差也只是退回普通解码,不会改变结果 。
SPEC-DEC Fast Inference from Transformers via Speculative Decoding
Leviathan, Kalman, Matias · Google/DeepMind · ICML 2023 · 投机解码开山论文,小模型起草 + 大模型验证,证明无损并给出复杂度分析
arXiv:2211.17192 SPEC-SAMP Accelerating Large Language Model Decoding with Speculative Sampling
Chen et al. · DeepMind · 2023 · 独立提出投机采样(拒绝采样),在对话模型上约 2× 加速
arXiv:2302.01318 接受率的实战经验 :温度越高,草稿与目标分布差异越大、接受率越低,高温创作场景收益会缩水;代码、数学、格式化输出(JSON/SQL)等“高可预测”任务接受长度最长——IDE 补全最先吃到投机红利正因此。评估时按自家任务的温度与内容分布实测接受率 ,别直接搬论文数字。
自投机:用模型自己的“浅层”当草稿 不想维护一个独立小模型,可以让目标模型自身在中间层提前输出(Early Exit / 早退) :用浅层快速起草,再走完整网络验证。只需少量微调让浅层具备预测能力,权重完全共享、部署简单,属于“自投机(Self-Speculative)”。
D&V Draft & Verify: Lossless Large Language Model Acceleration via Self-Speculative Decoding
Zhang et al. · 2023 · 自投机解码代表作,浅层起草 / 深层验证,无损
arXiv:2309.08168 Medusa:给大模型加几个“候选头” Medusa 在冻结的目标模型上新增若干轻量解码头(Medusa Heads) :头 1 预测下一个位置、头 2 预测下两个位置……各头给出 top 候选,组合成一棵候选树 ;再用 Tree Attention (为每条候选路径构造对应因果掩码)在一次前向 里验证整棵树。它不需要逐步自回归起草,配合典型采样(typical sampling)与前缀树,典型加速 2.2–3.6×。
Target 主干
(冻结,权重共享)
Medusa 头 1(+1 位) 头 2(+2 位) 头 3(+3 位) 头 4(+4 位)
候选树(top 候选组合)
Tree Attention:一次前向、按路径掩码验证整棵树
图 22 Medusa:冻结主干 + 多个新增候选头,对未来 k 个位置各提 top 候选并组合成树;Tree Attention 用自定义因果掩码在一次前向中验证所有路径,命中即一次输出多个 token。
MEDUSA Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads
Cai et al. · CMU · ICML 2024 · 多头 + 候选树 + Tree Attention,工程上易插拔
arXiv:2401.10774 EAGLE:在“特征层”而不是 token 层起草 Medusa 直接猜 token,EAGLE 更进一步:把目标模型中层的隐藏特征与已采样 token 一起喂给一个轻量自回归头,在“特征序列”上做预测 ,天然贴合目标模型的内部表示,接受率显著更高。三代演进:
EAGLE(ICML 2024) :特征 + token 起草,静态草稿树,约 3× 量级;
EAGLE-2(EMNLP 2024) :动态草稿树 ——根据上下文置信度自适应分配候选,在“容易错”的地方布更多分支;
EAGLE-3(2025) :提出 Training-Time Test(训练时就模拟测试时的多步草稿过程),去掉特征回归约束、融合低/中/高层特征统一建模,可随训练规模扩展,并原生支持推理(reasoning)模型 ,是当前公开方案中加速比第一梯队。
EAGLE EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty
Li et al. · Microsoft · ICML 2024
arXiv:2401.15077
EAGLE-2 EAGLE-2: Faster Inference with Dynamic Draft Trees
Li et al. · EMNLP 2024
arXiv:2406.16858
EAGLE-3 EAGLE-3: Scaling up Inference Acceleration via Training-Time Test
Li et al. · 2025 · Training-Time Test,支持推理模型,开源加速比领先
arXiv:2503.01840 MTP:把“多 token 预测”做进模型本体 DeepSeek-V3 的 MTP(Multi-Token Prediction,多 token 预测) 把投机能力直接做进模型:主模型之外串联若干 MTP 模块 ,每个模块接收上一位置的隐藏状态 + token embedding ,预测下一个 token;训练时每个模块都作为额外的多任务预测损失(还能提升主模型质量),推理时这些模块自然形成一条候选链 ,再由主模型一次并行验证。DeepSeek-R1 推理即用 MTP 加速。
主模型 输出 h、token
MTP 模块 1 预测 +1 token
MTP 模块 2 预测 +2 token
h+emb h+emb
候选链一次并行验证
接受前缀,无损
训练:MTP 作为多任务损失,同时提升主模型;推理:链式起草
图 23 MTP:主模型与 MTP 模块串联,沿“隐藏状态 + token”链式预测多个未来 token;训练即多任务学习、推理即候选链。相比外挂草稿,它与模型一体化、无额外模型维护成本(DeepSeek-V3/R1)。
DSv3 DeepSeek-V3 Technical Report
DeepSeek-AI · 2024 · MTP 多 token 预测模块的设计、训练损失与推理用法(另含 61 层 MLA、FP8 训练、MoE 细节)
arXiv:2412.19437 Lookahead Decoding:零训练、零小模型的 Jacobi 并行 Lookahead Decoding 完全不引入额外模型、也不做任何微调,而是用 Jacobi 迭代 把“串行解码”变成对一个 2D 窗口的并行猜测 :每条“猜测分支”在窗口内同时尝试多个未来位置(等价于并行 Jacobi 解码),每条“N-gram 分支”从历史维护的 n-gram 池 里取候选序列验证、命中后回填池子。一次前向可能确认多个 token,未命中也无损退回。
2D Jacobi 窗口(并行猜测)
The cat sat
N-gram 池
The cat sat ...
a dog loves ...
chasing after ...
确认的 token 直接输出
窗口向前滑动,继续猜测
Guess 分支 Jacobi 并行;无需训练 / 小模型
图 24 Lookahead:2D 窗口内 Guess 分支做 Jacobi 并行解码、N-gram 分支验证历史 n-gram 并回填;绿色为一次确认的 token。开箱即用、完全无损,适合不能改模型的部署场景。
LOOKAHEAD Break the Sequential Dependency of LLM Inference Using Lookahead Decoding
Fu et al. · Together AI · ICML 2024 · Jacobi 迭代 + n-gram 池,零训练并行解码
arXiv:2402.02057 同属零训练路线的还有 REST(Retrieval-Based Speculative Decoding) :草稿不从模型自身产生,而是从外部语料库检索 与当前上下文匹配的 n-gram 片段作为候选,特别适合代码补全、RAG 等输出大量复用已有文本的场景。
同族还有一个更轻的分支 Prompt Lookup Decoding :草稿不去外部语料库检索,而是直接在当前请求的 prompt 里 匹配 n-gram——代码编辑(输出大量重复上下文)、RAG 摘要(答案抄自检索文档)场景命中率极高,实现只需几十行、几乎零额外开销,常作为投机家族里“先试这个”的起步项。
家族全对比与选型 加速比为各论文/开源报告的典型量级,强依赖于任务(代码/数学等高可预测任务更高)、草稿与目标的匹配度、batch 与硬件;请以自家业务实测为准。 什么时候不该开投机解码 投机的本质是用空闲算力换带宽 :小 batch、带宽受限时,一次验证 k 个候选几乎不比验证 1 个贵,加速立竿见影;但 batch 一大,系统转向 Compute-Bound,验证整棵候选树的额外算力开始挤占吞吐,高并发场景开投机反而可能拉低 Goodput 。线上常见策略是按负载动态开关:低峰开投机追时延,高峰关掉保吞吐(vLLM / SGLang 均支持按并发阈值自动禁用);batch 偏大时也应缩短草稿长度、用小候选树。
能否修改 / 训练目标模型?
有匹配的小模型?
经典 Spec Decoding
Lookahead(零训练)
训练预算 / 可加结构?
Medusa / EAGLE
MTP(原生)
自投机(早退)
全部无损 ;结构化输出再叠加约束解码;推理(reasoning)模型优先 EAGLE-3 / 原生 MTP
高并发服务端:投机与 PD 分离、Continuous Batching 可叠加使用
图 25 选型决策:先看“能不能改模型”,再看训练预算与可加结构;不能改就走 Lookahead / 经典投机,能改则按改动量选自投机、Medusa/EAGLE 或原生 MTP。
05
Detokenizer:把 ID 拼回文字,送到用户眼前 DETOKENIZE & STREAM
采样产出的 ID 是机器内部表示,用户要看到的是文字。Detokenizer 是 Tokenizer 的逆过程:按 ID 查表得到 token 字符串,再按 BPE 的合并规则把它们拼接还原 。这一站计算量极小(仍是 CPU 侧的字符串操作),但有几个直接影响体验的工程细节。
流水线位置导航 · POSITION 输入 Tokenizer 文本转序号 Embedding ID 转向量 Transformer 主干计算 ×L Sampling 挑选序号 Detokenizer 序号转文本 输出 当前环节 · Detokenizer(ID 拼回文本)
采样产出的 ID
812 3051 619 1842
逆查表 ID → token 字符串
un believ able Ġidea
BPE 拼接还原
Ġ → 空格 Ċ → 换行 字节回退处理多语言
unbelievable idea
作为 chunk 流式推给前端
· 遇到停止符(如 <|im_end|> )立即结束、停止符本身不输出
· 投机解码一次确认多个 ID 时,批量 detokenize 后再统一推送
图 26 Detokenizer:ID 逆查表得到子词字符串,按 BPE 规则拼接(Ġ 还原为空格、Ċ 还原为换行),还原出的文本以 chunk 流式推送;停止符不输出,多语言经字节回退正确还原。
三个工程细节
流式优先 :不等整句生成完,每凑齐一个可显示的片段(一个词或标点边界)就立即推送,配合低 ITL 形成“打字机”体验;注意不要在多字节字符(中文/emoji)的中间切开,否则前端出现乱码。
特殊 token 过滤 :停止符、填充符、对话模板标记(<|im_end|> 等)只用于控制流程,绝不能出现在最终文本里。
与投机解码对齐 :一批被接受的 token 应一次性 detokenize ,避免逐个推送造成的抖动;未被接受的候选不进入这一步。
还有两类“输出形态”的细节:一是工具调用 / Function Calling ——其参数本质是一段受约束的 JSON(4.2),流式解析要按增量 JSON 的方式边收边校验,而不是攒到完整再 parse,否则工具执行要等到输出结束才能启动;二是内容安全审核 通常挂在这一环节——流式场景采用“缓冲若干 token 送审、命中风险立即截断”的策略,审核窗口会额外增加首 chunk 延迟,需要在体验与合规之间取平衡。
多模态输出 多模态模型的输出可以是文本、图像、音频或工具调用:文本走上述 Detokenizer;图像/音频由对应的扩散/声码器等生成模块产出,再与文本片段按时间线/布局混合呈现。无论输出形态如何,“模型产出内部表示 → 解码为用户可感知内容 → 流式交付”的结构是一致的。
06
并发请求:批处理、前缀复用与 PD 分离 SERVING & SCHEDULING 前面五章跟踪了一个请求从输入到输出的完整旅程;服务端真正面对的是成千上万个请求同时处在流水线的不同环节:有的在 Prefill、有的在 Decode、有的刚结束。这一层横切所有环节,核心命题是调度粒度、显存组织与架构解耦,目标是把 GPU 吞吐打满。本章先看静态做法的痛点与天花板(6.1),再讲机内调度手段(6.2),最后是架构级的 PD 分离(6.3)。
流水线位置导航 · POSITION 输入 Tokenizer 文本转序号 Embedding ID 转向量 Transformer 主干计算 ×L Sampling 挑选序号 Detokenizer 序号转文本 输出 并发请求 · 覆盖流水线每一个环节 Continuous Batching · PagedAttention · Chunked Prefill · RadixAttention · PD 分离
06 并发请求 · 多请求同时处在流水线的不同环节
多请求持续到达
全局调度器(每 iteration 重排)
GPU 资源池
6.1 背景
痛点·天花板·指标
Static Batching 三痛点
木桶效应 · 无法动态加入
按最大长度预留→碎片
带宽反推 TPS 天花板
7B/A10 ≈ 43 TPS(理论)
实测 ~30,差距即优化空间
服务指标体系
TTFT · ITL · TPS
Goodput(SLO 达标吞吐)
6.2 机内优化
调度器统一驱动
Continuous Batching
iteration 级进出
GPU 持续满载(ORCA)
Chunked Prefill
长 prompt 切块
与 Decode 交错护 ITL
RadixAttention
基数树 + 最长前缀匹配
公共前缀只算一次
6.3 架构解耦
PD 分离
Prefill 池 → KV 高速迁移(NVLink / RDMA / NIXL)→ Decode 池
两池硬件、卡数、并行策略独立扩缩容;P/D 吞吐差约 140 倍,混部双输
DistServe · Mooncake · Splitwise · NVIDIA Dynamo
脉络:机内手段把单 GPU 打满;P/D 矛盾无法调和时走向架构解耦——目标:Goodput 最大化、每 token 成本最小化
图 27 06 章结构地图 :6.1 背景(Static Batching 痛点、TPS 天花板、指标体系);6.2 机内优化(Continuous Batching / Chunked Prefill / RadixAttention);6.3 架构解耦(PD 分离)。
背景:并发处理时 GPU 算力的浪费 最简单的批处理是凑齐一批请求、同时开始、等整批都生成完再返回、再放下一批。它有三个致命问题:
木桶效应 :整批被最长的请求拖住,短请求早早算完也只能空等;
无法动态加入 :新请求必须等上一批全部结束,期间 GPU 槽位空闲;
显存按最大长度预留 :不管实际生成多少都按上限占位,内部碎片严重、且无法在请求间共享(3.2 的 PagedAttention 正是为解决这个问题)
Static Batching
Continuous
iteration 级调度
最慢者决定整批
空槽无法复用
不同颜色 = 不同请求;谁完成就立刻在该槽位放入新请求
每个 iteration 重新组 batch,GPU 几乎不空闲
吞吐显著高于静态批处理(业界主流默认)
图 28 Static Batching(上)整批同进同出,短请求空等最慢者、槽位浪费;Continuous Batching(下)把调度粒度从“整批”细化到每个 iteration(一次前向) ,请求完成后立即在空槽插入新请求,GPU 持续满载。
浪费之外,再算清单卡的理论天花板,才知道优化空间有多大。
STEP 1 · 权重
7B × 2B ≈ 14 GiB
FP16/BF16 常驻显存,A10 24GB 可容纳
→
STEP 2 · 带宽
600 GB/s
A10 GDDR6 峰值(H100 为 3.35TB/s)
→
STEP 3 · 读一遍
14 / 600 ≈ 23 ms
单 token 最短访存时间
→
STEP 4 · 理论上限
1 / 23ms ≈ 43 TPS
batch=1、纯读权重
理论 vs 现实 A10 上 7B 单请求实测约 30 TPS 量级 (随上下文变长继续下降)——因为还要读取随序列增长的 KV Cache、kernel launch / 调度开销、带宽利用率不可能 100%;同口径 H100 理论天花板约 238 TPS。理论值的意义是给出“天花板” :当实测离天花板很远时,说明还有调度或访存可挖;batch 拼大后吞吐可逼近“带宽×算术强度”的整体上限。
MoE 口径:上面按“每步读全部权重”估算;MoE 模型每步只读激活专家 的权重,如 Qwen3-30B-A3B 单 token 约读 3.3B × 2B ≈ 6.6 GiB,A10 上的理论天花板相应抬到 ~90 TPS 量级——代价是 30.5B 总参数仍需完整装进显存(单机放不下就要多卡并行分摊,见 6.3)。 谈优化前还要先定义「好」:下面这套指标贯穿本章与第 3 章。
机内优化:动态拼批、切块调度与前缀复用 6.1 的痛点对应三类机内手段:调度粒度细化到 iteration(Continuous Batching)、长 Prefill 切块交错(Chunked Prefill)、公共前缀缓存复用(RadixAttention);显存摆放问题(PagedAttention)已在 3.2 讲过。
Continuous Batching (ORCA 首创)把调度单位从「整批」细化到每个 iteration(一次前向):完成的请求立刻离开、空槽插入新请求,GPU 持续满载(时序对比见上图)。
ORCA Orca: A Distributed Serving System for Transformer-Based Generative Models
Yu et al. · OSDI 2022 · 首次提出 iteration-level 调度与 selective batching,是连续批处理的源头
USENIX OSDI'22 Continuous Batching 还有一个高负载下绕不开的问题:KV Cache 不够装时怎么办 。当并发请求的 KV 总量逼近显存上限,调度器必须抢占(Preemption) 一部分请求腾地方——vLLM 提供两种策略:重计算(Recompute) ,丢弃被抢占请求的全部 KV、轮到时重跑 Prefill,实现简单但时延开销大;换出(Swap) ,把 KV 临时搬到 CPU 内存、轮到时再搬回,省算力但吃 PCIe 带宽。工程上通常配合优先级队列与最大并发上限,把抢占压成偶发事件——频繁抢占本身就是“该扩容或上 PD 分离(6.3)”的信号 。
Prefill 是 Compute-Bound,一个几万 token 的长请求会连续占用 GPU 多个 iteration ,期间正在 Decode 的请求得不到调度,ITL 出现尖刺、用户明显卡顿。Chunked Prefill 把长 Prefill 切成固定小块(chunk),与 Decode 请求在 iteration 级别交错执行 ,必要时还把多个 prefill 块拼进同一 batch,兼顾首 token 时延与吞吐。chunk 大小是关键参数 :切得太小,Prefill 效率下降、调度开销上升;切得太大,ITL 尖刺依旧。vLLM 默认 chunk 约 2048 token(长 prompt 场景可调大到 4096–8192),正确姿势是固定业务流量、按 TTFT 与 ITL P99 实测调参。
无 Chunked:长 Prefill 独占
Prefill(连续数百 iteration)
Decode 请求全程排队 → ITL 尖刺、卡顿
Chunked:切块与 Decode 交错
P=Prefill块 D=Decode
ITL 保持平滑
图 29 Chunked Prefill:长 Prefill 被切成 chunk(橙)与 Decode(青)在 iteration 级交错,避免长请求阻塞解码;现代推理引擎(vLLM / SGLang / TensorRT-LLM)均已默认开启。
SARATHI Sarathi: Efficient LLM Inference by Pipelining Token Computation (Chunked Prefill)
Agrawal et al. · 2023 · 首次提出 chunked prefill + decode 流水
arXiv:2308.16369
SARATHI-SERVE Sarathi-Serve: Chase Away Prefix Queue Under Chunked Prefills
Agrawal et al. · OSDI 2024 · Stall-free 调度,延迟与吞吐协同
arXiv:2403.02310
多轮对话、Agent、共享系统提示、few-shot 场景里,大量请求共享相同前缀。SGLang 提出 RadixAttention :用一棵 基数树(Radix Tree) 维护所有处理过的 prompt,新请求自动做最长前缀匹配 ,命中的 KV 直接复用、未命中部分才算;缓存紧张时按 LRU 驱逐 最少使用的叶子。它与 PagedAttention 是搭档——分页管“块怎么放”,基数树管“哪些前缀能复用”。
ROOT The capital of
Britain → London France → Paris China → Beijing
青色节点:公共前缀
一次计算、多请求复用
叶子可 LRU 驱逐
图 30 RadixAttention 基数树:“The capital of”作为公共前缀只算一次并被三个请求共享;分叉部分各自计算。多轮对话 / Agent / 公共 system prompt 场景命中率极高。
SGLANG SGLang: Efficient Execution of Structured Language Model Programs
Zheng et al. · NeurIPS 2024/2025 · RadixAttention 自动前缀复用 + 结构化生成运行时
arXiv:2312.07104 一个工程提醒:RadixAttention 的收益完全取决于前缀命中率 ——多轮对话、共享 system prompt、Agent 场景命中率常超过 50%;但如果业务里每条 prompt 都互不相同(如独立文档的离线批处理),前缀缓存只会白占显存,此时应调低缓存容量甚至关闭。上线前用真实流量统计命中率(vLLM / SGLang 均暴露 prefix cache hit rate 指标),比盲目开启更重要。
架构级优化:PD 分离 当 Prefill 与 Decode 的资源矛盾在机内无法靠调度调和时,必然走向架构解耦。
为什么必须分离:两阶段资源诉求相差约 140 倍。
同一个模型、同一块卡,Prefill 与 Decode 的吞吐差距是数量级的。以 20 层模型在消费级卡上的实测为例(视频作者数据):Prefill 约 14,000 token/s,Decode 约 100 token/s,相差约 140 倍 。更麻烦的是二者对硬件的偏好相反:
Prefill 要强算力 (高 FLOPs、可接受较小显存),算力越猛 TTFT 越低;
Decode 要大显存 + 高带宽 (装得下权重与大量 KV、搬得快),算力反而不重要。
把两阶段混部(Co-located) 在同一批 GPU 上,会互相干扰:长 Prefill 拖慢 Decode 的 ITL,Decode 又占着算力让 Prefill 排队,资源配比无法同时满足两边,整体利用率与 SLO 双输。
吞吐差距(20 层模型实测)
Prefill
~14,000
tok/s
Decode ~100 tok/s
≈ 140×
集群利用率(示意)
混部 Co-located
~40%(互相干扰)
PD 分离 Disaggregated
~85%
两类资源独立扩缩容、各跑最适合的阶段
Mooncake:吞吐 +75%、TTFT −25%
图 31 左:Prefill/Decode 吞吐差约两个数量级;右:混部互相干扰、利用率低,PD 分离后两类资源独立配比、利用率与 SLO 同时改善(数值为论文/实测量级,具体随模型与硬件变化)。
怎么做:两池拆分,KV 迁移。
核心是把两阶段拆到不同 GPU 池、各自独立扩缩容 :请求先进 Prefill 池完成提示计算与首 token,生成的 KV Cache 通过高速互联整体搬运/复制 到 Decode 池,再由 Decode 池完成后续自回归生成并流式返回。难点不在“拆”,而在KV Cache 的高效迁移与全局调度 。
全局调度器 / 路由(SLO 感知)
Prefill GPU 池
高 FLOPs 配置,算力优先
KV 迁移层
RDMA / NVLink
GPUDirect / NIXL
页对齐、零拷贝传输
Decode GPU 池
大显存 / 高带宽配置
推送 KV
流式输出 token
图 32 PD 分离架构:全局调度器把请求导向 Prefill 池,KV 经高速迁移层送到 Decode 池独立生成。两池硬件型号、卡数、并行策略可完全不同,按各自瓶颈独立扩缩容。
两池内部的并行策略也可以各自选。 推理常用的并行方式有三种:张量并行(TP) 把每层权重切到多卡、每层两次 AllReduce——Decode 带宽受限时,TP 让单卡搬运量除以 N(图 32),是 Decode 池最常用的手段,代价是通信随卡数上升(A10 无 NVLink、走 PCIe,一般不超过 2–4 卡);流水并行(PP) 按层切分、卡间只传激活,通信少但调度复杂,推理用得少;专家并行(EP) 是 MoE 专属,专家分到不同卡、token 经 All-to-All 路由。Prefill 池偏算力、常配较大 TP;Decode 池偏带宽与显存,TP / EP 按 KV 容量与带宽目标定——这就是图 31 里“两池并行策略可完全不同”的具体含义。
一层权重矩阵 W(按列切成 4 块)
GPU 0 · 列块 1/4 GPU 1 · 列块 2/4
GPU 2 · 列块 3/4 GPU 3 · 列块 4/4
各算部分和 各算部分和
各算部分和 各算部分和
AllReduce
各部分和跨卡相加
完整输出
每层 2 次 AllReduce(注意力投影后、MLP 后);Decode 带宽受限时单卡权重搬运量 ÷ N,代价是通信开销随卡数上升
图 33 张量并行(TP):把一层权重按列切到 4 张卡,各卡只存、只读自己的分块并算部分和,再经 AllReduce 合并出完整输出。Decode 池常用 TP 压低单卡搬运量;无 NVLink 的卡(如 A10)通信走 PCIe,TP 规模不宜大。
三篇奠基论文,三种侧重。
DistServe DistServe: Disaggregating Prefill and Decoding for Goodput-optimized LLM Serving
Zhong et al. · UC Berkeley / UChicago · OSDI 2024 · 用 Goodput(SLO 达标吞吐)论证分离的必要性,两阶段独立部署、独立并行策略,Goodput 提升数量级
arXiv:2401.09670 Mooncake Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving
Qin et al. · Moonshot AI / 清华大学 · FAST 2025 最佳论文(期刊扩展版 ACM TOS 2025)· 以 KV Cache 为中心,Prefill/Decode 分离 + 跨 GPU/CPU/SSD 的全局 KV Cache Pool 与 KV Agent 调度;集群吞吐 +75%、TTFT −25%(Kimi 生产验证,已开源)
arXiv:2407.00079 Splitwise Splitwise: Efficient Generative LLM Inference Using Phase Splitting
Patel, Choukse et al. · Microsoft · ISCA 2024 · 把 Prefill/Decode 拆到最具性价比的异构硬件 上(强算力卡跑 Prefill、大显存/低成本卡跑 Decode),以最小化每 token 成本,KV 经 RDMA 迁移
arXiv:2311.18677 关键工程问题:KV Cache 怎么搬。
工程上还会做:KV 块页对齐、压缩后再传(FP8)、传输与计算重叠、只传增量 ,把迁移成本摊到流水线里,使它不成为新瓶颈。另一个配套手段是 KV 分层 offload :热 KV 留在 GPU 显存,温 KV 下沉 CPU 内存,冷 KV(如多轮对话的历史轮次)落 SSD——Mooncake 的全局 KV Pool 正是这一思路的集群化,让显存只装“正在用”的部分。
GPU HBM · 热 KV
正在 Decode 的请求 · TB/s 级带宽 · 最贵
CPU 内存 · 温 KV
被抢占 / 等待调度的请求 · 百 GB/s 级
SSD · 冷 KV
多轮历史、跨会话复用 · GB/s 级 · 最便宜
换出 / 换回 落盘 / 加载
命中即免重算 Prefill
Mooncake 把这套分层
做成集群级 KV Pool
图 34 KV 分层 offload:热 KV 留 GPU 显存、温 KV 下沉 CPU 内存、冷 KV 落 SSD;请求重新激活时命中即免于重跑 Prefill。层级越往下带宽越低、成本越省——Mooncake 的 KV Pool 正是这一思路的集群化。
前沿:PD 分离正在「产品化、标配化」。
NVIDIA Dynamo(2025 GTC 开源) NVIDIA 推出的开源分布式推理编排框架,原生支持 Prefill/Decode 分离、GPU 异构与 SLO 感知路由 ,并配套 NIXL(NVIDIA Inference Xfer Library) 做跨机 KV Cache 的异步零拷贝传输,与 TensorRT-LLM / vLLM 等引擎解耦。这标志着 PD 分离从“论文最佳实践”变成开箱即用的标准架构 ;vLLM、SGLang、Mooncake 也都已内置 disaggregated 模式。
两章手段如何叠加 机内优化(6.2)把单块 GPU 打满,架构解耦(6.3)让两类资源独立扩缩;它们与第 3 章的 KV Cache 家族、FlashAttention、量化全部可叠加——最终目标都是 SLO 达标前提下最大化 Goodput、最小化每 token 成本。
07
总结、落地清单与前沿趋势 SUMMARY & OUTLOOK
一句话串起全文
沿着一次请求走一遍:文字或图片经 Tokenizer(及视觉编码器)变成 ID 序列,Embedding 查表层把 ID 变成向量,Transformer 层在 Prefill/Decode 两节拍里完成推理计算,lm_head 把隐藏向量变回 logits,采样选出下一个 ID,Detokenizer 把 ID 拼回文字流式输出,再把选中的 ID 喂回入口循环往复 。每个环节的优化都有明确指向:输入侧 异步分词、识别公共前缀;计算侧 KV Cache、GQA/MLA、FlashAttention、量化与 KV 驱逐;调度侧 Continuous Batching、PagedAttention、Chunked Prefill、RadixAttention 与 PD 分离;采样侧 温度/Top-P 旋钮、约束解码与投机解码家族。它们大多无损、可叠加 ,最终目标是在 SLO 达标前提下最大化 Goodput、最小化每 token 成本。
$$\text{每 token 成本}\ \approx\ \frac{\text{GPU 时价}\times\text{卡数}}{\text{SLO 达标下的 Goodput(token/s)}\times 3600}$$
这条公式是全文所有优化的最终折算口径:Goodput 越高,每 token 成本越低 ——PD 分离的资源重配、Splitwise 的异构分工、KV 压缩换来的更高并发,最终都在这条公式上见效。
工程落地 Checklist(按流水线环节)
推理加速
优先选 GQA / MLA 架构,从源头减小 KV
开启 FlashAttention(Prefill)与 KV Cache(Decode)
权重 INT8 / AWQ(A10 无 FP8)、KV 上 KIVI(INT8)
Decode 开启 CUDA Graph,消除 kernel launch 开销
MoE 模型:显存按总参数规划、带宽按激活参数估算
长上下文叠加 H2O / SnapKV 驱逐
并发与调度
Continuous Batching 取代静态批处理
PagedAttention 分页,设合理 block(如 16)
Chunked Prefill 平衡 TTFT/ITL;RadixAttention 缓存前缀
高负载上 PD 分离,KV 走 RDMA/NVLink/NIXL
采样与输出
按决策图选投机方案(EAGLE/MTP/Lookahead)
按负载动态开关投机解码:低峰追时延、高峰保吞吐
结构化输出上约束解码(Outlines/XGrammar/GBNF)
特殊 token 过滤,避免在多字节字符中间切流
监控 TTFT / ITL P99 / TPS / Goodput 与 KV 命中率
压测口径:TTFT / ITL / TPS 建议用 vllm bench serve、NVIDIA GenAI-Perf 等基准工具、在接近真实的流量分布(prompt 长度、输出长度、并发曲线)下测量;平均值会掩盖长尾,SLO 相关指标一律看 P95 / P99。Goodput 的测法:固定 SLO 阈值、逐步加并发,达标率跌破线时的吞吐即 Goodput。
推理引擎怎么选
全文提到的引擎能力正在收敛(趋势 7),但侧重仍有差异,选型先看业务画像:
常见反模式(各章边界条件的汇总) ① 盲目调大 batch :吞吐升了、TTFT/ITL 劣化,Goodput 反而下降(6.1);② 高并发开投机解码 :系统已是 Compute-Bound,额外验证算力拖低吞吐(4.3);③ Compute-Bound 场景做权重量化 :W4A16 只省带宽,瓶颈不在带宽时无收益(3.4);④ 前缀各异的业务开 RadixAttention :命中率≈0 还白占显存(6.2);⑤ KV 驱逐不看 Attention Sink :丢掉开头几个 token,输出立刻崩坏(3.2)。共同教训:先用 Roofline 与指标判瓶颈,再选优化手段 。
前沿趋势(2025–2026)
PD 分离“标配化” :NVIDIA Dynamo + NIXL、vLLM/SGLang/Mooncake 全部内置,分离架构成为大规模部署默认项。
KV Cache 成为一等公民 :跨节点/跨层级(GPU/CPU/SSD)池化、持久化、按需复用甚至单独计费,系统设计从“以计算为中心”转向“以 KV 为中心” 。
推理(Reasoning / 思考)模型普及 :长 thinking 阶段让 Prefill/Decode 比例剧变,Chunked Prefill、PD 配比与面向推理模型的投机解码(EAGLE-3 等) 成为新重点。
MoE / EP 推理性价比 :大参数、小激活(如 Qwen3-30B-A3B),需要 expert 并行、All-to-All 通信与专家负载均衡配套。
测试时计算(Test-Time Compute) :多路径采样、树/并行验证、自评估与搜索进入推理引擎,天然依赖 Tree Attention 与批量验证能力。
硬件与精度 :GB200 NVL72 把整机做成一个 NVLink 域、HBM3e 与 FP8/FP4 普及,带宽与互联持续抬高 Roofline 屋顶。
引擎能力收敛 :vLLM、SGLang、TensorRT-LLM 在分页、前缀、PD、投机上能力趋同,竞争转向调度智能、异构支持与端到端成本。
稀疏与混合注意力进入主线模型 :NSA / MoBA 等可训练稀疏注意力与 SWA 混合层(Gemma 2/3、Qwen3-Next 等)把长上下文注意力成本压到近线性,"装得少"正从运行时手段变成模型结构的默认项(3.2)。
一个整体判断 这是一个“系统工程 + 算法理解”双密集 的方向:并发、缓存、调度、内存管理的系统经验几乎都能平移(分页=虚拟内存、Continuous Batching=动态线程池、PD 分离=读写分离、前缀树=连接复用),但必须建立在对 Transformer 计算特征与论文方法的理解之上——这也是按“一次请求从输入到输出”梳理全篇的原因。
建议的读论文顺序
打地基:Transformer → FlashAttention
显存与服务:vLLM/PagedAttention → SGLang → Sarathi-Serve
架构:DistServe → Mooncake → Splitwise
解码算法:Speculative Decoding → Medusa → EAGLE (→2→3)→ DeepSeek-V3 MTP → Lookahead
压缩与长上下文:StreamingLLM → H2O → SnapKV → YaRN → XGrammar
参考文献
Attention Is All You Need Vaswani et al. · NeurIPS 2017 · Transformer 原始论文 arXiv:1706.03762
Fast Transformer Decoding: One Write-Head is All You Need (MQA) Shazeer · 2019 arXiv:1911.02150
GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints Ainslie et al. · EMNLP 2023 arXiv:2305.13245
FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness Dao et al. · NeurIPS 2022 arXiv:2205.14135
FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning Dao · 2023 arXiv:2307.08691
FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision Shah et al. · NeurIPS 2024 arXiv:2407.08608
Orca: A Distributed Serving System for Transformer-Based Generative Models Yu et al. · OSDI 2022 · iteration-level 调度源头 USENIX OSDI'22
Efficient Memory Management for LLM Serving with PagedAttention (vLLM) Kwon et al. · SOSP 2023 arXiv:2309.06180
Sarathi: Efficient LLM Inference by Pipelining Token Computation Agrawal et al. · 2023 · Chunked Prefill arXiv:2308.16369
Sarathi-Serve: Chase Away Prefix Queue Under Chunked Prefills Agrawal et al. · OSDI 2024 arXiv:2403.02310
SGLang: Efficient Execution of Structured Language Model Programs (RadixAttention) Zheng et al. · NeurIPS 2024/2025 arXiv:2312.07104
DistServe: Disaggregating Prefill and Decoding for Goodput-optimized LLM Serving Zhong et al. · OSDI 2024 arXiv:2401.09670
Splitwise: Efficient Generative LLM Inference Using Phase Splitting Patel, Choukse et al. · ISCA 2024 arXiv:2311.18677
Mooncake: A KVCache-centric Disaggregated Architecture for LLM Serving Qin et al. · FAST 2025 最佳论文 / ACM TOS 2025 arXiv:2407.00079
NVIDIA Dynamo:开源分布式推理编排框架(含 NIXL KV 传输) NVIDIA · 2025 · PD 分离产品化 github.com/ai-dynamo/dynamo
Fast Inference from Transformers via Speculative Decoding Leviathan, Kalman, Matias · ICML 2023 arXiv:2211.17192
Accelerating LLM Decoding with Speculative Sampling Chen et al. · DeepMind · 2023 arXiv:2302.01318
Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads Cai et al. · ICML 2024 arXiv:2401.10774
EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty Li et al. · ICML 2024 arXiv:2401.15077
EAGLE-2: Faster Inference of Language Models with Dynamic Draft Trees Li et al. · EMNLP 2024 arXiv:2406.16858
EAGLE-3: Scaling up Inference Acceleration via Training-Time Test Li et al. · 2025 arXiv:2503.01840
Break the Sequential Dependency of LLM Inference Using Lookahead Decoding Fu et al. · ICML 2024 arXiv:2402.02057
DeepSeek-V2: A Strong, Economical, and Efficient MoE Language Model (MLA) DeepSeek-AI · 2024 arXiv:2405.04434
DeepSeek-V3 Technical Report (MTP / MLA / FP8) DeepSeek-AI · 2024 arXiv:2412.19437
Draft & Verify: Lossless LLM Acceleration via Self-Speculative Decoding Zhang et al. · 2023 arXiv:2309.08168
REST: Retrieval-Based Speculative Decoding Ankner et al. · 2023 · 用检索 n-gram 数据起草 arXiv:2311.08252
H2O: Heavy-Hitter Oracle for Efficient Generative Inference of LLMs Zhang et al. · NeurIPS 2023 arXiv:2306.14048
SnapKV: LLM Knows What You Are Looking for Before Generation Li et al. · NeurIPS 2024 arXiv:2404.14469
KIVI: A Tuning-Free Asymmetric 2bit Quantization for KV Cache Zhang et al. · ICML 2024 arXiv:2402.02750
GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers Frantar et al. · ICLR 2023 arXiv:2210.17323
SmoothQuant: Accurate and Efficient Post-Training Quantization for LLMs Xiao et al. · ICML 2023 arXiv:2211.10438
AWQ: Activation-aware Weight Quantization for On-Device LLM Compression Lin et al. · MLSys 2024 arXiv:2306.00978
Grammar-Constrained Decoding for Structured NLP Tasks without Finetuning Geng et al. · EMNLP 2023 arXiv:2305.13971
Efficient Guided Generation for Large Language Models (Outlines) Willard & Louf · 2023 arXiv:2307.09702
XGrammar: Flexible and Efficient Structured Generation Engine for LLMs Dong et al. · 2024 arXiv:2411.15100
Roofline: An Insightful Visual Performance Model for Multicore Architectures Williams, Waterman, Patterson · CACM 2009 ACM DOI
Efficient Streaming Language Models with Attention Sinks (StreamingLLM) Xiao et al. · ICLR 2024 · Attention Sink + 滑动窗口,KV 有界的无限流式生成 arXiv:2309.17453
Extending Context Window of Large Language Models via Positional Interpolation (PI) Chen et al. · Meta · 2023 · 位置插值扩上下文 arXiv:2306.15595
YaRN: Efficient Context Window Extension of Large Language Models Peng et al. · ICLR 2024 · 分频段 RoPE 外推,长上下文主流方案 arXiv:2309.00071
Native Sparse Attention: Hardware-Aligned and Natively Trainable Sparse Attention (NSA) Yuan et al. · DeepSeek-AI · 2025 · 可训练稀疏注意力 arXiv:2502.11089
MoBA: Mixture of Block Attention for Long-Context LLMs Lu et al. · Moonshot AI · 2025 · 块混合稀疏注意力(Kimi 长上下文方案) arXiv:2502.13189
Mistral 7B Jiang et al. · Mistral AI · 2023 · 滑窗注意力(SWA)进入主流模型的开端 arXiv:2310.06825
Min P Sampling: Balancing Creativity and Coherence at High Temperature Nguyen et al. · 2024 · 按比例动态截断的采样方法 arXiv:2407.01082
大模型推理与加速技术全景 · AI Infra 方向学习分享
本文基于个人学习笔记整理,并参考上述公开论文与开源框架文档;示意图为原创绘制,数据为论文/实测量级,具体指标请以业务实测为准。
分享人:__________ 日期:__________
↑
滚轮缩放 · 拖拽平移 · 双击复位 · ESC 退出
×
+ −
Fit
Close