
## 从上一篇的配置继续

[上一篇文章](https://zjshen14.github.io/en/blog/qwen-agentic-tuning-3090/)记录的是 Qwen3.8-27B 的 Q4_K_M 配置，关闭 MTP，使用 128K 总上下文。把单次回复的输出上限从 8K 提到 16K、32K，再把 reasoning effort 从 medium 改成 xhigh，交付数依次是 5、14、20、23，分母都为 24。

**24 的意思是八个任务各跑三次，不是 24 道不同题。** 后续的八次筛查，则是同样八个任务各跑一次。减少重复次数可以更快筛掉候选，但结论也会更容易受随机生成影响。

这套测试有六个 Python 任务和两个 TypeScript 任务，覆盖缓存、金额处理、事件流、路径处理、流水账、构建计划、异步池和分页。七个是自建的小型修复任务，另一个是在固定版本的 boltons 库中植入故障。Agent 必须读文件、修改代码、运行检查，再交付答案。它不是官方 SWE-bench，也不能代表大型真实仓库中的所有工作。

| 任务 | 独立验收主要检查什么 |
| --- | --- |
| cache | TTL 边界、假值、LRU 淘汰、失败操作后的状态 |
| wallet | SQLite 事务、并发写入、幂等重试、整数溢出 |
| eventstream | 分块 UTF-8/JSON、任意切分位置、错误及关闭状态 |
| boltons_paths | 上游路径 API、假值结果、错误诊断兼容性 |
| ledger | CSV/CLI 集成、大额金额精度、错误时原子输出 |
| buildplan | 全图校验、确定性顺序、反向依赖、深链 |
| async_pool | 并发上限、顺序、异常身份、进行中任务收尾 |
| pagination | 多文件接口、游标、去重、取消、异常分页 |

每个任务尝试权重相同，内部检查数量不决定其权重。每次编码尝试的预算是 1,800 秒、65,536 个生成 token 和 120 次工具调用；单次回复输出上限另行设置。Agent 能看到任务说明和公开测试，独立验收测试不放进它的工作区。

我分别记录两个结果：

- **功能通过**：代码通过独立验收、回归、公开检查，以及对应的语法或类型检查；受保护文件保持完好。有后续变更请求的任务，阶段一和最终代码都要通过各自要求。
- **交付通过**：功能通过之外，还要求正常结束、有最终交接说明，并完成可识别的自检；TypeScript 任务还要完成类型检查。

下文的生成速度统一用 **总生成 token ÷ 总解码秒数**，而不是把每题的 token/s 简单平均。计数包含 reasoning 和工具调用语法，排除输入处理时间。完整任务耗时还包括读文件、运行测试和等待工具，因此速度表不能直接当作任务完成速度，也不是 QPS。

## IQ3 和 IQ4 比原配置快，但质量比较没有那么简单

IQ3_S 来自 [ISTA-DASLab 的 GSQ-RCO 仓库](https://huggingface.co/ISTA-DASLab/Qwen3.8-27B-GSQ-RCO-GGUF)。它按不同权重张量的敏感程度分配精度，文件名中的 IQ3 不意味着每个张量都恰好是三比特。我使用带 MTP head 的文件，大小约 11.29 GiB；之前的 Q4_K_M 文件约 15.66 GiB。

这和 **Q8 KV** 是两件事。IQ3 描述权重压缩；Q8 KV 描述推理过程中保存的注意力缓存采用八比特格式。权重缩小释放的显存，可以留给缓存和运行时缓冲区。

我还测试了 [Bartowski 的 IQ4_XS 权重](https://huggingface.co/bartowski/Qwen3.8-27B-GGUF)，并在本地组装了 Q4_0 格式的 MTP head。下面是完成的开发集对照，均为八个任务、每题三次，128K 总窗口、32K 单次输出上限、xhigh reasoning。

| 配置 | 功能通过 | 交付通过 | 合并生成速度 |
| --- | ---: | ---: | ---: |
| 原 Q4_K_M，MTP 关闭 | 23/24 | 23/24 | 33.29 token/s |
| GSQ-RCO IQ3_S，MTP3，Q8 KV | 22/24 | 21/24 | 59.87 token/s |
| Bartowski IQ4_XS，本地 MTP2，Q8 KV | 22/24 | 22/24 | 62.36 token/s |

这里 IQ3 组合比原 Q4 组合的生成速度高约 **80%**。这是量化权重和投机解码一起改变之后的结果，不能把全部提升归因于 IQ3。原 Q4 和 IQ3 控制结果也来自较早的运行，并非同一时间随机交错采集。

表中的通过数保留原 **v2.0.1** 测试口径。后面会解释 Ledger 测试的修正；这三组历史结果尚未整体重新评分，因此不应把它们当作没有测量缺陷的最终质量排名。

IQ4 还接受了一组独立确认：四个不同任务，每个任务三个 seed，IQ4 和 Q4 各 12 次。两组都达到 **11/12 功能及交付通过**，生成速度分别为 64.72 和 34.47 token/s。它增加了新任务上的证据，但四个任务仍不足以证明普遍的质量等价。这是后来为 IQ4 建立的确认实验，和上一篇文章中尚未启动的确认计划不同。

更直接影响选择的是最后一轮新 seed 对照：IQ4 和 IQ3 各跑八次，交错安排顺序。

| 配置 | 功能及交付通过 | 合并生成速度 | 八次任务总耗时 |
| --- | ---: | ---: | ---: |
| IQ3_S＋MTP3 | 7/8 | 58.17 token/s | 3,801.9 秒 |
| IQ4_XS＋MTP2 | 6/8 | 62.73 token/s | 3,880.1 秒 |

IQ4 的生成速度高了 **7.8%**，但这次少通过一个任务，任务总耗时还高了约 **2.1%**。其中 wallet 出现了实际的数值溢出处理问题。因此，我把 IQ4 留作可选配置，没有把它视为明确优于 IQ3 的替代品。八次尝试也不足以断言 IQ4 的总体质量更差。

保留 Q4_K_M 也有加速空间。同一份 Q4 文件、Q8 KV 和 128K 总窗口下，开启 MTP3 后，8K 目标输入的生成速度由 **37.94 升到 51.06 token/s**，32K 目标输入由 **32.52 升到 43.68 token/s**，都提高约 34%。这组是每种输入、每种模式三个 seed，固定生成 1,024 token 的短测，开启后再关闭 MTP，顺序没有随机化，也没有执行生成代码验证正确性。因此它能单独说明 Q4 上的速度收益，不能证明完整编码交付质量。

## 其他调参为什么没有直接成为推荐

除了换量化版本，我还做了线程数、CUDA 等待方式、batch、MTP head 精度、KV 精度和 ngram 投机组合的筛查。短输入筛查一般使用冷缓存的 8K、32K 输入，生成 1,024 token，每个输入重复三个 seed，并保留前后基线。

| 调整 | 观察到的结果 |
| --- | --- |
| CPU 线程从 8 降到 4、2、1 | 没有看到生成速度提升 |
| CUDA blocking wait | 两种输入下均略慢，没有解决速度问题 |
| ngram 与 MTP4 组合 | 没有超过该轮基线 |
| 更大的 batch | 对 8K 和 32K 输入的收益不同，没有一致提升 |
| F16 主 KV cache | 部分短输入组合更快，但显存需求更高 |
| 更小的 IQ3_XXS、不同权重布局和 MTP head 精度 | 有短输入速度收益，需要继续接受编码测试 |

其中一些候选没有完成计划中的 24 次编码尝试。GSQ IQ3_XXS 的跟进完成了八次，功能及交付为 5/8，对应 IQ3 控制为 6/8；另一组 Bartowski IQ3_XXS 跟进完成了 12 次，候选为 9/12，对应控制为 10/12。这些部分样本没有支持直接替换当前选择，未完成的尝试也没有被计为失败。

这轮筛查最有用的作用，是告诉我哪些收益值得进入更贵的编码测试。短文本连续生成可以提高 token/s，但 agent 的代码检查、回复长度和重试行为可能改变最终结果。

## MTP2 到 MTP6，编码任务中的 MTP4 最快

MTP 使用模型附带的预测 head 提出草稿 token，再由主模型验证。本地这个模型只有一个 MTP head，增加深度时会反复调用它。MTP4 的含义是最多提出四个草稿 token，不保证每轮都接受四个。

更深的草稿需要更多预测和验证工作。如果后面的草稿频繁被拒绝，增加深度反而会变慢。

短输入筛查曾偏向 MTP2。随后，我固定 IQ3_S、Q8 KV、128K 总窗口和 64K 单次输出上限，对 MTP2、3、4、5、6 各跑八个编码任务。每个任务一个共同 seed，合计 40 次完成的尝试。

| MTP 最大草稿数 | 合并生成速度 |
| --- | ---: |
| 2 | 57.98 token/s |
| 3 | 60.72 token/s |
| 4 | **61.31 token/s** |
| 5 | 58.08 token/s |
| 6 | 56.37 token/s |

在这批任务中，MTP4 比 MTP2 快约 **5.7%**，继续加到 5 或 6 没有收益。它是当前机器和这批工作负载中的首选，不是所有模型、上下文和 GPU 的通用 sweet spot。

即使在这里，更高 token/s 也没有自动转化为更快交付：按原测试中 MTP2 和 MTP4 都交付成功的七个任务计算，总耗时分别为 2,727.4 和 2,741.3 秒，MTP4 略长约 0.5%。生成内容和工具使用也参与决定任务耗时。

## Ledger 的失败，一次需要更多输出，另一次需要修测试

Ledger 反复失败，最初很容易让人怀疑是上下文不够。诊断后，它实际暴露了两种问题。

第一种是**单次回复被截断**。在 IQ3_S＋MTP3 的一次配对诊断中，只把输出上限从 32K 改成 64K，保留 128K 总窗口和其他参数。原尝试在 32,768 token 处结束长回复，没有完成生产代码修改；新尝试的最长回复达到 **40,612 token**，最终通过功能和交付检查。最大实际序列只有 **73,472 token**，仍远低于 128K。

对这一次失败，增加输出预算有帮助，增加总窗口不是必要条件。代价也很明确：任务耗时由 628 秒增至 1,140 秒。这不是一个让所有失败自动消失的设置。

第二种出现在后来的 MTP 深度对照。五组 Ledger 答案都被同一个读取错误测试拒绝，但它们没有耗尽上下文或输出预算。测试中的假文件对象没有实现正常文件的上下文管理和读取接口，输出捕获对象也没有标准的 `.buffer` 接口。四个答案在触达预期的读取错误前就失败；另一个在向标准错误写出诊断时失败。

我只修正这些模拟接口，保留注入的读取异常和所有验收要求。**五份未修改的答案都从 12/13 变成 13/13 验收通过。** 故意不处理读取异常的负面对照仍然失败，参考答案和此前通过的答案仍然通过。

随后我建立并验证了 **v2.0.2** 测试版本，重新检查 MTP4 的八份已有答案，包括阶段一和最终代码。结果从原来的 7/8 变成 **8/8 功能及交付通过**，没有重新调用模型，也没有修改这些答案。

这次修正不改变原始记录，也不会自动把所有历史量化对照升级为新分数。它让我更谨慎地解释失败：输出截断、代码缺陷、测试缺陷和机器保护停机，需要分别诊断。

## 220K 能跑，256K 要看是否保留 MTP

这里的 K 按 1,024 token 计算。**总窗口由输入和随后生成的输出共享**：192K 输入加 64K 输出，对应 256K 总窗口；170K 输入加 50K 输出，对应 220K 总窗口。

最大输出是上限，不是每次都要生成这么多。如果服务器的总窗口保持不变，仅修改客户端输出上限，不一定额外分配同样大小的显存；但若希望保留相同的最大输入能力，再扩大输出余量，就需要更大的总窗口及相应运行内存。

在这张 3090 上，IQ3_S 和 Q8 主 KV 的容量测试结果是：

| 总窗口和投机设置 | 结果 |
| --- | --- |
| 192K＋MTP4 | 179,532 token 输入，短输出测试通过 |
| 220K＋MTP4 | 相同长输入通过，整张 GPU 显存峰值约 22.80 GiB |
| 256K＋MTP4 | 启动时显存分配失败 |
| 256K，MTP 关闭，减小 batch | 长上下文迁移实验通过 |

所以“3090 能跑 256K”和“3090 能跑 256K＋MTP4”是不同配置。MTP 不只需要额外权重，还会增加缓存或运行时缓冲区需求。256K＋MTP4 日志中一次 1 GiB 缓冲区申请失败，也不能被解释成“只差 1 GiB 显存”。

220K 容量测试使用的是约 179K 的实际输入和短输出，尚未覆盖 170K 输入后连续生成完整 50K 输出的路径。窗口能启动、长输入能推理、长编码任务能正确交付，是三个需要分别验证的条件。

## 长上下文的帮助来自保留信息

为了测试大窗口是否有实际帮助，我构造了一道跨服务 schema 迁移任务：相关的新规格分散在很长的材料里，夹杂过期规格，最终要求迁移 12 个指定服务。它有 **198 个独立验收检查，但只有一个任务、一个 seed**。

三组都使用 IQ3_S、Q8 KV、关闭 MTP 和相同生成参数。区别在于如何提供输入。

| 输入策略 | 实际输入 token | 验收检查 | 输入处理＋解码耗时 |
| --- | ---: | ---: | ---: |
| 256K 窗口，完整材料 | 179,532 | 198/198 | 1,583 秒 |
| 128K 窗口，预先筛选相关文件 | 6,383 | 198/198 | 712 秒 |
| 128K 窗口，简单保留材料首尾 | 54,755 | 138/198 | 1,851 秒 |

完整材料使模型拿到了全部相关规格；简单截取首尾则丢掉九个服务的规格，导致失败。但提前按已知相关文件筛选输入，也完成了同样的任务，而且更快。这里没有验证一个真实 agent 能否自行检索到所有正确文件。

这道实验支持大窗口在避免信息丢失时有价值，也支持有效筛选输入可以减少成本。它没有证明 256K 普遍提高编码质量，更没有证明首尾截取是 128K 的最佳用法。

220K 的真实 coding 对照则还没完成。已经完成的 cache 和 wallet 都通过功能及交付；第三个 eventstream 运行时，CPU 温度采样达到 **93.25°C**，触发设定为 92°C 的停止保护。最终只完成 2/8，其余六个没有有效评分。

wallet 很能说明速度指标的区别：从 128K 改为 220K 后，生成速度由约 56.18 升到 59.77 token/s，但生成量从 35,165 增至 46,162 token，任务耗时由 654 秒变成 835 秒。**生成速度高了约 6.4%，任务却多花约 27.7% 时间。** 这一次观察不能证明窗口扩大导致模型变啰嗦，但足以说明不能只看 token/s。

## DFlash2 在这张 3090 上没有超过 MTP4

[DFlash](https://z-lab.ai/projects/dflash/)和 MTP 都提出草稿并交给主模型验证，但草稿生成方式不同：本地 MTP 逐步生成草稿；DFlash 使用单独的轻量 block diffusion 模型，并行提出一整块 token。[DFlash2](https://inco.ai/blog/dflash2/)进一步改进草稿选择和块内信息交互。

这次我用同一个 IQ3_S 目标模型、Q8 主 KV、220K 总窗口，比较 MTP4 和 DFlash2。DFlash2 使用 Q4_K_M 草稿权重，最多提出七个草稿 token；两种路径的草稿 KV 都用 F16。启用 DFlash2 时关闭 MTP，分别独立运行。

| 实际输入 | 输出长度 | MTP4 | DFlash2 | DFlash2 相对变化 |
| --- | ---: | ---: | ---: | ---: |
| 8,207 token | 512 token | 54.82 token/s | 53.01 token/s | −3.3% |
| 32,783 token | 512 token | 49.11 token/s | 46.24 token/s | −5.8% |
| 179,532 token | 128 token | 30.01 token/s | 28.84 token/s | −3.9% |

这些是相同冷输入下，每种配置各一次的短生成测量，排除输入处理时间。最长输入那组的完整请求时间，DFlash2 反而略短，约 303 秒对 307 秒，因为请求耗时还包括输入处理。因此可以说它的生成阶段略慢，不能说它每个请求都更慢。

按每 200 毫秒采样的整张 GPU 显存计算，DFlash2 峰值约 **23.33 GiB**，MTP4 约 **22.80 GiB**，相差约 **540 MiB**。DFlash2 峰值时只剩约 690 MiB 空闲显存。这轮没有 OOM，CPU 峰值为 82.75°C。

这些测量没有包含完整编码任务，不能得出 DFlash2 编码质量相同或更差的结论。它们也没有覆盖长输出。就目前的实测，我没有理由为了生成速度把 MTP4 换成 DFlash2。

对投机解码，正确的主模型验证和采样是保持目标模型分布的前提；这不等于不同路径会逐字输出相同答案，更不等于 IQ3 目标模型与原 Q4 权重质量完全相同。权重量化和草稿验证的影响，需要分开看。

## 吞吐量和功耗

两段接近完整的早期编码运行中，显卡板卡的时间加权平均功耗约 **329W**。这是 GPU 读数，没有包含 CPU、其他组件和电源损耗；整机功耗需要插座侧测量。

按每周 168 小时持续解码，61.31 token/s 可以外推到约 **3,708 万生成 token/周**。它包含思考和工具语法，实际 agent 还要处理输入、等待工具和散热休息，因此这不是已交付代码量，也不能直接折算成云服务 subscription 的 token quota。

## 我现在会选的实验配置

对于这批常见修复任务，我会先用下面这组参数：

| 项目 | 当前选择 |
| --- | --- |
| 权重 | Qwen3.8-27B GSQ-RCO IQ3_S，带 MTP head |
| 主 KV cache | K/V 均为 Q8_0 |
| 投机解码 | MTP，最大草稿数 4 |
| 总上下文 | 131,072 token |
| 单次回复输出上限 | 65,536 token，共享上述总窗口 |
| 生成参数 | temperature 1.0，top_p 0.95，top_k 20，min_p 0，repeat penalty 1 |
| 思考 | 开启，reasoning effort 为 xhigh |
| 执行 | 单并发，Flash Attention，模型层全部放在 GPU |
| batch / ubatch / CPU threads | 512 / 256 / 8 |

这里“全部放在 GPU”指模型层，不意味着整个编码流程不使用 CPU。文件操作、测试、类型检查和推理运行时的调度仍会用到 CPU；GPU 推理也不会使测试子进程的温度问题消失。

运行栈仍以 llama.cpp b11146、CUDA 12.8 和 OpenCode 2.0.20 为基准。这是我目前优先采用的实验配置，日常服务的全局默认值并没有在这些实验中被自动改写。各轮实验顺序和温度条件并不完全一致；例如 MTP 深度对照的五次 cache 尝试使用 90°C 保护阈值，后续使用 92°C，期间也包含人工暂停。

需要长输入时，可以考虑 220K 总窗口，计划留 170K 输入和 50K 输出预算，但完整编码验证仍有六个任务待完成。256K 加 MTP4 的显存问题、DFlash2 的长输出和编码质量，也还需要各自的证据。

我还调研了社区的 [Coder390 模型及配套量化](https://huggingface.co/nerkyor/Qwen3.8-27B-Coder390-EfficientThink-Opus5.5-GPT6Astra-Grok4.7-DSV4Pro-K3-SFT-RLOO-MTP-DFlash2)。它包含额外训练，不能仅作为另一个量化文件与这里的同一基座对照；我尚未在这张 3090 上跑它，因此没有把宣传成绩放进本地速度或质量排名。

接下来最值得做的，是完成修正测试后的重复质量对照，以及剩余的 220K 编码任务。当前的结果已经足够让我优先使用 IQ3_S＋Q8 KV＋MTP4，但要回答“在更广泛的编码工作里还能保持多少质量”，还需要更大的任务集和更多重复。
