前几篇把显存的钱花到了极致:第 11 篇深挖 KV Cache 的结构与命中率,第 9、10 篇用量化把权重压掉一半多。但显存省下来只解决"装得下、并发开得多",用户体感的另一半——生成时一个字一个字往外蹦的速度——还没碰过。本篇讲"时间":decode 阶段的加速技术群,主角是投机解码(speculative decoding)。
这是《本地大模型部署实战》系列第 12 篇,收官篇。先定位 decode 为什么慢,再拆投机解码"草稿加验证"的原理与无损性,算清 2~3 倍收益的来源公式,然后用 vLLM 的 --speculative-config 实际挂一个 EAGLE 草稿头,接着过一遍自草稿、MTP、n-gram 几条变体路线,最后把量化、批处理、编译加速放进同一张瓶颈地图,收束全系列。本文按"瓶颈定位 → 原理 → 公式 → 实操 → 全景 → 总结"组织。
1、自回归解码的瓶颈
第 2 篇讲硬件时埋过一个结论:GPU 的算力增长远快于显存带宽,大模型推理迟早卡在搬数据上。decode 阶段把这个剪刀差吃满了。自回归生成的每一步——给定前文、算下一个 token 的分布——都要把整个模型跑一遍:几十层 transformer、全部权重从显存搬到计算单元,只为产出 1 个 token。生成 500 个 token,就是串行重复 500 次全过程。
batch=1 时这笔账尤其亏。以第 5 篇的口径算:Qwen2.5-7B 的 Q4 权重约 4.1 GB,每生成 1 个 token 的计算量约 14 GFLOPs,算术强度约 3.4 FLOP/byte;而 4090 的算力带宽比约 80 FLOP/byte,相差 20 多倍。这一步是访存瓶颈:算力大部分时间闲着,等权重和 KV Cache 搬完。单步耗时的量级拆解如下。
decode 单步耗时拆解(7B Q4,4090,batch=1,量级示意)
搬全部权重 约 4 ms ████████████████████ 4.1 GB ÷ 1 TB/s 带宽
算 1 个 token 不足 1 ms ██ 14 GFLOPs,算力占用个位数
读 KV Cache 约 1 ms █████ 随上下文变长
每生成 1 个 token 重复一遍全过程,纯带宽决定的单流天花板约 250 token/s
解读:单步下限由"读一遍权重"的带宽时间决定,约 4 ms 折合单流上限约 250 token/s,实际再叠加 KV 读取、kernel 启动与采样开销,只能做到它的几分之一。瓶颈定位后,加速只有三个方向:少搬字节(量化,第 9、10 篇)、一趟搬运摊给更多请求(批处理,第 5 篇),以及本篇——让一次前向产出不止 1 个 token。
2、投机解码的原理
decode 慢的根源是串行:每步只出 1 个 token,却每步都付一遍全模型的访存成本。注意一个不对称:模型前向本身是并行算的——prefill 一次吞几百个 token 毫不费力,贵的从来不是"多算几个位置",而是"多跑几遍"。投机解码的思路由此而来:用便宜的东西猜,让大模型一次并行验证。
流程分两阶段。草稿阶段:一个便宜得多的草稿器——小模型或轻量预测头——自回归连猜 k 个 token。验证阶段:大模型把"前文加这 k 个草稿 token"当作一次前向的输入,一次算出每个位置各自的输出分布,然后逐位比对:与目标分布吻合的草稿 token 接受,第一个不吻合处拒绝,该位置改用大模型自己的采样结果顶上。时序对比如下。
解读:一轮下来大模型只跑一次前向,却吐出 3 个 token;哪怕草稿全猜错,验证前向也保证至少产出 1 个(拒绝位的修正 token),不会白跑。更关键的是无损性:验证采用修改过的拒绝采样(思路出自 Leviathan 等人的论文),数学上保证最终输出序列的分布与直接用大模型采样完全一致——草稿只决定快慢,不改变输出分布。这与"干脆蒸馏个小模型上线"有本质区别:后者快但质量打折,投机解码快而分布不变。
注意:验证前向比单步 decode 多算 k 个位置的 logits,看似多花算力,但第 1 节说过 decode 正卡在带宽上、算力闲着——投机解码恰好把闲置算力换成带宽时间,这是它能"白赚"的物理基础。
3、接受率与收益公式
收益由两个参数决定。接受率 α:草稿 token 与目标分布吻合的概率,衡量草稿与目标模型的契合度。草稿成本比 c:草稿一步前向的耗时除以大模型一步。设每轮猜 k 个 token,逐位近似独立时,一轮的期望产出 E = (1 - α^(k+1)) / (1 - α)(含拒绝位的修正 token),一轮成本约 1 + c·k 个"大模型步",加速比即两者相除。代入几组典型值。
| 接受率 α | 猜测数 k | 期望产出 E | 加速比(c=0.05) |
|---|---|---|---|
| 0.6 | 3 | 2.18 | 1.9 倍 |
| 0.7 | 4 | 2.77 | 2.3 倍 |
| 0.8 | 5 | 3.69 | 3.0 倍 |
解读:接受率是全部收益的杠杆——α 从 0.6 提到 0.8,加速比翻过 2,这就是社区实测"2~3 倍常态"的来源:通用对话负载常见 1.4~1.6 倍,契合度高的 EAGLE 类方案 2.5 倍上下,理想条件更高。反过来 k 并非越大越好:α 低时多猜的部分全数白猜,还抬高验证成本,曲线会在某个 k 后回落——EAGLE 论文干脆让头自己学着"知难而退",低置信位置提前停。
成本端同样重要:草稿必须足够便宜,c 大了收益被 1 + c·k 吃光。独立小模型(如 0.5B 打 7B)的 c 约 0.1;EAGLE 式单层头的 c 能低到 0.03 量级——这正是第 5 节自草稿路线的动机。
4、vLLM 投机解码实操
原理落到 vLLM 只有一个参数:--speculative-config,收一段 JSON。以 EAGLE 草稿头为例,官方文档的典型写法如下(环境沿用第 5 篇装的 v0.32.0)。
vllm serve Qwen/Qwen2-7B-Instruct \
--speculative-config '{
"method": "eagle",
"model": "yuhuili/EAGLE-Qwen2-7B-Instruct",
"num_speculative_tokens": 5
}'
解读:method 选投机方法,model 指向草稿权重,num_speculative_tokens 就是公式里的 k。常用键如下。
| 参数 | 类型 | 说明 |
|---|---|---|
method |
string | 投机方法:eagle、eagle3、mtp、draft_model、ngram、suffix 等 |
model |
string | 草稿权重路径;ngram、suffix、mtp 无需独立权重 |
num_speculative_tokens |
int | 每轮猜测的 token 数 k |
draft_tensor_parallel_size |
int | 草稿侧张量并行度,随主模型规模配置 |
效果观察两步。启动日志会回显 speculative 配置并加载草稿头;跑请求时,日志与指标里能看到每轮平均接受长度(acceptance length),它直接对应第 3 节的 E。判读方法:接受长度长期低于 2,说明草稿不契合,换草稿或调小 k;接近 k+1,说明还有余量,可以加 k 再试。收益对照用第 6 篇的压测脚本:同参数开关投机解码各跑一轮,对比 token/s 与延迟分位。
注意:草稿头必须与目标模型配套——同 tokenizer、同架构族,从 yuhuili 的 EAGLE 系列里挑与目标模型同名的那只。EAGLE-3 的方法值是
eagle3,早期版本仅覆盖 Llama 与 Qwen 系,完整支持矩阵以官方投机解码文档为准。
5、自草稿与多头方案
独立草稿模型有三个工程麻烦:多一份权重要下载维护、显存多占一份、契合度还不保证。于是有了自草稿(self-drafting)路线:草稿不是另一个模型,而是目标模型自带的轻量预测头,训练后随目标权重一起发布。
Medusa 是最早的代表:给目标模型最后一层挂上若干解耦的预测头,一次前向同时预测后面多个位置,再配合树注意力把多条候选路径拼成一棵树、一次验证。EAGLE 把这条路推得更彻底——论文发现在特征层(倒数第二层隐状态)而不是词面层面做递归猜测,契合度显著更高:头只需一层 transformer(对应第 3 节的 c≈0.03),α 却能做到 0.7 以上;EAGLE-3 进一步用多层特征融合再抬一截。vLLM 目前主推的正是 EAGLE 家族。
还有一条免训练路线:MTP(Multi-Token Prediction)。模型训练时就自带多 token 预测模块——DeepSeek-V3 的开源权重是典型——vLLM 里 "method": "mtp" 直接挂载,不用另找草稿。要给自家微调模型训草稿头,官方的 speculators 库统一了 EAGLE 式草稿的训练流程,产物可直接部署进 vLLM。Medusa 一系在 vLLM 当前文档的支持列表里已淡出,其多头思想由 EAGLE 家族与 speculators 承接。
6、N-gram 与后缀投机
自草稿再往前一步:连预测头都不要,草稿直接从输入文本里找。n-gram 投机依据一个朴素的统计事实——很多负载里"接下来要生成的片段"在上下文里出现过。它在已生成的文本里匹配 n-gram,命中后把"当年接在后面的片段"直接当草稿,交给大模型验证。配置如下。
vllm serve Qwen/Qwen2.5-Coder-7B-Instruct \
--speculative-config '{
"method": "ngram",
"num_speculative_tokens": 4,
"prompt_lookup_min": 2,
"prompt_lookup_max": 5
}'
解读:prompt_lookup_min 与 prompt_lookup_max 是匹配窗口的上下界(默认均为 5),窗口越短候选越多、接受率越参差。它的主场是高重复文本:代码补全(缩进、括号、样板代码反复出现)、答案就在输入里的文档问答、Agent 的工具调用输出(每轮 JSON 字段与格式高度雷同)——这类场景接受率可以高得反常,而成本为零:不多占显存、不加载任何权重。
后缀解码(suffix decoding)是 n-gram 的强化版:把见过的全部文本——各请求的 prompt、历史输出、跨请求的全局缓存——建成后缀树,从树里取结构化的候选片段,Snowflake 的论文实测 Agent 类高重复负载收益最猛,vLLM 以 "method": "suffix" 内置。边界同样明确:开放式闲聊的 α 很低,收益微弱甚至为负——草稿白猜还要付验证成本,这类负载请回到第 5 节的 EAGLE 路线。
7、推理加速手段全景
至此,系列的加速手段凑齐了整张地图。它们各打不同的瓶颈,互相正交、可以叠加,但收益不相乘——每样吃掉的是总时间里不同的一段。
| 手段 | 作用的瓶颈 | 一句话定位 | 系列篇目 |
|---|---|---|---|
| 量化 | 显存与权重带宽 | 同样的 token 少读一半字节 | 第 9、10 篇 |
| PagedAttention 与批处理 | 显存碎片与吞吐 | 一批请求分摊一次搬权重 | 第 5 篇 |
| 前缀缓存 | 重复 prefill 计算 | 相同前缀只算一次 | 第 5、7 篇 |
| 投机解码 | 串行 decode 的访存浪费 | 一次前向换多个 token | 本篇 |
| 编译与 kernel 融合 | 算子与框架开销 | 压掉调度与 kernel 启动 | — |
编译一栏补两句。TensorRT-LLM 代表"整图编译"路线:把模型编译成融合算子加显式捕获的计算图,压掉框架调度与 kernel 启动开销,代价是构建流程重、模型支持滞后于 PyTorch 生态。轻量版是 torch.compile,vLLM 默认启用、--enforce-eager 可整体关掉,收益中等但零迁移成本。选型判断第 8 篇横评给过结论:绝大多数团队先把量化、批处理、投机解码配平,编译栈只在追最后 20% 时进场。
8、负载类型与收益边界
同一份 speculative-config,不同负载的回报天差地别,上线前先对号入座。
收益最大的是长生成、低并发:写作、代码补全、长摘要——逐 token 串行占比高,batch 小意味着算力闲置最多,验证的额外计算最接近免费。单用户桌面场景(第 3、4 篇的 llama.cpp 与 Ollama 同样内置投机解码)体感最明显:蹦字速度肉眼可见变快。
无感的是首 token 延迟(TTFT):它由 prefill 决定,投机解码只作用于 decode,prefill 一点不受益——TTFT 高的病根要去第 7 篇的前缀缓存里找。收益缩水的是高并发:batch 大到算力接近吃满后,验证不再免费,官方文档把投机解码定位在"中低 QPS(每秒请求数)的延迟优化",吞吐型场景收益中等甚至相互拖累——这时优先第 5 篇的批处理。
一句话判据:用户盯着屏幕逐字等的负载,投机解码收益最大;服务器排队拼吞吐的负载,先把批处理与量化配平。
9、总结
回顾全篇链条:decode 是访存瓶颈,每生成 1 个 token 都要付一遍搬全部权重的带宽时间,算力闲着;投机解码让便宜的草稿连猜 k 个 token、大模型一次前向并行验证,输出分布数学上不变,快而不损;收益由接受率 α 与草稿成本比 c 决定,α 0.7~0.8、c 0.05 量级对应 2~3 倍常态;工程上 vLLM 用一段 --speculative-config 挂 EAGLE 草稿头,n-gram 与后缀投机在高重复负载里零成本吃肉。这些手段与量化、批处理、编译栈各打一个瓶颈,正交可叠加。至此系列十二篇收官:从硬件账、llama.cpp 内核,到 vLLM 生产部署与加速全景,本地大模型的部署链路全部走通。
留三道练习:
- 练习一:开关投机解码各压测一轮,对比 token/s 与 P95,再取 k=3、5、8 三档找最优值
- 练习二:抽样 10 条历史输出,估算 4-gram 接受率,判断 ngram 值不值得开
- 练习三:笔算 α=0.75、c=0.05、k=6 的理论加速比(答案约 2.7 倍)
对于已按第 6 篇把服务跑起来的读者,建议今天就拿 EAGLE 草稿头做一轮开关对照——这是全系列里"改动一个参数、体感提升最直观"的一项;测完把接受长度与压测数字记进容量规划文档,收官。

