在 A100 32GB 显卡上部署 Qwen3.8-27B
2026-08-17

单张 A100 32GB SM80 显卡,跑 27B 混合注意力模型,256K 上下文 + MTP 投机解码 + 工具调用全开。本文记录完整的部署参数、踩坑过程和实测速度表。


1. 硬件环境

部件 规格
GPU NVIDIA DRIVE-PG199-PROD,32 GiB 显存(车载版本A100),SM80(Ampere,compute capability 8.0)
CPU Intel Xeon W-2125 @ 4.00GHz(6 核)
内存 40 GB
驱动 / CUDA NVIDIA 595.84;CUDA 13.3 工具链(随 Python 环境安装)
存储 1 TB(模型 + 环境占用约 60GB)

几个平台特性,后面所有决策都和它们有关:

  • SM80 没有原生 FP8 张量核(fp8e4nv 是 SM89+/SM90 才有的)——这是 KV cache 压缩方案选择的分水岭;
  • 显卡为车规功耗设计,长时间满载后温度 44→74°C,SM 时钟稳定 1260MHz,无降频。

2. 模型:Qwen3.8-27B-AWQ-MTP

社区量化版 shawnw3i/Qwen3.8-27B-AWQ-MTP(基于 Qwen/Qwen3.8-27B):

  • 27.3B dense混合注意力:64 层 = 48 层 linear_attention(GDN)+ 16 层 full_attention,每 4 层一次全注意力;
  • 多模态(27 层视觉塔),训练上下文 262,144 tokens
  • AWQ W4A16(group_size 128,Marlin kernel),磁盘 19GB:11.4GB int4 打包权重 + 6GB 未量化的 BF16 部分(embedding、lm_head、linear_attn 的 in_proj、视觉塔、MTP 模块)——"18GB 模型"里只有 65% 是 Q4;
  • 内置 MTP(Multi-Token Prediction)投机解码模块(1 层 transformer,权重在 model_extra_tensors.safetensors),与主模型共享 embedding/lm_head,显存只多 ~3GB;
  • 下载工具:ftllm download <repo> --tool aria2c -x 8 -j 4(多线程秒级拉满带宽)。

3. 部署:vLLM 0.27.1 + pm2

软件栈

  • Python 3.13.13 + uv 虚拟环境(/root/llm/.venv),vLLM 0.27.1(PyPI 最新),torch 2.13.0+cu130,flashinfer 0.6.16.post3;
  • pm2 托管(vllm-qwen38-27b-awq,端口 5000,OpenAI 兼容 API)。

最终启动命令(run-qwen38-27b-awq.sh

export VLLM_USE_FLASHINFER_SAMPLER=0   # 绕开 flashinfer 采样 kernel 的 CUB 编译崩溃(见 §5)

vllm serve /root/llm/models/Qwen3.8-27B-AWQ-MTP \
    --host 0.0.0.0 --port 5000 \
    --attention-backend FLASHINFER \
    --kv-cache-dtype fp8 \
    --max-model-len 262144 \
    --reasoning-parser qwen3 \
    --enable-auto-tool-choice \
    --tool-call-parser qwen3_coder \
    --speculative-config '{"method":"mtp","num_speculative_tokens":3}' \
    --max-num-seqs 1 \
    --gpu-memory-utilization 0.98 \
    --served-model-name qwen38-27b-awq-mtp \
    --enable-log-requests \
    --enable-prompt-tokens-details \
    --enable-prefix-caching

关键参数为什么这么定(全部经过实测对比):

参数 选择 理由
--attention-backend FLASHINFER FlashInfer SM80 上唯一能 fp8 KV 的后端;长上下文 decode 稳定(见 §4.2)
--kv-cache-dtype fp8 fp8 KV 池 285,575 tokens,是 fp16 的 2 倍,撑起 256K 上下文
--max-model-len 262144 训练上限 KV 池恰好覆盖完整 256K
--speculative-config MTP × 3 3 drafts 2/3/4 实测,3 是全场景最优点(§4.3)
--max-num-seqs 1 单并发 MTP 能装进 32GB 的关键(Mamba cache / graph 池 / 工作区全压到单槽)
--gpu-memory-utilization 0.98 压满 32GB 卡跑 27B 的余量策略
--tool-call-parser qwen3_coder XML 模板 模型 chat template 是 <tool_call> XML 格式

运行态:显存 30.4/32 GiB,启动 ~90 秒(kernel 编译缓存命中),pm2 save 持久化。


4. 实测速度

测试方法:每个上下文长度用独立随机文本(开头互不相同,避免 prefix cache 跨长度污染);cold=首次请求,warm=同 prompt 二次请求(命中前缀缓存);生成任务为写 ~1500 字说明文(约 800~1000 tokens,保证 decode tps 准确);MTP 接受率取自 /metrics 计数器差值。

4.1 最终配置总览(FLASHINFER + fp8 + 256K + MTP3)

上下文 模式 TTFT prefill t/s decode t/s MTP 接受率 缓存命中
0 cold 0.15s 231* 68.8 46.7% 0
1K cold 0.34s 2,391 69.6 46.4% 0
32K cold 10.36s 2,372 70.1 47.4% 0
32K warm 1.17s 21,034 70.1 47.4% 22,400
128K cold 60.38s 1,625 69.8 49.1% 0
128K warm 2.05s 48,086 69.8 49.1% 96,000
240K cold 155.35s 1,184 62.0 48.5% 0
240K warm 4.33s 42,522 62.0 48.5% 180,800

* 0 上下文仅 33 tokens,prefill 被固定开销摊薄,无参考意义。

要点

  • decode 跨上下文几乎恒定(62~70 t/s)——这是 FlashInfer split-KV 内核的功劳(对比见下);
  • prefix cache 命中时 240K 的 TTFT 只要 4.3 秒(冷启动 155s),固定前缀场景体验接近短上下文;
  • 长上下文 cold prefill 变慢是物理规律(attention 计算量随长度增长)。

4.2 注意力后端 × KV 精度对比(同一写作任务、MTP3)

上下文 FLASH_ATTN + fp16 FLASHINFER + fp16 FLASHINFER + fp8 TURBOQUANT 4-bit
0 89.1 t/s 69.0 68.8 143.4*
1K 91.3 71.2 69.6 141.1*
32K 54.2 70.8 70.1 63.0*
128K 22.1 61.1 69.8 86.7*
240K 62.0
最大上下文 128K 128K 256K 256K(但输出崩坏)

* TurboQuant 数字不可信:无校准 4-bit KV 导致长生成退化为重复循环(** ** ** / !!!!),速度测的是"循环复读机"。

结论:FA2 的 decode 成本随上下文线性增长(128K 掉到 22 t/s);FlashInfer 靠 split-KV(KV 切块多 SM 并行 + 在线 softmax 合并)保持恒定;fp8 KV 因为 KV 读取带宽减半,在 128K 还额外 +14%。

4.3 MTP draft 数量调优(2 / 3 / 4)

上下文 spec=2 decode spec=3 decode spec=4 decode 接受率 2/3/4
0 65.4 68.8 68.7 59% / 47% / 39%
1K 62.9 69.6 69.1 55% / 46% / 40%
32K 66.7 70.1 66.3 63% / 47% / 38%
128K 66.0 69.8 65.7 63% / 49% / 40%

接受率随 draft 数单调下降(猜得越多越难命中),每步产出在 3 时最高(~1.9 token/步)。

4.4 任务类型对 decode 的影响(MTP 是内容相关的)

任务 单步 decode 说明
摘要 / 短问答(greedy) 12.3ms ~240 t/s 输出模板化,接受率高
复述上文(100% 接受率) 27.8ms 115~144 t/s 接受率拉满但 MTP 前向开销大
写 1500 字说明文 ~28ms 62~75 t/s 自由长文,接受率 ~47%
代码 / 工具调用 正常 qwen3_coder parser 全通(含并行工具调用闭环)

⚠️ 教训:"MTP 接受率高 = 快"不成立。复述任务接受率 100%,但每步要跑 3 次 MTP 前向(~28ms/步),比接受率 67% 的摘要(12.3ms/步)还慢。速度 = 接受率 × 单步吞吐,两者都要看。

4.5 与 llama.cpp 的对比(同一模型家族、同卡)

指标 llama.cpp(Q4_K_M GGUF) vLLM + FLASHINFER + MTP(AWQ)
decode(写作) ~38 t/s 62~70 t/s
prefill ~950-1,000 t/s 1,200~2,400 t/s
最大上下文 203K(无 MTP) 256K(带 MTP)
长上下文 decode 稳定性 随长度下降 恒定

5. 踩坑记录(每个都花了真金白银的时间)

  1. flashinfer 0.6.16 + CUDA 13.3 的 CUB 头文件不兼容:JIT 编译 sampling.cuhBlockAdjacentDifference has no member FlagHeads → EngineCore 崩溃循环。解法:VLLM_USE_FLASHINFER_SAMPLER=0(采样走 vLLM 原生路径;attention kernel 用另一套头文件,不受影响)。
  2. SM80 开不了 fp8 KV? 默认后端确实不行:FLASH_ATTN 报"requires FA3 on SM90 or FA4 on SM100",TRITON 报"fp8e4nv requires SM89+"。但 FLASHINFER 后端支持 SM80 + fp8 KV(存储压缩 + 软件反量化),代码层面 supports_compute_capability: 8.0~12.1 明确放行。别被第一个报错劝退。
  3. FA2 长上下文 decode 崩塌:batch=1 时 FA2 无并行度可挖,128K 上下文单步 90ms;FlashInfer 的 split-KV 把长 KV 切块并行,单步恒定 ~28ms。长上下文服务请直接选 FlashInfer。
  4. MTP 装不进 32GB:主模型 18.6GB + MTP 模块 ~3GB + KV + graph 池超出预算,报错还误导("MTP 需要再加载一份权重"是错的——日志确认 Sharing target model embedding weights,drafter 只多 ~1GB)。真正的解法是 --max-num-seqs 1(Mamba cache / graph 池 / 工作区全部单槽化)。
  5. TurboQuant 无校准 4-bit KV 输出崩坏:短问答正常,长生成退化为 ** ** ** / !!!! 循环。这类激进量化必须配 TurboQuant 校准过的 checkpoint,无校准变体(_nc)别碰。
  6. "隐形思考 token":vLLM 0.27 的 qwen3 reasoning parser 对 Qwen3.8 的思考 token 处理不完整——模型思考时 token 不计入 content 也不计入 reasoning_content(但计入 usage),表现为"生成 1600 tokens 正文 0 字"的假数据。测速时用 chat_template_kwargs: {"enable_thinking": false} 规避;真实服务里则要留意长思考请求的"空回答"(社区建议服务端固定 reasoning_effort: medium)。
  7. FlashInfer + 投机解码的 cudagraph 降级vLLM #49547):自动降级 PIECEWISE,约 -16%,SM80 无 workaround(trtllm-gen 路径要 SM100+),等上游 RFC #49488。已知税,接受。
  8. prefix caching 别关:实测关闭后摘要 decode 从 240 掉到 127 t/s(Mamba cache 模式切换的副作用),还损失 warm 秒级 TTFT。

6. 结论

在 32GB SM80 平台上,Qwen3.8-27B-AWQ-MTP 的最优部署形态是:

FlashInfer 后端 + fp8 KV cache + 256K 上下文 + MTP×3 + 单并发 + prefix caching

  • 写作类任务稳定 62~70 t/s(跨 0~240K 上下文持平),摘要/问答类 ~240 t/s;
  • 256K 全量上下文 + 工具调用 + 推理模式全开;
  • 相比 llama.cpp:decode 快 1.6~1.8 倍,prefill 快 2 倍以上,上下文从 203K 提到 256K;
  • 硬件的物理边界(SM80 无 FP8 核、车规功耗)决定了 fp8 只能是"存储压缩",但这已经够用。

测试脚本:benchmarks/bench_ctx_cold_warm.py(冷/热 + MTP 接受率)、bench_ctx_cold_warm_128k.py(128K 变体)、bench_ctx_prefill_decode.py(prefill 专项)。


阅读:10   评论: 0 💬
添加新的评论
Copyright © Longbill 2008-2026