
概述
本项目是一套面向生产环境的部署方案,用于通过 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
hfCLI。 - 如果访问检查点需要身份验证,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 doctordoctor 命令会检查互连网络、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不带子命令时,脚本会依次执行 doctor、download 和 serve。
发送基本聊天请求
服务器就绪后,调用其与 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_STEPS、SPEC_TOPK和SPEC_DRAFT:NEXTN 推测解码的默认值分别为3、1和4。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 兼容聊天和补全接口使用本地服务器。
