跳到主要内容
推理优化

5.5 vLLM 投机解码实战:配置、实测与验收

vLLM v0.26 的 --speculative-config 统一配置入口,draft_model / ngram / eagle3 / mtp 四种方法的完整示例,以及用官方脚本实测接受率与加速比的验收流程

vLLMspeculative-configEAGLE-3N-gramDraft Model实测

前四节把原理和边界讲完了,这一节落地。vLLM 从 v0.20 起把投机解码的所有配置收敛到统一的 --speculative-config(JSON),旧的 --speculative-model--num-speculative-tokens 独立参数已废弃。本节以 vLLM v0.26.0 为基线,给出四种主流方法的完整配置,然后走一遍”实测接受率 → 算加速比 → 决策”的验收流程——这是 5.4 节决策框架的实操版。

📑 目录


1. 统一配置入口:—speculative-config

所有投机解码参数都通过 --speculative-config 传一个 JSON 对象,Python 侧对应 LLM(..., speculative_config={...})。核心字段:

字段类型说明
methodstring提案方法:draft_modelngramsuffixeagleeagle3mtp 等;能从 model 推断时可不填
modelstring草稿模型 / EAGLE 头 / 辅助权重标识。ngramsuffixmtp 可省略
num_speculative_tokensint > 0每轮提案的草稿 Token 数;方法自带元数据时可省略
draft_tensor_parallel_sizeint ≥ 1草稿模型的 TP 大小,只能 1 或与 Target 相同(5.2 第 3 节)
max_model_lenint ≥ 1草稿模型的上下文上限
parallel_draftingbool并行草稿生成(PARD),仅 EAGLE / draft_model 方法
rejection_sample_methodstringstrict(默认)/ probabilistic / synthetic
synthetic_acceptance_ratefloatsynthetic 模式下要模拟的目标平均接受率
use_heterogeneous_vocabbool跨词表 TLI 算法开关(5.2 第 4 节)

方法专属字段:

方法专属字段
ngramprompt_lookup_max(默认 5)、prompt_lookup_min
suffixsuffix_decoding_max_tree_depth(24)、suffix_decoding_max_cached_requests(10000)、suffix_decoding_max_spec_factor(1.0)、suffix_decoding_min_token_prob(0.1)
draft_modelquantization(草稿的量化方式)、use_heterogeneous_vocab

💡 提示tensor_parallel_size 不是 speculative_config 的合法字段——草稿的 TP 用 draft_tensor_parallel_size(误传 tensor_parallel_size 会触发警告)。temperaturetop_p 等采样参数也不是投机配置,它们在 SamplingParams 里。


2. 四种方法完整配置示例

2.1 Draft Model:Qwen3-8B + Qwen3-0.6B

同家族小模型,最通用的入门组合:

vllm serve Qwen/Qwen3-8B \
    --gpu-memory-utilization 0.8 \
    --speculative-config '{
      "method": "draft_model",
      "model": "Qwen/Qwen3-0.6B",
      "num_speculative_tokens": 5
    }'

Python 侧等价写法:

from vllm import LLM, SamplingParams

llm = LLM(
    model="Qwen/Qwen3-8B",
    speculative_config={
        "method": "draft_model",
        "model": "Qwen/Qwen3-0.6B",
        "num_speculative_tokens": 5,
    },
)
outputs = llm.generate(["The future of AI is"], SamplingParams(temperature=0.8, top_p=0.95))

📌 关键点gpu_memory_utilization 要给草稿模型留出显存。0.6B 草稿约需 1-2GB,0.8 的利用率通常安全;如果启动时草稿模型加载 OOM,把它降到 0.7-0.75 再试。

2.2 N-gram:零模型兜底方案

vllm serve Qwen/Qwen3-8B \
    --speculative-config '{
      "method": "ngram",
      "num_speculative_tokens": 5,
      "prompt_lookup_max": 4,
      "prompt_lookup_min": 2
    }'

2.3 EAGLE-3:当前最高收益的 Self-Draft

需要先准备 EAGLE-3 草稿头权重(HuggingFace 上有现成的,如 RedHatAI/Llama-3.1-8B-Instruct-speculator.eagle3):

llm = LLM(
    model="meta-llama/Llama-3.1-8B-Instruct",
    tensor_parallel_size=2,
    speculative_config={
        "method": "eagle3",
        "model": "RedHatAI/Llama-3.1-8B-Instruct-speculator.eagle3",
        "draft_tensor_parallel_size": 2,
        "num_speculative_tokens": 2,   # 按草稿头训练时的步数设置
    },
)

💡 提示:EAGLE 草稿头是按固定步数训练的(通常 2-3 步),num_speculative_tokens 应与训练步数一致,不是越大越好。EAGLE-1 的权重在 HF 上有大量现成的(如 yuhuili/EAGLE-LLaMA3.1-Instruct-8B),EAGLE-3 的稍少但主流模型基本都有社区版本。注意 vLLM 要求权重格式与 method 匹配:EAGLE-3 的权重必须用 method: "eagle3" 加载。

2.4 MTP:模型自带,零训练成本

vllm serve deepseek-ai/DeepSeek-V3 \
    --speculative-config '{
      "method": "deepseek_mtp",
      "num_speculative_tokens": 2
    }'

Qwen3-Next、GLM-4-MoE 等带 MTP 的模型同理(方法名见 5.3 第 6 节的表)。

2.5 一键对比所有方法

vLLM 官方提供了离线对比脚本,一个命令跑完所有方法:

python examples/features/speculative_decoding/spec_decode_offline.py \
    --method eagle3 \
    --num-spec-tokens 2 \
    --output-len 256 \
    --print-output

--method 支持 ngram / eagle / eagle3 / mtp / draft_model,脚本会自动打印接受率指标(见下节)。


3. 实测一:用官方脚本测接受率

spec_decode_offline.py 会输出四个关键指标(通过 llm.get_metrics() 读取):

Metric 名含义
vllm:spec_decode_num_drafts总轮数(共发起多少次提案-验证迭代)
vllm:spec_decode_num_draft_tokens草稿总 Token 数
vllm:spec_decode_num_accepted_tokens被接受的草稿 Token 总数
vllm:spec_decode_num_accepted_tokens_per_pos按位置分解的接受次数(Vector)

脚本打印的 mean acceptance length 就是 5.1 节公式里的 E[L]E[L]

total_num_output_tokens: 2560
num_drafts: 100
num_draft_tokens: 200
num_accepted_tokens: 150
mean acceptance length: 2.50          # = 1 + 150/100,即每轮平均产出 2.5 个 Token
acceptance rate at position 0: 0.80   # 第一个草稿位置被接受的比例
acceptance rate at position 1: 0.70   # 第二个草稿位置(条件于位置 0 被接受)

💡 提示:位置 0 的接受率是”无条件接受率”,位置 i 的接受率是”前 i 个都接受了”的条件接受率——它天然递减。看报告时别把”位置 1 接受率 0.7”误解为”第二个 Token 单独被接受的概率 0.7”,而是”前两个都被接受的联合事件概率”。

3.1 单次测量不够,要按场景分层

接受率随内容变化(5.4 第 1 节),所以用你的真实负载测,而不是用示例 prompt 测:

  1. 从线上日志抽样 200-500 条真实请求(按业务类型分层:代码/对话/结构化)
  2. 用脚本的 dataset 加载功能(--dataset 参数)回放
  3. 分别统计各分层的接受率,取业务加权平均
python spec_decode_offline.py --method draft_model --draft-model Qwen/Qwen3-0.6B \
    --dataset /path/to/your/requests.jsonl --output-len 256

4. 实测二:在线服务对比延迟与吞吐

离线脚本测的是”单请求加速潜力”,在线实测回答”真实服务收益”。用 vLLM 自带的 benchmark:

# 基线:不开投机
python benchmarks/benchmark_serving.py \
    --backend openai --model Qwen/Qwen3-8B \
    --endpoint /v1/completions --dataset <真实请求> \
    --num-prompts 200 --request-rate 1

# 实验组:开投机
python benchmarks/benchmark_serving.py \
    --backend openai --model Qwen/Qwen3-8B \
    --speculative-config '{"method": "draft_model", "model": "Qwen/Qwen3-0.6B", "num_speculative_tokens": 5}' \
    --num-prompts 200 --request-rate 1

--request-rate 是关键旋钮——分别测 1(低 QPS)和 20/50(高 QPS),你会看到 5.4 第 2 节的现象:低 QPS 下 TTFT/TPOT 显著下降,高 QPS 下吞吐(Output Token Throughput)可能打平甚至下降。

对比维度至少要有:

指标低 QPS(request-rate=1)高 QPS(request-rate=50)
TTFT(首 Token 延迟)基本不变(Prefill 不受影响)基本不变
TPOT(Token 间延迟)↓ 40-70%变化小
Output Throughput(Token/s)同量级可能 ↓

📌 关键点:验收的黄金标准是你的业务指标——比如”P95 TPOT 是否达标”(第 7 章 Goodput 视角)。如果 TPOT 从 40ms 降到 18ms 让你的 P95 SLO 达标率从 90% 提到 99%,这就是值得的收益;如果 SLO 本来就宽松,1.5x 的 TPOT 改善可能不值得引入第二个模型。


5. 验收流程:数据驱动的开/关决策

把 5.4 的决策框架和上面的实测串成一条流水线:

第 1 步 场景体检
   ├─ 延迟敏感还是吞吐敏感?→ 吞吐敏感直接跳过投机
   ├─ 输出确定性高吗(代码/结构化/对话)?→ 预估接受率区间
   └─ GPU 利用率多少?→ >85% 先别急着开

第 2 步 提案器选型(5.2/5.3 的决策表)
   ├─ 有原生 MTP → method=mtp,零成本先试
   ├─ 有同家族小模型 → draft_model
   ├─ 有 EAGLE-3 权重 → eagle3(收益最高)
   └─ 都没有、任务重复 → ngram / suffix

第 3 步 离线测接受率(第 3 节,用真实负载)
   └─ mean acceptance length < 1.5(≈接受率 0.5 以下)→ 停,不值

第 4 步 在线测延迟与吞吐(第 4 节,低 QPS + 高 QPS 各一轮)
   ├─ TPOT 改善 ≥ 30% 且吞吐不降 → 开
   ├─ TPOT 改善 < 30% → 结合运维成本权衡
   └─ 高 QPS 吞吐下降 → 配动态投机解码,或限流降 QPS

第 5 步 灰度上线
   ├─ 先 10% 流量,观察 P95 延迟、接受率指标、OOM
   └─ 稳定后逐步放量;把接受率指标接入监控(Prometheus 可采)

💡 提示:第 3 步的”接受率 < 0.5 就停”不是教条——如果目标是极致的延迟(比如实时语音 Agent),1.4x 也值得;如果目标是省钱,<2x 就别折腾。流程比阈值重要:接受率、TPOT、吞吐三个数测出来,决策自然清晰。


6. 常见问题与排错

症状原因处理
启动报错:methodmodel 不匹配EAGLE-1/2/3 权重格式不同,method 必须对应确认权重来源,EAGLE-3 权重必须 "method": "eagle3"
草稿模型加载 OOMgpu_memory_utilization 太高,没给草稿留显存降到 0.7-0.75,或设 max_model_len 限制草稿上下文
启动日志出现 SpeculativeConfig(method='draft_model', ...) 但实际是 MTP 模型版本不支持该模型的 MTP 路径,回退成通用 draft_model升级 vLLM 到支持该 MTP 类型的版本
吞吐反而下降高 QPS 下验证算力争抢(5.4 第 2 节)限流、降低 num_speculative_tokens、或关闭投机
输出与基线不一致分布级无损 ≠ 逐次确定(5.1 第 7 节)确认不是 bug:用贪心 + 同 seed 复现;采样模式下差异正常
num_speculative_tokens 设太大收益不增边际收益递减(5.1 第 5 节),EAGLE 受训练步数限制从 2-5 开始扫,看 mean acceptance length 的增速
想用跨词表草稿模型词表不一致报错"use_heterogeneous_vocab": true(TLI,仅贪心草稿)

📝 总结

  • 配置入口--speculative-config JSON,核心字段 method / model / num_speculative_tokens / draft_tensor_parallel_size
  • 四种方法示例draft_model(同家族小模型)、ngram(零成本)、eagle3(最高收益,注意训练步数)、mtp(模型自带)
  • 接受率实测spec_decode_offline.py + llm.get_metrics(),看 mean acceptance length 与按位置接受率;用真实负载分层测
  • 在线实测benchmark_serving.py 分别跑低/高 QPS,对比 TTFT、TPOT、吞吐——延迟收益与吞吐代价分开看
  • 验收流水线:场景体检 → 选型 → 离线接受率 → 在线对比 → 灰度;三个数字(接受率、TPOT、吞吐)驱动决策
  • 排错要点:method 与权重匹配、显存预留、高 QPS 负收益、分布级无损 ≠ 逐次确定

🎯 自我检验清单

  • --speculative-configtensor_parallel_size 为什么不是合法字段?
  • 四种方法的 num_speculative_tokens 分别怎么定?
  • mean acceptance length 怎么从 metrics 算出来?按位置接受率为什么递减?
  • 为什么低 QPS 和高 QPS 的实测结果要分开看?
  • 验收流水线五步分别测什么、决策阈值是什么?
  • 遇到”输出与基线不一致”先排查什么?

📚 参考资料