投机解码的第二本账:长上下文把瓶颈从权重搬到了 KV Cache

从 SparseSpec-L(arXiv 2607.27735)的加速公式 S=(αk+1)/(kγ+1) 出发,算清投机解码的三变量账本:为什么 Eagle-3 这样的短上下文冠军在 60K 上下文会跌破 1×,为什么"效率反转"的判据是 α 与 γ 的赛跑,以及"可召回的淘汰"如何把 γ、α、k 三个变量同时做对。接续 Medusa 深读与 vLLM KV cache 系列。

Eagle-3 是投机解码排行榜上的常客:在 XSum 摘要任务上,草稿接受率 67.2%,端到端加速 2.24×。把同一套系统放到 LongBench 的长上下文任务上,接受率崩到 8.4%,加速跌到 0.89×——比不用投机解码还慢。冠军没有变笨,是账本换了:它优化的那本账,在长上下文下根本不是瓶颈所在。

Medusa 深读里我们算过第一本账:batch 小的时候,解码是 memory-bound,每生成一个 token 都要把全部权重从 HBM 搬一遍,投机解码的杠杆就是”搬一遍权重的钱已经花了,一次多验证几个 token”。那本账里,搬运的对象是权重

这篇要算的是第二本账。上下文长到几万 token 之后,每次 forward 要搬的不只是权重,还有越滚越大的 KV cache——搬运的主角换人了,投机解码的每一个设计决策都要跟着重谈。载体是一篇 2026 年 7 月底的论文:A Sparse Glimpse of the Whole: Train-Free Self-Speculative Decoding(SparseSpec-L,Liu et al.)。它好在两点:先给了一个显式的加速公式,把”什么时候投机解码会更慢”变成一道可以求导的题;再用三步棋把公式里的三个变量同时做对。

读完你会带走一个可复用的框架:评估任何投机解码方案,先问三个数——γ、α、k。

一、账本:一个可以求导的加速公式

投机解码一步的流程是:起草 k 个 token → 目标模型一次 forward 并行验证 → 接受其中前 m 个连续正确的,再免费带走一个验证 token。设:

  • CvC_v:一次验证 forward 的成本(约等于一次普通解码步);
  • CdC_d:起草一个 token 的成本,γ=Cd/Cv\gamma = C_d / C_v 是相对起草开销;
  • α=E[m/k]\alpha = \mathbb{E}[m/k]:期望接受率。

那么每花 kCd+CvkC_d + C_v 的成本,期望产出 αk+1\alpha k + 1 个 token,加速比为:

S(k)=αk+1kγ+1S(k) = \frac{\alpha k + 1}{k\gamma + 1}

这个式子值得盯着看十秒钟。对 kk 求导(把 α\alpha 暂时当常数):

Sk=αγ(kγ+1)2\frac{\partial S}{\partial k} = \frac{\alpha - \gamma}{(k\gamma + 1)^2}

分母恒正,所以符号完全由 αγ\alpha - \gamma 决定

  • α>γ\alpha > \gamma:接受率跑赢起草成本,k 越长越快;
  • α<γ\alpha < \gamma:每多起草一个 token,期望收益抵不上开销,k 越长越

现实比这更残酷:α\alpha 不是常数,它随 k 增长而衰减——草稿是自回归生成的,越往后的 token 建立在越不可靠的前缀上,尾部接受概率不断走低。于是存在一个临界点:尾部边际接受概率跌破 γ 的那一刻,继续加长步长就开始倒贴。论文把这叫 efficiency inversion(效率反转),并给了实测:MagicDec 在 LongBench v2 上 k=2 时加速 1.74×,把 k 拉到 16,接受率崩到 6.3%,加速变成 0.36×——花三倍时间干同一件事。

这就是第一性原理层面的收获:投机解码不是”步长越长越好”的免费午餐,它是 γ\gammaα\alphakk 三个变量的约束优化。任何论文吹加速比,先问它这三个数各是多少。

二、瓶颈搬家:为什么长上下文杀死了草稿模型

公式解释了”怎么算账”,还没解释”为什么长上下文下账变了”。拿 Llama-3.1-8B 算一笔具体的:

  • 权重:8B 参数,FP16 约 16 GB,每步搬一遍,与上下文长度无关;
  • KV cache:32 层 × 8 个 KV 头(GQA)× head_dim 128 × K/V 两份 × 2 字节 = 128 KB/token。上下文 60K 时约 7.5 GB——已经是权重的一半;batch 开到 4,KV cache 变成 30 GB,反超权重成为搬运的大头

第一本账里”验证 k 个 token 和生成 1 个几乎一样贵”的前提,是搬运量以权重为主。第二本账里,每次 forward 的成本被 KV cache 主导,两个推论立刻成立:

推论一:草稿模型救不了你。 传统方案用小模型起草,省的是权重搬运;但草稿模型要想接受率高,也得看完整个上下文——它自己的 KV cache 一样随上下文膨胀。更糟的是 Eagle-3 这类从目标模型 hidden state 上训练出来的草稿头,训练分布里根本没见过 60K 的上下文,特征错位直接把 α 打到 8.4%。这不是工程失误,是优化对象选错了

推论二:省 KV 才是省对了地方。 既然成本大头是 KV cache 的读取,那起草时的降本杠杆就应该是”少读 KV”,而不是”换小模型”。这正是 SparseSpec-L 的起点。

顺带一提,这个”瓶颈搬到哪,架构就长成什么样”的规律,和 vLLM 前缀缓存系列看到的是同一条:KV cache 是当代 serving 系统的第一稀缺资源,谁管好它谁赢。

三、三步棋:每一步对准公式里的一个变量

SparseSpec-L 的全名是”稀疏地看一眼全局”——用目标模型自己加一份稀疏化的 KV cache 起草,不训练、不引入任何草稿模型。三个组件分别攻 γ、α、k:

3.1 降 γ:拿 10% 的 KV cache 给自己起草

起草时不用完整 KV cache,而是给每层每个注意力头维护一份稀疏索引,只保留约 10% 的 token:

  • Sink tokens:开头若干个位置(StreamingLLM 发现的”注意力锚点”);
  • Recent tokens:最近若干个位置(局部上下文);
  • Important tokens:剩余预算给”历史上被反复注意的 token”——按重要性分数取 top-K。

起草一步只需一次 Gather 把这些索引对应的 KV 拿出来算注意力。KV 搬运量降到 1/10,γ 就被压下来了。从论文实测数字反推很直观:LongBench v2 上 α=72.9%、平均 k=11.26、加速 2.79×,代入公式解出 γ≈0.2——起草一个 token 只花验证一步约五分之一的成本,这就是 k 敢开到 11 的底气(对照:γ≈0.7 的方案,k 超过 3 就该反转了)。

3.2 保 α:淘汰必须可逆

问题来了:重要性分数从哪来?谁被淘汰谁被保留,选错了 α 就崩。这里是全文最漂亮的两个设计:

重要性信号是白捡的。 验证那一步本来就要对全上下文算稠密注意力——注意力权重矩阵已经算出来了。SparseSpec-L 直接回收这些权重:对每个历史 token,累加最近 W=16 个 query 位置分给它的注意力,就是它的重要性分数。零额外 forward,信号却来自目标模型自己的”真实视线”。

淘汰只动索引,不动数据。 稠密 KV cache 从不真正删除任何 token,被”淘汰”的只是不进入本轮草稿索引;每次验证后用新鲜的注意力统计重建索引,上一轮被排除的 token 随时可以被召回。对比 SnapKV/MagicDec 这类永久剪枝——删了就是删了,后面的问题恰好要用到被删的 token 时,α 断崖式下跌(实测 SnapKV 版 MagicDec 在 k=10 时已劣于最朴素的 StreamingLLM 策略)。

这一条值得抽象出来记住:cache 管理里,“索引的稀疏”和”数据的删除”是两个自由度,混为一谈就把可逆决策做成了不可逆决策。 同样的错误在 agent 上下文管理里天天发生——之前对比 Claude Code 与 Codex 的上下文淘汰时见过一模一样的结构:摘要压缩是”动数据”,检索式回填是”动索引”。

3.3 调 k:用熵在线决定这一步敢赌多长

α 随任务、随生成阶段波动,固定 k 必然两头吃亏。SparseSpec-L 的控制器用草稿 token 的输出熵做在线信号:

  1. 每个草稿 token 记录其分布熵 HiH_i;验证后知道它被接受还是拒绝;
  2. 用 EMA 分别维护”被接受 token 的平均熵”Hˉacc\bar H_{acc} 和”被拒绝的”Hˉrej\bar H_{rej} 两个类中心;
  3. 新草稿 token 按到两个中心的距离软分类,得到接受概率 pip_i,进而算出步长为 k 时的期望产出 m=1ki=1mpi\sum_{m=1}^{k}\prod_{i=1}^{m}p_i
  4. 在候选集合里选期望效率最高的 kk^*
k=argmaxkK1+m=1ki=1mpikCd+Cvk^* = \arg\max_{k \in \mathcal{K}} \frac{1 + \sum_{m=1}^{k}\prod_{i=1}^{m}p_i}{kC_d + C_v}

直觉就是:模型自信(低熵)时放长赌注,不确定性飙升时立刻收短。控制器开销 <0.5% 步延迟。消融很能说明问题:固定 k=4 接受率高达 93.4% 但只有 2.10×(太保守),固定 k=12 最优 2.69×,k=20 反转跌回 2.62×;自适应拿到 2.79×,胜过所有固定值。

四、数字:账算对了之后

Llama-3.1-8B-Instruct,单张 A40,上下文 64K 以内(LongBench v2 / ∞-Bench):

方案接受率 α平均步长 k加速比
自回归基线11.00×
独立草稿模型50.3%2.941.22× / 0.95×
MagicDec (SnapKV)80.1%1.591.74× / 1.68×
Eagle-31.95%~1.10.89× / 0.92×
SparseSpec-L72.9%11.262.79× / 2.60×

注意读法:SparseSpec-L 的 α(72.9%)低于 SnapKV 版 MagicDec(80.1%),却快得多——因为后者只敢开 k=1.59,前者敢开 k=11.26。单看接受率会选错方案,三个数要一起看,这正是第一节那个公式的意义。输出分布严格无损(沿用标准投机解码的接受规则),3B 到 14B 模型上泛化为 1.55×–2.79×。

五、边界:这本账没算进去的

按灰度原则把适用边界摊开:

  • 验证被迫放弃 FlashAttention。 回收注意力权重的前提是把它显式算出来,而 FlashAttention 的核心优化恰恰是永不物化这个矩阵。60K 上下文下索引更新每步 41 ms——“信号白捡”的代价是验证 kernel 变慢,作者自己承认这里有明显优化空间。这是个真实的取舍:可观测性和算子效率打架,和 serving 系统里”要 metrics 还是要延迟”是同构问题。
  • 熵信号只是”中等可靠”。 接受与否的预测 AUC 只有 0.638,任务间波动大:RULER 大海捞针上自适应步长带来 +17.3% 吞吐,∞-Bench 上只是持平最优固定值。负载越异构,自适应越值钱;负载单一时,调好一个固定 k 就够了。
  • 评测口径偏窄:单卡 A40、上下文 ≤64K、每次只生成 128 token,没进真实 serving 引擎。batch 实验只到 4(16K 上下文下 batch 4 时 2.45×,趋势是 batch 越大 KV 占比越高、优势越大,但更大 batch 未验证)。

六、带走的框架:三个数 + 一条设计律

把这篇和 Medusa 深读的”四问”拼起来,投机解码的评估框架就完整了:

  1. γ 是多少? 起草成本省在哪——短上下文省权重(小模型/多头),长上下文省 KV(稀疏索引)。省错了地方,其他全白搭。
  2. α 是多少,随 k 怎么衰减? 尤其要看目标场景的分布内外——Eagle-3 的 67% → 8.4% 就是分布外崩塌的样本。
  3. k 谁来定? 固定 k 隐含”负载均匀”假设;效率反转的存在意味着 k 天然应该是个在线决策。

外加一条能迁移出推理系统的设计律:淘汰要可逆——稀疏化索引,而不是删除数据。 从 KV cache 到 agent 上下文到任何分层存储,凡是”重要性判断可能出错”的地方,都该把”这轮不看”和”永远失去”分成两个操作。

下一篇的自然延伸:这套稀疏起草如果进 vLLM,会和 PagedAttention 的 block 粒度、前缀缓存的复用逻辑发生什么化学反应——留个钩子。

参考文献