最近常在油管刷到老特每日一发的视频(辛苦啦
),看着看着一路顺藤摸瓜找到了这个论坛,又看到站内这篇 R9700 + Qwen3.8-27B 的实测。看完原帖和评论区各种折腾之后手痒了,刚好自己也有一张 R9700,那就跟着折腾一遍。
先感谢原帖作者的实测和分享,我这次不少测试思路也是受到这篇帖子的启发:
[R9700 32GB 跑 Qwen3.8-27B,llama.cpp Vulkan + MTP 实测与踩坑记录]
第一次在论坛发帖,本来只想简单记录一下,结果折腾着折腾着就啰里八嗦写了这么长一篇
。
排版和阅读体验如果有什么不太舒服的地方,还请大家多多包涵。
我的平台和原帖有一个比较大的区别:我不是标准桌面 PCIe x16 平台,而是 铭凡 (Minisforum) AI X1 Pro + OCuLink + DEG1 + R9700,操作系统也是 Windows 11 + AMD 官方驱动 + llama.cpp Vulkan。
所以这次主要想看几个问题:
- R9700 通过 OCuLink 跑 Qwen3.8-27B 的实际表现如何?
UD-Q4_K_XL和UD-Q6_K_XL在 R9700 上速度差多少?- Q8 KV + 128K Context 是否实用?
- Qwen3.8 的 MTP 在 Windows / Vulkan 下能带来多少实际收益?
spec-draft-n-max应该设多少?
先说结论:
在我这套环境和测试 workload 下,UD-Q4_K_XL + Q8 KV + 128K Context + MTP 的甜点是
n-max=3。长代码生成实测约 43.2–43.4 t/s,而且复测结果比较稳定。
| 场景 | 实测 |
|---|---|
| Q4 Raw Decode(tg128) | 29.46 t/s |
| Q6 Raw Decode(tg128) | 22.72 t/s |
| Q4 MTP 最佳长输出 | 43.44 t/s |
| Q4 MTP 复测长输出 | 43.20 t/s |
| MTP 最佳参数 | n-max=3 |
| Prompt Prefill,8443 tokens | 584.39 t/s |
| Context | 128K |
| KV Cache | Q8_0 / Q8_0 |
一、测试平台

Minisforum AI X1 Pro + Radeon AI PRO R9700 32GB,通过 OCuLink + Minisforum DEG1 外接,独立 ATX 电源供电。
| 项目 | 配置 |
|---|---|
| 主机 | Minisforum AI X1 Pro |
| CPU | AMD Ryzen AI 9 HX 470 |
| 系统内存 | 96 GB |
| iGPU | AMD Radeon 890M |
| UMA Frame Buffer | 8 GB |
| GPU | ASRock Radeon AI PRO R9700 Creator |
| VRAM | 32 GB |
| GPU 连接 | OCuLink |
| eGPU Dock | Minisforum DEG1 |
| PSU | be quiet! Power Zone 2 850W |
| OS | Windows 11 Pro |
这次 LLM 推理明确指定:
Vulkan0 = AMD Radeon AI PRO R9700
890M 没有参与模型 GPU offload。
llama-bench --list-devices:
Vulkan0: AMD Radeon AI PRO R9700
32624 MiB, 31704 MiB free
Vulkan1: AMD Radeon(TM) 890M Graphics
79994 MiB, 75994 MiB free
R9700 Vulkan backend 同时识别到:
fp16: 1
bf16: 1
int dot: 1
matrix cores: KHR_coopmat
二、软件与推理环境
这次除了跑 llama-bench 做标准化性能测试之外,我的实际使用环境是 DeepSeek Harness(DSH)+ llama.cpp。
DSH 通过本机 OpenAI-compatible API 连接 llama-server,整体链路大致如下:
DSH
↓
OpenAI-compatible API
↓
llama-server
↓
Vulkan0
↓
R9700
| 项目 | 配置 |
|---|---|
| Agent / 前端 | DeepSeek Harness(DSH) |
| API | llama.cpp OpenAI-compatible API |
| API 地址 | 127.0.0.1:8080/v1 |
| llama.cpp | build: 758443071 (10612) |
| Backend | Vulkan |
| GPU | Vulkan0 / R9700 |
| GPU Offload | 全部 |
| Parallel | 1 |
| Flash Attention | ON |
| KV Cache | Q8_0 / Q8_0 |
| Context | 131072(128K) |
| Reasoning | ON |
| Speculative Decoding | MTP |
| MTP Device | Vulkan0 |
llama-server 启动后,DSH 通过下面的模型 alias 连接:
qwen3.8-27b@q4_k_xl
主要测试模型:
Qwen3.8-27B-UD-Q4_K_XL.gguf
Qwen3.8-27B-UD-Q6_K_XL.gguf
这篇里其实有两种不同性质的测试,后面会分开写:
-
llama-bench
用来测 Q4 / Q6 的标准化 Prompt Processing(pp)和 Raw Token Generation(tg),方便做比较。 -
llama-server + MTP实际长输出测试
用实际 Coding / 长文本 workload 测试 MTP,包括不同spec-draft-n-max设置;部分测试由 DSH 作为前端连接本机llama-server。
所有最终的 Prompt、Generation、Draft Acceptance、Mean Len 等性能数据,都是直接取自 llama-server 的 timing log,不是 DSH 显示的估算速度。
所以后面看到的 29.46 t/s 和 43.2~43.4 t/s 代表的是两种不同测试:
29.46 t/s = llama-bench Q4 tg128(Raw Decode)
43.2~43.4 t/s
= llama-server + MTP 实际长输出
两者可以用来观察 Raw Decode 与实际 MTP workload 的差异,但不是完全相同的 benchmark,不能直接当成严格的 apples-to-apples MTP 加速率。
三、先跑 llama-bench:Q4 vs Q6
为了把模型本身的基础性能和 MTP 后的实际 server generation 分开看,我先用 llama-bench 跑 Q4 和 Q6。
两者使用相同参数:
-dev Vulkan0
-ngl 999
-fa on
-ctk q8_0
-ctv q8_0
-p 512,2048,8192
-n 128
-r 3
Benchmark 结果
| 测试 | UD-Q4_K_XL | UD-Q6_K_XL |
|---|---|---|
| 模型大小 | 16.34 GiB | 23.55 GiB |
| pp512 | 680.55 ± 0.46 t/s | 655.10 ± 0.53 t/s |
| pp2048 | 662.92 ± 8.77 t/s | 646.17 ± 1.21 t/s |
| pp8192 | 629.81 ± 2.33 t/s | 607.60 ± 3.55 t/s |
| tg128 | 29.46 ± 0.06 t/s | 22.72 ± 0.04 t/s |
这里最明显的是 decode。
Q4:
29.46 t/s
Q6:
22.72 t/s
以 Q6 为基准,Q4 的 tg128 大约快 29.7%。
Prefill 的差距反而只有几个百分点。
这也让我最后比较倾向把 UD-Q4_K_XL 当成 R9700 32GB 的 daily driver:不仅 decode 更快,而且模型少占约 7 GiB VRAM,对大 Context / KV cache 也更友好。
四、接下来测试 MTP
llama-bench tg128 是很好的标准化 raw decode reference,但我的实际用途不是只生成 128 tokens。
我主要用本地模型做 coding / agent,所以接下来使用实际的长代码生成 workload 测 llama-server + MTP。
最终 Q4 server 配置:
& "D:\AI\Apps\llama.cpp\b10612-vulkan\llama-server.exe" `
--model "D:\AI\Models\LLM\unsloth\Qwen3.8-27B-GGUF\Qwen3.8-27B-UD-Q4_K_XL.gguf" `
--mmproj "D:\AI\Models\LLM\unsloth\Qwen3.8-27B-GGUF\mmproj-F16.gguf" `
--device Vulkan0 `
--gpu-layers all `
--ctx-size 131072 `
--parallel 1 `
--flash-attn on `
--cache-type-k q8_0 `
--cache-type-v q8_0 `
--spec-type draft-mtp `
--spec-draft-device Vulkan0 `
--spec-draft-ngl all `
--spec-draft-n-max 3 `
--spec-draft-n-min 0 `
--spec-draft-p-min 0.75 `
--reasoning on `
--host 127.0.0.1 `
--port 8080 `
--alias "qwen3.8-27b@q4_k_xl"
五、MTP n-max 调优
这里是这轮测试里我觉得最有意思的部分。
同一类长代码生成 workload 下,我测试了不同的 spec-draft-n-max。
| MTP 设置 | Generation | Acceptance | Mean Len |
|---|---|---|---|
n-max=2 |
39.50 t/s | 90.51% | 2.62 |
n-max=3 |
43.44 t/s | 88.59% | 3.13 |
n-max=4 |
43.19 t/s | 86.58% | 3.49 |
n-max=5 |
33.40 t/s | 82.80% | 3.70 |
结果很明显:
2 → 3:明显变快
3 → 4:基本持平,3 略快
4 → 5:性能明显下降

所以在我这里:
n-max=3是 sweet spot。
n-max=5 虽然平均 draft length 更长,但 acceptance 已经掉到 82.8%,额外 speculative work 的成本反而把实际 throughput 拉低到:
33.40 t/s
所以 MTP 的 n-max 看来并不是越高越好。
六、n-max=3 再跑一次确认
第一次比较好的结果:
Generation 43.44 t/s
Acceptance 88.59%
Mean Len 3.13
后来重新启动 server,用相同的核心配置又跑了一次:
prompt eval time = 14447.55 ms / 8443 tokens
= 584.39 tokens per second
eval time = 238937.76 ms / 10324 tokens
= 43.20 tokens per second
total time = 253385.31 ms / 18767 tokens
draft acceptance = 0.87117
= 6147 accepted / 7056 generated
mean len = 3.11
整理一下:
| 场景 | 实测 |
|---|---|
| Prompt Prefill,8443 tokens | 584.39 t/s |
| 长输出 Generation,10324 tokens | 43.20 t/s |
| MTP Draft Acceptance | 87.12% |
| MTP Mean Len | 3.11 |
| 总处理 tokens | 18767 |
| 总耗时 | 约 253.4 秒 |
| Context | 128K |
| KV Cache | Q8_0 / Q8_0 |
| MTP | n-max 3 / p-min 0.75 |
两次 n-max=3:
43.44 t/s
43.20 t/s

平均:
43.32 t/s
两次只差约 0.6%,所以我觉得把这套配置的实际长输出性能记成:
约 43.3 t/s
是比较合理的。
而且第二次实际生成了 10,324 tokens,不是很短的 benchmark。
七、Raw decode 29.46 t/s,MTP workload 约 43.3 t/s
把几个数字放在一起看:
| 测试 | Generation |
|---|---|
llama-bench tg128 |
29.46 t/s |
| MTP 长代码生成 #1 | 43.44 t/s |
| MTP 长代码生成 #2 | 43.20 t/s |
| MTP 两次平均 | 43.32 t/s |
从数值上看:
29.46 → 43.32 t/s
约高 47%。
不过这里必须说明:
这不是严格 apples-to-apples 的 +47% MTP benchmark。
llama-bench tg128 和实际长代码生成是不同 workload,所以我把 29.46 t/s 当成 standardized raw decode reference,而不是宣称“开启 MTP 必定提升 47%”。
真正比较有意义的是:在我的实际 coding workload 中,MTP 调好后可以长期维持在 43 t/s 左右。
八、还试了 -b 16384 -ub 2048
看到一些 llama.cpp 调优讨论后,我也测试了:
-b 16384
-ub 2048
结果:
| 配置 | Generation | Prompt | Acceptance |
|---|---|---|---|
| 默认 batch / MTP3 | 43.44 t/s | 583.45 t/s | 88.59% |
-b 16384 -ub 2048 / MTP3 |
42.84 t/s | 583.03 t/s | 87.33% |
在我的 workload 上没有提升,反而慢了一点。
所以最后没有保留这两个参数。
九、为什么最后选择 Q4 而不是 Q6?
目前对我来说:
| 项目 | UD-Q4_K_XL | UD-Q6_K_XL |
|---|---|---|
| 模型大小 | 16.34 GiB | 23.55 GiB |
| tg128 | 29.46 t/s | 22.72 t/s |
| 相对 Q4 decode | 100% | 77.1% |
| VRAM 余量 | 较多 | 较少 |
| 128K Context | 更宽松 | 更紧 |
| 日常 Coding / Agent | 我的选择 | 偏质量时考虑 |
Q6 的量化质量理论上当然更好。
但 R9700 是 32GB VRAM。
我的实际目标又包括:
- 128K Context
- Q8 KV
- MTP
- mmproj
- coding agent
- 长 session
所以多出来的 VRAM headroom 对我来说很有价值。
目前我的 daily driver 会选择:
UD-Q4_K_XL
十、128K Context + Q8 KV
这次最终配置使用:
--ctx-size 131072
--parallel 1
--cache-type-k q8_0
--cache-type-v q8_0
我没有为了 benchmark 把 context 降到很小。
原因很简单:我的目标是实际接 coding agent 使用,而不是只追求一个最高 t/s 数字。
Q4 模型约 16.34 GiB,因此在 R9700 32GB 上仍然可以给 KV cache、MTP 和其他 runtime allocation 留出不少空间。
这也是我觉得 Q4 在 32GB 卡上特别合适的原因之一。
十一、关于 OCuLink
我的 R9700 并不是插在桌面 PCIe x16 主板上,而是:
Minisforum AI X1 Pro
│
OCuLink
│
Minisforum DEG1
│
Radeon AI PRO R9700 32GB
OCuLink 的 PCIe host bandwidth 显然不等于桌面 PCIe x16。
不过对于模型已经完整驻留 VRAM 的 LLM inference,decode 阶段的大部分权重访问发生在 GPU 本地显存,因此 PCIe 链路带宽不一定会像某些需要频繁 CPU
GPU 数据交换的 workload 那样成为主要瓶颈。
这次 OCuLink 环境下实测:
| 场景 | 实测 |
|---|---|
| Q4 pp512 | 680.55 t/s |
| Q4 pp2048 | 662.92 t/s |
| Q4 pp8192 | 629.81 t/s |
| Q4 tg128 | 29.46 t/s |
| Q4 MTP 长输出 | 约 43.2~43.4 t/s |
从目前结果来看,这套 OCuLink 配置下的 llama.cpp Vulkan 推理表现正常,没有观察到明显异常的性能瓶颈。
不过这里要特别说明:我没有同一张 R9700 在 PCIe x16 下的直接 A/B 测试数据。
所以这些结果只能证明这套 OCuLink + R9700 配置能够达到上述性能,不能据此得出“OCuLink 相比 PCIe x16 没有性能损失”的结论。
如果以后有机会用同一张 R9700、同一个 llama.cpp build、同一个 GGUF 和完全相同参数分别测试 OCuLink 与 PCIe x16,再来量化 OCuLink 对 Prefill 和 Decode 的实际影响会比较有意义。
十二、BIOS / ReBAR
测试期间也检查了一下 BIOS。
确认:
Resizable BAR Support = Enabled
UMA Frame Buffer = 8 GB
Windows 正常识别 R9700:
AMD Radeon AI PRO R9700
PCI bus 200, device 0, function 0
我这版 Minisforum BIOS 没有找到一个独立可见的 Above 4G Decoding 开关,因此这里不写成“已确认开启”。
没有为了跑分去修改隐藏 BIOS 设置。
十三、和原帖结果的关系
这也是我觉得比较有意思的地方。
原帖作者的环境、quant、KV 设置等和我并不完全一样,所以两边数字不能直接当作同一 benchmark 排名。
但一个值得继续研究的差异是 MTP n-max。
我的环境:
Windows 11
AMD proprietary Vulkan driver
llama.cpp build 758443071 (10612)
UD-Q4_K_XL
Q8 KV
128K
R9700 / OCuLink
在这个组合下:
n-max=3最合适。
而原帖以及评论区的其他配置有不同的 sweet spot。
这说明 MTP 最佳参数很可能跟以下因素都有关系:
- quant
- KV cache type
- backend
- driver
- llama.cpp build
- workload
- draft acceptance rate
所以我现在的感觉是:
不要直接照抄别人的
n-max,最好自己跑 2 / 3 / 4 / 5。
R9700 跑一次这种 sweep 成本并不高,但最后可能差很多。
十四、目前的 Daily Driver 配置
经过这轮测试,我准备先把下面这套作为日常配置:
Model: Qwen3.8-27B UD-Q4_K_XL
GPU: R9700 / Vulkan0
GPU offload: all
Context: 131072
Parallel: 1
Flash Attention: ON
KV:
K = q8_0
V = q8_0
MTP:
n-max = 3
n-min = 0
p-min = 0.75
Reasoning: ON
实际长代码生成:
≈ 43.3 t/s
完整启动命令:
& "D:\AI\Apps\llama.cpp\b10612-vulkan\llama-server.exe" `
--model "D:\AI\Models\LLM\unsloth\Qwen3.8-27B-GGUF\Qwen3.8-27B-UD-Q4_K_XL.gguf" `
--mmproj "D:\AI\Models\LLM\unsloth\Qwen3.8-27B-GGUF\mmproj-F16.gguf" `
--device Vulkan0 `
--gpu-layers all `
--ctx-size 131072 `
--parallel 1 `
--flash-attn on `
--cache-type-k q8_0 `
--cache-type-v q8_0 `
--spec-type draft-mtp `
--spec-draft-device Vulkan0 `
--spec-draft-ngl all `
--spec-draft-n-max 3 `
--spec-draft-n-min 0 `
--spec-draft-p-min 0.75 `
--reasoning on `
--host 127.0.0.1 `
--port 8080 `
--alias "qwen3.8-27b@q4_k_xl"
十五、总结
这轮测试下来,我自己的几个结论:
1. R9700 32GB 跑 Qwen3.8-27B Q4 很舒服
模型完整 GPU offload 后,还有足够空间留给大 Context 和 KV。
2. Q4 和 Q6 的 decode 差距比 prefill 明显得多
Q4 tg128 = 29.46 t/s
Q6 tg128 = 22.72 t/s
对我的 coding / agent 用途,Q4 的综合平衡更好。
3. MTP 很值得开,但需要调
我的实际长代码 workload:
n-max 2 → 39.50 t/s
n-max 3 → 43.44 t/s
n-max 4 → 43.19 t/s
n-max 5 → 33.40 t/s
n-max=3 是明显的 sweet spot。
4. -b 16384 -ub 2048 在我的环境没有帮助
所以没有保留。
5. 128K + Q8 KV 是可以实际使用的
我更愿意牺牲一点理论最高 benchmark,换取真正适合 coding agent 的配置。
6. OCuLink 环境下的推理表现正常
目前没有观察到明显异常的性能瓶颈,但因为缺少同卡 PCIe x16 的直接 A/B 测试,所以这里只作为 OCuLink 环境下的实测数据点,不对 OCuLink 相比 PCIe x16 的性能损失做定量结论。
最后感谢原帖作者和评论区参与测试的网友。
这轮测试很大程度上是受到原帖的启发。我这里主要补充一个:
Windows + AMD 官方 Vulkan + OCuLink + R9700 + UD-Q4_K_XL / Q6_K_XL
的数据点。
如果其他 R9700 用户有 Linux/RADV、ROCm、PCIe x16,或者不同 llama.cpp build 下同一个 Q4_K_XL 的数据,也欢迎一起对比。
尤其想看看大家的:
llama-bench tg128
MTP n-max 2 / 3 / 4 / 5
draft acceptance
到底差多少。