双 NVIDIA L20 实测:Qwen3.8-27B 的 BF16、FP8、MTP、单卡表现,以及与 Qwen3.6 MoE 的差距
双 NVIDIA L20 实测:Qwen3.8-27B 的 BF16、FP8、MTP、单卡表现,以及与 Qwen3.6 MoE 的差距
本文记录一次真实服务器上的部署与性能测试。目标不是做理想化的显卡跑分,而是回答一个更实际的问题:在两张 NVIDIA L20 上,Qwen3.8-27B 应该使用 BF16 还是 FP8?开启 MTP 后单路速度能提升多少?单卡是否值得?它能否替代当前速度超过 100 token/s 的 Qwen MoE Agent 模型?
一、先说结论
五种部署方式使用同一套输入和输出长度测试后,结果如下:
| 部署方式 | 单流 decode | 单流端到端 | TTFT | 4 路并发总吞吐 |
|---|---|---|---|---|
| Qwen3.8-27B BF16,双卡 TP2 | 25.96 token/s | 25.54 token/s | 369 ms | 91.72 token/s |
| Qwen3.8-27B FP8,双卡 TP2 | 29.46 token/s | 29.02 token/s | 303 ms | 123.73 token/s |
| Qwen3.8-27B FP8,双卡 TP2 + MTP3 | 56.33 token/s | 53.68 token/s | 473 ms | 180.25 token/s |
| Qwen3.8-27B FP8,单卡 | 17.41 token/s | 17.21 token/s | 409 ms | 72.70 token/s |
| 现有 Qwen3.6-35B-A3B MoE,BF16 双卡 | 151.98 token/s | 144.60 token/s | 183 ms | 367.79 token/s |
结论可以概括成四句话:
- Qwen3.8 的 FP8 比 BF16 更快、更省显存,基本没有继续用 BF16 做主服务的性能理由。
- FP8 开启 MTP 后,单流 decode 从 29.46 提升到 56.33 token/s,提升 91.19%,效果非常明显。
- FP8 单卡虽然能够运行,但单流只有 17.41 token/s,不适合低延迟 Agent。
- 即便开启 MTP,Qwen3.8 的单流速度也只有现有 Qwen3.6 MoE 的 37%左右。如果替代条件是“速度不能相差太多”,那么当前仍不满足。
需要特别说明:token/s 不是“中文字符/秒”或“单词/秒”。不同 tokenizer、语言和输出结构会影响用户看到的实际文字速度。
二、服务器配置
这不是一台完全空闲的跑分服务器。测试期间 GPU 0 上还运行着一个 OCR 服务,占用约 1.57 GiB 显存,因此结果更接近真实业务共存环境。
硬件
| 项目 | 配置 |
|---|---|
| CPU | 2 × Intel Xeon Gold 6530 |
| 物理核心/线程 | 64 核 / 128 线程 |
| NUMA | 2 nodes |
| 内存 | 251 GiB,无 Swap |
| GPU | 2 × NVIDIA L20 |
| 单卡可见显存 | 46068 MiB,约 45 GiB |
| NVIDIA Driver | 580.173.02 |
| 磁盘 | 447 GB + 1.7 TB 逻辑盘 |
| 文件系统 | ext4,合计约 2.1 TB |
| 测试时可用磁盘 | 约 1.2 TB |
软件
| 项目 | 版本 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| Kernel | 5.15.0-186-generic |
| Docker | 29.4.1 |
| Docker Compose | v5.1.3 |
| Qwen3.8 镜像 | vllm/vllm-openai:qwen38 |
| Qwen3.8 镜像 Digest | sha256:4a2f33a884222f7049b983263ad9976f89452bb81affecf5b67d89ad35c1bc31 |
| Qwen3.8 vLLM | 0.1.dev19754+g3a0914114 |
| 现有 MoE vLLM | 0.19.1.dev6+g6d4a8e6d2 |
两类服务使用的 vLLM 构建不同,所以这不是“完全相同软件栈下的学术对比”,而是“服务器上两个实际可部署方案的生产视角对比”。
三、模型与磁盘占用
本次下载和测试的主要模型:
服务器原有的对照模型实际是:
- Qwen3.6-35B-A3B
它之前被口头称为“Qwen3.5 MoE”,但容器挂载目录和 config 均表明实际模型是 Qwen3.6-35B-A3B。其 Transformers 架构类仍叫 Qwen3_5MoeForConditionalGeneration,这是代码架构名称,不能据此把模型版本判断成 Qwen3.5。
| 模型 | 权重/目录占用 | 权重分片 |
|---|---|---|
| Qwen3.8-27B BF16 | 51.747 GiB,du 约 52 GB | 18 |
| Qwen3.8-27B FP8 | 28.747 GiB,du 约 29 GB | 66 |
| Qwen3.6-35B-A3B BF16 | du 约 67 GB | 26 |
FP8 相比 BF16 少 23 GiB,权重体积下降 44.45%。
下载完成后逐个解析了 safetensors 文件头,并按 index 检查所有分片:
- BF16:18/18,缺失 0,非空 incomplete 文件 0;
- FP8:66/66,缺失 0,非空 incomplete 文件 0。
下载方式
网络环境使用 Hugging Face 镜像:
1 | export HF_ENDPOINT=https://hf-mirror.com |
实际部署中,第一次下载遇到 Xet CAS 401。加入 HF_HUB_DISABLE_XET=1 后改走普通 HTTP,两个模型均成功完成下载。
四、部署方式
所有 Qwen3.8 服务都采用 OpenAI-compatible API,监听 8000 端口。同一时间只运行一个大模型,避免显存互相影响。
公共参数如下:
- 最大上下文:32768;
gpu-memory-utilization=0.90;max-num-seqs=8;max-num-batched-tokens=8192;- text-only;
- prefix caching;
- reasoning parser:qwen3;
- tool parser:qwen3_coder;
- Tensor Parallel 双卡部署使用 TP2。
1. FP8 双卡基线
核心 Compose 配置如下:
1 | services: |
2. BF16 双卡
BF16 与 FP8 使用相同参数,只修改模型目录、served model name 和 dtype:
1 | volumes: |
3. FP8 双卡 + MTP
Qwen3.8 的 config 中包含一个 MTP hidden layer。按照官方 vLLM Qwen3.8 配方,在 FP8 TP2 基础上增加:
1 | command: |
served model name 单独设置成 qwen3.8-27b-fp8-mtp,避免与普通 FP8 混淆。
4. FP8 单卡
单卡固定使用 GPU 1,避开 GPU 0 上的 OCR:
1 | environment: |
其他上下文、批处理和采样相关参数保持不变。
5. 现有 Qwen3.6 MoE
服务器原有容器使用以下核心参数:
1 | 模型:/models/Qwen3.6-35B-A3B |
这个部署没有启用 MTP,也没有启用 text-only,因此还会初始化视觉 encoder cache。它依然明显快于 Qwen3.8,说明主要优势来自 MoE 每 token 只激活约 3B 参数,而不是测试参数偏向它。
五、部署中遇到的实际问题
1. L20 上的 custom all-reduce 报错
Qwen3.8 BF16 首次启动时,在 CUDA Graph 阶段出现:
1 | custom_all_reduce.cuh:164 'invalid argument' |
加入以下参数后,两种精度均通过 PyNCCL 稳定启动:
1 | --disable-custom-all-reduce |
因此所有双卡 Qwen3.8 结果都采用相同的 PyNCCL 通信方式。
2. L20 缐少部分 FP8 专门调优配置
官方 qwen38 镜像提示,部分 W8A8 block shape 没有对应的 NVIDIA L20 调优文件,会回退到默认 Triton FP8 kernel:
1 | Using default W8A8 Block FP8 kernel config. |
这意味着本文记录的是当前镜像的真实表现,但未来 vLLM 如果补充 L20 专用配置,FP8 仍可能继续提升。
3. MTP 增加冷启动和首 token 延迟
MTP 需要额外编译 draft/eagle head 和 speculative CUDA Graph:
- MTP engine profile/compile:约 215.84 秒;
- 普通 FP8 首次 engine 初始化:约 206.23 秒;
- 单卡首次 engine 初始化:约 204.04 秒。
编译会进入缓存,后续重启可以明显缩短,但第一次部署需要预留几分钟。
六、测试方法
为了避免只比较“短提示、短输出”的理想数据,本次使用较长上下文和固定长输出:
| 项目 | 设置 |
|---|---|
| Prompt tokens | 3472 |
| 每次输出 | 固定 512 tokens |
| 预热 | 64 output tokens |
| 单流测试 | 5 次 |
| 并发测试 | 4 路 × 3 轮 |
| temperature | 0 |
| seed | 42 |
| ignore_eos | true |
| 请求方式 | Streaming |
| 客户端位置 | 与推理服务同机 |
指标定义:
- decode token/s:首 token 之后的稳定生成速度;
- 端到端 token/s:从发起请求到输出结束,包含 TTFT;
- TTFT:Time To First Token;
- 4 路总吞吐:四个独立请求同时进行时的合计输出速度。
这里的 4 路吞吐不是“单个回答达到 180 或 367 token/s”。它表示四个请求共享 GPU,四份回答的 token/s 相加。
七、完整结果
单流与并发
| 部署方式 | decode 均值 | 端到端均值 | TTFT 均值 | 4 路总吞吐 |
|---|---|---|---|---|
| Qwen3.8 BF16 TP2 | 25.9619 | 25.5445 | 369.24 ms | 91.7179 |
| Qwen3.8 FP8 TP2 | 29.4640 | 29.0237 | 303.20 ms | 123.7267 |
| Qwen3.8 FP8 TP2 + MTP3 | 56.3328 | 53.6802 | 472.84 ms | 180.2471 |
| Qwen3.8 FP8 单卡 | 17.4080 | 17.2057 | 408.63 ms | 72.7024 |
| Qwen3.6-35B-A3B MoE TP2 | 151.9773 | 144.6014 | 183.17 ms | 367.7857 |
稳定性
| 部署方式 | decode min / median / max | 4 路 min / median / max |
|---|---|---|
| BF16 TP2 | 25.9589 / 25.9604 / 25.9668 | 91.6760 / 91.7237 / 91.7539 |
| FP8 TP2 | 29.4579 / 29.4610 / 29.4713 | 123.7133 / 123.7301 / 123.7367 |
| FP8 TP2 + MTP3 | 54.9691 / 56.2572 / 58.4411 | 151.3570 / 188.4414 / 200.9430 |
| FP8 单卡 | 17.4069 / 17.4082 / 17.4089 | 72.6561 / 72.6747 / 72.7766 |
| Qwen3.6 MoE | 151.9462 / 151.9739 / 152.0212 | 352.5549 / 373.7171 / 377.0850 |
普通 BF16、FP8 和单卡结果非常稳定。MTP 四并发波动明显更大,与不同输出片段上的 speculative acceptance rate 有关。
显存与 KV cache
| 部署方式 | 模型加载显存/卡 | 可用 KV cache/卡 | KV tokens |
|---|---|---|---|
| Qwen3.8 BF16 TP2 | 25.17 GiB | 13.66 GiB | 389,802 |
| Qwen3.8 FP8 TP2 | 13.85 GiB | 24.32 GiB | 693,589 |
| Qwen3.8 FP8 TP2 + MTP3 | 14.07 GiB | 23.73 GiB | 534,820 |
| Qwen3.8 FP8 单卡 | 27.57 GiB | 9.43 GiB | 134,485 |
| Qwen3.6 MoE TP2 | 32.86 GiB | 3.30 GiB | 86,592 |
MTP 的模型显存只比普通 FP8 略高,但 speculative scheduling 和 padding 让 KV tokens 从 693,589 降到 534,820,下降约 22.89%。
八、如何理解这些结果
FP8 是否值得?
值得。
相对 BF16:
- 单流 decode 提升 13.49%;
- 端到端提升 13.62%;
- 四路吞吐提升 34.90%;
- 权重体积下降 44.45%;
- KV cache tokens 增加约 77.93%。
在这台双 L20 上,普通部署应优先选 FP8。
MTP 是否值得?
对于长输出 Agent,值得。
FP8+MTP 相对普通 FP8:
- 单流 decode:+91.19%;
- 端到端:+84.95%;
- 四路总吞吐:+45.68%;
- TTFT:增加 55.95%。
服务端观测到:
- 平均接受长度:2.31~2.70 tokens;
- draft 接受率:43.5%~56.6%;
- 第一个预测位置接受率最高,越往后越低。
因此 MTP 很适合 512-token 这类较长输出;对于几十 token 的短回答,较高 TTFT 会吃掉一部分收益。
单卡是否值得?
取决于目标。
如果目标是释放一张 GPU,单卡可以正常服务,甚至能够跑满四并发;但单流速度比 FP8 TP2 低 40.92%,四路吞吐低 41.24%。
所以单卡是“资源节省方案”,不是“低延迟方案”。
Qwen3.8 能否替代当前 MoE Agent?
只看速度,目前不能。
Qwen3.8 FP8+MTP 与现有 MoE 相比:
- 单流 decode 只有 37.07%;
- 单流端到端只有 37.12%;
- 四路总吞吐只有 49.01%;
- TTFT 高约 2.58 倍。
现有 MoE 的单流速度是 Qwen3.8 MTP 的约 2.70 倍。
这并不表示 MoE 一定“更好”。速度快是因为每 token 只激活约 3B 参数。Qwen3.8 是否在推理质量、工具调用、长上下文或具体 Agent 任务上更强,需要另一套业务 A/B 测试,不能从 token/s 推导。
九、最终选择建议
如果是我的部署决策,会这样选:
- 当前 Agent 速度优先:继续使用 Qwen3.6-35B-A3B MoE。
- 必须使用 Qwen3.8 的新能力:选择 FP8 TP2 + MTP3。
- 多用户吞吐优先:Qwen3.8 仍选择 FP8+MTP,但要关注四并发波动。
- 只想节省一张 GPU:选择 FP8 单卡,接受约 41%的速度下降。
- BF16:只保留作为数值精度和业务质量对照,不作为性能首选。
真正决定替换 Agent 模型前,还应补充:
- 实际工具调用成功率;
- 多轮任务完成率;
- reasoning 与非 reasoning 的可见延迟;
- 长上下文正确率;
- JSON/结构化输出稳定性;
- 相同 Agent 任务的端到端完成时间,而不仅是 token/s。
十、复现时的注意事项
- 同一时间只运行一个大模型;
- 使用完全相同的 prompt/output 分布;
- 固定 temperature、seed 和 ignore_eos;
- 区分 decode token/s、端到端 token/s 和 TTFT;
- 不要把四路总吞吐误解为单个请求速度;
- 记录其他常驻 GPU 服务的显存占用;
- 固定 Docker 镜像 digest,而不是只写 latest;
- 首次编译和缓存后重启要分开记录;
- MoE 与稠密模型的 token/s 不可脱离激活参数量直接解释。
参考链接
以上数据来自同一台服务器、同一套基准脚本的实测。文章只讨论推理性能,不对不同模型的回答质量做未经验证的推断。