推测解码为什么能加速大模型推理
大模型生成文本有一个天然限制:它通常是一个 token 一个 token 往外吐。
这叫自回归生成。前一个 token 出来以后,模型才能继续生成下一个 token。结果就是,哪怕 GPU 很强,decode 阶段也容易变成一段很长的串行过程。
推测解码要解决的,就是这个串行瓶颈。
推测解码(Speculative Decoding):让一个更小、更快的草稿模型先猜多个 token,再让目标大模型一次性验证这些 token。猜对的直接接受,猜错的由目标模型修正。它的目标是用更少的大模型前向次数生成更多 token。
先猜,再验证
我通常这样解释推测解码:小模型先做草稿,大模型当审核。
假设目标模型本来要生成“我爱中国”:
Step 1: 输入“我”,输出“爱”
Step 2: 输入“我爱”,输出“中”
Step 3: 输入“我爱中”,输出“国”
Step 4: 输入“我爱中国”,输出 EOS
传统方式需要大模型跑 4 次。
推测解码会让草稿模型先猜:“爱 中国 EOS”。然后目标模型把这几个候选 token 放在一起验证。如果前两个 token 命中,第三个 token 没命中,那也不是失败。系统至少用一次目标模型前向确认了两个 token,还顺手修正了错误位置。
Draft Model(草稿模型):负责快速提出候选 token 的小模型或轻量模块。它不决定最终输出质量,只负责提高“猜中”的概率。
Target Model(目标模型):真正要部署的大模型。最终接受或修正 token 的权力在它手里,所以推测解码可以在数学上保持目标模型的输出分布。
接受率决定收益
推测解码能不能加速,关键看接受率。
接受率(Acceptance Rate):草稿模型提出的候选 token 中,被目标模型接受的比例。比如草稿猜 5 个 token,目标模型接受 3 个,接受率就是 0.6。
接受率越高,一次目标模型验证能“带走”的 token 越多,加速越明显。接受率太低,就会出现小模型白忙活的情况:草稿计算花了时间,但目标模型没接受几个。
这里有一个容易误解的点:草稿模型不是越大越好。草稿模型太小,猜不准;太大,又把节省下来的计算成本吃回去了。真正要找的是“足够便宜,同时足够像目标模型”的平衡点。
Medusa:不额外部署小模型
Medusa 的思路很工程化:既然额外部署一个草稿模型会让系统复杂,那能不能在原模型上加多个预测头?
Medusa:一种给大模型增加多个解码头的推理加速框架。它让模型不仅预测下一个 token,还尝试预测后续几个 token,然后再做验证。
它的优势是部署形态更统一,不一定要维护一个独立 draft model。对很多线上系统来说,这比“再挂一个小模型”更容易管理。
但它也有代价:你要训练或适配这些额外 decoding heads,还要处理 Tree Attention 这类验证结构。也就是说,Medusa 简化的是模型部署数量,不是把工程复杂度完全消灭。
Tree Attention(树状注意力):可以理解为一次性验证多条候选 token 路径时使用的 attention 结构。它不是简单的一条序列,而是要处理候选树上的分支关系。
EAGLE:在特征层做草稿
EAGLE 的路线更进一步。它不是只在 token 层面硬猜,而是利用目标模型的中间特征来预测后续 token。
EAGLE:一种基于特征预测的推测解码方法。它用轻量 draft 模块预测后续特征和 token,再交给目标模型验证,从而提升候选质量。
EAGLE-1 和 EAGLE-2 已经能带来明显加速,但在大 Batch 场景下会遇到一个问题:当 GPU 已经接近 Compute-Bound,草稿阶段带来的额外计算可能抵消收益。
Compute-Bound(计算受限):系统瓶颈在计算能力上,GPU 算力已经接近吃满。继续增加额外计算,不一定能换来更高吞吐。
Memory-Bound(内存受限):系统瓶颈在显存带宽或内存访问上,计算单元没有完全吃满。推测解码在这种场景下更容易把空闲算力利用起来。
教案里有个判断很关键:Batch 小的时候,decode 阶段更容易 memory-bound,推测解码加速明显;Batch 已经很大时,GPU 接近 compute-bound,推测解码的边际收益会下降。
这也是我会纠正的一个常见说法:推测解码不是任何场景都一定加速。它是否划算,要看 batch size、草稿成本、接受率和目标模型当前瓶颈。
EAGLE-3 解决了误差累积
EAGLE-1 和 EAGLE-2 的一个隐藏问题,是训练和推理不一致。
训练时,draft 模块看到的是目标模型的真实特征;推理时,它看到的可能包含自己上一步预测出来的特征。一步错,后面就会累积误差,接受率逐步下降。
EAGLE-3 的改进点是 Training-time Test。
Training-time Test(训练时测试):在训练阶段模拟推理时的多步生成,让 draft 模块提前适应“自己预测过的中间状态”。这样推理时遇到误差累积,模型不至于马上崩掉。
这个思路很像训练方式从“看标准答案做题”变成“闭卷模拟考试”。模型训练时就见过自己可能犯错的路径,线上推理时稳定性更好。
教案里的结论也很明确:EAGLE-1/2 在 Batch=64 时几乎没有吞吐收益,而 EAGLE-3 仍能保持约 1.38x 的吞吐提升。这说明它不是只在实验室小 batch 里好看,而是更贴近高并发生产场景。
和 vLLM 结合时,难点不只是算法
把推测解码接进 vLLM,不是把论文名字写进启动参数就结束了。
它至少有三个工程冲突。
第一,草稿阶段和 Continuous Batching 的节奏不同。草稿阶段常常更适合小 batch 或 micro-batch,而 vLLM 主流程希望动态 batch 保持 GPU 利用率。
第二,Medusa 或 EAGLE 的验证阶段可能需要 Tree Attention、特殊 mask 或自定义 attention backend。
第三,草稿模型和目标模型都会占显存,也都会产生 KV Cache。这里又回到了第一篇文章讲的 PagedAttention:如果没有统一的 KV Cache 管理,推测解码可能把显存压力放大。
一个简化的 vLLM + EAGLE iteration 可以这样理解:
# 中文注释:从当前 batch 里挑出适合做推测解码的请求
draft_requests = select_for_speculation(current_batch)
# 中文注释:轻量 EAGLE 模型先生成 3 到 5 步候选 token 树
for step in range(max_draft_tokens):
draft_features = eagle_model.forward(target_features, previous_tokens)
draft_tokens = sample(draft_features)
# 中文注释:目标模型并行验证候选 token,并返回被接受的长度
verified_tokens, accepted_length = tree_verify(
draft_tokens,
target_model_logits,
)
# 中文注释:只保留被接受 token 对应的 KV blocks,释放被拒绝路径占用的 blocks
update_block_table(request, accepted_length)
这段流程里,算法收益和系统调度绑在一起。只要候选选择、验证、显存释放任意一环做得粗糙,加速都可能打折。
用不用呢?
推测解码的本质不是“让模型乱猜”,而是“用便宜计算换掉一部分昂贵计算”。
我会用四个问题判断它是否值得上生产:
- 当前 decode 阶段是 memory-bound 还是 compute-bound?
- 草稿模型或草稿头的成本有多低?
- 接受率是否足够稳定?
- 大 batch 下吞吐是否真的提升,而不是只优化了单请求延迟?
如果这些问题回答不清楚,推测解码很容易从加速器变成额外负担。反过来,如果接受率稳定、草稿成本低、KV Cache 管理也跟得上,它确实是大模型推理服务里很有价值的一把刀。