AB
AiBoss站
教程

投机解码(Speculative Decoding)原理与配置指南

教程

投机解码(Speculative Decoding)原理与配置指南

投机解码用小模型先草拟若干候选 token,再由大模型一次前向并行验证,在不改变输出分布的前提下把推理速度提升到 2 至 3 倍。本教程讲清内存带宽瓶颈、草拟—验证循环的接受与拒绝规则、Medusa / Eagle / Prompt Lookup 三类变体,以及在推理框架中启用它的配置要点与适用边界。

大语言模型生成文本时,每产出一个 token 都要把全部权重从显存搬进计算单元一次。计算单元本身并不慢,慢的是这场反复发生的数据搬运,工程上称为「受内存带宽限制」。投机解码(Speculative Decoding)针对的正是这一点:它不改模型权重、不重新训练、不牺牲输出质量,只换一种生成策略,就能把推理速度提高到原来的 2 至 3 倍。本教程面向需要在推理服务里做性能优化的工程师,从瓶颈成因讲到草拟—验证循环的判定规则,再讲到 Medusa、Eagle、Prompt Lookup Decoding 三类现代变体,最后给出在推理框架中启用该技术的配置思路与取舍判断。

准备工作

投机解码不是一项需要从零搭建的工程。在主流推理框架里,它通常是一个配置开关,但在打开之前,有几件事需要先确认清楚,否则很容易出现「开了反而更慢」的情况。

确认推理框架是否内置支持

Hugging Face 的 text-generation-inference、vLLM、llama.cpp 都把投机解码做成了内置选项。使用这些框架时,工作重点不是实现算法,而是选对草拟模型、调对候选长度。如果所用框架没有内置支持,则需要自行实现草拟与验证两段逻辑,工作量会显著上升。

准备一对匹配的草拟模型与目标模型

经典方案需要两个模型:

  • 草拟模型(draft model):参数量远小于目标模型,负责快速生成候选 token 序列。它同样是自回归生成,只是因为体积小,速度快得多。
  • 目标模型(target model):真正要对外提供服务的那个大模型,负责对候选序列做一次并行验证。

两者必须使用同一套分词器(tokenizer),否则候选 token 无法被目标模型直接评分。此外,草拟模型与目标模型的「风格」越接近,接受率越高,收益越明显。用同系列的小尺寸模型搭配大尺寸模型,通常比跨系列混搭更稳妥。

确认显存余量

草拟模型要额外占用显存。即便它比目标模型小很多,在显存已经吃紧的部署里也可能成为压垮骆驼的那根稻草。启用前先算清楚:目标模型权重、KV 缓存、草拟模型权重三者之和是否仍在显存预算之内。

确认负载形态

这一步经常被跳过,但它直接决定投机解码是帮忙还是添乱。判断依据见后文「注意事项」一节。

操作步骤

第一步:理解为什么标准生成慢

标准自回归生成的过程是:模型读取此前所有 token,在数十亿参数上完成一次完整计算,输出恰好一个新 token;然后为下一个 token 把整件事重做一遍,直到回答结束。

瓶颈不在矩阵运算速度。现代 AI 加速卡做这类矩阵数学极快。问题在于模型的数十亿参数存放在显存里,每生成一个 token 之前,全部权重都要从显存传输到处理器。真正卡住的是这次数据传输,不是计算本身。一次只生成一个 token,意味着计算单元大部分时间在等数据搬运,处于空转状态。往服务器上加更多算力并不能实质提速,因为限制因素是数据搬得多快,而不是算得多快。

第二步:把「逐个生成」换成「批量草拟 + 并行验证」

核心思路很直接:不再一次生成一个 token,而是一次生成一批候选 token,再并行验证它们。具体由两个模型分工完成:

  1. 草拟模型快速生成一小段候选 token,通常是 4 到 8 个。这是它对目标模型接下来会说什么的猜测。
  2. 目标模型把整段候选一次性评分。它只加载一次权重,就对整个候选序列完成评估,而不是每个 token 加载一次。
  3. 目标模型从第一个候选开始,逐个判断接受还是拒绝。
  4. 一旦某个候选被拒绝,就从修正后的分布中采样一个正确的 token,然后从该位置重新开始草拟—验证循环。

关键在于第 3 步的判定规则,它决定了输出质量能否与目标模型单独生成时完全一致。

第三步:掌握接受与拒绝的判定规则

对每个候选 token,目标模型比较两件事:自己认为该 token 出现的概率,以及草拟模型认为它出现的概率。

  • 目标模型至少和草拟模型一样确信:该 token 直接接受。
  • 草拟模型比目标模型更确信:该 token 以一定概率被接受,这个概率随两者置信度差距的扩大而下降。
  • 被拒绝:从经过调整的分布中采样一个修正 token。这个调整正是为了抵消两个模型预测之间的差异。

这套统计方法给出一个数学保证:最终输出的概率分布,与目标模型自己逐个生成每个 token 时的分布完全相同。也就是说,输出质量不是「近似」的,而是可证明一致的。

第四步:估算一次循环的产出

最好情况下,全部候选都被接受,目标模型还会在末尾额外产出一个 token。这样系统以大约一次目标模型前向的开销,产出了 5 到 9 个 token。

最坏情况下,第一个草拟 token 就被拒绝并替换。此时相比标准解码反而略有额外开销,因为草拟模型的生成时间已经付出去了。输出质量在两种情况下都不受影响,但需要清楚:模型对搭配不佳时,代价是轻微变慢,而不只是「没有收益」。

第五步:理解加速从何而来

标准生成中,从显存加载目标模型权重占据了主要时间预算,每生成一个 token 就触发一次昂贵的显存读取,计算单元只能干等。启用投机解码后,目标模型权重在每个投机步中只加载一次,然后被应用到多个被接受的 token 上。GPU 的并行计算能力终于能在整个候选序列上做有意义的工作,而不是在单 token 读取之间空转。

实际加速幅度主要取决于接受率,也就是草拟模型的候选通过目标模型验证的比例。搭配良好的模型对在常见任务上,接受率通常在 70% 到 80% 之间,对应的实际加速落在 2 到 3 倍。文本可预测性强、重复度高的任务,接受率更高,收益也更大。

第六步:按场景选择现代变体

原始方案需要额外维护一个草拟模型,带来显存与工程上的开销。后续几种技术保留了核心思想,但去掉了独立草拟模型的必要性。需要注意,其中一些方案用更简单的实现或更高的吞吐量,换掉了原方法的严格分布保证,不过对输出质量的实际影响通常可以忽略。

方案草拟来源特点
经典双模型独立的小尺寸草拟模型有严格的分布一致性保证;需额外显存与运维成本
Medusa目标模型自身在目标模型最后一层挂接多个额外预测头,每个头独立预测一个未来位置,无需外部模型
Eagle目标模型的内部隐状态基于隐状态而非最终输出 token 做预测;隐状态携带更丰富的上下文信息,在复杂或领域特定文本上接受率更高
Prompt Lookup Decoding提示词与对话历史完全不需要第二个模型;扫描已有文本中可能在回答里复现的片段,直接作为候选

Prompt Lookup Decoding 在代码编辑与文档摘要这类任务上尤其有效,因为输出经常复用输入中的词汇与结构。Eagle 适合复杂或垂直领域文本。Medusa 适合不想额外维护一个模型的部署环境。

第七步:在推理框架中启用

在 text-generation-inference、vLLM、llama.cpp 这类框架里,启用投机解码属于配置变更,而不是研究项目。需要配置的内容通常包括:

  • 指定草拟模型(经典方案)或指定投机解码方法(Medusa、Eagle、Prompt Lookup 等变体);
  • 设定每次草拟的候选 token 数量,常见起点是 4 到 8;
  • 按需调整与接受率相关的采样参数。

各框架的参数名称、默认值与可用选项差异较大,且随版本变化,具体取值请以所用框架官网的当前文档为准。不要凭记忆填写参数名,也不要照抄其他框架的配置。

一个完整示例

下面用一个最小场景串起整个流程:为代码补全服务启用投机解码。这里描述的是配置思路与判断顺序,具体参数名以所用框架的当前文档为准。

场景设定

  • 服务类型:代码补全,单请求、低并发,用户期待即时反馈。
  • 输出长度:中等偏长,补全片段往往有几十到上百个 token。
  • 输入输出关系:补全内容大量复用当前文件中的标识符、函数名与代码结构。

这三个特征都指向投机解码的有利区间:输出较长、请求不密集、提示与回答共享词汇。

第一步:选定方案

由于代码补全的输出高度依赖输入上下文,Prompt Lookup Decoding 是成本最低的起点——它不需要第二个模型,不额外占显存,直接扫描提示与历史中的可复用片段作为候选。如果实测接受率不理想,再考虑引入同系列的小尺寸草拟模型,或改用基于隐状态的方案。

第二步:配置候选长度

候选长度从 4 到 8 起步。太短则每次验证的收益有限,太长则在接受率下降时浪费更多草拟开销。代码补全场景中,由于重复片段往往成段出现,可以从中段取值开始试。

第三步:跑一轮基线对比

在开启投机解码前后,分别用同一批真实请求测量两个指标:

  • 接受率:候选 token 中被接受的比例。这是决定收益的核心变量。
  • 端到端延迟:从请求发出到完整响应返回的时间。

如果接受率落在 70% 到 80% 区间,端到端延迟通常能看到 2 到 3 倍的改善。如果接受率明显偏低,先检查草拟模型与目标模型是否同系列、分词器是否一致,再考虑换方案。

第四步:验证输出质量未变

经典双模型方案与 Prompt Lookup 的验证逻辑都保留了目标模型的输出分布,因此质量应当与未启用时一致。但 Medusa、Eagle 等变体可能放弃严格的分布保证,此时需要用同一批提示对比开启前后的输出,确认实际影响在可接受范围内。

第五步:决定是否保留

如果服务形态发生变化——例如从单请求转为高并发批处理——需要重新评估。原因见下一节。

注意事项

批处理场景可能反而降低吞吐

这是最容易踩的坑。在高度批处理的部署中,投机解码可能实际损害吞吐量,因为草拟 token 会占用本可以服务更多请求的显存与算力。是否启用要看负载形态:

  • 适合启用:生成长输出;一次只服务一个请求而非大批量;提示与回答共享词汇或结构。
  • 谨慎启用:高吞吐批量服务。

问答、文档摘要、代码补全通常收益最大。

模型搭配不佳会带来负收益

如果第一个草拟 token 就被拒绝,草拟时间已经付出,整体比标准解码还慢一点。所以「开了投机解码」不等于「一定更快」,接受率才是决定因素。上线前务必实测,不要假设。

严格分布保证并非所有变体都有

经典双模型方案通过修正采样,保证最终输出与目标模型单独生成时的分布完全一致。Medusa、Eagle、Prompt Lookup 等变体为了简化实现或提高吞吐,可能放弃这一严格保证。对输出质量敏感的场景,需要单独评估。

分词器必须一致

草拟模型与目标模型若使用不同分词器,候选 token 无法被目标模型直接评分,整个验证环节失效。选型时先确认这一点。

显存与运维成本

经典方案要额外维护一个草拟模型,带来显存占用与版本管理负担。Medusa 与 Prompt Lookup 分别从「改造目标模型」和「不引入第二个模型」两个方向绕开这一成本,选型时可优先考虑。

参数与默认值以官网为准

各推理框架的配置项名称、默认候选长度、支持的变体列表都在持续演进。本文不给出具体参数值,实际配置时请查阅所用框架官网的当前信息。价格、配额、版本可用性同理,均以官方当前公布为准。