MTP 让本地编码更快,但能放心开启吗?
开启 MTP 后,这张 RTX 3090 的生成吞吐量从 36.0 提升到 56.2 tokens/s,约快 56%。两次双方都完成的缓存任务,也分别省下了约 20% 和 40% 的时间。
不过,一组转账任务出现了补丁质量差异。我会继续测试 MTP,暂时保留关闭它的默认配置。
这轮实验来自上一篇本地部署文章下的读者建议:试试 MTP,或带 MTP 的量化版本。那张挖以太坊留下的 3090,已经通过 OpenCode 跑起了编码 Agent;这次我想知道,提速之后能否更早交付正确补丁。
为此,我们用同一份模型文件做了 8 组配对、共 16 次运行。每组保持任务、随机种子和初始环境相同,只切换 MTP 开关。
MTP 先拟草稿,再由主模型验证
普通生成通常一步产生一个 token。MTP(Multi-Token Prediction,多 token 预测)用内置预测头先提出接下来几个 token,再让主模型验证。连续接受多个候选时,就能减少逐 token 解码的步骤。这是 llama.cpp 的一种推测解码路径。
主模型仍负责验证。推测解码论文说明,正确的算法可以保留目标模型的输出分布。因此,加速不必天然以降低模型能力为代价。
现有 Qwen3.8-27B Q4_K_M GGUF 已包含 MTP 预测层,这次直接使用它,没有换成另一份 Unsloth 量化。比较中的两条服务器命令,只有 --spec-type none 和 --spec-type draft-mtp 这一处不同。
生成快了 56%,完成任务省时 20%–40%
生成吞吐量衡量每秒输出多少 token,其中也包括模型的思考输出。任务总耗时则包含读源码、调用工具和跑测试,更接近拿到补丁前实际等了多久。
| 指标 | MTP 关闭 | MTP 开启 |
|---|---|---|
| 编码运行累计生成吞吐量 | 36.0 tokens/s | 56.2 tokens/s |
| 预设独立检查合计通过 | 35/80 | 26/80 |
| 在时限内完成并通过预设检查 | 2/8 | 2/8 |
双方都完成的两次缓存任务,给了我们最直接的省时证据:
| 配对运行 | MTP 关闭 | MTP 开启 | 总耗时减少 |
|---|---|---|---|
| 配对一 | 192.0 秒 | 153.5 秒 | 20.1% |
| 配对二 | 431.2 秒 | 259.0 秒 | 39.9% |
这两次都更早拿到了通过预设检查的补丁。失败的任务即使更快结束,也不算成功任务提速。后续提示会随 Agent 的操作分叉,所以累计吞吐量也不是全程生成相同文本的纯速度对照。
短回复速度与生成计时口径
相同首轮请求的短回复,关闭 MTP 为 38.9–39.8 tokens/s,开启为 74.0–84.2 tokens/s。它们只是较短的工具选择响应,不能据此推断整个编码任务耗时减半。
累计吞吐量按所有已完成生成的目标输出 token 总数,除以对应服务端生成时间总和计算。包括 reasoning(模型的思考输出)和工具调用;不计输入处理或被拒绝的草稿。超时中断、没有最终计时记录的生成被排除。
任务总耗时包括输入处理、工具调用和 Agent 自己跑测试;排除服务启动与事后独立评分。
九项检查的差距,来自同一次转账修复
35/80 对 26/80 的差距,全部集中在同一道转账题、同一个随机种子。缓存、账本和构建规划题的配对得分均相同。
关闭 MTP 时,Agent 写出了生产代码补丁,事后通过全部十项独立检查。但它在 480.1 秒达到截止时间,没有完成最终交付。
开启 MTP 时,Agent 在 186.1 秒结束,没有修改生产代码,只通过原始实现就能通过的一项检查。
这组的关闭候选在检查中表现更好,两边却都没达到完整交付标准。所以,我们分别记录补丁正确性和按时完成交付:完整交付数仍是 2/8 对 2/8。九项相关测试的差异,也不能当作九个独立任务的回退。
各任务得分,以及早期探索中没有重现的差异
| 任务 | MTP 关闭,两次得分 | MTP 开启,两次得分 |
|---|---|---|
| TTL 缓存 | 10/10、10/10 | 10/10、10/10 |
| CSV 账本 | 1/10、1/10 | 1/10、1/10 |
| 增量构建规划 | 1/10、1/10 | 1/10、1/10 |
| SQLite 转账 | 1/10、10/10 | 1/10、1/10 |
“完成并通过”要求未超时、进程成功退出、受保护的规格和配置未修改、公开及新增测试通过,且十项独立检查全部通过。它不表示已经覆盖所有可能的缺陷。
早期探索中,构建规划题也曾出现两种模式分数不同的现象;在这轮更严格的控制下,它没有重现。旧探索分数没有混入这轮结果。
缓存任务还提醒我,预设检查全绿后仍要看实际代码:一个 MTP 候选新增的 TTL 验证,在极大整数上触发了溢出。同一配对的关闭候选通过了额外探针。这是极端 API 边界,值得记录,但不能据此推断日常错误频率或确定 MTP 是根因。
额外审查:缓存整数溢出与双方共同遗漏
缓存题的四次运行都通过十项预设检查。其中一个 MTP 候选新增 math.isfinite(ttl)。任务允许有限的正整数 TTL;探针传入 10**400,并使用每次递增的整数时钟时,验证触发了整数转浮点的 OverflowError。同一配对中关闭 MTP 的候选通过。
账本的精确大金额、表头和读取错误探针,在双方、两个种子下均失败。转账的目标账户整数溢出探针,在第二组配对中关闭通过、开启失败;第一组双方均失败。
额外审查在评分之后进行,没有反馈给模型,也没有追加入原来的 80 项。配对记录保留了细节。
更快输出,仍然会用完同样的预算
多数失败运行有一个共同现象:模型把 8,192-token 单次输出预算耗在思考上,以 length 结束,没有进入实际编辑。许多 1/10 是原始代码的得分,不能理解成完成了十分之一的修复。
增加上下文容量解决不了这个限制。上下文决定一次能容纳多少输入与输出;单次输出上限决定这一轮能生成多少内容。MTP 可以更快输出,却不会自动增加这份预算。
这也让质量比较难以下定论:两种模式都经常没写出补丁,可供比较的有效修复很少。每题只有两个种子、共四个小型 Python 项目;80 项检查彼此相关,不是 80 个独立样本。
转账配对的差异值得追查,目前尚未定位根因。批量验证的数值行为、状态处理和采样细节都是排查方向。Agent 的一次不同操作,也可能改变后续输入和补丁;这些仍是可能解释,没有被这轮实验确认。
实验控制了什么,结论适用于哪里
每题使用两个随机种子,分别开启和关闭 MTP,第二组反转顺序。每次重建相同初始代码,固定工作目录、提示、工具、权限与生成设置。十项独立测试放在 Agent 工作区之外,结果不反馈给模型。
代理核对了实际发出的完整首轮请求:8 组全部一致,初始文件哈希也一致。每次重启服务,双方都关闭前缀缓存复用。因此,这轮还不能预测日常缓存续聊的收益。
完整配置、请求核对与适用范围
| 项目 | 固定设置 |
|---|---|
| 模型与 GPU | Qwen3.8-27B Q4_K_M,同一份 GGUF;RTX 3090 24GB |
| 软件 | llama.cpp b11146 / CUDA 12.8;OpenCode 2.0.20 |
| 服务 | 131,072-token 上下文容量;单槽位;模型层全部在 GPU |
| 缓存与计算 | K/V 均为 q8_0;Flash attention;batch 512 / microbatch 256 |
| 生成 | medium thinking;temperature 1.0;top_p 0.95;top_k 20 |
| 预算 | 每次生成最多 8,192 tokens;每任务最多 480 秒 |
| 配对种子 | 4242、8675309 |
| 推测解码 | 关闭 none / 开启 draft-mtp;草稿上限固定为 3 |
耗时表中的配对一、二分别对应种子 4242、8675309。
两边均关闭 target 和 draft 的 backend sampling,不使用合成接受率。每次运行的初始提交、Agent 标题、项目配置与评分器相同;实际请求报告的前缀缓存 token 数均为零。第一组按关→开,第二组按开→关运行。
这是每次重启服务、无前缀缓存复用的实验。任务计时排除服务启动,但包含输入处理、工具调用和 Agent 自己跑测试的时间;事后独立评分不计入。桌面和其他背景 GPU 活动未完全控制。
最大实际输入是 20,057 tokens。128K 是配置容量,这轮没有测满 128K 的编码表现,也没有测日常缓存续聊的加速幅度。
暂时保留默认配置,下一轮先放宽输出预算
对这套环境,我会继续保留关闭 MTP 的默认配置。两次缓存任务省时 20%–40% 的收益很有价值;在扩大使用前,我想先核查转账补丁的差异。
下一轮先同步提高两边的输出预算,再增加配对种子和更接近日常工作的任务。缓存续聊另测。这样才能判断,提速是否稳定转化为更早完成正确补丁。
如果你也在试 MTP,可以同时记录生成速度、任务耗时、独立测试和最终交付,再结合自己最常做的任务决定是否开启。
数据与参考
- 配对实验 JSON:16 次运行的分数、耗时、生成计时、请求核对和额外探针。
- 方法与数据说明:附件不含实验日期、地点、个人路径、会话标识或原始对话;是结果记录,不是完整复现套件。
- 上一篇:本地部署 Qwen3.8-27B + OpenCode:安装与接入方法。首次实验与本轮是不同批次,分数不能拼接。
- llama.cpp b11146 推测解码文档与推测解码论文:机制背景;这张卡的结果来自配对记录。
微信扫一扫分享
用微信扫描上方二维码,即可在手机端阅读或分享到朋友圈。