【实测】NVIDIA DGX Spark 本地部署 Qwen3.5-35B-A3B-FP8 完整教程 + 性能分析
硬件环境:NVIDIA DGX Spark(GB10 超级芯片,128GB 统一内存,LPDDR5x 273 GB/s) 软件环境:vLLM v0.16.1rc1(cu130-nightly),Docker 容器化部署 模型:Qwen/Qwen3.5-35B-A3B-FP8(官方 FP8 量化版,37.5 GB)
一、背景与选型
1.1 为什么选 Qwen3.5-35B-A3B?
Qwen3.5-35B-A3B 是阿里通义千问团队发布的 MoE(混合专家)架构模型,总参数 35B,激活参数仅 3B,兼顾了大模型的推理能力和小模型的推理速度,非常适合本地 Agent 工作流部署。
1.2 为什么选 FP8 量化?
| 量化格式 | 模型大小 | 精度损失 | DGX Spark 稳定性 |
|---|---|---|---|
| BF16(原版) | 65 GB | 0% | ✅ 稳定 |
| FP8(推荐) | 37.5 GB | < 0.5% | ✅ 稳定 |
| NVFP4(社区版) | 23.4 GB | ~1-2% | ❌ cudaErrorIllegalInstruction(已知 Bug) |
FP8 是目前 DGX Spark 上最优的量化选择:
- 官方 Qwen 团队发布,经过充分验证
- 精度损失极小(< 0.5%,在 12K+ MMLU-Pro 基准测试中验证)
- 模型大小从 65GB 降至 37.5GB,KV 缓存空间翻倍
- NVFP4 在 ARM64 GB10 上有已知 CUDA kernel 崩溃问题(vLLM Issue #35519),暂不推荐
二、环境准备
2.1 硬件要求
- NVIDIA DGX Spark 或其他搭载 GB10/B200 的设备
- 至少 80GB 统一内存(运行 FP8 模型 + KV 缓存)
- 建议 128GB 统一内存以充分利用 262K 上下文
2.2 软件依赖
# 确认 Docker 和 NVIDIA Container Toolkit 已安装
docker --version
nvidia-smi
# 安装 ModelScope(用于下载模型)
pip install modelscope --break-system-packages
三、下载模型
使用 ModelScope 国内镜像下载,速度更快:
modelscope download --model Qwen/Qwen3.5-35B-A3B-FP8
模型将下载到:/root/.cache/modelscope/hub/models/Qwen/Qwen3.5-35B-A3B-FP8
下载完成后确认文件完整性:
ls -lh /root/.cache/modelscope/hub/models/Qwen/Qwen3.5-35B-A3B-FP8/
# 应看到 14 个 safetensors 分片文件,总大小约 37.5 GB
四、启动 vLLM 服务
4.1 完整启动命令
# 1. 先清理旧容器(防止名字冲突)
docker stop qwen35-fp8 && docker rm qwen35-fp8
# 2. 启动解锁版容器
docker run -d \
--name qwen35-fp8 \
--gpus all \
--ipc=host \
--network=host \
--privileged \
--security-opt seccomp=unconfined \
-p 8000:8000 \
-e VLLM_LOGGING_LEVEL=INFO \
-e PYTHONUNBUFFERED=1 \
-v /root/.cache/modelscope/hub/models/Qwen/Qwen3.5-35B-A3B-FP8:/model \
vllm/vllm-openai:cu130-nightly \
--model /model \
--served-model-name Qwen3.5-35B-A3B \
--max-model-len 262144 \
--gpu-memory-utilization 0.88 \
--enable-prefix-caching \
--enable-auto-tool-choice \
--tool-call-parser qwen3_coder \
--reasoning-parser qwen3 \
--attention-backend FLASH_ATTN \
--trust-remote-code \
--limit-mm-per-prompt '{"image": 0, "video": 0}'
4.2 参数详解
| 参数 | 值 | 说明 |
|---|---|---|
--served-model-name |
Qwen3.5-35B-A3B |
API 调用时使用的模型名 |
--max-model-len |
262144 |
262K 上下文,FP8 模型内存充裕可开满 |
--gpu-memory-utilization |
0.88 |
留 12% 给系统和 CUDA 框架 |
--enable-prefix-caching |
(开启) | 开启前缀缓存,多轮对话显著加速 |
--enable-auto-tool-choice |
(开启) | 自动工具调用,Agent 必备 |
--tool-call-parser |
qwen3_coder |
Qwen3 系列专用工具解析器 |
--reasoning-parser |
qwen3 |
解析 <think> 推理标签 |
--attention-backend |
FLASH_ATTN |
FlashAttention 加速注意力计算 |
--limit-mm-per-prompt |
{"image": 0, "video": 0} |
禁用多模态 profiling,加快启动 |
--security-opt |
seccomp=unconfined |
核心修复:禁用 Docker 默认的安全过滤,允许 Triton 编译器调用底层系统接口进行 JIT 编译 |
--privileged |
(开启) | 必要权限:赋予容器宿主机完整权限,防止 GPU 驱动在加载自定义内核时被拦截 |
--trust-remote-code |
(开启) | 信任模型代码:Qwen3.5 新架构包含自定义 Python 脚本,需显式开启以加载 modeling_qwen.py |
--network |
host |
网络直通:移除 Docker 网桥 NAT 开销,提升高并发下的网络吞吐性能 |
--ipc |
host |
共享内存:允许容器直接使用宿主机共享内存,避免多进程数据交换(如 PyTorch DataLoader)时内存溢出 |
4.3 ⚠️ 注意事项
不要加 --kv-cache-dtype fp8:FP8 量化模型的权重已经是 FP8,额外指定 KV cache 为 FP8 会导致 Mamba block_size(2096)超过 max_num_batched_tokens(2048)的限制,服务无法启动。
不要加 --trust-remote-code:官方 FP8 模型不需要此参数,会产生无用警告。
五、验证服务启动
5.1 查看启动日志
docker logs -f qwen35-fp8
正常启动过程约需 3-4 分钟,完整流程:
Loading safetensors checkpoint shards: 100% | 14/14 [01:22] # 加载模型权重
Capturing CUDA graphs (decode, FULL): 100% | 35/35 [00:53] # 编译 CUDA 图
INFO: Application startup complete. # 服务就绪
5.2 验证 API 可用
# 确认模型已注册
curl http://localhost:8000/v1/models
# 发送测试请求
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.5-35B-A3B",
"messages": [{"role": "user", "content": "9.11 和 9.9 哪个大?"}],
"temperature": 0.6
}'
六、性能测试
6.1 测速脚本
# 关闭 thinking 模式,测纯生成速度
start=$(date +%s%N)
result=$(curl -s http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.5-35B-A3B",
"messages": [
{"role": "system", "content": "/no_think"},
{"role": "user", "content": "详细介绍量子计算原理,写2000字。"}
],
"temperature": 0.6,
"max_tokens": 2000
}')
end=$(date +%s%N)
elapsed=$(( (end - start) / 1000000 ))
tokens=$(echo $result | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['usage']['completion_tokens'])")
echo "耗时: ${elapsed}ms | tokens: $tokens | 速度: $(echo "scale=1; $tokens * 1000 / $elapsed" | bc) t/s"
6.2 实测性能数据(DGX Spark GB10)
| 测试场景 | 速度 | 备注 |
|---|---|---|
| BF16 + Thinking 开启 | ~31 t/s | 原始基准 |
| FP8 + Thinking 开启 | ~43 t/s | +39% 提升 |
| FP8 + Thinking 关闭 | 50.3 t/s | +62% 提升,最优日常场景 |
vLLM 日志实时确认(每 10 秒打印一次吞吐统计):
Engine 000: Avg generation throughput: 50.7 tokens/s, Running: 1 reqs, GPU KV cache usage: 0.1%
6.3 性能分析
为什么是 50 t/s 而不是更高?
GB10 的 LPDDR5x 统一内存带宽为 273 GB/s。在 decode 阶段,推理速度受限于内存带宽(而非计算能力)。
理论上限估算:
- FP8 模型大小:37.5 GB
- 每个 token 需读写模型权重约 1 次:37.5 GB × 2 ÷ 273 GB/s ≈ 0.275 秒/token ≈ 55-60 t/s 理论上限
实测 50.3 t/s = 理论带宽利用率约 85%,已非常健康。
Thinking 模式对速度的影响:
开启 /think 时,模型会先生成大量内部推理 token(<think>...</think>),这些 token 同样消耗带宽,导致"可见生成速度"从 50 t/s 降至 ~43 t/s。实际推理质量更高,但响应时间更长。
七、使用建议
7.1 Thinking 模式控制
Qwen3.5 支持通过 system prompt 动态控制推理模式:
# 关闭 thinking(适合工具调用、代码执行等结构化任务)
{"role": "system", "content": "/no_think"}
# 开启 thinking(适合复杂推理、数学证明、深度分析)
{"role": "system", "content": "/think"}
推荐策略:
- 默认
/no_think(50 t/s,响应快) - 遇到复杂推理任务临时加
/think
7.2 前缀缓存效果
开启了 --enable-prefix-caching 后,多轮对话中重复的 system prompt 和历史消息会被缓存,第二轮起的响应延迟显著降低。
查看缓存命中率:
docker logs qwen35-fp8 2>&1 | grep "Prefix cache hit rate"
多轮 Agent 工作流运行一段时间后,命中率可达 30-60%。
7.3 流式输出
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.5-35B-A3B",
"messages": [{"role": "user", "content": "你好"}],
"stream": true
}'
7.4 工具调用示例
import openai
client = openai.OpenAI(
base_url="http://localhost:8000/v1",
api_key="token-local"
)
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取天气信息",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "城市名称"}
},
"required": ["location"]
}
}
}]
response = client.chat.completions.create(
model="Qwen3.5-35B-A3B",
messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
tools=tools,
tool_choice="auto"
)
print(response.choices[0].message)
八、资源消耗一览
| 指标 | BF16 原版 | FP8 量化版 |
|---|---|---|
| 模型占用内存 | 65 GB | 37.5 GB |
| 可用 KV Cache | ~28 GB | ~80 GB |
| 最大支持上下文 | 131K tokens | 262K tokens |
| 启动时间 | ~3 min | ~4 min(多 14 个分片) |
| GPU KV Cache 使用率(空载) | 0.1% | 0.1% |
九、常见问题
Q1:启动时卡在视觉编码器 profiling
Encoder cache will be initialized with a budget of 16384 tokens...
原因:Qwen3.5 是多模态模型,vLLM 默认会对图像编码器做一次推理 profiling。
解决:加 --limit-mm-per-prompt '{"image": 0, "video": 0}' 跳过多模态 profiling(纯文本场景不需要视觉能力)。
Q2:启动报 block_size must be <= max_num_batched_tokens
Assertion failed, In Mamba cache align mode, block_size (2096) must be <= max_num_batched_tokens (2048)
原因:加了 --kv-cache-dtype fp8 导致 block_size 增大。
解决:去掉 --kv-cache-dtype fp8,FP8 量化模型不需要此参数。
Q3:NVFP4 社区模型报 cudaErrorIllegalInstruction 崩溃
原因:ARM64 GB10 平台上,vLLM 的 FLASHINFER_CUTLASS NVFP4 kernel 存在已知 Bug(Issue #35519)。
解决:使用官方 FP8 模型,等待 nvidia/Qwen3.5-35B-A3B-NVFP4 官方版本发布。
Q4:API 返回 404 model does not exist
原因:请求中的模型名与 --served-model-name 不一致。
解决:确认使用 "model": "Qwen3.5-35B-A3B"(不是 openai/Qwen3.5-35B-A3B)。
Q5:trust_remote_code 警告
The argument `trust_remote_code` is to be used with Auto classes. It has no effect here and is ignored.
说明:无害警告,不影响功能。去掉 --trust-remote-code 参数即可消除。
十、后续优化路线
| 阶段 | 方案 | 预期收益 | 状态 |
|---|---|---|---|
| 现在 | FP8 + vLLM | 50 t/s,稳定 | ✅ 已完成 |
| 近期 | FP8 + SGLang | ~55-60 t/s,多轮 Agent 场景 RadixAttention 加成 | ⏭️ 可选 |
| 等待 | 官方 NVFP4 | ~70-80 t/s,模型仅 23 GB | ⏳ 等 nvidia/ 官方发布 |
总结
在 NVIDIA DGX Spark 上部署 Qwen3.5-35B-A3B-FP8 的最优实践:
-
选模型:官方 FP8(
Qwen/Qwen3.5-35B-A3B-FP8),稳定可靠,精度损失 < 0.5% - 选推理框架:vLLM cu130-nightly,原生支持 GB10 CUDA 12.1
- 关键配置:禁用多模态 profiling、不叠加 KV cache FP8、开启前缀缓存
- 速度结论:50.3 t/s(no_think)/ 43 t/s(thinking),比 BF16 提升 39-62%
- 内存收益:37.5 GB 模型 + 80 GB 可用 KV Cache,支持 262K 超长上下文
对于本地 Agent 工作流(代码生成、文件操作、工具调用),默认 /no_think 模式下 50 t/s 的响应速度完全满足实时交互需求。
测试时间:2026年3月2日 硬件:NVIDIA DGX Spark(GB10,128GB LPDDR5x) 软件:vLLM v0.16.1rc1.dev111+gafd089f23,Docker cu130-nightly