跳到主要内容
AI教程

在两台 DGX Spark 上部署 Qwen3.8 Flash Next 176B

使用仓库中的单文件方案,在两台 NVIDIA DGX Spark 节点上下载、修补并部署 Qwen3.8-Flash-Next-NVFP4,同时满足 GB10 统一内存限制和模型的 SM121 稀疏注意力要求。

两台 DGX Spark 部署 Qwen3.8 Flash Next 176B

概述

本项目是一套面向生产环境的部署方案,用于通过 SGLang 提供 RadixArk/Qwen3.8-Flash-Next-NVFP4 服务。该模型是一个采用 NVFP4 量化的混合专家模型,约有 1760 亿个参数,大小为 135 GB。

随附的 start.sh 脚本使用张量并行将模型分布到两台 NVIDIA DGX Spark 系统上,其中 TP=2。节点通过直连的 ConnectX-7 200 Gb RoCEv2 链路通信。运行后,头节点会在 0.0.0.0:8888 上公开与 OpenAI 兼容的 API。

该方案不仅仅是一个启动器。它会下载并验证权重、将其同步到工作节点、在两个节点上构建经过修补的容器镜像、启动集群,并等待 API 就绪。它采用幂等设计,因此重复运行时可以继续中断的下载、复用缓存并替换过期容器。

该方案提供的功能

  • 双节点张量并行服务:一台 DGX Spark 运行 rank 0 和 SGLang 路由器,另一台运行 rank 1。
  • 与 OpenAI 兼容的端点:API 支持聊天、补全、推理输出、工具调用解析,以及文本加图像输入。
  • 长上下文:默认上下文长度为 900000 个 token,通过 YaRN 将模型原生的 262,144-token 上下文扩展到该长度。
  • NEXTN 推测解码:默认推测设置为 3/1/4,两个节点均启用 CUDA 图解码。
  • SM121 兼容性:构建过程为 Qwen Sparse Attention 路径应用 Triton 回退实现,解决其原本无法在 DGX Spark 上编译的问题。
  • 运维命令:脚本包含预检、下载、启动、停止、状态、日志和冒烟测试功能。

README 报告称,在测试的双节点集群上,单个解码流的速度为每秒 64.4 个 token,两个流的聚合速度为每秒 116.8 个 token。使用四个流时,聚合吞吐量为每秒 114.1 个 token。

为何必须使用 SM121 内核补丁

Qwen4Exp 架构通过 Qwen Sparse Attention 后端路由注意力。其 flash-attention 解析器优先使用经典 FA2,否则使用 flash-attn-4 CuTe DSL 接口。在 DGX Spark 的 SM121 架构上,该回退路径会因 MLIR 布局一致性错误而编译失败。

该仓库通过构建包含兼容 SM121 的 Triton 注意力回退实现的衍生 SGLang 镜像,解决了这一启动阻塞问题。

生成的 .patch/ 构建上下文包含 qsa_fa_fallback.py,这是一个针对模型 QSA 调用约定定制、采用 FlashDecoding 风格的可变长度内核。它支持分组查询注意力、最大 256 的头维度以及在线 softmax。它还会在设备上读取 cu_seqlens,从而在后端重写序列表时维持 CUDA 图重放的有效性。

在 Docker 构建期间,该方案会修补 qwen_sparse_attn_backend.py,使其在 is_sm100_supported() 为 false 时选择 Triton 回退实现。因此,在受支持的 B100 和 B200 数据中心 GPU 上,标准路径仍保持不变。

所需硬件和软件

集群硬件

  • 两台 NVIDIA DGX Spark 系统,每台均配备 GB10 GPU、采用 SM121 架构并拥有 128 GB 统一内存。
  • 两台计算机的 ConnectX-7 端口直接相连,中间不经过交换机。
  • 两个节点上相关的 RoCE 接口均处于活动状态,例如一个节点上的 rocep1s0f1/enp1s0f1np1,以及另一个节点上的 rocep1s0f0/enp1s0f0np0
  • 具有足够的存储空间,以容纳约 135 GB 的检查点、容器镜像、缓存和临时构建数据。

头节点软件

  • Docker。
  • Hugging Face hf CLI。
  • 如果访问检查点需要身份验证,Shell 环境中必须设置 Hugging Face token。
  • 从头节点到工作节点的免密码 SSH 访问。

使用以下命令在头节点上安装 Hugging Face CLI:

pip install hf

默认情况下,工作节点通过名为 spark2 的 SSH 别名访问。工作节点的登录用户名默认与在头节点上运行 start.sh 的用户名相同。可以在 .env 中更改这些设定。

配置双节点集群

在头节点上克隆仓库,进入其目录并创建本地配置文件:

git clone <this-repo>
cd <this-repo>
cp .env.example .env

编辑 .env,至少确认头节点 RoCE IP、工作节点 RoCE IP 和 SSH 目标地址。默认配置使用以下私有网络地址:

HEAD_CX7_IP=10.0.22.1
WORKER_CX7_IP=10.0.22.2
WORKER_HOST=spark2

如果工作节点使用其他账户,请设置 WORKER_USER。如需完全控制 SSH 目标地址,请将 WORKER_SSH 设置为类似 user@host 的值。Shell 环境变量的优先级高于 .env 中的值。

预期拓扑

客户端连接到头节点端口 8888 上的 API。头节点运行 rank 0、SGLang 服务器和路由器。rank 1 在工作节点上运行。NCCL 流量固定使用两台系统之间直连的 ConnectX-7 RoCEv2 链路。

该方案使用 NCCL_NET=IB,启用兼容 InfiniBand 的 RoCE 传输,并针对该配置禁用 NVLS 和 CUMEM。它还可以预加载暂存于主机上的 NCCL 2.30.7 构建版本。此行为默认通过 USE_HOST_NCCL=1 启用。

验证环境

下载模型前,运行内置预检:

./start.sh doctor

doctor 命令会检查互连网络、GPU、RAM、磁盘容量、SSH 连接、端口以及部署限制。在开始大型下载和镜像构建之前,请修复所有报告的网络、身份验证、存储或资源问题。

下载并同步模型

将检查点下载到头节点,验证后同步到工作节点:

./start.sh download

默认的 DOWNLOAD_MODE=rsync 会让头节点下载文件,然后将其复制到工作节点。该操作支持断点续传。如果希望每台计算机分别从 Hugging Face 下载,请设置:

DOWNLOAD_MODE=direct

不要在 GB10 上使用 SGLang 的 --load-format dummy 选项测试此模型。根据仓库中的崩溃分析,dummy 初始化器会暂时将 fp8 参数转换为 fp16。因此,模型中 51.2 GB 的 fp8 PLE n-gram 表可能产生超过 150 GB 的临时内存需求,导致一台仅有约 121.7 GB 可用统一 DRAM 的系统完全卡死。

构建修补后的镜像并启动服务

使用以下命令启动双节点部署:

./start.sh serve

该命令会运行预检,确认权重和镜像可用,在两个节点上构建经过 SM121 修补的镜像,启动 TP2 集群,并等待 API 就绪。生成的本地镜像名为 qwen38-flashnext-dspark:local

首次启动大约需要十分钟,因为其中包括加载 135 GB 权重、JIT 编译和 CUDA 图捕获。脚本默认允许最多等待 WAIT_TIMEOUT_MIN=90

如需全自动完成首次运行,请使用:

./start.sh

不带子命令时,脚本会依次执行 doctordownloadserve

发送基本聊天请求

服务器就绪后,调用其与 OpenAI 兼容的聊天端点:

curl http://127.0.0.1:8888/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "Qwen3.8-Flash-Next-NVFP4",
    "messages": [
      {
        "role": "user",
        "content": "Explain RoCEv2 in one paragraph."
      }
    ]
  }'

默认启用推理功能,推理内容会单独流式传输。要针对单次请求禁用思考,请在 JSON 正文中添加 chat_template_kwargs

{
  "model": "Qwen3.8-Flash-Next-NVFP4",
  "messages": [
    {"role": "user", "content": "Summarize tensor parallelism."}
  ],
  "chat_template_kwargs": {
    "enable_thinking": false
  }
}

通过与 OpenAI 兼容的标准 image_url 内容部分可以支持图像输入。README 确认文本和图像组合输入可以正常工作,但没有提供完整的图像请求示例。

连接与 OpenAI 兼容的客户端

支持自定义 OpenAI 端点的应用程序可以使用以下基础 URL:

http://127.0.0.1:8888/v1

模型标识符为:

Qwen3.8-Flash-Next-NVFP4

如果客户端即使在本地端点不验证请求时仍要求填写 API key,仓库示例会使用 dummy 并禁用身份验证标头。相关模型能力和兼容性设置包括:

  • 启用推理。
  • 支持文本和图像输入。
  • 900000-token 上下文窗口。
  • 示例客户端配置最多支持输出 32768 个 token。
  • 使用 max_tokens 作为输出 token 字段。
  • 示例兼容性配置不支持 developer 角色。
  • 不支持推理强度参数。

管理服务器

这个单一启动器提供主要的管理命令:

  • ./start.sh serve 执行预检,确保镜像和权重存在,启动 TP2 并等待服务就绪。
  • ./start.sh download 下载、验证并同步权重,但不启动服务器。
  • ./start.sh stop 删除两个容器并终止日志跟踪进程。
  • ./start.sh status 报告两个节点上的容器状态。
  • ./start.sh logs [N] 显示头节点和工作节点日志的最后 N 行。
  • ./start.sh smoke 向正在运行的 API 发送一次快速贪心补全请求。
  • ./start.sh doctor 重新执行完整的环境和部署方案预检。

诊断启动问题时,请检查 .serve.log.sglang.log.sglang-worker.log。第一个文件记录启动器输出,后两个文件分别包含头节点和工作节点的容器日志。

了解 GB10 内存预算

每台 DGX Spark 都提供由 CUDA 分配、锁页主机内存、Docker 和操作系统共享的统一物理内存池。因此,该方案使用保守的静态内存比例,而不是将主机内存和 GPU 内存视为彼此独立的资源。

报告的单节点内存布局包括:NVFP4 专家、稠密、MTP 和视觉权重约占 62.5 GB;fp8 PLE 表的锁页主机内存约占 11 GB;可容纳约 956,800 个 token 的 9 GB bf16 KV 缓存;Mamba/GDN 状态约占 3.6 GB;CUDA 图以及 NCCL 或 cuBLAS 工作区约占 8 GB。

最终 CUDA 可见分配量约为 95.6 GB,另有约 17.5 GB 可用于其他工作。锁页 PLE 表不会在 nvidia-smi 中显示为单进程设备分配,但它仍会消耗同一物理 DRAM。在评估实际可用余量时,请监控 SGLang 日志中的 available_gpu_mem 值,或 free -h 输出中的可用内存列。

保持启用 PLE 卸载

不要在 GB10 上添加 --no-ple-offload-embedding。SGLang 自动规则会让 PLE 嵌入表保持卸载到 CPU。覆盖此行为可能会将每个 rank 约 26 GB 的锁页主机内存放到 GPU 一侧,导致计算机内存超额使用。

保留瞬时预填充余量

QSA 索引器会创建一个 fp32 logits 工作区,其大小随 chunk × history 增长。当分块大小为 4096、历史长度为 300,000 个 token 时,计入相关 gather 和 top-k 副本后,该瞬时内存可能需要约 8 至 10 GB。

随附的参数值经过刻意保守设置:

MEM_FRACTION_STATIC=0.82
CHUNKED_PREFILL_SIZE=1024
MAMBA_FULL_MEMORY_RATIO=0.3

对于 900,000-token 上下文,在没有结合可用统一内存预算分析瞬时内存峰值之前,不要将 CHUNKED_PREFILL_SIZE 提高到 1024 以上。仓库报告称,分块大小 4096 与 MEM_FRACTION_STATIC=0.85 组合使用足以让计算机卡死。

避免分配器实验

该方案明确建议不要设置 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True。此配置尚未针对该部署得到验证,作者使用的已知可用 DGX Spark 方案中也没有此设置。

调整重要参数

可在 .env 中设置参数,也可以在 Shell 中导出。Shell 值具有更高优先级。最可能需要调整的设置包括:

  • PORT默认为 8888,API 绑定到所有接口。
  • CONTEXT_LENGTH默认为 900000
  • MAX_RUNNING_REQUESTS默认为 16,但按默认比例,Mamba 配置会将实际并发量限制为 14 个槽位。
  • SPEC_STEPSSPEC_TOPKSPEC_DRAFTNEXTN 推测解码的默认值分别为 314
  • KERNEL_PATCH默认为 1,以构建并使用 SM121 回退镜像。
  • IMAGE直接使用指定镜像并跳过修补。
  • CPUSET针对 GB10 的较大 CPU 核心,默认为 5-9,15-19。将其设为空值可禁用固定绑定。
  • EXTRA_ARGS在最后追加额外的 SGLang 参数,从而允许后设置的值覆盖先前设置。

处理思考和工具调用循环

一个已知的 SGLang 问题可能会影响同时使用默认思考、OpenAI 工具和 qwen3_coder 工具调用解析器的会话。服务器可能重复发出 token ID 0;此分词器会将其显示为 !,直至达到 max_tokens

首选的解决方法是仅针对发送工具的请求禁用思考:

"chat_template_kwargs": {"enable_thinking": false}

如需在使用工具解析器时为整个服务器禁用思考,请停止部署并使用覆盖参数重新启动:

./start.sh stop
EXTRA_ARGS='--tool-call-parser qwen3_coder --default-chat-template-kwargs {"enable_thinking":false}' ./start.sh serve

如果已经在 .env 中配置了 EXTRA_ARGS,请将这些选项合并到现有设置中。不要在提供工具的同一请求中重新启用思考。如果不使用解析器,思考可以正常工作,但工具调用会作为普通内容中的 <tool_call> XML 出现,而不是结构化的 message.tool_calls。README 还建议在使用此解决方法时,将智能体温度保持在 0.7 或以下。

高级可靠性和性能提示

使用推测解码提升吞吐量

NEXTN 推测解码是实测配置中的主要吞吐量驱动因素。使用默认的 3/1/4 链时,每个解码步骤会在一次前向传递中验证四个草稿 token。测试集群在两个流时达到接近每秒 117 个聚合 token 的峰值;随着更多流争用剩余内存,吞吐量随后趋于稳定。

在需要时选择确定性

默认配置中的贪心解码无法实现逐比特复现。接近并列的 token 偶尔可能在不同运行之间发生变化,这可能是 SM121 上 NVFP4 MoE GEMM 的浮点归约差异所致。如需速度较慢但具有确定性的行为,请使用以下命令重新启动:

EXTRA_ARGS="--moe-runner-backend triton" ./start.sh serve

正确理解 TileLang 警告

在 JIT 编译期间,TileLang 可能报告 Logits(bx, position) 被多个线程写入。仓库认为这是误报,因为计算得出的位置彼此不重叠,但当 group 是运行时值时,检查器无法证明这一性质。如有必要,可以使用 PassKey.TL_DISABLE_DATA_RACE_CHECK 将其隐藏。

保护外部访问

API 绑定到 0.0.0.0,因此可以通过任何获准的接口访问。README 介绍了来自 LAN 或 Tailscale 客户端的访问方式,但没有添加身份验证层。如果该端点不应被普遍访问,请配置适当的主机防火墙、专用网络或代理控制措施。

结论

该仓库将困难的双节点部署转化为可重复执行的工作流。其主要贡献在于将兼容 SM121 的 Qwen Sparse Attention 回退实现、严格受限的 GB10 统一内存设置、直连 RoCEv2 张量并行,以及单一幂等运维脚本结合在一起。

请从随附的默认设置开始,在部署前运行 ./start.sh doctor,并避免使用 dummy 权重、禁用 PLE 卸载、采用过大的预填充分块以及使用实验性分配器设置。集群就绪后,应用程序可以通过熟悉的 OpenAI 兼容聊天和补全接口使用本地服务器。