大模型推理还在“一个字一个字蹦”?在 OpenVINO™ GenAI 中上手 EAGLE-3 草稿模型
EAGLE-3作为新一代投机解码(speculative decoding)技术的重要突破,其核心价值在于突破了传统投机解码依赖完全独立草稿模型的技术局限。
作者:武卓、卢致翔
做过本地大模型推理的开发者,通常都会遇到一个很现实的问题:模型能力够强,但输出就是不够“跟手”。尤其是在本地代码生成、对话助手、Agent 工具调用这类场景里,用户真正感知到的并不是模型参数有多大,而是它首字出来够不够快、整段生成够不够流畅。而自回归解码的天然顺序性,决定了大模型往往只能“一个 token 一个 token”往前走,这也是生成时延迟居高不下的根源。OpenVINO™ 对投机解码的支持中也明确指出,这类方法的目标就是在保持主模型精度的前提下减少主模型推理次数,并且在低并发、时延敏感场景里收益最明显。
这也是为什么 EAGLE-3 值得开发者关注。EAGLE-3作为新一代投机解码(speculative decoding)技术的重要突破,其核心价值在于突破了传统投机解码依赖完全独立草稿模型的技术局限。该技术通过训练一个轻量级"草稿头部"(draft head)——通常为单层自回归预测模块——直接集成到目标模型中,实现了架构层面的创新优化。其技术特点在于草稿头部能够复用目标模型的内部特征映射进行token预测,在仅增加极少参数量的前提下实现显著的推理加速效果。
EAGLE-3的技术突破主要体现在两个核心创新维度:首先是多层特征融合(Multi-Layer Fusion)机制,该机制通过读取并融合低层特征(句法/词元级规律)、中层特征(语义/句子结构)以及高层特征(高层决策、未来token关联),构建多层融合式草稿头部和候选分支树结构,从而提升预测命中率与系统稳定性。这种多层结构相比单层顶层特征提供了更稳定、更全面、更抗噪声的特征表示,其中较低层特征不会随采样误差快速恶化,而高层特征则有助于定位全局语义一致性,从根本上缓解了特征不确定性(feature uncertainty)问题。
其次是训练阶段测试(Training-Time Test)创新,EAGLE-3在训练过程中实施了关键的技术改进:摒弃传统的"干净真实特征"训练方式,主动模拟推理时的噪声环境,即训练时向草稿头部输入的不是ground-truth链,而是类似"EAGLE-3在实际推理时会遇到的噪声特征",这种被称为分布错配消除(distribution mismatch removal)的方法使模型真正学会在噪声环境中进行前向预测,确保接受率(acceptance rate)在多步预测中不再迅速衰减,大幅提升了深度草稿的成功率,这正是EAGLE-3实现性能跃升的核心技术原因。
在 OpenVINO™ 2026.0 中, OpenVINO™ GenAI把这项技术终于变成了开发者可以直接上手的能力。开发者可以用额外的 EAGLE3 草稿模型来提升每秒生成的token数,并且这部分支持也已经扩展到NPU。换句话说,EAGLE-3 不再只是论文里的“更快方法”,而是已经进入 OpenVINO™ 的实际开发链路。
分步指南:
步骤1: 环境准备
克隆openvino.genai GitHub仓库

从openvino.genai GitHub仓库克隆OpenVINO™ GenAI的开源代码。
git clone --recursive https://github.com/openvinotoolkit/openvino.genai.gitcd openvino.genai
导航至投机解码示例文件夹:
<your_path>\openvino.genai\samples\python\text_generation
准备一个 Python 虚拟环境并激活它,然后安装 ../../deployment-requirements.txt 以运行示例。
pip install --upgrade-strategy eager -r ../../export-requirements.txt
按照“快速入门样例”指南获取有关如何设置环境并使用 OpenVINO™ GenAI 进行推理的详细信息。一旦安装了 OpenVINO™ GenAI,下一步就是下载并转换模型以便进行推理。
步骤2: 准备主模型和EAGLE-3草稿模型
这里把模型准备分成两部分:
-
主模型:比如 Qwen3-8B 对应的 OpenVINO™ 版本
-
草稿模型:与主模型匹配的 EAGLE-3 草稿模型
主模型这一侧相对简单,像 OpenVINO™/Qwen3-8B-int4-ov 这样的模型可以直接从魔搭社区OpenVINO™专区大语言模型合集下载使用。更值得注意的是 EAGLE-3 draft model 的准备方式。从魔搭社区下载Qwen3-8B的EAGLE-3草稿模型 https://modelscope.cn/models/AngelSlim/Qwen3-8B_eagle3 ,并利用optimum-Intel完成模型导出为OpenVINO™ IR格式:
optimum-cli export openvino --model AngelSlim/Qwen3-8B_eagle3 --task text-generation-with-past --weight-format int4 –group-size 128 –ratio 1.0 --trust-remote-code <output_dir>
注: 对于NPU的草稿模型,推荐使用Per-Channel对称的量化方式和INT8的数据格式(--weight-format int8 --sym --group-size -1),可获得更好的性能体现。
步骤3: 先跑一个“没有 EAGLE-3”投机解码的推理作为基线
这一步的意义很简单:先确认主模型单独跑是通的。OpenVINO™ GenAI 的基础调用方式本身就非常轻量,LLMPipeline(model_path, device) 加上 generate() 就能把本地文本生成流程跑起来。
import openvino_genai as ov_genaiprompt = "请用 Python 写一个快速排序,并解释时间复杂度。"pipe = ov_genai.LLMPipeline("models/main_model", "CPU")config = ov_genai.GenerationConfig()config.max_new_tokens = 256result = pipe.generate(prompt, config)print(result)
步骤4: 把 EAGLE-3 草稿模型接进 OpenVINO™ GenAI
接入 EAGLE-3 之后,代码层面的变化其实不大。核心有两个点:
用 draft_model(...) 加载草稿模型
在 GenerationConfig 里设置 num_assistant_tokens
这也是 OpenVINO™ GenAI 官方 投机解码文档给出的标准接法。
import openvino_genai as ov_genaidef streamer(subword: str):print(subword, end="", flush=True)return Falseprompt = "请用 Python 写一个快速排序,并解释时间复杂度。"main_device = "GPU" # 也可以换成 CPU / NPU,取决于你的环境draft_device = "GPU" # 也可以换成 CPU / NPU,取决于你的环境scheduler_config = ov_genai.SchedulerConfig()scheduler_config.cache_size = 2draft = ov_genai.draft_model("models/eagle3_draft_model", draft_device)pipe = ov_genai.LLMPipeline("models/main_model",main_device,scheduler_config=scheduler_config,draft_model=draft,)config = ov_genai.GenerationConfig()config.max_new_tokens = 256config.num_assistant_tokens = 5pipe.generate(prompt, config, streamer)
注意:如果推理设备为NPU,代码需要做一些更多设置,能够获得更好的性能,参考代码如下所示:
device = 'NPU'config = create_generation_config()draft_model = openvino_genai.draft_model(args.draft_model_dir, device, MAX_PROMPT_LEN=1024, MIN_RESPONSE_LEN=512,NPU_COMPILER_TYPE="DRIVER")pipe = openvino_genai.LLMPipeline(args.model_dir, device, CACHE_DIR="D:\\work\\model_cache",MAX_PROMPT_LEN=1024, MIN_RESPONSE_LEN=512, NPU_COMPILER_TYPE="DRIVER", draft_model=draft_model)config.num_assistant_tokens = 5res = pipe.generate(prompt, config, streamer)
完整的推理代码,包含基线测试的参考代码,参考文末的附录所示。
获得更好性能的一些配置小贴士:
-
当前版本面向用户开放的主要配置接口为num_assistant_tokens参数,用于控制草稿模型单次推理生成的辅助token数量,后续版本将逐步开放更多精细化配置接口以满足不同应用场景需求。
-
num_assistant_tokens参数支持动态配置,典型取值范围为3-7,用户应根据使用的模型模型及业务场景的要求进行合理选择,以实现推理性能的最优。
-
在NPU上部署时,num_assistant_tokens参数值应严格控制在小于等于7。
-
草稿模型和主模型需要部署在相同的加速硬件上(比如:同在iGPU或者同在NPU)。
根据 OpenVINO™ GenAI 当前文档,会发现这套接口本身就是为“主模型 + 草稿模型”这种 投机解码方式准备好的:draft_model()、LLMPipeline(..., draft_model=...)、config.num_assistant_tokens 这些入口都已经标准化了。对开发者来说,这点非常友好——你不需要自己写一套校验逻辑,只需要把模型准备好,把参数调起来。
步骤5: Demo实例对比
以下是在Intel最新的酷睿Ultra3系列处理器X7 385H上运行demo的对比视频
无EAGLE-3模型效果
有EAGLE-3模型效果
OpenVINO™ 2026.0 这次把 EAGLE-3 带进 OpenVINO™ GenAI,它的意义不只是“又多支持了一种 投机解码的方法”,而是给开发者释放了一个很明确的信号:本地大模型推理的优化,不再只是量化、裁剪、KV cache 这些老招,而是正在进入更聪明的解码阶段。
对于开发者来说,这件事尤其有价值。因为你并不需要重写整套推理框架,也不需要把工程完全切到另一套 serving 栈里;在 OpenVINO™ GenAI 里,你依然可以沿用熟悉的 LLMPipeline 接口,把 EAGLE-3 草稿模型接进来,然后开始做自己的本地代码助手、Agent、文档问答或其它 GenAI 应用。
更多资源
OpenVINO™ GenAI 官方文档
OpenVINO™ GenAI示例
反馈与问题提交
附录:
在NPU上运行含EAGLE-3草稿模型的OpenVINO™ GenAI推理部署及基线测试代码:
#!/usr/bin/env python3# Copyright (C) 2024-2025 Intel Corporation# SPDX-License-Identifier: Apache-2.0import argparseimport openvino_genaidef streamer(subword):print(subword, end='', flush=True)# Return flag corresponds whether generation should be stopped.return openvino_genai.StreamingStatus.RUNNINGdef print_simplified_metrics(res, is_speculative_decoding=False):"""Print simplified performance metrics"""if is_speculative_decoding:# Speculative Decoding metricsif res.extended_perf_metrics:main_model_metrics = res.extended_perf_metrics.main_model_metricsprint(f"MAIN MODEL")tpot_mean = main_model_metrics.get_tpot().meantokens_per_sec = 1000.0 / tpot_mean if tpot_mean > 0 else 0print(f" TPOT: {tpot_mean:.2f} ms/iteration ({tokens_per_sec:.2f} Tokens/S)")print(f" Num generated token: {main_model_metrics.get_num_generated_tokens()} tokens")# 添加 Acceptance rate 计算和打印num_accepted_tokens = res.extended_perf_metrics.get_num_accepted_tokens()print(f" Num accepted token: {num_accepted_tokens} tokens")print()else:# Regular inference metricsif hasattr(res, 'extended_perf_metrics') and res.extended_perf_metrics:main_model_metrics = res.extended_perf_metrics.main_model_metricsprint(f"MAIN MODEL")tpot_mean = main_model_metrics.get_tpot().meantokens_per_sec = 1000.0 / tpot_mean if tpot_mean > 0 else 0print(f" TPOT: {tpot_mean:.2f} ms/iteration ({tokens_per_sec:.2f} Tokens/S)")print(f" Num generated token: {main_model_metrics.get_num_generated_tokens()} tokens")print(f" Num accepted token: N/A (Regular inference mode)")print()elif hasattr(res, 'perf_metrics') and res.perf_metrics:metrics = res.perf_metricsprint(f"MAIN MODEL")# TPOT (Time Per Output Token)if hasattr(metrics, 'get_tpot'):tpot = metrics.get_tpot()tpot_mean = tpot.meantokens_per_sec = 1000.0 / tpot_mean if tpot_mean > 0 else 0print(f" TPOT: {tpot_mean:.2f} ms/iteration ({tokens_per_sec:.2f} Tokens/S)")# Number of generated tokensif hasattr(metrics, 'get_num_generated_tokens'):print(f" Num generated token: {metrics.get_num_generated_tokens()} tokens")print(f" Num accepted token: N/A (Regular inference mode)")print()else:print("MAIN MODEL")print(" Performance metrics not available")print()def create_generation_config():config = openvino_genai.GenerationConfig()config.do_sample = Falseconfig.top_p = 0.95config.top_k = 20config.max_new_tokens = 512config.temperature = 0.6config.stop_token_ids = {151645, 151643}return configdef main():parser = argparse.ArgumentParser()parser.add_argument('model_dir', help='Main model directory path')parser.add_argument('--draft_model_dir', help='Draft model directory path (optional, enables Speculative Decoding)')args = parser.parse_args()# Default prompts for testingprompts = ['Please write a quicksort in Python and explain the time complexity. /no_think']device = 'NPU'config = create_generation_config()# Initialize pipelineif args.draft_model_dir:print("Running Speculative Decoding mode...")draft_model = openvino_genai.draft_model(args.draft_model_dir, device,MAX_PROMPT_LEN=1024, MIN_RESPONSE_LEN=512,NPU_COMPILER_TYPE="DRIVER")pipe = openvino_genai.LLMPipeline(args.model_dir, device,CACHE_DIR="D:\\work\\model_cache",MAX_PROMPT_LEN=1024,MIN_RESPONSE_LEN=512,NPU_COMPILER_TYPE="DRIVER",draft_model=draft_model)config.num_assistant_tokens = 5is_speculative = Trueelse:print("Running regular inference mode...")pipe = openvino_genai.LLMPipeline(args.model_dir, device,CACHE_DIR="D:\\work\\model_cache",MAX_PROMPT_LEN=1024,LLM_MIN_RESPONSE_LEN=512,NPU_COMPILER_TYPE="DRIVER")is_speculative = False# Process promptsfor i, prompt in enumerate(prompts, 1):print(f"Prompt: {prompt}")print("Output: ", end='')res = pipe.generate([prompt], config, streamer)print()print_simplified_metrics(res, is_speculative)if __name__ == '__main__':main()
OpenVINO 小助手微信 : OpenVINO-China
如需咨询或交流相关信息,欢迎添加OpenVINO小助手微信,加入专属社群,与技术专家实时沟通互动。
更多推荐



所有评论(0)