Kotonia
ログイン今すぐ始める

Kotonia Articles

投机解码(MTP)对日语闲聊不起作用——acceptance 36% vs 71% 实测

在 vLLM 中启用 ThinkingCap-Qwen3.6-27B 的原生 MTP head,实测单流 decode 速度。draft acceptance 在英语代码生成场景是 71%,日语随意聊天场景只有 36%,收益因场景而天差地别。

作者 3分钟阅读
#llm#vllm#speculativedecoding#localllm#gpu
其他语言日语英语

TL;DR

  • 在 vLLM 中启用了 ThinkingCap-Qwen3.6-27B(NVFP4)的原生 MTP(Multi-Token Prediction)head,实测单流 decode 速度
  • MTP 的 draft acceptance:英语代码生成 71%,日语随意聊天只有 36%。速度提升相应是 1.85 倍 vs 1.12 倍,因场景不同天差地别
  • 「MoE 和 dense 的激活参数量差 9 倍,速度就该差 9 倍」是错误的。实测差距只有 2.5 倍,9 倍到 2.5 倍的落差可以完全用带宽数学解释(量化降一档,9→5 倍;固定开销进一步压缩,5→2.5 倍)
  • 类似语音聊天这样的实时日语对话场景,不要指望投机解码带来收益;agent / 代码场景则几乎是白捡的近 2 倍提速

背景:从 MoE 换成 dense,速度成了问题

当时在评估把线上运行的本地 LLM——一个激活参数 3B 的 35B-A3B MoE 模型——替换成 dense 27B 模型。指令遵循和 agentic 表现是 dense 更好,问题在于 decode 速度:实时语音聊天跑在同一个推理引擎上,因此有一条硬约束——「如果对话变慢了,这个方案就作废」。

这时候候选模型自带的 MTP(Multi-Token Prediction)head 就变得有意思了:投机解码能不能补上 dense 在速度上的劣势?这是这篇文章要回答的问题。

环境与测量方法

  • GPU:RTX PRO 6000 Blackwell(96GB)
  • vLLM 0.24.0 / 模型:ThinkingCap-Qwen3.6-27B-NVFP4(权重 ~19.7GB + MTP head bf16 0.85GB)
  • --speculative-config '{"method":"qwen3_5_mtp","num_speculative_tokens":3}' / --kv-cache-dtype fp8
  • 对比对象:Agents-A1(35B-A3B MoE,fp8,不启用投机解码)
  • 单流、流式输出,测量 TTFT 和 decode tok/s(completion_tokens / 首 token 之后的实际耗时)
  • acceptance 通过 vLLM /metrics 的差值计算:
acceptance = Δ vllm:spec_decode_num_accepted_tokens_total
           / Δ vllm:spec_decode_num_draft_tokens_total

两个场景:ja_chat(带人设的日语随意聊天,512 token 上限)和 code_agent(英语编程任务,2048 token 上限)。

结果

decode tok/s(中位数)MoE 35B-A3B fp8dense 27B 原始dense 27B + MTPMTP acceptance
日语随意聊天17772.080.5(×1.12)36.1%(92/255)
英语代码生成17770.7131.0(×1.85)71.4%(2795/3912)

TTFT 在所有配置下都是 50〜100ms,没有明显差异。

原始 decode 速度不随场景变化(72 vs 70.7),这是典型的带宽受限 dense 模型行为——差距完全来自 MTP 的 acceptance。同一个模型、同一个 draft head,代码场景命中七成,日语闲聊连四成都不到。

为什么日语闲聊命中率低

投机解码的收益完全取决于 draft 能多准确地猜中主模型的输出。容易猜中的是下一个 token 熵较低的文本。

  • 代码:语法约束强,boilerplate、缩进、关键字等「几乎是唯一解」的 token 大量存在,draft 可以稳稳收割
  • 日语随意聊天:句尾、措辞、语气词的变化本质上非常多。在「〜だね」「〜だよ」「〜かな」这几种说法都自然成立的节点上,draft 根本无从下注

再加上,社区里关于 MTP / 投机解码的评测普遍偏向英语 + 代码场景。把「投机解码快 2 倍」这类结论直接套用到日语对话产品上,实际收益大概率打对折都不止。 反过来说,翻译或模板化程度较高的文本生成,在日语场景下也可能有收益(本文未测量)。

「激活参数差 9 倍,速度只差 2.5 倍」的构成

另一个反直觉的数字,是 MoE(激活 3B)和 dense 27B 之间的速度差。参数比是 9 倍,但 177 对 71 的实测差距只有 2.5 倍

decode 是带宽受限的,起决定作用的不是参数量,而是每个 token 需要读取的权重字节数

  • MoE 35B-A3B @ fp8:激活 ~3B × 1 byte + shared expert + attention ≈ ~4 GB/token
  • dense 27B @ NVFP4:~0.56 byte/param(+ bf16 embedding 等)≈ ~20 GB/token

也就是说真实比值不是 9 倍,而是 ~5 倍(FP4 的 byte/param 是 fp8 的一半,把 9 压缩到 5)。再把理论天花板和实测对比:

带宽理论值(~1.7TB/s)实测天花板利用率
MoE 35B-A3B~425 tok/s177~42%
dense 27B FP4~85 tok/s71~84%

dense 已经跑到接近带宽天花板,而 MoE 被 kernel 启动、sampler 等固定开销吃掉了理论天花板的一半以上。tok/s 越高的一侧,固定开销对理论比值的压缩效应越明显,5 倍因此被压缩到 2.5 倍。「MoE 更快」这句话是对的,但在单流场景下远没有宣传比值那么夸张——反过来说,dense 那边看起来的劣势,也没有宣传数字那么绝望。

运维结论

  1. 实时日语对话场景不要指望投机解码带来收益。 acceptance 只有 36% 时,收益不足以带来可感知的体感提升。如果对话链路的速度是硬需求,就应该按原始 decode 速度(= bytes/token)来选型
  2. agent / 代码场景下,MTP 几乎是白捡的。 一个 flag,1.85 倍提速,而且 head 是模型自带的,额外 VRAM 成本只有 ~1GB
  3. acceptance 要在自己的实际负载上测。 只需要取一次 /metrics 的差值,五分钟就能知道结果。英语代码场景的 benchmark 数字,套用不到日语对话场景上
  4. 最终我们优先考虑指令遵循能力,全面切换到了 dense 27B,并且在事先实测的基础上,接受了对话链路 0.45 倍的速度代价。正因为决策之前就有了分场景的实测数据,这个判断才没有变成一种精神胜利

本文是 kotonia.ai 语音聊天 / 桌面智能体基础设施重构记录的一部分。相关文章:《本地 LLM 谎称执行了 Python》(指令遵循侧的验证)。

Kotonia 将语音 AI、AI 聊天、图像生成和团队协作整合到一个 AI 工作区中。

试用 Kotonia