vLLM 投机解码(Speculative Decoding)配置与原理全指南:方法选型、--speculative-config 详解与无损性保障
本文是 vLLM 投机解码(Speculative Decoding)的中文技术指南。投机解码是一类让"小模型先行预测、大模型批量验证"的推理加速技术,专门用于降低 LLM 在中低 QPS、内存受限(memory-bound)负载下的逐 token 延迟(inter-token latency)。读完本文,你将掌握 vLLM 内置的全部投机方法(EAGLE / MTP / Draft Model / PARD / MLP / N-Gram / Suffix / 动态投机 / 自适应验证)如何选型、如何通过统一的 --speculative-config 与 speculative_config 完成离线与在线部署配置、自定义 proposer 接入方式,以及投机解码在 vLLM 中"无损保证"的确切含义与边界。
本文以 docs/features/speculative_decoding/README.md 为主干,并结合其下 EAGLE、MTP、Draft Model、PARD、MLP、N-Gram、Suffix、Dynamic Speculative Decoding、Adaptive Verification、Per-Request Acceptance Metrics 等系列指南,以及配置类 vllm/config/speculative.py 的实现细节整理而成。
一、投机解码的价值与适用场景
投机解码的核心思路是:先用一个更小、更快的 draft 模型(起草模型) 一次性生成 K 个候选 token(称为"投机深度"),再由 target 模型(目标模型) 对这些候选 token 做一次批量前向验证,一次解码步即可"吃掉"多个 token。相比逐个 token 串行生成,它用额外的计算换来了更少的串行解码轮次。
在 vLLM 中启用投机解码的最典型动机是降低 中低 QPS(queries per second)场景下的内存受限负载的逐 token 延迟。因为此时 GPU 算力并未打满,验证额外 draft token 的边际算力几乎免费,而减少的串行轮次则直接转化为更低的 TPOT。vLLM 将这一方法的无损性保证作为设计约束(详见本文「七、无损保证」一节),使其在加速的同时不改变目标模型的采样分布。
若希望为优化后的投机解码训练自己的 draft 模型,可参考 speculators.md,实现与 vLLM 无缝衔接的训练与集成流程。
二、vLLM 支持的投机方法总览
vLLM 支持两大类投机方法:
- 模型类方法:EAGLE、MTP、Draft Model、PARD、MLP speculator 等,延迟降低效果最好;
- 轻量方法:N-Gram、Suffix 等,无需额外加载模型,在流量高峰期不会给显存/算力带来增量压力,可获得中等程度的加速。
方法清单与对应文档如下:
- EAGLE
- Multi-Token Prediction (MTP)
- Draft Model
- Parallel Draft Model (PARD)
- Multi-Layer Perceptron
- N-Gram
- Suffix Decoding
- Hidden State Extraction
- Dynamic Speculative Decoding
- Adaptive Verification
- Per-Request Acceptance Metrics
2.1 方法选择速查表
下表是 vLLM 官方给出的定性选型起点。需要强调的是:实际收益取决于你的模型家族、流量模式、硬件与采样设置,请结合自身环境用可复现的测量来验证。
| 方法 | 低 QPS(延迟导向) | 高 QPS(吞吐导向) | 备注 |
|---|---|---|---|
| EAGLE | 高收益 | 中到高收益 | 强大的通用型模型类方法。 |
| MTP | 高收益 | 中到高收益 | 目标模型原生支持 MTP 时效果最佳。 |
| Draft model | 高收益 | 中收益 | 需要单独的 draft 模型。 |
| Parallel Draft Model | 高收益 | 中到高收益 | draft 模型延迟低。 |
| MLP speculator | 中到高收益 | 中收益 | 存在兼容的 MLP speculator 时效果良好。 |
| N-gram | 低到中收益 | 中收益 | 轻量、易启用。 |
| Suffix decoding | 低到中收益 | 中收益 | 无需额外 draft 模型;投机深度动态可变。 |
| Custom Proposer | 视情况而定 | 视情况而定 | 自带自定义 proposer 类(实验性)。 |
| Dynamic Speculative Decoding | 高收益 | 高于基础 SD 方法 | 适用于 RL 或 QPS 波动的负载。 |
| Adaptive Verification | 高收益 | 高于基础 SD 方法 | 依据 drafter 置信度逐请求调整验证规模;目前仅支持 DSpark。 |
在真实环境中进行可复现测量,可使用离线示例 examples/features/speculative_decoding/spec_decode_offline.py(该脚本还演示了如何抽取请求级接受率),或参考 benchmark CLI 指南。
三、模型类投机方法逐一详解
3.1 Draft Model(独立草稿模型)
Draft Model 方法使用一个与目标模型同词表、同家族的小模型作为起草器。离线模式下,通过 LLM(..., speculative_config={...}) 传入配置即可,例如以 Qwen3-8B 为目标、Qwen3-0.6B 为草稿模型、每次投机 5 个 token:
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="Qwen/Qwen3-8B",
tensor_parallel_size=1,
speculative_config={
"model": "Qwen/Qwen3-0.6B",
"num_speculative_tokens": 5,
"method": "draft_model",
},
)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
等效的在线(server)启动方式通过 --speculative-config 传同一个 JSON:
vllm serve Qwen/Qwen3-4B-Thinking-2507 \
--host 0.0.0.0 \
--port 8000 \
--seed 42 \
-tp 1 \
--max-model-len 2048 \
--gpu-memory-utilization 0.8 \
--speculative-config '{"model": "Qwen/Qwen3-0.6B", "num_speculative_tokens": 5, "method": "draft_model"}'
注意:--speculative-config 中既声明了目标模型的常规 serve 参数,也完整承载了投机相关配置——客户端请求补全的代码(如通过 OpenAI SDK 指向 http://localhost:8000/v1)完全无需改变。
弃用提示:早期通过
--speculative-model单独指定草稿模型、再叠加--num-speculative-tokens等参数的做法已被弃用。所有投机解码相关配置都应统一放在--speculative-config中。
3.2 EAGLE / EAGLE-3
EAGLE(Extrapolation Algorithm for Greater Language-model Efficiency)是一种将特征层自回归与 token 采样解耦的高效起草器:它在特征层做自回归推测,预测特征后一次性解码出整棵草稿树,大幅提升草稿与目标分布的吻合度。
EAGLE(二代)示例:
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="meta-llama/Meta-Llama-3-8B-Instruct",
tensor_parallel_size=4,
speculative_config={
"model": "yuhuili/EAGLE-LLaMA3-Instruct-8B",
"draft_tensor_parallel_size": 1,
"num_speculative_tokens": 2,
"method": "eagle",
},
)
EAGLE-3(method: "eagle3")示例:
llm = LLM(
model="meta-llama/Meta-Llama-3-8B-Instruct",
tensor_parallel_size=2,
speculative_config={
"model": "RedHatAI/Llama-3.1-8B-Instruct-speculator.eagle3",
"draft_tensor_parallel_size": 2,
"num_speculative_tokens": 2,
"method": "eagle3",
},
)
EAGLE 类型的 checkpoint 现已广泛分布于公开模型库(例如 yuhuili 与 RedHatAI 发布的系列 speculator 模型),可直接填入 model 字段使用。vLLM 的版本兼容性上有一项历史注意事项:若使用较早的 vLLM(低于 0.7.0),需要先运行社区提供的转换脚本对 speculative 模型做格式转换,再以 "model": "path/to/modified/eagle/model" 指向转换产物。
从源码角度看,EAGLE-3 之所以需要额外的约束,是因为它属于"需要返回中间层 hidden states"的起草器。在 vllm/config/speculative.py 中,compute_hash() 会将这些方法(eagle3、extract_hidden_states、dflash、dspark)单独标记为 uses_aux_hidden_states,并把 draft 模型的 eagle_aux_hidden_state_layer_ids(抽取出草稿特征所用的目标层号)纳入计算图哈希因子——不同层号意味着不同的计算图结构,vLLM 会据此保证缓存/图复用不会跨越不兼容的配置。
3.3 MTP(Multi-Token Prediction,原生多 token 预测)
MTP 的特点是不需要额外加载 draft 模型:目标模型本身在预训练阶段就带有多 token 预测头,vLLM 直接调用模型原生的 MTP 能力。适用条件:
- 目标模型原生支持 MTP(vLLM 内置映射了大量 MTP 模型族,如 DeepSeek、MiMo、GLM、Kimi、Qwen3-Next、Exaone、MiniMax-M3、Gemma 4 等,见 vllm/config/speculative.py 中的
MTPModelTypes); - 希望以最小的额外配置获得模型级投机效果。
离线示例(MiMo-7B-Base,投机深度取 1):
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="XiaomiMiMo/MiMo-7B-Base",
tensor_parallel_size=1,
speculative_config={
"method": "mtp",
"num_speculative_tokens": 1,
},
)
在线示例:
vllm serve XiaomiMiMo/MiMo-7B-Base \
--tensor-parallel-size 1 \
--speculative-config '{"method":"mtp","num_speculative_tokens":1}'
使用要点:
- MTP 只对 vLLM 已支持的、带 MTP 能力的模型家族有效;若模型不支持 MTP,请改用 EAGLE 或 Draft Model 方法;
num_speculative_tokens控制投机深度,从较小的值(如1)起步通常是不错的默认选择;- 从 vllm/config/speculative.py 中的
hf_config_override()可以看到,vLLM 在配置阶段会自动把各家的原生模型类型(如deepseek_v3→deepseek_mtp、MiMoForCausalLM→mimo_mtp等)改写为对应的 MTP 架构,并读取num_nextn_predict_layers/mtp_num_hidden_layers等字段补全n_predict,因此用户侧通常只需声明method: "mtp"。
Gemma 4 Assistant 模型:MTP 路径而非通用 draft
Gemma 4 assistant checkpoint 在 vLLM 中被当作 Gemma 4 MTP speculator 处理,而不是通用 draft model,尽管它们同样通过 --speculative-config 的 model 字段传入。为 Gemma 4 配置 assistant checkpoint 时必须使用 "method": "mtp",例如:
vllm serve google/gemma-4-E2B-it \
--tensor-parallel-size 1 \
--max-model-len 8192 \
--speculative-config '{"method":"mtp","model":"gg-hf-am/gemma-4-E2B-it-assistant","num_speculative_tokens":1}'
E2B、E4B、12B、26B-A4B 与 31B 等 Gemma 4 IT assistant checkpoint 均受支持。Tower 类变体使用 model_type: gemma4_assistant,无编码器的 Gemma 4 Unified 变体(12B)使用 model_type: gemma4_unified_assistant;vLLM 内部会把两者都映射为 Gemma4MTPModel,并通过 proposer 将 assistant 层与目标模型共享 KV cache(配置阶段会把 num_kv_shared_layers 置 0,改由 proposer 在模型构建后建立跨模型 KV 共享,见 vllm/config/speculative.py)。
排障提示:如果启动日志中出现 SpeculativeConfig(method='draft_model', ...)(针对 Gemma 4 assistant checkpoint),说明当前安装的 vLLM 版本不包含该路径的 Gemma 4 MTP 支持——此时它会被当作通用 draft model 处理,多模态 Gemma 4 目标在初始化阶段可能失败。正确做法是升级到支持 Gemma 4 MTP 的 vLLM 版本,而不是强行把 assistant checkpoint 塞进通用 draft-model 投机流程。
3.4 Parallel Draft Model(PARD)
PARD 通过 parallel_drafting: true 开启 并行起草:所有投机 token 一次性并行生成(而非串行逐 token 递推),从而把 draft 阶段的延迟压到极低。PARD 权重经过专门的并行训练(例如 amd/PARD-Qwen3-0.6B)。
离线示例(Qwen3-8B 目标 + PARD 草稿,一次投机 12 个 token):
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="Qwen/Qwen3-8B",
tensor_parallel_size=1,
speculative_config={
"model": "amd/PARD-Qwen3-0.6B",
"num_speculative_tokens": 12,
"method": "draft_model",
"parallel_drafting": True,
},
)
在线示例:
vllm serve Qwen/Qwen3-4B \
--host 0.0.0.0 \
--port 8000 \
--seed 42 \
-tp 1 \
--max-model-len 2048 \
--gpu-memory-utilization 0.8 \
--speculative-config '{"model": "amd/PARD-Qwen3-0.6B", "num_speculative_tokens": 12, "method": "draft_model", "parallel_drafting": true}'
需要留意的是,parallel_drafting 仅在 vllm/config/speculative.py 中标注为 仅与 EAGLE 和 draft-model 两类方法兼容,且要求草稿模型经过并行起草训练,否则会破坏草稿分布。
3.5 MLP Speculator
MLP speculator(在配置中对应 method: "mlp_speculator")是一类把草稿预测同时条件化在上下文向量(context vectors)与已采样 token上的起草模型,训练与推理方式与 IBM 的 MLPSpeculator 系列一致:
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="meta-llama/Meta-Llama-3.1-8B-Instruct",
tensor_parallel_size=1,
speculative_config={
"model": "ibm-ai-platform/llama3-8b-accelerator",
"draft_tensor_parallel_size": 1,
"method": "mlp_speculator",
},
)
公开可用的 MLP speculator 权重以 IBM 的 *-accelerator 系列为主(覆盖 llama2/llama3、code llama、granite 等多档尺寸,如 llama3-8b-accelerator、llama2-70b-accelerator、granite-3b-code-instruct-accelerator 等)。已知问题:ibm-ai-platform/llama3-70b-accelerator 会因 MLPSpeculatorConfig 缺少 num_attention_heads 属性而报 AttributeError,官方 issue 仍在跟踪修复中,使用该 70B 权重前请留意版本状态。
四、轻量投机方法详解
4.1 N-Gram 投机
N-Gram 完全不加载额外模型:它通过在提示词(prompt)内部做 n-gram 匹配来产生候选 token。适用于提示中本身包含大量可自重复文本的场景。配置 method: "ngram",并配合 prompt_lookup_min/prompt_lookup_max 界定 n-gram 窗口:
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="Qwen/Qwen3-8B",
tensor_parallel_size=1,
speculative_config={
"method": "ngram",
"num_speculative_tokens": 5,
"prompt_lookup_max": 4,
},
)
4.2 Suffix Decoding
Suffix Decoding(论文见 arXiv:2411.04975)是 N-Gram 的进阶:它同样利用"最近 n 个已生成 token"做模式匹配,但有三个关键差异——(1) 不仅能匹配 prompt,还能匹配历史生成文本;(2) 用频次统计提议最可能的后续;(3) 对每个请求在每步解码自适应地投机可变数量的 token,以获得更高的接受率。它对高重复度任务(代码编辑、agentic 循环如 self-reflection/self-consistency、RL rollout)效果尤其明显。
使用前需安装依赖 Arctic Inference(pip install arctic-inference)。由于投机 token 数是动态的,num_speculative_tokens 在这里表示上限,官方建议设高一些(如 16 或 32,32 为推荐默认):
from vllm import LLM, SamplingParams
prompts = ["The future of AI is"]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(
model="Qwen/Qwen3-8B",
tensor_parallel_size=1,
speculative_config={
"method": "suffix",
"num_speculative_tokens": 32,
},
)
Suffix Decoding 的相关键位在 vllm/config/speculative.py 中有直接对应的实现(suffix_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),其机制是:全局 + prompt 两棵后缀树用于前缀匹配;spec factor 依据前缀匹配长度换算本次可投机的 token 数上限(max_spec_tokens = max_spec_factor * prefix_match_length);只有频次估计概率 ≥ suffix_decoding_min_token_prob 的 token 才被投机;全局后缀树缓存超过 suffix_decoding_max_cached_requests 时按 FIFO 淘汰,设为 0 则禁用全局缓存(仅保留 prompt 树)。
4.3 Hidden State Extraction(隐藏状态抽取,训练 EAGLE 用)
Hidden State Extraction 面向数据生产而非推理加速:它让 vLLM 在推理时把目标模型的中间层激活保存下来(.safetensors),供训练 EAGLE 类草稿模型、知识蒸馏或模型内部离线分析使用。通过 KV transfer 连接器(ExampleHiddenStatesConnector,kv_role="kv_producer")把 hidden states 写盘,完整脚本见 examples/features/speculative_decoding/extract_hidden_states_offline.py。
import tempfile
from vllm import LLM, SamplingParams
from vllm.config.kv_transfer import KVTransferConfig
from vllm.distributed.kv_transfer.kv_connector.v1 import (
example_hidden_states_connector,
)
with tempfile.TemporaryDirectory() as tmpdir:
llm = LLM(
model="Qwen/Qwen3-8B",
speculative_config={
"method": "extract_hidden_states",
"num_speculative_tokens": 1,
"draft_model_config": {
"hf_config": {
"eagle_aux_hidden_state_layer_ids": [1, 2, 3, 4],
},
},
},
kv_transfer_config=KVTransferConfig(
kv_connector="ExampleHiddenStatesConnector",
kv_role="kv_producer",
kv_connector_extra_config={
"shared_storage_path": tmpdir,
},
),
)
在线方式性能更佳时建议使用 RAM 文件系统(如 /dev/shm/),客户端生成后尽快清理:
vllm serve Qwen/Qwen3-8B \
--speculative_config '{"method": "extract_hidden_states", "num_speculative_tokens": 1, "draft_model_config": {"hf_config": {"eagle_aux_hidden_state_layer_ids": [1, 2, 3, 4]}}}' \
--kv_transfer_config '{"kv_connector": "ExampleHiddenStatesConnector", "kv_role": "kv_producer", "kv_connector_extra_config": {"shared_storage_path": "/dev/shm/hidden_states"}}'
每个请求产出包含 hidden_states(形状 [num_tokens, num_extracted_layers, hidden_size])与 token_ids(形状 [num_tokens])的 .safetensors 文件,路径回填到 output.kv_transfer_params["hidden_states_path"]。相关配置键包括:
| 参数 | 默认值 | 说明 |
|---|---|---|
shared_storage_path |
/tmp |
hidden state 文件的保存目录(未逐请求指定路径时使用) |
allow_custom_save_path |
False |
是否允许客户端经 hidden_states_path 指定自定义路径;关闭时客户端路径被忽略并告警。仅建议在可信客户端环境开启,因为自定义路径可写入服务器任意位置 |
num_writer_threads |
8 |
异步写盘的线程池大小 |
use_synchronization_lock |
True |
使用文件锁,使并发读取者阻塞到写入完成;批量生成场景可关闭 |
逐请求选项(离线经 SamplingParams(extra_args={"kv_transfer_params": {...}}),在线作为 API 请求顶层字段 kv_transfer_params)包括 hidden_states_path(自定义保存路径)与 include_output_tokens(是否连生成 token 的 hidden states 一并保存,默认 False 只存 prompt 部分)。注意该特性与 chunked prefill 不兼容,需要禁用后者。
五、--speculative-config 配置模式完全解析
vLLM 已把投机解码的所有设置统一收敛到 --speculative-config(在线 CLI / 配置文件)或 speculative_config(Python 侧 LLM(...))这一个入口中,二者共用同一套 JSON schema。
CLI 传入一个 JSON 对象即可:
vllm serve <target-model> \
--speculative-config '{
"method": "draft_model",
"model": "<draft-model>",
"num_speculative_tokens": 5
}'
Python 侧等价写法为 LLM(..., speculative_config={...})。下表是面向用户的高频键位(并非完整 schema,完整字段参考 engine arguments reference 与 vllm.config.SpeculativeConfig 的 API 文档):
5.1 通用键
以下键在各类投机配置中都较常用;其中一部分仅对模型类方法(如 draft_model、mtp、eagle3、dflash)生效:
| Key | 类型 | 默认值 | 允许值 / 含义 |
|---|---|---|---|
method |
string |
None |
投机方法。常用取值包括 draft_model、ngram、suffix、mtp、eagle3、dflash。若省略,vLLM 会在配置允许时尽可能根据其他字段推断方法。 |
model |
string |
None |
draft 模型、EAGLE head 或辅助模型标识。对 ngram、ngram_gpu、suffix、mtp 常可省略。 |
num_speculative_tokens |
integer > 0 |
None |
每步提议的投机 token 数。对无法从模型元数据推断的方法而言是必填项。 |
draft_tensor_parallel_size |
integer >= 1 |
None |
draft 模型的张量并行度。 |
max_model_len |
integer >= 1 |
None |
draft 模型的最大上下文长度。 |
parallel_drafting |
boolean |
false |
启用并行起草。仅兼容 EAGLE 与 draft-model 方法。 |
rejection_sample_method |
string |
standard |
standard、synthetic 或 block。 |
synthetic_acceptance_rates |
list[float] |
None |
synthetic 拒绝采样下逐位置的无条件接受率。每项取值 [0, 1];列表长度必须等于 num_speculative_tokens;必须单调不增。 |
synthetic_acceptance_length |
float |
None |
synthetic 的目标平均接受长度,取值范围 [1, num_speculative_tokens + 1]。与 synthetic_acceptance_rates 互斥。 |
use_heterogeneous_vocab |
boolean |
false |
允许 draft 与 target 使用不同词表。初始化时会构建 token 级交集,并把 draft logits 约束到共享 token 上。仅兼容 method=draft_model。开启时暂不支持概率式 draft 采样(draft_sample_method='probabilistic')。 |
Gemma 4 提醒(再次强调):Gemma 4 assistant checkpoint 应作为 Gemma 4 MTP speculator 处理,即用
"method": "mtp"并把 assistant checkpoint 放进model,参考 MTP 指南。若启动日志对 Gemma 4 assistant checkpoint 显示SpeculativeConfig(method='draft_model', ...),则说明安装版本不含该路径的 Gemma 4 MTP 支持,应升级版本而非强行走通用 draft-model 路径。
5.2 N-Gram 专用键
| Key | 类型 | 默认值 | 含义 |
|---|---|---|---|
prompt_lookup_max |
integer >= 1 |
两个边界都省略时为 5;否则省略时镜像 prompt_lookup_min |
N-gram 窗口大小上限。 |
prompt_lookup_min |
integer >= 1 |
两个边界都省略时为 5;否则省略时镜像 prompt_lookup_max |
N-gram 窗口大小下限。 |
示例:
vllm serve <target-model> \
--speculative-config '{
"method": "ngram",
"num_speculative_tokens": 4,
"prompt_lookup_min": 2,
"prompt_lookup_max": 5
}'
5.3 Suffix Decoding 专用键
| Key | 类型 | 默认值 | 含义 |
|---|---|---|---|
suffix_decoding_max_tree_depth |
integer |
24 |
前缀匹配与投机长度合计的最大树深。 |
suffix_decoding_max_cached_requests |
integer |
10000 |
全局后缀树缓存的最大请求数;设 0 禁用全局缓存。 |
suffix_decoding_max_spec_factor |
float |
1.0 |
投机长度相对前缀匹配长度的倍数上限。 |
suffix_decoding_min_token_prob |
float |
0.1 |
投机某 token 所需的最低估计概率。 |
示例:
vllm serve <target-model> \
--speculative-config '{
"method": "suffix",
"num_speculative_tokens": 8,
"suffix_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
}'
5.4 跨词表 Draft 模型(Token-Level Intersection,TLI)
默认情况下 vLLM 要求 draft 与 target 共享同一词表。将 use_heterogeneous_vocab: true 开启后,即可使用 TLI(Token-Level Intersection) 算法,从而允许使用来自不同模型家族、带不同 tokenizer 的 draft 模型。
初始化时,vLLM 通过对 token 字符串做规范化后计算两个词表的交集,建立起两个词表间的映射;draft logits 在采样前被约束到共享 token 集合上,采样得到的 token ID 在送入拒绝采样前再翻译回 target 词表。示例如下(Qwen3-8B 目标 + SmolLM2-135M 草稿,跨家族混用):
from vllm import LLM, SamplingParams
llm = LLM(
model="Qwen/Qwen3-8B",
speculative_config={
"method": "draft_model",
"model": "HuggingFaceTB/SmolLM2-135M-Instruct",
"num_speculative_tokens": 3,
"use_heterogeneous_vocab": True,
},
gpu_memory_utilization=0.5,
)
对应字段定义见 vllm/config/speculative.py(use_heterogeneous_vocab: bool = False,并注释限定 method='draft_model')。当前限制:TLI 仅支持 greedy draft 采样(draft_sample_method='greedy' 即默认值);概率式接受(draft 采样温度 > 0)尚不支持,将在未来版本加入。
5.5 配置注意事项(Notes)
- CLI 的
--speculative-config期望一个 JSON 对象;若使用 YAML 配置文件,应写成嵌套映射而非转义的 JSON 字符串; tensor_parallel_size不是speculative_config中的合法键,请改用draft_tensor_parallel_size。源码中tensor_parallel_size字段被保留仅为向误传的用户发出告警(vllm/config/speculative.py);temperature、top_p之类属于采样参数(SamplingParams/ 服务端sampling_params),不要混入--speculative-config;target_model_config、draft_model_config、target_parallel_config、draft_parallel_config、draft_load_config等内部字段由 vLLM 在 post-init 阶段自动填充,不应当由用户设置;use_heterogeneous_vocab目前仅支持 greedy draft 采样。
六、进阶:动态投机、自适应验证与自定义 Proposer
6.1 Dynamic Speculative Decoding(按并发度调 K)
为什么需要动态 SD? 投机解码每步要为每个序列验证 K 个 token。当 batch size(BS)增大时,实际参与验证的序列数为 BS×K,计算量随之上升;一旦 BS×K 越过临界 BS,投机解码反而会拖慢解码速度(TPOT)。动态 SD(Dynamic SD)的做法是把 K 随并发度调优到最优值,从而在保持收益的同时避免过冲。
典型使用场景:
- 并发波动的工作负载:同一个部署在并发升高时自动调低 K;
- RL rollout 尾段:一轮 rollout 开始时 BS 高、尾段只剩少数长尾请求持续产出大量 token 而拖慢整体进度——此时需要把 K 调高来加速尾段。
启用方式是在某个 SD 方法的配置中加入 num_speculative_tokens_per_batch_size(一个 [start_bs, end_bs, optimal_K] 三元组列表,含义为当并发落在闭区间 [start_bs, end_bs] 时使用 optimal_K 个 draft token):
--speculative-config '{
"method": "eagle",
"model": "yuhuili/EAGLE-LLaMA3.1-Instruct-8B",
"num_speculative_tokens": 3,
"num_speculative_tokens_per_batch_size": [
[1, 64, 3],
[65, 128, 1],
[129, 512, 0]
]
}'
即:并发在 [1, 64] 时 K=3;在 [65, 128] 时 K=1;在 [129, 512] 时 K=0(不产生任何 draft token)。字段定义见 vllm/config/speculative.py(num_speculative_tokens_per_batch_size: list[tuple[int, int, int]],batch-size 区间左闭右闭)。在线示例:
# Dynamic SD + Eagle drafter
VLLM_USE_V2_MODEL_RUNNER=0 vllm serve meta-llama/Llama-3.1-8B-Instruct \
--speculative-config '{
"method": "eagle",
"model": "yuhuili/EAGLE-LLaMA3.1-Instruct-8B",
"num_speculative_tokens": 3,
"num_speculative_tokens_per_batch_size": [
[1, 64, 3],
[65, 128, 1],
[129, 512, 0]
]
}'
# Dynamic SD + Eagle3 drafter
VLLM_USE_V2_MODEL_RUNNER=0 vllm serve meta-llama/Llama-3.1-8B-Instruct \
--speculative-config '{
"method": "eagle3",
"model": "yuhuili/EAGLE3-LLaMA3.1-Instruct-8B",
"num_speculative_tokens": 3,
"num_speculative_tokens_per_batch_size": [
[1, 16, 5],
[17, 32, 4],
[33, 64, 3],
[65, 128, 1],
[129, 512, 0]
]
}'
已知限制:已在 Eagle、Eagle-3、DFlash 上测试通过,其他 SD 方法可能无法开箱即用;完整 cudagraph 仅在 Model Runner V2 下可用(MRv1 对该特性只支持 piece-wise cuda graph);不兼容数据并行(--data-parallel-size > 1),因为各 DP rank 独立调度可能选出不同的 K 值,导致 DP 集合通信发散与死锁——启用 DP 时 vLLM 会自动禁用 num_speculative_tokens_per_batch_size 并回退到静态 num_speculative_tokens。
6.2 Adaptive Verification(自适应验证)
投机解码的本质是"用更少的解码步换更多的计算"。在 batch size = 1、GPU 处于内存受限(算力空闲)时这是好交易:多余的 draft token 几乎免费;但在 batch size = 256 时则非常微妙——draft token 与真实 token 争抢同一份算力,每个被拒 token 都是浪费的计算,累积到一定程度吞吐反而下降。而逐位置的接受率衰减很快,算力空闲时该投机位"免费值得赌一把",一旦算力饱和这种赌注就产生真实的吞吐代价。拐点随负载与负载相关的接受率移动,因此没有任何静态 num_speculative_tokens 能同时适配所有并发度。
Adaptive Verification 的思路是逐步决策验证多少草稿:每个(请求、位置)的草稿位按"生存概率"(该请求逐位置置信度的累计乘积)打分,得分最高的草稿位被准入,直到全局预算耗尽;草稿位跨请求竞争——高置信请求的第 5 位可以胜过低置信请求的第 1 位,于是高置信请求保留下整块草稿,低置信请求可能在 1~2 个 token 后被裁剪。预算来自启动时 profile 出的成本模型:vLLM 测量不同 shape 下每一步的代价,选择能最大化"每秒期望接受 token 数"的 token 数。实际效果是一个配置即可覆盖整个负载区间,基本消除了逐部署调 num_speculative_tokens 的需要。
支持范围:Adaptive Verification 需要逐位置接受率估计,当前仅支持带 confidence head 的 DSpark。默认关闭,开启方式(DeepSeek-V4-Flash-DSpark 示例):
vllm serve deepseek-ai/DeepSeek-V4-Flash-DSpark \
--tokenizer-mode deepseek_v4 --trust-remote-code \
--speculative-config '{
"method": "dspark",
"model": "deepseek-ai/DeepSeek-V4-Flash-DSpark",
"num_speculative_tokens": 7,
"draft_sample_method": "probabilistic",
"enable_adaptive_verification": true
}'
置 enable_adaptive_verification: false 则退化为对每个请求都验证完整草稿块。要求与限制:
- attention 后端必须容忍"设备端决定 query 长度"(CPU 侧长度只作为上界);依赖 CPU 长度做规划的 attention 后端会被 attention selector 排除,对硬编码后端(hard-wire)的模型则会在启动时被拒绝;
- 必须使用完整 cudagraph(步进成本从捕获的图中测量),因此
--enforce-eager会在启动时被拒绝; - 不支持 LoRA(逐 token 的 LoRA 映射基于 CPU 侧边界构建)与 pipeline parallelism(成本曲线与置信度只存在于最后一个 rank)。
成本 profile 调优:步进成本默认基于 8192 token 的合成 KV 上下文做 profile。服务超长上下文的部署可通过环境变量 VLLM_ADAPTIVE_VERIFICATION_PROFILE_CONTEXT_LEN 提高该值,以让 profile 读取更贴近真实的 cache 量:
export VLLM_ADAPTIVE_VERIFICATION_PROFILE_CONTEXT_LEN=131072
6.3 Custom Proposer Backend(实验性)
你还可以通过 custom_class 方法注入自己的 proposer 类:将 method 设为 custom_class,model 设为自定义类的完整模块路径。自定义类须在实例化时接收一个 VllmConfig,并实现 propose 方法。示例配置:
speculative_config.method = "custom_class"speculative_config.model = "your_module.YourCustomProposerClass"
对应 method 的取值空间(含 custom_class、ngram、medusa、mlp_speculator、draft_model、suffix 等)见 vllm/config/speculative.py 中定义的 SpeculativeMethod 字面量类型。
七、投机解码的无损保证(Lossless Guarantees)
vLLM 中的投机解码在追求推理效率的同时维持输出质量,其"无损"含义从三个层面界定:
-
理论无损(Theoretical Losslessness):投机解码采样在理论上无损,精度上限取决于硬件数值精度。浮点误差可能造成输出分布的细微偏差(这是投机采样这一类方法本身已知的边界,详见加速 LLM 解码的投机采样原始论文)。
-
算法无损(Algorithmic Losslessness):vLLM 对投机解码的实现经过算法级无损验证,核心验证手段包括:
- Rejection Sampler 收敛性:确保 vLLM 拒绝采样器的样本与目标分布一致,验证代码位于 tests/samplers/test_rejection_sampler.py;
- 贪心采样等价性:确认开启投机解码的贪心采样与不开启的贪心采样完全一致,验证 vLLM 的投机解码框架(连同 vLLM 前向传播与拒绝采样器)具备无损保证。此类性质由 tests/v1/spec_decode 下 e2e 测试断言实现(几乎全部测试都在验证该性质)。
-
vLLM 的 Logprob 稳定性:vLLM 当前不保证 token logprob 跨运行的稳定性——同一请求在不同运行中可能出现不同输出。详见 FAQ 中 "Can the output of a prompt vary across runs in vLLM?"。
即使在无损框架下,开启与关闭投机解码的输出仍可能因以下因素产生差异:
- 浮点精度:硬件数值精度差异可能导致输出分布出现微小偏差;
- Batch Size 与数值稳定性:batch size 的变化可能引起 logprob 与输出概率的波动(可能是批量算子中的非确定性行为或数值不稳定性所致)。
缓解策略参见上述 FAQ 条目。
八、已知功能不兼容(Known Feature Incompatibility)
- 截至
vllm<=0.15.0,pipeline parallelism 与投机解码不可组合; vllm<=0.10.0不支持基于 draft model 的投机解码。
(若使用早于上述版本的 vLLM,请注意相应能力缺失;本文所有配置示例以当前仓库版本的实现为准。)
九、给 vLLM 贡献者与深入研究者的指引
- 想进一步理解投机解码运行时机制,建议从配置入口 vllm/config/speculative.py 出发,其
SpeculativeConfig定义了全部键位、类型约束与校验逻辑(例如synthetic接受率与目标平均接受长度的互斥换算_acceptance_length_to_rates、Qwen3-Omni DSpark 的专门校验_validate_qwen3_omni_dspark等); - 需要测量与复现的读者可使用 examples/features/speculative_decoding/spec_decode_offline.py,或按 benchmarking CLI 文档 使用基准 CLI;逐请求接受率在响应
metrics.speculative_decoding中给出(见 Per-Request Acceptance Metrics 与 per-request metrics 文档); - 服务端聚合的 spec-decode 指标(如
vllm:spec_decode_num_drafts_total、vllm:spec_decode_num_draft_tokens_total、vllm:spec_decode_num_accepted_tokens_total)可从/metrics的 Prometheus 端点获取,与逐请求字段在纯n==1负载下按求和关系对账; - 训练自家 speculator 模型的集成流程见 speculators.md;
- 完整 CLI 参数语义以 engine arguments reference 为准,
SpeculativeConfig的 API 细节可查vllm.config.SpeculativeConfig的文档字符串,其中关于计算图哈希(compute_hash)、后缀解码默认值(suffix_decoding_*)、拒绝采样方法(rejection_sample_method、draft_sample_method)等均有逐字段注释。
实战建议:方法选型时不要只看定性收益表——先在目标模型家族上确定是否原生支持 MTP、是否有现成的高质量 EAGLE/草稿权重,再从最低投机深度起步,配合
--per-request-spec-decode-metrics(summary级别)观察mean_acceptance_length与draft_acceptance_rate,最后用基准脚本在目标负载/并发/采样设置下做可复现测量,再决定是否引入 Dynamic SD 或 Adaptive Verification 这类自适应机制。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00