MTP 加速不是玄学:为什么写代码快 171%,写小说却慢了 9%

123 阅读11分钟

本地大模型推理最近有一个很热的关键词:MTP。

Multi-Token Prediction,多 token 预测。简单说,就是让模型不要一个 token 一个 token 地慢慢吐,而是先预测一小串候选 token,再由主模型验证。猜对了,就少跑几步;猜错了,就回到正常生成。

听起来像免费的加速按钮。

但 Reddit r/LocalLLaMA 上一组围绕 Qwen3.6 27B 的 benchmark 给出了更复杂的答案:

MTP 在编码任务里可以让 F16 模型快 171%,但在 Q4_K_M 的创作任务里反而慢 9%。

同一个模型,同一个推理机制,同一类参数,结果可以从“明显加速”变成“负收益”。

这组数据真正有价值的地方,不是又多了一个漂亮的 tok/s 数字,而是把 speculative decoding 的收益边界摊开了:它不是普适加速,而是高度依赖任务类型、量化方式和推理链路。

一组反直觉的测试结果

测试来自 Reddit 用户 ex-arman68。

他此前发布过 Qwen3.6 27B 的 MTP GGUF,并观察到本地推理速度明显提升。但随后有用户反馈,在某些任务和量化组合下,开启 speculative inference 后反而更慢。

于是他重新做了一轮系统测试。

测试条件大致如下:

  • 模型: Qwen3.6 27B
  • 硬件: Apple Silicon M2 Max 96GB
  • 推理框架: llama.cpp 的 MTP PR 分支
  • 测试规模: 300+ 组 benchmark
  • 任务类型:代码、事实问答、分析、创作
  • temperature: 0.0 / 0.3 / 0.7
  • 量化: Q4_K_M / Q5_K_M / Q6_K / Q8_0 / F16
  • MTP 层量化:q8 与匹配模型量化均有测试

最后的结果很清楚:temperature 和 MTP 层量化不是主要变量。真正决定收益的,是 任务类型模型量化形态

先看原帖核心表格。下面是开启 MTP 后的累计平均 decode 速度,并与不开 MTP 的基线做对比。

| 量化 | 不开 MTP 基线 | 代码 | 事实问答 | 分析 | 创作 |

|---|---:|---:|---:|---:|---:|

| Q4_K_M | 15.1 | 19.7 | 17.5 | 14.9 | 13.7 |

| Q5_K_M | 13.1 | 19.2 | 16.5 | 14.7 | 12.6 |

| Q6_K | 13.4 | 20.1 | 17.6 | 15.2 | 13.4 |

| Q8_0 | 11.4 | 25.4 | 21.7 | 18.6 | 16.9 |

| F16 | 6.6 | 17.9 | 14.9 | 12.6 | 11.0 |

只看代码任务,MTP 几乎是全线有效。

Q4_K_M 从 15.1 tok/s 提到 19.7 tok/s

Q8_0 从 11.4 tok/s 提到 25.4 tok/s

F16 从 6.6 tok/s 提到 17.9 tok/s

但创作任务完全是另一幅画面。

Q4_K_M 从 15.1 tok/s 降到 13.7 tok/s

Q5_K_M 从 13.1 tok/s 降到 12.6 tok/s

Q6_K 基本持平。

只有 Q8_0 和 F16 仍然有明显收益。

这不是跑分噪音,而是 speculative decoding 的机制决定的。

关键不在预测,而在命中

MTP 的工作方式很像给主模型配一个草稿员。

草稿员先写出几个 token,主模型逐个验证。如果草稿正确,就直接采用;如果错误,就回退到主模型正常生成。

因此 MTP 的收益取决于两个变量:

第一,草稿生成本身有多便宜。

第二,草稿 token 被接受的比例有多高。

第二点尤其关键。原帖给出了不同任务的 draft token acceptance rate:

| 任务类型 | 草稿 token 接受率 | 典型场景 |

|---|---:|---|

| 代码 | 79%-89% | 写函数、debug、重构 |

| 事实问答 | 62%-70% | 定义、翻译、数学证明 |

| 分析 | 48%-56% | trade-off 拆解、技术比较 |

| 创作 | 39%-48% | 故事、诗歌、头脑风暴、角色扮演 |

配图:MTP 草稿 token 的接受与回退流程 配图:MTP 草稿 token 的接受与回退流程

代码任务的接受率接近 80%-90%

这并不意外。代码天然有强结构:括号、缩进、函数签名、类型、常见 API、错误修复模式,都会限制下一个 token 的分布。MTP 提前猜几个 token,命中率很高。

创作任务则相反。

故事、诗歌、角色扮演和头脑风暴的输出路径更开放。下一句可以转折,可以铺垫,可以换视角,也可以突然跳到另一个意象。模型仍然能写,但“提前猜中下一串 token”这件事会难很多。

原帖作者的观察很直接:代码任务中大约 4/5 的草稿 token 是正确的 ,创作任务里则 不到一半

这解释了为什么 MTP 在代码里像加速器,在创作里可能变成额外负担。

量化越轻,越不能无脑开

另一张表更适合用来做工程决策。它把不同任务、不同量化下的 MTP 收益直接换算成百分比。

| 使用场景 | Q4_K_M | Q5_K_M | Q6_K | Q8_0 | F16 |

|---|---:|---:|---:|---:|---:|

| 编码 | +31% | +47% | +50% | +123% | +171% |

| 事实问答 | +16% | +26% | +31% | +90% | +125% |

| 分析 | -1% | +12% | +13% | +64% | +91% |

| 创作 | -9% | -4% | -1% | +48% | +67% |

配图:不同任务与量化下的 MTP 收益热力图 配图:不同任务与量化下的 MTP 收益热力图

这张表背后有两个结论。

第一, 编码任务几乎总是 MTP 友好场景

即便是 Q4_K_M,编码任务也有 31% 提升。到 Q8_0 和 F16,提升直接超过 100%

第二, 低比特量化 + 开放式生成,是 MTP 的高风险组合

Q4_K_M / Q5_K_M 在创作任务上都出现负收益。Q6_K 也基本没有收益。

原因不难理解。

Q4_K_M 本身已经很小,基线速度达到 15.1 tok/s 。MTP 草稿流程带来的额外计算、验证、上下文管理开销,不再那么容易被抵消。

F16 则完全不同。

F16 版本约 51GB ,基线速度只有 6.6 tok/s 。每生成一个 token,都要付出更高的内存带宽成本。只要 MTP 有一定接受率,每个被接受的 token 都能省下一次昂贵的主模型计算。

这也是为什么 F16 在创作任务里仍然有 67% 提升,而 Q4_K_M 会变慢。

MTP 的最佳土壤,其实可以概括得很简单:

模型足够重,主模型前向足够贵,输出又足够可预测。

编码任务刚好符合这个条件。

draft token 不是越多越好

MTP 还有一个容易被低估的参数:一次预测多少个 draft tokens。

预测太少,节省不了多少主模型计算。

预测太多,接受率会快速下降,错误草稿会带来更多无效工作。

原帖作者测试后认为,对 Qwen3.6 27B 来说, 3 个 draft tokens 是多数场景下的甜点位。

但 F16 是个例外。

因为 F16 的基线速度太慢,每一个被接受的 token 都非常值钱,所以 N=4 反而比 N=3 更好。原帖给出的对比是 17.9 tok/s vs 16.2 tok/s

这说明未来成熟的本地推理系统不应该只有一个固定 MTP 配置。

更合理的方式,是根据模型量化、任务类型、上下文长度和硬件状态动态切换。

写代码时可以更激进。

写创作时可以保守,甚至直接关闭。

decode 快,不等于整体快

这组 benchmark 主要看 decode,也就是模型生成输出的速度。

但真实 Agent 工作流里,prefill 同样重要。

coding agent 往往不是拿一个短 prompt 直接写答案,而是先读取大量上下文:项目文件、报错日志、工具执行结果、历史对话、检索片段。模型“读材料”的阶段,就是 prefill。

评论区里有用户给了一个很有价值的反馈。

他在 Radeon AI Pro 9700 上测试时,开启 MTP 后生成速度从大约 26 tg/s 提到 40 tg/s ,但 prompt processing 从 1400 t/s 掉到 650 t/s

另一个用户在 2 张 RTX 3090 上跑 Qwen3.6 27B Q8,也观察到类似情况:不开 MTP 的 prefill 大约 2400 t/s ,开启后大约 1400 t/s

如果一个任务是短输入、长输出,decode 提升会很明显。

如果一个任务是长输入、短输出,prefill 下降可能直接吃掉 decode 的收益。

很多 Agent 的真实负载并不是“生成一篇长文”,而是多轮读取、分析、调用工具、返回短结果。此时只盯着 tok/s generation,很容易高估 MTP 的体验收益。

llama.cpp PR 讨论里也有人提到 prefill 下降问题。PR 作者 am17an 回复称已经注意到,会继续修复。

配图:Agent 推理链路中的 prefill 与 decode 配图:Agent 推理链路中的 prefill 与 decode

MoE 上的收益还要另算

MTP 在 dense 模型上的逻辑相对清晰。

但如果换成 MoE,情况可能变复杂。

评论区有用户指出,MoE 模型做 speculative decoding 时,可能需要在更多 experts 之间切换。尤其是部分 offload 到 CPU / GPU 的场景,专家路由、内存搬运和 draft 验证成本都会影响最终收益。

原帖作者也认为,MTP 对小 MoE 模型未必合适;dense 模型受益更明显,而且模型越大,收益越大。

这点对最近的本地模型讨论很关键。

Qwen3.6 35B-A3B、各种 MoE coding model、部分 offload、GGUF 量化,都是社区正在高频测试的组合。MTP 在这些组合里能不能稳定产生收益,不能直接套用 dense 27B 的结论。

它需要按模型结构重新测试。

还没到开箱即用

这次测试依赖 llama.cppPR #22673 ,标题是 “llama + spec: MTP Support”。

这个 PR 创建于 2026 年 5 月 4 日 ,截至资料整理时仍然是 open 状态,还没有合并进主分支。

PR 描述里提到,作者在 Qwen3.6 27B 和 Qwen3.6 35B-A3B 上做过测试,使用 3 个 draft tokens 时通常能看到约 75% 的稳定接受率,并获得超过 2 倍 的基线加速。

但限制也很明确:

  • --mmproj 暂不可用
  • -np > 1 并行序列暂不可用
  • Vulkan / ROCm / 多 GPU tensor split 等后端仍有用户反馈问题
  • 有人遇到乱码输出、崩溃、vision 组合 crash
  • prefill 下降仍在修复中

所以 MTP 现在更像一个已经证明方向正确的工程分支,而不是稳定可复制的生产能力。

它值得折腾,但还不适合被包装成“所有本地模型一键起飞”。

本地推理开始进入任务调度阶段

这组 benchmark 最有价值的地方,是把本地推理从“单一速度指标”推进到了“任务感知策略”。

过去评估本地模型,常见问题是:

这个模型能不能塞进显存?

每秒多少 token?

上下文能开多长?

但 Agent 场景下,这些问题还不够。

更现实的问题是:

  • 当前任务是 coding、factual QA、analysis,还是 creative writing?
  • 当前模型是 Q4、Q8,还是 F16?
  • 当前瓶颈是 decode,还是 prefill?
  • 当前上下文是 4k、10k,还是 100k?
  • 当前后端是 Metal、CUDA、Vulkan,还是 ROCm?
  • 当前是否 MoE、是否 partial offload、是否多请求并发?

这些变量共同决定 MTP 应不应该开启,以及 draft token 数应该设多少。

成熟的本地 Agent 系统,未来很可能不会固定使用一种推理模式。

它会像数据库查询优化器一样,根据任务类型和运行状态选择策略:

代码补全、函数重构、bug 修复,开启 MTP。

开放式写作、角色扮演、头脑风暴,降低 draft 数或关闭 MTP。

长上下文仓库分析,优先评估 prefill 成本。

高精度大模型,适当更激进。

低比特小模型,避免为了 speculative decoding 付出过高额外开销。

MTP 的长期意义,不是单纯把 tok/s 拉高,而是逼着推理系统开始理解“任务形态”。

别问开不开,先问用来干什么

MTP 不是万能加速键。

它更像一个只在特定路况下高效工作的涡轮。

代码任务结构强、token 可预测,MTP 的接受率高,收益明显。

创作任务开放度高、路径分散,MTP 更容易猜错,低比特量化下甚至会拖慢。

高精度大模型每一步都贵,猜中一个 token 就很值钱。

低比特模型本来就快,MTP 的额外开销会更刺眼。

这组 benchmark 给出的提醒很直接:不要只问“开不开 MTP”,而要问“什么任务、什么模型、什么量化、什么上下文、什么后端”。

本地推理正在从粗放调参进入细粒度调度。

对 Agent 来说,这可能比某一次 tok/s 翻倍更重要。

原始链接与参考资料

Reddit 原帖:

www.reddit.com/r/LocalLLaM…

前序 Reddit 帖:Qwen3.6 27B 使用 MTP 获得 2.5x 推理加速:

www.reddit.com/r/LocalLLaM…

llama.cpp PR #22673:MTP Support:

github.com/ggml-org/ll…

froggeric Qwen3.6-27B-MTP-GGUF:

huggingface.co/froggeric/Q…