首页
/ vLLM EAGLE 投机解码实战:EAGLE/EAGLE3 草稿模型配置、源码实现与接受率评测

vLLM EAGLE 投机解码实战:EAGLE/EAGLE3 草稿模型配置、源码实现与接受率评测

2026-09-06 19:08:57作者:范垣楠Rhoda

本文以 vLLM 的 EAGLE 系列投机解码(speculative decoding)为主线,覆盖 Eagle Drafter 与 Eagle3 Drafter 两种模式的完整配置方法、speculative_config 各参数含义,并结合仓库源码深入剖析 EAGLE 草稿头的架构命名、Proposer 调用链与"embedding + 目标模型隐状态"融合的前向实现,最后讲解如何利用仓库内置离线脚本提取请求级接受率(acceptance rate)来量化加速效果。读完后,你可以直接在生产环境配置 EAGLE 投机解码,并具备验证其无损性与性能收益的完整手段。

EAGLE 投机解码在 vLLM 中的定位

vLLM 官方文档将投机解码定位为降低中低 QPS(queries per second)、内存受限(memory-bound)场景下逐 token 延迟的手段(见 docs/features/speculative_decoding/README.md)。在官方提供的方法谱系中,EAGLE 属于"基于模型的"方法:

模型基方法(EAGLE、MTP、draft model、PARD、MLP)能带来最好的延迟收益;而 n-gram、suffix 等轻量方法在高负载下不增加额外开销,只提供中等加速。

EAGLE 的核心思想(Extrapolation Algorithm for Greater Language-model Efficiency)是训练一个轻量草稿头(drafter),它以目标模型上一轮的隐藏状态(hidden states)加上 token embedding 作为输入,极低成本地"外推"出后续若干 token 的候选,再由目标模型一次性并行验证。由于草稿头只有一到两层 Transformer 层、参数量远小于目标模型,在中低负载下能显著摊薄每步解码的延迟。

vLLM 支持两个 EAGLE 变体,通过 speculative_config 中的 method 字段切换:

method 说明 草稿头架构前缀
eagle 第一代 EAGLE,输入为 token embedding 与目标模型隐状态的拼接 Eagle{原架构},如 EagleLlamaForCausalLM
eagle3 EAGLE-3,额外利用多层隐状态 Eagle3{原架构},如 Eagle3LlamaForCausalLM

架构命名规则直接由 EAGLE 配置类在加载草稿模型时改写,见 vllm/transformers_utils/configs/eagle.pymethod="eagle" 时把目标架构名加上 Eagle 前缀;method="eagle3" 时加 Eagle3 前缀(若架构名已含前缀则保持不变)。同一个 EAGLEConfig 还承载 truncated_vocab_size 等字段,用于控制草稿头输出层词表规模。

Eagle Drafter 配置示例

以下是最典型的 EAGLE 离线推理配置:目标模型为 Llama 3 8B Instruct(4 卡张量并行),草稿模型使用社区预训练好的 EAGLE 头,独立使用 1 卡张量并行,每步投机 2 个 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="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",
    },
)

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}")

参数逐项解读:

取值 含义
model yuhuili/EAGLE-LLaMA3-Instruct-8B 草稿头(EAGLE 头)的标识符,可以是 Hugging Face 仓库名或本地路径
draft_tensor_parallel_size 1 草稿模型自身的张量并行度,与目标模型的 tensor_parallel_size=4 相互独立
num_speculative_tokens 2 每步由草稿头提出并等待目标模型验证的 token 数
method eagle 显式指定投机方法;省略时 vLLM 会尝试从草稿模型信息推断

关于 method 的自动推断:从 vllm/config/speculative.py 的源码结构看,当未显式给出 method 时,vLLM 会检查草稿模型配置与模型名,例如草稿模型名中包含 eagle3 字样时会自动归一化为 method="eagle3"。因此显式写出 method 是最稳妥的做法,可以避免歧义。

EAGLE 方法额外支持两个开关(在 examples/features/speculative_decoding/spec_decode_offline.py 中均有对应命令行入口):

  • disable_padded_drafter_batch(默认 false):控制草稿批次是否做 padding 对齐;
  • parallel_drafting(默认 false):并行草稿生成,官方文档注明仅与 EAGLE 及 draft_model 类方法兼容。从 vllm/config/speculative.py 的内部方法表中可以看到,eagle3 对应原生 EAGLE3 不支持并行草稿,而 P-EAGLE 变体支持(草稿深度为 K-1)。

Eagle3 Drafter 配置示例

Eagle3 Drafter 与 Eagle Drafter 的配置方式一致,区别在 method 字段与草稿模型本身:

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=2,
    speculative_config={
        "model": "RedHatAI/Llama-3.1-8B-Instruct-speculator.eagle3",
        "draft_tensor_parallel_size": 2,
        "num_speculative_tokens": 2,
        "method": "eagle3",
    },
)

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}")

与上文示例相比:method 改为 eagle3,草稿模型换成 EAGLE-3 训练的 speculator 权重,且示例中草稿模型与目标模型同用 2 卡张量并行。由于 EAGLE-3 草稿头本身容量更大、对多层隐状态建模,仓库中自带的回归基线(见下文)也显示其平均接受长度高于经典 EAGLE。

源码剖析:EAGLE 草稿头如何工作

Proposer 入口

vLLM V1 引擎中 EAGLE 的提案逻辑由 vllm/v1/spec_decode/eagle.py 中的 EagleProposer 承担,它继承自通用基类 SpecDecodeBaseProposervllm/v1/spec_decode/llm_base_proposer.py),构造时的关键参数是 pass_hidden_states_to_model=True——这正体现了 EAGLE 的数据流:每个解码步,目标模型的前向会顺带产出隐状态,Proposer 将这些隐状态直接喂给草稿头,而不是让草稿头从零开始重算。

草稿头前向:embedding 与隐状态的融合

以 Llama 家族的 EAGLE 头实现 vllm/model_executor/models/llama_eagle.py 为例,可以看到三个标志性结构:

  1. 融合层 fcL110-L118):一个 ReplicatedLinear,输入维度为 hidden_size * 2、输出为 hidden_size,把 token embedding 与上一轮隐状态在最后一维拼接后投影到单一隐状态空间:

    self.fc = ReplicatedLinear(
        input_size=self.config.hidden_size * 2,
        output_size=self.config.hidden_size,
        bias=False,
        ...
    )
    

    前向(L123-L130)为 hidden_states = self.fc(torch.cat((input_embeds, hidden_states), dim=-1)),之后再进入一层(或少数几层)标准 LlamaDecoderLayer

  2. 跳过首层 input_layernormL43-L57):EAGLE 论文实现中第一层不做输入归一化,源码用 nn.Identity() 替换并附原始实现引用注释,这是 EAGLE 草稿头与"普通小模型"的关键差异之一。

  3. 权重名映射L64-L75):通过 WeightsMapper 把 HuggingFace 风格的 q_proj/k_proj/v_projgate_proj/up_proj 映射到 vLLM 融合后的 qkv_projgate_up_proj,保证社区发布的 EAGLE 权重可以直接加载。

仓库为不同目标模型家族都提供了对应的 EAGLE 头实现,例如 llama_eagle.pyllama_eagle3.pydeepseek_eagle.pydeepseek_eagle3.pyqwen3_eagle3.pymistral_eagle.pyllama4_eagle.pycohere_eagle.py 等。选择草稿模型时应确认其对应的目标模型家族已有对应实现。

无损性保障

官方 README(docs/features/speculative_decoding/README.md)给出了三点无损性论述:理论上投机解码采样在硬件浮点精度内无损;算法层面 vLLM 用 tests/samplers/test_rejection_sampler.py 验证拒绝采样收敛到目标分布,并用 tests/v1/spec_decode 下的端到端断言验证"greedy + 投机解码 == greedy";同时明确 logprob 不保证跨运行稳定。因此 EAGLE 配置下开启投机不会改变(greedy 场景)生成结果本身,只影响延迟。

预训练 EAGLE 草稿模型的选择

无需自己训练,Hugging Face 上已有两类主流社区维护的 EAGLE 草稿模型集合(按名称在 HF Hub 检索即可):

  • RedHatAI/speculator-models 集合:覆盖 Llama、Mistral 等主流家族的 speculator/EAGLE 头;
  • yuhuili 发布的 EAGLE 系列:如 yuhuili/EAGLE-LLaMA3-Instruct-8Byuhuili/EAGLE3-LLaMA3.1-Instruct-8B

选择草稿头的基本原则:

  1. 与目标模型严格对应:EAGLE 头是在特定目标模型上训练的,词表、层结构都绑定该模型家族;
  2. 方法匹配:EAGLE-3 训练的权重必须用 method="eagle3" 加载,经典 EAGLE 权重用 method="eagle"
  3. 版本注意:官方文档保留了历史提醒——若使用较老版本的 vLLM(0.7.0 之前),需先运行官方提供的转换脚本改造 EAGLE 权重目录,再把改造后的本地路径填入 model。当前仓库版本已内置完整加载路径,按上述配置直接加载即可。

离线评测:提取请求级接受率

仓库自带了一个功能完整的离线评测脚本 examples/features/speculative_decoding/spec_decode_offline.py,它正是 eagle.md 文档指向的"更详细的离线示例"。核心用法:

python examples/features/speculative_decoding/spec_decode_offline.py \
  --method eagle \
  --eagle-dir yuhuili/EAGLE-LLaMA3.1-Instruct-8B \
  --num-spec-tokens 3 \
  --tp 1 \
  --dataset-name hf \
  --dataset-path philschmid/mt-bench \
  --num-prompts 80 \
  --enable-chunked-prefill \
  --print-output

脚本关键参数(见 L43-L76 的解析逻辑):

  • --method:支持 ngrameagleeagle3mtpdraft_model 五种方法;
  • --eagle-dir:EAGLE 头路径;不指定时默认 yuhuili/EAGLE-LLaMA3.1-Instruct-8B(eagle)或 yuhuili/EAGLE3-LLaMA3.1-Instruct-8B(eagle3),见 L109-L115
  • --num-spec-tokens:投机深度;--tp:目标模型并行度;
  • --parallel-drafting / --disable-padded-drafter-batch:对应上文两个 EAGLE 开关;
  • --print-output:打印逐条 prompt 的生成文本。

脚本的亮点是请求级接受率统计L185-L221):通过 llm.get_metrics() 读取四个指标——

  • 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(各位置接受数向量)

并据此输出平均接受长度(mean acceptance length)以及每个投机位置上的接受率,可以直观判断"加深 num_speculative_tokens 是否还划算"——越靠后的位置接受率衰减越快。

脚本还内置 --test 回归模式(L232-L259):在 1xH100、80 条 mt-bench prompt、num_spec_tokens=3、greedy 采样条件下,断言平均接受长度落在期望值 2% 误差内——eagle 方法期望约 2.296eagle3 方法期望约 2.811。这一内置基线也佐证了 EAGLE-3 草稿头的接受长度显著优于经典 EAGLE,可作为你本地环境性能回归的参照锚点(实际数值随硬件与批次构成浮动)。

在线服务:--speculative-config JSON 配置

除 Python API 外,vllm serve 同样接受 JSON 形式的投机配置,两个键位与 Python 字典完全一致(docs/features/speculative_decoding/README.md 的 schema 说明):

vllm serve meta-llama/Meta-Llama-3-8B-Instruct \
  --tensor-parallel-size 4 \
  --speculative-config '{
    "method": "eagle",
    "model": "yuhuili/EAGLE-LLaMA3-Instruct-8B",
    "draft_tensor_parallel_size": 1,
    "num_speculative_tokens": 2
  }'

几条容易踩坑的注意事项(同样来自官方 README 的 Notes 部分):

  • tensor_parallel_size 不是 speculative_config 的合法键,草稿模型并行必须写 draft_tensor_parallel_size
  • temperaturetop_p 属于采样参数,不放进投机配置;
  • target_model_configdraft_parallel_config 等内部字段由 vLLM 自动填充,用户不应设置;
  • 已知不兼容:截至 0.15.0 版本,流水线并行(pipeline parallelism)与投机解码不可组合使用。

小结

  • vLLM 中启用 EAGLE 投机解码只需在 speculative_config 中给出四个核心键:methodeagle/eagle3)、model(草稿头)、num_speculative_tokensdraft_tensor_parallel_size
  • 源码层面,EAGLE 草稿头以"token embedding + 目标模型隐状态"拼接过 fc 投影层进入少量 Transformer 层(vllm/model_executor/models/llama_eagle.py),由 vllm/v1/spec_decode/eagle.pyEagleProposer 在每个解码步消费目标模型透传的隐状态完成提案;
  • examples/features/speculative_decoding/spec_decode_offline.py 提取逐位置接受率,可以定量指导 num_speculative_tokens 的取值,并利用内置 --test 基线(eagle ≈ 2.296 / eagle3 ≈ 2.811 平均接受长度)做回归验证;
  • 选择草稿头时确认目标模型家族匹配、方法变体一致,并优先使用社区针对你的目标模型训练过的 EAGLE 权重。
登录后查看全文
热门项目推荐
相关项目推荐