自回归解码有一个无法回避的结构性约束:它是严格串行的。第 n 个 token 不出来,第 n+1 个就没法开始。哪怕 GPU 闲得发慌,也只能一个一个来。
但正如 1.3 反复强调的,解码阶段是memory-bandwidth-bound(受显存带宽限制)的——每一步的时间几乎全花在把模型权重读进计算单元,真正的乘加计算只占很小一部分。这就带来一个关键推论:
speculative decoding(投机解码)就建立在这个不对称上:让一个便宜的模型快速猜出接下来的 K 个 token(草稿),再让昂贵的目标模型一次性验证这 K 个猜测。猜对的部分直接采纳,从第一个猜错的地方截断重来。猜得准时,一次昂贵的前向传播就产出了好几个 token。
这个思路和 CPU 的speculative execution(投机执行)如出一辙:在等待慢速操作时,先赌一个分支往下算,赌对了白赚,赌错了回滚。区别只是这里赌的是 token,回滚的代价是几次浪费的草稿计算。
投机解码最容易被误解的一点是:它不是近似加速,输出质量没有任何损失。这不是「效果差不多」,而是数学上的严格等价——通过一种特殊的接受/拒绝采样规则,最终产出的 token 序列与直接用目标模型采样服从完全相同的分布。
直觉上是这样:草稿 token 以目标模型给它的概率为准被接受,一旦被拒,就从一个经过修正的残差分布里重新采样,恰好补偿掉草稿模型带来的偏差。所以草稿模型的质量只影响速度,不影响正确性——猜得差顶多是白费力气,绝不会污染输出。这个性质极其重要:它意味着开启投机解码不需要重新做质量评估,这在工程上是罕见的好事。
投机解码的收益由三个量决定,缺一不可:
把草稿模型的开销算进来,净加速大致是「期望产出 ÷ (1 + K × 草稿模型相对成本)」。于是三个失效条件一目了然:
① 接受率太低。草稿模型和目标模型的分布差太远,猜十次错八次,草稿计算全部白费,净效果是变慢。这也是为什么草稿模型通常要选同系列、同 tokenizer的小模型——分布相近才猜得准。
② 草稿模型不够便宜。如果草稿模型是目标模型的 1/3 大,跑 4 步草稿就花掉了 1.3 倍目标模型前向的时间,收益被吃光。经验上草稿模型要小一到两个数量级才划算。
③ batch 已经很大。这是最容易被忽略、也最致命的一条。投机解码的全部前提是「算力有空闲,多验证几个 token 不要钱」。但在高并发服务端,连续批处理已经把算力喂饱了——此时验证 K 个 token 的计算量是实打实的额外开销,那个「几乎免费」的假设直接失效。投机解码本质上是在用算力换延迟。算力富余(低并发、本地推理、大模型小 batch)时它是白赚;算力紧张(高并发服务)时它是负收益,甚至会拉低整体吞吐。
一句话记忆:投机解码优化的是延迟,不是吞吐。它让单个用户感觉更快,但会消耗更多总算力。如果你的目标是「同样的卡服务更多人」,它多半不是你要的东西;如果你的目标是「让这一个用户的响应更快」,它可能非常有效。这个取舍与 2.1 节的 latency-throughput 主题是同一件事的两面。
Leviathan、Kalman、Matias 的这篇论文提出了投机解码算法。它的出发点是一个语言学上的观察:困难的语言建模任务里往往包含大量容易的子任务——句子的后半截、固定搭配、代码里的样板结构,这些位置用一个小得多的模型就能预测得八九不离十。
条件同样要记住:这是在 T5-XXL 上、以标准 T5X 实现为基线测得的。它是一个 encoder-decoder 模型,测试负载与今天典型的高并发聊天服务相差很大——不要把 2–3× 直接套用到你的场景上。
这项工作真正的分量在于两点:其一,它指出了「验证比生成便宜得多」这个此前未被利用的不对称性;其二,它证明了加速可以做到分布无损,从而把这类优化从「质量换速度」的范畴里摘了出来。后续的 Medusa、EAGLE、n-gram 查表等一系列变体,改的都是「草稿从哪来」,而分布无损的验证框架基本延续了下来。
独立草稿模型:最原始的形态,用同系列的小模型(如 70B 配 1B)。默认要求草稿与目标模型的 tokenizer(词表)一致,才能逐位置比对。vLLM 自 2026-07 起提供可选的异构词表模式,但限于独立草稿模型方式、且只支持贪心草稿采样,接受率需实测。
n-gram / prompt lookup:不用任何模型,直接从输入上下文里查找重复片段作为草稿。零额外显存、零训练成本,在「输出大量复述输入」的任务(代码编辑、文档改写、RAG 摘要)上接受率意外地高,是性价比最高的先试项。
EAGLE 系 / 原生 MTP 头:在目标模型上加轻量预测头,一次前向直接给出多个位置的候选,省掉独立草稿模型的部署负担。EAGLE 头需要一轮小规模训练,通常在特征层做预测,接受率高于朴素多头方案。若模型本身自带 MTP(multi-token prediction,多 token 预测)头,可直接用作草稿,无需另外训练草稿模型;vLLM 文档已将 MTP 列为一等方法。早期的 Medusa 多头方案已在 vLLM main 分支移除(2026-10),尚未发版。
框架支持:vLLM、TensorRT-LLM 等主流框架均已内置投机解码支持,可配置草稿长度 K(常见 3–5)。K 不是越大越好——K 增大,一次验证的潜在收益上升,但被拒时浪费的草稿计算也线性上升,通常存在一个由接受率决定的最优值,需实测。
上线前必测:在真实并发下对比开/关的 TTFT、TPOT 与总吞吐。只在 batch=1 下测会得到过于乐观的结论;很多团队正是这样把一个降低总吞吐的配置发到了生产。
B 和 D 适合,A 和 C 不适合。判断只需问一句:算力有没有富余?我要的是延迟还是吞吐?
B ✓:单用户、batch=1,算力大量闲置,且代码补全的输出高度可预测(样板结构多),接受率天然高。这是投机解码的理想场景。
D ✓:GPU 空闲 = 算力免费,要求响应快 = 目标是延迟。正好是「用富余算力换延迟」的定义。
A ✗:GPU 已打满,连续批处理已经吃掉了所有算力余量。此时投机解码的额外验证计算是真实成本,会挤占本可服务其他请求的算力,总吞吐下降。
C ✗:只关心总耗时 = 纯吞吐目标,而投机解码提升的是延迟、消耗的是算力。正确做法是把 batch 开到最大。
记住这条判断线:投机解码是「算力换延迟」,所以它的适用区间和高并发服务天然冲突。
期望产出:(1 − 0.7⁵)/(1 − 0.7) = (1 − 0.168)/0.3 ≈ 2.77 个 token/轮。
每轮成本(以目标模型一次前向为 1 单位):1(验证) + 4 × 0.1(草稿) = 1.4 单位。
净加速 ≈ 2.77 / 1.4 ≈ 1.98×,即约 2 倍。
敏感性检查(比结果本身更值得做):若 α 掉到 0.4,期望产出 = (1−0.4⁵)/0.6 ≈ 1.65,净加速 ≈ 1.65/1.4 ≈ 1.18×——收益几乎消失。若草稿模型成本升到 1/3,α=0.7 时净加速 ≈ 2.77/2.33 ≈ 1.19×。
结论:接受率和草稿成本任何一个恶化,收益都会迅速塌缩。这解释了为什么投机解码在实验室里漂亮、在生产里经常令人失望——真实流量的接受率通常低于精心挑选的测试集。上线前务必用真实流量实测 α。
不会。投机解码通过特定的接受/拒绝采样规则保证最终输出与直接用目标模型采样服从相同分布——草稿被拒时会从修正后的残差分布重新采样,恰好抵消草稿模型引入的偏差。
所以草稿模型差只有一个后果:接受率低 → 白费算力 → 变慢,甚至比不开还慢。质量始终由目标模型独自决定。
工程含义:这是一个可以放心开关的优化——不需要重跑质量评估,A/B 只需比较延迟和吞吐。在满是「质量换速度」权衡的推理优化里,这种「纯粹的工程优化」很少见,值得单独记住。
前提成立的原因:解码阶段受显存带宽限制。一次前向的时间主要花在把全部模型权重从显存读进计算单元;同时验证 K 个 token 位置只是多做了一点矩阵计算,而算力单元本来就在空转。所以耗时几乎不随 K 增长——省的是带宽,多花的是本来就闲置的算力。
不成立的条件(这才是考点):当算力已经被占满时。具体有三种情况——① 大 batch 服务:连续批处理已把算力喂饱,验证的计算量变成真实开销;② K 取得过大:验证的计算量累积到足以由算力主导;③ 长上下文:attention 部分的计算量随序列长度增长,算力占比上升。
能主动指出「这是一个带前提的优化,而前提在高并发下会失效」,比只会描述算法流程更能体现系统判断力。