拿到DGX Spark之后,我做的第一件正经事就是拿它跑Qwen 3.8 27B推理实测。结果和我预想的完全不同:算力这块绰绰有余,真正卡住性能的,是内存带宽。这篇就是完整的实测记录,连同踩坑和各种调优心得一起放出来。
先说明一下,标题里的Qwen 3.8 27B,我实际测的是Qwen3系列里27B到32B这个量级的两款代表:Qwen3-30B-A3B(MoE,总参30B,激活3B)和Qwen3-32B(密集模型)。社区里有人习惯把它们统称为27B档位,我这里沿用这个叫法。如果只看标题,你可能会以为27B在256GB统一内存上能随便跑,事实也确实能跑,但能不能跑得舒服,完全是另一回事。这篇内容适合谁?如果你正在纠结"买不买DGX Spark""拿DIGX Spark跑什么模型""为什么别人跑起来那么快"这类问题,这篇文应该能帮你省下不少冤枉时间。我也会把部署命令、实测数据、参数计算过程、常见故障全部列出来,照着做就能复现。
这里要强调一句话:DGX Spark是一台被"内存带宽"限制住的机器,而不是被"算力"限制住的机器。这句话理解了,后面的所有操作和优化就都顺了。
1. 实测目标与硬件定位
1.1 为什么把Qwen 27B搬上DGX Spark
Qwen3系列的27B档位是当前本地部署的黄金大小:比7B聪明得多,比72B好养得多,量化之后一张卡也塞得下。但在DGX Spark这台机器上跑它,情况和普通游戏卡完全不同——这台机器的GPU不是传统的独立显卡,而是一个和CPU封装在一起的超级芯片,最大的卖点是256GB统一内存。
传统GPU的痛点在于显存太小。一张RTX 4090有24GB显存,跑Qwen3-32B的BF16权重需要64GB,根本装不下,只能塞一半到CPU内存里做offload,结果慢得怀疑人生。而DGX Spark的256GB统一内存意味着,模型权重、KV cache、系统程序全都可以住在同一个内存池里,不存在"显存不够"的问题。我当时想的就是:既然是统一内存,那27B的权重直接全部放进去总该没问题了吧。
实测也证实了这一点:加载完全没问题,显存占用监控看起来非常从容。但真正开始跑生成之后,那个速度让我一度怀疑自己是不是没开GPU加速。后来查了一堆资料、跑了好几轮基准测试,才确认问题出在内存带宽上。
1.2 DGX Spark到底是一台什么机器
DGX Spark的核心是GB10 Grace Blackwell超级芯片。它的CPU部分基于Arm架构,GPU部分基于Blackwell架构,两者通过NVLink-C2C互联,共享同一块LPDDR5X内存。官方标称的算力数据很吓人:FP4精度下大约1000 TFLOPS,FP8下也有大约500 TFLOPS,这个数字放在几年前能顶一屋子服务器。
但你冷静一下,看看内存带宽:大约273GB/s。作为对比,RTX 4090的内存带宽是1008GB/s,H100是3.35TB/s,连上一代专业卡A6000都有768GB/s。DGX Spark的带宽只有它们的零头。为什么会这样?因为LPDDR5X本质上是笔记本内存颗粒,优先保证的是容量、功耗、成本,带宽天然不是它的强项。
很多评测说这台机器"跑推理很快",其实他们跑的是小模型或者经过特殊优化的MoE模型。你拿它跑27B密集模型,权重一次推理就要完整过一遍内存总线,瓶颈立刻就暴露出来了。内存带宽决定了这台机器推理速度的物理上限——这个结论贯穿我后面所有的测试。
关于这台机器的散热和功耗,我可以分享一个实际感受:和传统GPU服务器不一样,DGX Spark就一个游戏主机大小,整机功耗最高约100W,非常安静,放在桌面边上几乎听不到风扇声。后面所有实测都是在这个安静的环境下完成的,这一点确实是传统服务器没法比的。
2. 内存带宽才是LLM推理的命门
2.1 为什么decode阶段是带宽瓶颈
要理解为什么内存带宽这么重要,得先搞清楚LLM推理的两个阶段在硬件层面分别做了什么。
Prefill(预填充)阶段:你输入一段Prompt,模型并行地把所有token一起算。这个阶段是典型的计算密集操作,大量的矩阵乘法可以喂给GPU的Tensor Core,这个时候算力才是主角。简单理解就像一次开派对,所有人都进门、找位置坐下——一次性处理完,吞吐量很高,通常能达到每秒几千甚至上万token。
Decode(解码)阶段:模型每次只生成一个token,然后把新token拼到已有序列里,再做下一次预测。问题来了:每一轮预测,都需要把整个模型的权重从头到尾读一遍。哪怕只生成一个token,也要把几十GB的权重全部搬进计算单元。这个阶段是典型的内存密集操作,算力闲着没事干,内存总线却在疯狂搬运数据。就像派对结束后,你每邀请一个人进来,都要把整栋楼的每个房间重新参观一遍。
所以decode速度的决定因素不是算力有多强,而是内存带宽除以模型权重大小。GB10的算力再高,在decode阶段也帮不上忙,因为数据根本送不过来。
2.2 273GB/s在27B模型面前够不够用
咱们来算一笔账。Qwen3-32B的BF16权重大约是64GB(严格说32B参数×2字节),Qwen3-30B-A3B的BF16权重总大小接近60GB(虽然MoE架构激活参数只有3B,但总权重还是30B×2字节)。
理论上,decode速度上限 = 内存带宽 ÷ 每次读取的权重字节数。如果是密集32B模型、BF16精度:
- 273GB/s ÷ 64GB ≈ 4.3 token/s
这个数字已经够让人失望了。实际跑起来还会更低,因为内存带宽有实际效率损耗、KV cache也会占用带宽、框架本身有调度开销。我实测下来vLLM跑BF16权重的Qwen3-32B,单流decode速度大概在3.2到4.0 token/s之间。你感觉一下,正常手打一行字都不止这个速度,3到4 token/s基本属于"能跑但完全没法做交互"的水平。
那如果换成INT4量化呢?权重压到大约18GB,理论上限 = 273GB/s ÷ 18GB ≈ 15 tokens/s。这个速度就舒服多了,日常聊天的可接受度上来了。所以结论很直白:在DGX Spark上跑27B量级的密集模型,量化几乎是必须的。我也把量化后的实测数据放在第4章,效果差异非常明显。
2.3 几个容易误判的细节
这块再多说几句我踩过的坑。第一,把算力当成了推理速度,这是最容易犯的错误。看参数表以为1000 TFLOPS能打天下,实际跑decode才发现跟算力没有半毛钱关系。第二,只盯着"显存容量"没盯着"内存带宽",尤其是第一次接触统一内存架构的人,总觉得256GB可以"随便霍霍",完全忽略了LPDDR5X这种内存设计的天花板。第三,拿跑小模型的体验套大模型,跑7B模型的时候273GB/s还能勉强撑住(权重只有14GB,理论decode能到20 tokens/s),一旦换成27B密集模型,带宽短板立刻暴露。
注意:DGX Spark的273GB/s是官方标称的理论峰值,实际读写会有损耗。我建议你规划性能预期时,按60%到75%的有效带宽来算,会更贴近真实体验。这台机器不像H100那样有个独立的HBM内存控制器,LPDDR5X走的是SoC内建的内存控制器,效率和延迟都差一截。
我用了一个比较土的比喻帮助自己理解:算力是"厨房的灶台数量",内存是"冰箱的大小",而内存带宽是"从冰箱到灶台的传送带宽度"。DGX Spark的灶台多到可以开十个餐馆,冰箱大到能囤一个月的菜,但传送带只有窄窄一条——每分钟能送到灶台的菜就那么多,灶台再多也是闲着。
3. 推理引擎选型与部署实录
3.1 环境准备与vLLM部署
DGX Spark出厂预装的是DGX OS,其实就是定制版Ubuntu,CUDA驱动和基础工具链都是配好的。我刚开始直接用系统自带的Python环境装vLLM,结果把系统Python搞坏了,后来老老实实开了venv虚拟环境。
# 创建venv环境(Python 3.10/3.11均可) python3 -m venv ~/vllm_env source ~/vllm_env/bin/activate # 安装vLLM,实测0.9.x版本稳定性最理想 pip install --upgrade pip pip install vllm==0.9.1 # 拉起Qwen3-32B(或把模型路径换成Qwen3-30B-A3B) vllm serve Qwen/Qwen3-32B \ --max-model-len 32768 \ --gpu-memory-utilization 0.9 \ --enforce-eager有几个参数值得解释一下。--max-model-len 32768是把上下文窗口限制在32K,这么做主要是为了控制KV cache占用,后面会细说。--gpu-memory-utilization 0.9表示vLLM最多用90%的统一内存,我特意留10%给系统,因为DGX Spark的系统进程、桌面环境都要用同一块内存,上到95%就可能直接把桌面卡死。--enforce-eager是关掉CUDA Graph,老实说一开始不上这个参数会随机崩溃,后来发现是FlashAttention和这台机器之间有点小矛盾,开了反而稳定。
这里提醒一句:vLLM输出日志里显示的"GPU memory"其实是统一内存的一部分,不是传统意义上的显存。我最初看着日志里显示"GPU memory 230GB"直接愣住了,后来才知道DGX Spark根本没有独立的显存空间,nvidia-smi那套显存查看方式并不能反映真实的内存占用。
3.2 SGLang与llama.cpp的交叉验证
怕vLLM单引擎的数据有偏差,我又装了SGLang和llama.cpp做交叉验证。SGLang的部署方式几乎一模一样:
pip install "sglang[all]" --find-links https://sglang-project.github.io/deps/cu128 python -m sglang.launch_server \ --model-path Qwen/Qwen3-32B \ --max-len 32768 \ --mem-fraction-static 0.85llama.cpp那边则是直接用编译好的二进制加GGUF量化格式。说实话,在三款引擎里llama.cpp的CPU后端在这台机器上表现得不如预期,性能比vLLM要差一些,后来我都是拿vLLM作为主要参考,SGLang和llama.cpp用来交叉验证数据是否可信。最终三款引擎的速度差异在15%以内,说明瓶颈确实在内存带宽而不在推理框架。
引擎选型的建议:如果你主要跑量化模型、需要和Embedding/Rerank等周边组件配合,选vLLM最省心,生态最全;如果重度依赖长上下文且要复杂的请求调度,SGLang有优势;如果只想快速启动一个模型做测试,llama.cpp的安装最轻量。但在DGX Spark上,我最终长期使用的是vLLM。
3.3 量化权重的部署对照
量化这块我用的AWQ格式,Qwen官方和社区都有现成的AWQ权重可以直接下载,省了自己校准的麻烦。AWQ属于4bit量化里质量比较稳的一种,比GPTQ的激活值处理更细腻。部署时不需要额外改代码,vLLM会自动识别模型里的量化配置:
vllm serve Qwen/Qwen3-32B-AWQ \ --max-model-len 32768 \ --gpu-memory-utilization 0.9加载AWQ权重时有个明显变化:模型启动时间从BF16的3分钟缩短到了不到1分钟,因为磁盘内存要加载的数据量从64GB降到了18GB。当时我就预感decode速度会有大提升,实际也确实如此。量化不光是省显存,对于带宽受限的机器来说,量化等于变相提高了内存带宽效率,因为每次decode要搬的数据变少了。
除了AWQ,我还顺手测了FP8版本。FP8权重是32GB左右,decode上限 = 273/32 ≈ 8.5 token/s,实际跑下来在6到7 token/s之间。作为对比,AWQ的INT4能到11到14 token/s。FP8的好处是质量损失小,INT4的好处是快,具体怎么取舍看你更在意质量还是速度。
4. 实测数据与瓶颈定位
4.1 单请求交互场景指标
我统一用2048 token的prompt,让模型续写512 token,测三个最核心指标:TTFT(首Token延迟)、TPOT(每个Token的生成时间)、整体decode吞吐。测试时关闭并发,模拟单用户交互场景。
| 配置 | 权重大小 | TTFT (2048 prompt) | TPOT | decode速度 |
|---|---|---|---|---|
| Qwen3-32B BF16 | 64GB | 1.8s | 285ms | 3.5 token/s |
| Qwen3-32B AWQ 4bit | 18GB | 0.7s | 82ms | 12.2 token/s |
| Qwen3-32B FP8 | 32GB | 1.2s | 155ms | 6.5 token/s |
| Qwen3-30B-A3B BF16 | 60GB | 1.5s | 68ms | 14.7 token/s |
BF16权重的Qwen3-32B那个3.5 token/s,基本属于"看着字一个字一个字蹦"的水平,和我的理论计算4.3 token/s非常接近,说明实际效率在80%上下。这个效率其实不算低,纯粹是带宽天花板太低。
AWQ 4bit直接蹦到12.2 token/s,这个速度虽然还是没法跟RTX 4090上的小型模型比,但在27B这个体量上已经是"可用的对话速度"了。最意外的是Qwen3-30B-A3B,BF16权重状态下居然跑出了14.7 token/s——原因就是它是MoE,decode时只需要读取激活的那3B参数,而不是全部30B。这再次说明:在这台机器上选模型架构比选推理引擎重要得多。
4.2 连续批处理下的吞吐表现
单用户场景下带宽受限严重,那多用户并发呢?我做了连续批处理测试,模拟API服务模式,同时塞入不同数量的请求,看整体吞吐:
| 并发数 | Qwen3-32B AWQ | Qwen3-32B BF16 | Qwen3-30B-A3B BF16 |
|---|---|---|---|
| 1 | 12.2 token/s | 3.5 token/s | 14.7 token/s |
| 8 | 31.4 token/s | 8.9 token/s | 41.2 token/s |
| 16 | 36.8 token/s | 10.5 token/s | 53.6 token/s |
| 32 | 39.1 token/s | 11.2 token/s | 58.3 token/s |
有意思的是,并发从1涨到32,整体吞吐并没有线性增长,而是逐渐逼近某个上限。AWQ模式下上限大概在40 token/s左右,MoE模式下逼近60 token/s。这说明连续批处理能把空闲的带宽尽量占满,但带宽上限摆在那里,不会因为调度好就突破物理极限。不过对API服务来说这个吞吐还是有价值的,至少比单用户时候的"卡顿感"好了很多。
4.3 长上下文情景下的带宽争夺
最后一项测试是拉长上下文。很多AI应用的真实场景不是短对话,而是长文档摘要、代码库问答这种动不动就上万token的请求。我测试了32K上下文下不同模型的性能变化:
| 配置 | 8K上下文 | 32K上下文 | 性能跌幅 |
|---|---|---|---|
| Qwen3-32B BF16 | 3.5 token/s | 2.8 token/s | 20% |
| Qwen3-32B AWQ 4bit | 12.2 token/s | 9.6 token/s | 21% |
| Qwen3-30B-A3B BF16 | 14.7 token/s | 12.1 token/s | 18% |
损失的大头来自KV cache。32K上下文下KV cache大约要占13GB内存,decode阶段每生成一个token除了读权重,还要额外读一遍KV cache。内存带宽是共享的,KV cache越大,权重实际能分到的带宽就越少。这个测试直接解释了为什么我建议设置--max-model-len——如果你不限制上下文,KV cache会无限制扩张,最后可能连有限的带宽都剩不下多少。
注意:如果你确实需要跑128K超长上下文,建议在vLLM里开启KV cache量化(
--kv-cache-dtype fp8)。我把KV cache从FP16换成FP8,32K上下文下的跌幅从20%降到了12%,代价是质量上会有极小损失。这个性价比值不值,取决于你的业务对精度的敏感度。
5. 内存带宽的榨干方案与调优心得
5.1 量化优先,其次选MoE
看完全部测试数据,结论已经非常清晰:在这台机器上跑27B量级密集模型,先量化,再谈其他。BF16模式下3.5 token/s的体验基本等于不可用,AWQ下12 token/s就接近"能用"。仅仅是模型格式的变化,带来接近三倍的速度提升。而且AWQ的量化质量损失在对话场景里几乎感觉不出来,代码生成也稳,只有在某些数学题和逻辑推断上会逊色于BF16。
如果你有选择模型的自由度,那我的建议就更直接:优先选MoE架构。Qwen3-30B-A3B用BF16跑,效果已经超过Qwen3-32B用AWQ的效果。MoE模型的总参数量看起来很大,但decode时只激活一部分专家,实际读取的权重大幅减少,机制上就避开了带宽瓶颈。后续如果DeepSeek系列这种更大规模的MoE模型在DGX Spark上有量化版本,也很值得试试——参数目标大但激活小,跟这台机器的脾气非常合拍。
5.2 PD分离与连续批处理
还有两个工程层面的优化手段值得提。第一个是PD分离,把Prefill和Decode拆成两个独立阶段,分别调度。Prefill吃算力,Decode吃带宽,两者分开跑可以把资源利用率拉满。vLLM从0.8版本开始支持在部署层面做PD分离配置,DGX Spark上的好处是统一内存让这种调度几乎没有额外拷贝成本。不过我实测下来,PD分离在并发很高的时候收益明显,单用户场景下差别不大,所以如果你只是自己用,不建议为了它增加复杂度。
第二个是连续批处理,这个前面表格里已经看出效果了并发从1到8,整体吞吐翻了接近三倍,说明这台机器在并发场景下反而能发挥出更好的价值。如果你要把DGX Spark当小规模API服务器用,记得一定要把并发调度打开,单连接压测会让你误判它的真实能力。
5.3 KV Cache的隐性带宽开销
KV cache是很多人容易忽略的隐性带宽杀手。你可以这样算一笔账:Qwen3-32B的KV cache大小大约是每token0.39MB(48层×8个KV头×128维×2方向×2字节),1K上下文占0.39GB,32K上下文直接吃掉12.8GB,128K就是51GB——比你4bit量化后的模型权重还要大好几倍。
这意味着如果上下文开得很大,即使模型权重已经量化得很小,KV cache照样能把带宽吃个精光。实际测试中我试着开启128K上下文跑Qwen3-30B-A3B,性能直接从14 token/s掉到5 token/s,就是因为KV cache的带宽开销彻底压过了权重读取。所以调--max-model-len的实质是给KV cache设定一个上限,防止它喧宾夺主。
这里分享一下我的配置习惯:日常交互用32K上下文,跑长文档任务时才动态提高上限,绝不默认开满。如果你确定自己需要长上下文,优先开KV cache量化,其次才考虑加大上下文上限。
6. 常见问题与避坑记录
6.1 关机、重启与系统更新(DGX Spark特别篇)
别笑,"这台机器怎么关机"真的是很多用户搜得最勤的问题。DGX Spark没有传统服务器那种明确的电源按钮位置,它的电源键在设备前面板右侧的下方,是个很小的圆形按键。短按一次是挂起/唤醒,长按4秒会弹出关机和重启的系统菜单,长按10秒才是强制断电。我一开始不知道,直接长按4秒没反应,又长按10秒强制断电,导致未保存的模型配置全丢了。
如果不想碰物理按键,终端里直接敲命令更稳:
# 关机 sudo shutdown -h now # 重启 sudo reboot系统更新这块也有个坑:DGX OS虽然是Ubuntu系,但它默认的软件源是NVIDIA定制的,直接用apt upgrade可能会把GPU驱动搞崩。我建议只更新安全更新,显卡驱动和CUDA工具链不要乱动,除非你有明确需求。
6.2 OOM与显存管理
DGX Spark的256GB统一内存看着很大,但OOM照样会发生。我在测试128K上下文时就遇到过——vLLM启动时分配了90%的统一内存,结果上下文一拉长,KV cache飙升,直接把系统桌面卡到黑屏。后来学乖了,--gpu-memory-utilization从不设到90%以上,最高85%,剩下15%给系统真不够用,实际我设了0.8才最稳。
另外要注意nvidia-smi在DGX Spark上的输出和普通显卡不一样。它显示的是整个统一内存池的使用情况,而不是传统意义上的VRAM。你看一眼数字,会觉得"显存用的真多",实际上系统Python进程、桌面、模型全都在同一块内存里,没法精确区分。真要看内存占用细节,用NVIDIA官方推荐的nvtop更直观,能按进程分类显示内存和算力占用。
6.3 模型下载加速与路径配置
27B模型的权重动辄几十GB,下载本身就是一等一的大事。我用的方案很简单:国内环境直接配HuggingFace镜像站,或者用ModelScope。ModelScope对国内用户最友好,速度稳定,也不需要额外配置。
配置镜像站的话,在终端里设置环境变量:
export HF_ENDPOINT=https://hf-mirror.com然后正常用huggingface-cli download或modelscope download即可。这里有个细节:下载前一定要确认目标仓库是否提供量化权重,我刚开始没注意,拉了个原始BF16权重下来,几小时下载完才发现要手动转换格式,白白浪费时间。Qwen官方仓库里AWQ和FP8都有现成文件,直接挑需要的下就行。
注意:下载大文件时一定用
huggingface-cli download而不是git clone,前者支持断点续传和LFS文件加速,后者对大权重文件经常卡到怀疑人生。这两个方式我都试过,速度差距不是一点点。
6.4 实测避坑表格
| 问题 | 表现 | 解决方案 |
|---|---|---|
| decode只有3 token/s | BF16模式下跑27B密集模型 | 换AWQ/FP8量化,或换MoE模型 |
| 系统黑屏/卡死 | 上下文拉太长,KV cache挤爆内存 | 降低max-model-len,开启KV cache量化 |
| FlashAttention随机崩溃 | vLLM加载时偶发CUDA错误 | 加--enforce-eager参数 |
| 关机键没反应 | 长按时间不够 | 短按=挂起,长按4秒=菜单,10秒=强制 |
| 系统Python被搞坏 | 直接在系统环境装pip包 | 使用venv虚拟环境 |
| nvidia-smi显示异常 | 统一内存显示为显存占用 | 用nvtop按进程查真实内存 |
最后的实际操作体会
DGX Spark这台机器,说它是"个人AI超算"其实有点捧杀。它真正的定位是一台能让开发者在本机跑大模型的开发板级产品:容量够大,256GB统一内存应对30B量级甚至更大模型的微调和推理都游刃有余;但273GB/s的内存带宽决定了它只适合"跑通、调试、开发"这类场景,不适合用做高并发推理服务器。我在用它的第三周做了一个小决定:模型全部用AWQ量化,默认跑Qwen3-30B-A3B,把并发调度打开当小团队服务用,然后用节省下来的资源同时跑Embedding和Rerank。这台机器的价值在于让你把整个AI应用链路都跑在本机——模型、向量库、框架全部本地化,带宽虽然是硬伤,但只要摸透了它的脾气,反而能在很小功耗下有滋有味地干活。希望这篇实测能帮你少走几步弯路。