系列总览见 投机解码方案对比。前置:Medusa、EAGLE 与 EAGLE-2、MTP。

问题:EAGLE 加数据也涨不动

EAGLE-3(Li 等,arXiv 2503.01840,NeurIPS 2025)的出发点是一个反直觉的观察:给 EAGLE 的 draft 喂更多训练数据,收益只有一点点。作者把原因归到两处:

  1. 特征回归损失限制了 draft 的表达能力。 EAGLE 要求 draft 输出「逼近 target 的下一个末层特征」(L_reg),draft 的 hidden 被钉死在 target 特征的空间里。但 draft 真正要做的只是猜对 token,特征长什么样无所谓。
  2. 末层特征只为下一个 token 服务。 target 的末层被训练成「马上要投到词表上」,对 t+2、t+3 的信息已经被挤掉了。draft 要往后多猜几步,最好看中间层。

抽象:只预测 token,并让训练和推理看到同样的输入

直接去掉 L_reg 并不行。论文的消融显示,去掉之后第 1 步接受率上升了,但第 2 步一塌糊涂:

解法叫 training-time test:训练时就把推理过程展开。第 1 步用 target 特征,第 2、3……步把 draft 自己的输出 a 喂回去当输入,在每一步都对 token 算交叉熵。这样 draft 在训练时就见过「自己的输出当输入」的分布,也就不再需要 L_reg 把输出拉回 target 空间。

EAGLE-3 的 training-time test

实现上只需要改 self-attention 的 mask:模拟步里,query 对「原始数据」位置正常因果注意,对模拟步自己产生的 key 只看对角线(同一个位置在前几步的输出),这部分用逐元素点积算,不必真的做一次完整的 attention。官方代码展开 7 步,第 i 步损失权重 0.8^i(论文正文没有写这两个值)。

与同期 HASS 的区别:HASS 也在训练里模拟多步,但保留了特征损失和末层输入;EAGLE-3 两者都去掉了。

draft 结构

下图右列就是 EAGLE-3,可以和 EAGLE、DeepSeek MTP 对照着看:

EAGLE、MTP、EAGLE3 的 draft 结构

训练与结果

局限:没测 405B、671B 这种规模;batch 越大收益越小;服务化测试用的是链而不是树。 ### 在 SGLang 里

EAGLE3 是独立的枚举值,但 worker 和 EAGLE 共用 EAGLEWorkerV2,树构造、verify、draft extend 完全相同(见 上一篇)。差别集中在两处:target 要多吐几层 hidden,draft 模型换成 models/llama_eagle3.py。

target 侧的多层捕获。 set_eagle3_layers_to_capture(如 models/llama.py)在 draft 配置没给层号时默认捕获 [2, N // 2, N − 3];配置里给了 eagle_aux_hidden_state_layer_ids 时每个加 1,因为 SGLang 在「第 i 层之前」捕获,等价于第 i−1 层的输出。这些 hidden 在 prefill 和 verify 时顺带拼好,交给 draft。

draft 侧的结构和论文 / 官方代码一致:

参数上 EAGLE-3 沿用 EAGLE 的 (steps, topk, draft tokens) 与默认值。论文里的大 batch 结论在 SGLang 里也成立:大 batch 时应该用 topk = 1 的链,或打开 --speculative-adaptive,按 batch size 分桶自动调 steps(只对 topk = 1 的 EAGLE / EAGLE3 生效)。

小结

EAGLE-3 的关键一步是承认「draft 只需要猜对 token,不需要像 target」。去掉特征回归之后,draft 的输入就不必局限于末层特征,可以融合低中高三层;为了弥补训练和推理输入分布的差异,用 training-time test 在训练时就展开多步。回报是 draft 能随数据量持续变强,并在大 batch 下仍有收益。但它仍是串行 draft,k 个 token 要 k 次前向,k 很难开大。下一篇 DFlash 换了一个思路:一次前向出一整块。