DGX Spark · part 44
[Benchmark] GLM-5.3-Flash 塞進一台 DGX Spark:108.72 GB、15.5 tok/s、視覺能用
❯ cat --toc
- 前言
- 旗艦塞不下,Flash 塞得下:216.72 GB vs 108.72 GB
- 選 `UD-Q2_K_XL`,不選官方建議的 `IQ3_XXS`
- 唯一會讓你白忙的地方:CUDA toolkit 必須是 13.0
- 給了 `-DCMAKE_CUDA_COMPILER` 還不夠
- ready 85 秒,262K 和 32K 一樣快
- 中文比英文快 5.39%,而且看得出機制
- 每秒字元數不能拿來當速度用
- 輸出是繁體,一整段只有一個錯字
- 寫 code 比寫散文快 52%
- 視覺可以用,但要先拿掉一個旗標
- 同機四顆模型:它是最慢的那個
- 進階:為什麼掛上圖片就 500?
- 差別在引擎,不是模型
- 上游有修法,但被擋著
- 進階:兩個會浪費你一小時的操作坑
- `reasoning_effort` 一定要顯式給
- headless Chrome 渲 Three.js 不能加 `--disable-gpu`
- 收工
TL;DR
單台 DGX Spark(121 GB)跑得動 GLM-5.3-Flash:UD-Q2_K_XL 108.72 GB,ready 85 秒,英文散文 15.40 tok/s、中文 16.23。中文比英文快 5.39%,因為 MTP 的 draft 接受率高了 5 個百分點。原生視覺可用,OCR 逐字全中 —— 但要拿掉 --spec-type,兩者現在不能並用。唯一會讓你白忙的是 CUDA toolkit:12.x 炸在 warmup、13.2 不報錯但輸出亂碼,只有 13.0 對。

前言
新模型發布那天最掃興的一句話,是「你的機器不夠大」。
GLM-5.3 發布後我去查能不能塞進那台 DGX Spark,查到的第一篇說不行、要兩台。那篇的作者在文章裡自己寫了 "we have not run GLM 5.3 Flash on Spark hardware ourselves" —— 那是估算,不是實測。
我把它跑起來了,一台,108.72 GB。這篇是完整的配方加上跑出來的數字,包含一個到現在還沒人公開量過的東西:它的原生視覺在單台上能不能用。
前面幾集在同一台機器上跑過 DeepSeek-V4-Flash 和 Qwen3.8-Flash-Next,文末有同機對照表。
旗艦塞不下,Flash 塞得下:216.72 GB vs 108.72 GB
下面的數字是拿 HuggingFace API 逐檔加總出來的,不是「參數量 × 位元數」的估算:
| 最小的 GGUF | 121 GB 塞得下? | |
|---|---|---|
| 旗艦 GLM-5.3(744B-A40B) | UD-IQ1_S 216.72 GB | ❌ 差將近兩倍 |
| GLM-5.3-Flash(320B-A18B) | UD-IQ1_S 93.09 GB | ✅ |
Flash 不是旗艦的縮小版,是另一套基底模型。config.json 裡寫的是 glm5_next / Glm5NextForConditionalGeneration:288 個 routed 專家加 1 個 shared,每個 token 取 8 個;45 層,層型是 linear_attention 三層配 deepseek_sparse_attention 一層循環;帶一層 MTP(num_nextn_predict_layers: 1);max_position_embeddings 是 1,048,576。
還有 vision_config,所以它原生就是多模態的。授權是 MIT,旗艦那邊是 GLM-5.3 License。
選 UD-Q2_K_XL,不選官方建議的 IQ3_XXS

unsloth/GLM-5.3-Flash-GGUF 的階梯:
| 量化 | 大小 | 121 GB |
|---|---|---|
| UD-IQ1_S | 93.09 GB | ✅ |
| UD-IQ1_M | 97.58 GB | ✅ |
| UD-Q2_K_XL | 108.72 GB | ✅ 本文用這個 |
| UD-IQ3_XXS | 120.37 GB | ⚠️ 權重就吃光了 |
| UD-Q3_K_XL 以上 | 147.54 GB+ | ❌ |
Unsloth 自己的文件建議 128 GB 機器用 UD-IQ3_XXS。那個建議拿權重去對總記憶體,漏了 KV cache 這一項。120.37 GB 的權重放進 121 GB 的機器,剩下的空間連 32K 的 KV 都不夠,更別說 262K。
Q2_K_XL 載入之後 free -g 是 used 107 / available 13-14,沒有逼近上限。這 12 GB 的差距就是能不能開長 context 的差別。
另外還要抓一個 mmproj-F16.gguf(1.13 GB),視覺那節會用到。
唯一會讓你白忙的地方:CUDA toolkit 必須是 13.0

動手前先對這張表:
| 項目 | 要求 | 怎麼驗 |
|---|---|---|
| GPU | GB10 / sm_121a | nvidia-smi |
| CUDA toolkit | 13.0 | <toolkit 路徑>/bin/nvcc --version 要回 13.0.x |
| 統一記憶體 | 121 GB | free -g |
| 磁碟 | 權重 109 GB + 餘裕 | df -h |
| 作業系統 | aarch64 Linux | uname -m |
toolkit 版本錯了會有兩種完全不同的症狀,而且第二種難抓得多:
| toolkit | 症狀 |
|---|---|
| 12.x 標頭 | server 在 warmup 炸 CUDA error: invalid argument,連 ready 都到不了 |
| 13.2 | 不報錯、正常啟動、正常回應 —— 但輸出是亂碼 |
| 13.0 | ✅ |
第二種你會先懷疑模型、再懷疑量化、然後懷疑提示詞,而問題其實在編譯器。
給了 -DCMAKE_CUDA_COMPILER 還不夠
CMake 找 CUDA toolkit 的路徑,跟你指定的 compiler 是兩套獨立的搜尋。只給 compiler 的話,它會用你指定的 nvcc 去編,但標頭仍照自己的順序找,通常先撈到系統路徑下的舊版。
結果是新編譯器配舊標頭:cudaLaunchKernelEx 的 cudaLaunchConfig_t 佈局對不上,kernel launch 回 invalid argument,炸在 warmup 的第一個 soft_max。
兩個變數都要給:
git clone https://github.com/eauchs/llama.cpp.git
cd llama.cpp
# 這個 commit 已經不在該分支 head 的祖先鏈上,要明確 fetch 才拿得到
git fetch origin 8a8d0bcc4d5fdf024c457526245bec4bc3a12adc
git checkout 8a8d0bcc4d5fdf024c457526245bec4bc3a12adc
cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release \
-DCUDAToolkit_ROOT=<你的 13.0 路徑> \
-DCMAKE_CUDA_COMPILER=<你的 13.0 路徑>/bin/nvcc
cmake --build build --target llama-server -j 20
建完看這一行,它是唯一的驗收條件:
-- Found CUDAToolkit: <13.0 路徑>/targets/sbsa-linux/include (found version "13.0.88")
不是 13.0.x 就重來。cmake 會把它印出來,而它就在 -- The CUDA compiler identification is NVIDIA 13.0.88 的旁邊一行 —— 兩行不一致就是這個病。建置在 GB10 上花 166.57 秒。
ready 85 秒,262K 和 32K 一樣快
./build/bin/llama-server \
-m <UD-Q2_K_XL 第一個 shard> \
--host 127.0.0.1 --port 8010 \
-ngl 99 -c 262144 -ctk q8_0 -ctv q8_0 \
-fa on --jinja --spec-type draft-mtp
262144 和 32768 兩種 context 都是 85 秒 ready,載入時間不隨 context 變。
⚠️ 不要試 1M context。 統一記憶體機器沒有乾淨的 OOM 牆,超過之後是 swap thrash,整台機器會失去排程 —— ssh 過得了 banner 但命令送不進去。我的機器不在旁邊,那次等了很久。
環境逐字:
主機 NVIDIA GB10 · 121 GiB 統一記憶體 · aarch64
驅動 580.159.03 · CUDA toolkit 13.0.88
build llama.cpp 0.3.0-dev (build 10677, commit 8a8d0bcc4)
CMAKE_CUDA_ARCHITECTURES=121a-real
模型 unsloth/GLM-5.3-Flash-GGUF UD-Q2_K_XL,4 shards,108,720,071,427 bytes
中文比英文快 5.39%,而且看得出機制
同一顆 server、同一組參數,只換題目。max_tokens=1024、temperature=0、reasoning_effort="low",各跑三發:
| 語言 | decode tok/s(中位) | range | MTP 接受率 | completion tokens |
|---|---|---|---|---|
| EN | 15.40 | 15.08-15.51 | 36.01% | 333 |
| ZH | 16.23 | 15.83-16.69 | 41.03% | 362 |
快的原因不用猜:MTP 的 draft 接受率高了 5.01 個百分點。接受得多,驗證回合就少,出字就快。三發合併之後數據一致(EN 364/1008 = 36.11%,ZH 431/1053 = 40.93%)。
temperature=0 的確定性通過了:EN 三份 content 的 SHA-256 相同,ZH 三份也相同。六發 finish_reason 全是 stop,沒有排除樣本。
這跟「CJK 一定比較慢」的直覺相反,所以要講清楚哪個數字才算數。
每秒字元數不能拿來當速度用
| chars/s(中位) | 字元/token | |
|---|---|---|
| EN | 64.88 | 4.4 |
| ZH | 15.47 | 1.01 |
差四倍,但那不是速度差,是 token 密度加上模型自己選的篇幅(英文寫了 1,456 字元、中文 367 字元)。核心速度看 tok/s,chars/s 只能拿來估「你要等多久才看到成品」。
輸出是繁體,一整段只有一個錯字
對繁中場景這是決定性的一格。字形證據:燈塔、綢緞、皺褶、裡、鐘錶、闔上。
那篇散文的一段:
黎明前的海是墨色的,像一匹未經裁剪的綢緞,皺褶裡藏著整夜的風。
他站在燈塔頂端,看著燈火轉過最後一圈。那束光掃過海面時,浪頭便短暫地
亮了起來,像有誰在水底睏開了眼睛,又闔上。
「像有誰在水底睏開了眼睛」——應該是「睜」。整段就這一個字錯,而這是 2.4-bit 專家的代價,照實記。
寫 code 比寫散文快 52%
丟一題:用 Three.js 從 CDN 載入,只用方塊堆出一座天守閣 —— 石垣基座、逐層收分、每層出簷、頂上裝飾,配地面與光照,相機自動繞行。要一個開了就能看的單一 HTML 檔。
| completion tokens | 2,136 |
| wall | 92.06 s |
| decode | 23.64 tok/s |
| content | 5,249 字元,結尾有 </html> |
| 一發就成 | 是(finish_reason=stop) |
對了的:石垣基座、三層逐層收分、每層出簷、白牆深瓦、地面光照、自動繞行,一眼認得出是天守閣。錯了的:頂上的裝飾生成了十字架,不是鯱也不是擬宝珠。日式天守閣頂著西洋十字 —— 提示詞只寫了 "decorative finial",這一半算題目沒講清楚。
| 工作 | decode tok/s |
|---|---|
| 體素天守閣(Three.js) | 23.64 |
| 中文散文 | 16.23 |
| 英文散文 | 15.40 |
同一顆 server、同一組旗標,差別還是在接受率 —— code 的下一個 token 比散文好猜。
視覺可以用,但要先拿掉一個旗標
這是我最想知道的一格,因為社群沒有人公開量過。
視覺要換一支 build。unsloth 自己那支 PR 同時有模型架構和視覺投影器:
git clone -b glm5next/upstream https://github.com/unslothai/llama.cpp.git
cd llama.cpp && git checkout d07e71ede7
cmake -B build -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release \
-DCUDAToolkit_ROOT=<你的 13.0 路徑> \
-DCMAKE_CUDA_COMPILER=<你的 13.0 路徑>/bin/nvcc
cmake --build build --target llama-server llama-mtmd-cli -j 20
configure 4.87 秒、build 136.19 秒。上膛:
./build/bin/llama-server \
-m <UD-Q2_K_XL 第一個 shard> \
-ngl 99 -c 32768 -ctk q8_0 -ctv q8_0 -fa on --jinja \
--mmproj <mmproj-F16.gguf 路徑>
注意沒有 --spec-type。 那是必要條件,理由在文末的進階那節。ready 97 秒。
三層驗收:
| 層 | 題目 | 結果 |
|---|---|---|
| 機制 | /v1/models | capabilities: ["completion","multimodal"] |
| 低標 | 64×64 純紅 PNG,問它什麼顏色 | Red |
| 高標 | 1200×400 白底黑字 OCR | 讀出 THE SILVER ROBOT READS SEVEN BLUE MAPS.,編輯距離 0 |
| 文字沒退化 | The capital of France is | **Paris**,finish_reason: stop |
三個請求 HTTP 全部 200。高標那張圖的 ground truth 跨了兩次 run 的目錄,我用 sha256 確認是同一張才認那個 0 —— 跨 run 比對一定要驗 hash,不能靠檔名。
圖片被編碼進 context 的速度是 678 tokens @ 193.94 tok/s。
同機四顆模型:它是最慢的那個
全部同一台 GX10、同樣英文散文:
| 模型 | 量化 | decode tok/s |
|---|---|---|
| Qwen3.8-Flash-Next | IQ1_S | 32.27 |
| DeepSeek-V4-Flash-0731 | vLLM sparkinfer | 24.95 |
| Qwen3.8-Flash-Next | Q4_K_XL | 23.38 |
| GLM-5.3-Flash | Q2_K_XL | 15.50 |
散文上它是最慢的。它值錢的地方是原生多模態、1M 架構和 MIT 授權,不是速度。跨模型跨量化只能當數量級參考,別當精確對打。
拿來對外面比:NVIDIA 論壇上有一組 2 台 Spark 跑 vLLM NVFP4 的散文數字是 19.58 tok/s。我們一台拿到 15.40 / 16.23,一半的硬體換八成的速度。
⚠️ 社群那些 46.9 / 62.9 tok/s 的高分我不拿來對打,因為沒有一家公開提示詞。有個 repo 的作者自己寫了「不附提示詞的單流 tok/s 沒有意義」,那句話我同意。
進階:為什麼掛上圖片就 500?
不讀這節不影響使用,前面的配方照抄就能跑。這節是給想知道那個旗標為什麼要拿掉的人。
帶著 --spec-type draft-mtp 送圖片,兩個請求都回 HTTP 500:
E decode: failed to initialize batch
E spec process: llama_decode(ctx_dft) head=0 failed rc=-1 (pos=36)
E srv decode: failed to process speculative batch
the last position stored in the memory module of the context (i.e. the KV cache)
for sequence 3 is X = 19
it is required that the sequence positions remain consecutive: Y = X + 1
兩次跑的差別只有這一個旗標,其餘逐字相同。
第一眼看到 500 很容易讀成「模型看不懂圖」,但錯誤裡點名的是 ctx_dft —— 那是 draft context,不是視覺路徑。目標那邊已經走到 36,draft 停在 19,差 17 格,正好是圖片佔掉的位置。

差別在引擎,不是模型
llama.cpp 的投機解碼把 draft 放在第二個獨立的 llama_context(tools/server/server-context.cpp 裡的 llama_context * ctx_dft),它有自己的 KV cache。而圖片是以 embedding 進入主 context 的,process_mtmd_chunk 走 mtmd_helper_decode_image_chunk(),位置推進量取自 mtmd_input_chunk_get_n_tokens()。
同步 draft 的線其實接好了 —— 那個函式收一個 callback,裡面呼叫 common_speculative_process。所以這不是「沒做」,是那條路上有東西沒生效。
翻 common/speculative.cpp 會看到四個用到獨立 draft KV 的實作,它們對圖片批次的處置分兩種:
| 實作 | 對圖片(embedding)批次 |
|---|---|
draft_eagle3 | embd != nullptr 就 return true 跳過 → draft KV 留洞 |
draft_mtp | 同上,而且前面有一行 // TODO: how to make it work with vision tokens? |
draft_dflash / draft_dspark | 不跳過,但注入時把 M-RoPE 的多維位置壓成同一個純量 |
draft_simple | 沒有守衛。它的 draft() prompt 會經 get_text_tokens() 壓成純文字,但 process() 直接把收到的 batch 丟進 llama_decode —— 不能據此認為圖片批次被擋住了 |
五個 ngram 家族的 process() 是 // TODO: implement; return true,構造上碰不到這題。
判準因此不是「你用哪種投機」,是這個模式有沒有自己的 draft KV。原始碼裡是明文的:add_config_if_enabled(..., params.draft.ctx_dft != nullptr) 只套在那四個上。Gemma-4 那類共用 target KV 的(is_mem_shared)也不會撞到。
vLLM 和 SGLang 的 MTP 讓 assistant layers 共用 target 的 KV,所以位置對不齊這一整類問題在那邊不存在 —— 但它們在多模態餵給 draft 的接縫上各自也有 open issue。分水嶺是引擎的 KV 設計,不是模型。
上游有修法,但被擋著
PR #25144 是一個 +16/-6、單一檔案的修正:給 draft 自己的位置空間,不再沿用 target 的。作者比了兩種做法,結果很清楚 —— 單純放寬位置檢查會不當機但接受率 0(洞還在,draft 沒用);重新編號才真的能用。
ggerganov 沒有合併它,原話是要先把 llama_batch 重構到能同時帶 vision 和 target embedding,「supporting this properly for all cases」。那張 PR 確實只修 draft_mtp,不碰 eagle3 也不碰 dflash,所以他的理由站得住。
我把那個 patch 套進我們的 build 量了一次。git apply --check 回 0,乾淨套用:
| 組別 | 發數 | draft_n | accepted | 接受率 | tok/s(中位) |
|---|---|---|---|---|---|
| 散文 | 3 | 1585 | 581 | 36.66% | 17.61 |
| 含圖續寫 | 3 | 1106 | 724 | 65.46% | 21.52 |
圖片不再 500,散文的 36.66% 跟沒 patch 的 36.01% 幾乎一樣,文字端沒被傷到。
但六發長輸出裡 llama_decode[1] returned -1 出現 2,661 次,而 head=0 的失敗數是 0 —— 多頭 MTP 的第一顆頭以外全在報錯。同一個錯誤字串在沒 patch 的 log 裡命中 0 次,所以不能推給既有行為。那個 48.50% 的加權接受率是 server 真的回的 timings,可是實際上只有部分 draft 路徑在工作,還背著大量重試成本。
所以這個 patch 目前只能當實驗證據,還不能上線。要視覺就拿掉 --spec-type,那句話到今天為止還是對的。
進階:兩個會浪費你一小時的操作坑
reasoning_effort 一定要顯式給
不給的話,複雜的生成題會把整個 completion 預算燒在 thinking:
| max_tokens | reasoning 字元 | content 字元 | wall |
|---|---|---|---|
| 8,192 | 28,851 | 0 | 500 s |
| 16,384 | 54,842 | 0 | 1,018 s |
想了十七分鐘,一個字都沒開始寫。加上 reasoning_effort:"low" 之後同一題:reasoning 剩 1,155 字元、content 5,249 字元、92 秒完成。
headless Chrome 渲 Three.js 不能加 --disable-gpu
天守閣那題的產物要開來看才知道對不對,而 headless Chrome 加了 --disable-gpu 之後 Three.js 拿不到 WebGL,畫面全黑,而且畫面上沒有任何錯誤。要開 console 才看得到 THREE.WebGLRenderer: Error creating WebGL context.。
正解:
--use-gl=angle --use-angle=swiftshader --enable-unsafe-swiftshader
一片空白很容易讓人以為「模型生的 code 壞了」,而那是渲染器的問題,不是模型的。
收工
一台 121 GB 的機器跑 320B 模型,結論是可以,而且不用退到 1-bit。要挑的話:量化選 UD-Q2_K_XL 別選官方建議的 IQ3_XXS(那個建議沒算 KV)、toolkit 只能是 13.0、-c 從 32768 起跳、要視覺就把 --spec-type 拿掉。
速度它是同機最慢的一顆,15.5 tok/s。但它是唯一一顆在這台機器上又能看圖、又是 MIT、又有 1M 架構的,而且中文比英文快。
同系列其他篇:Qwen3.8-Flash-Next:1770 億參數 + 262K 一起開 · DeepSeek-V4-Flash 284B Q2 的品質實測
常見問題
- 一台 DGX Spark 跑得動 GLM-5.3 嗎?
- 旗艦版跑不動,Flash 版跑得動。旗艦 GLM-5.3(744B-A40B)最小的 GGUF 是 UD-IQ1_S 216.72 GB,單台 121 GB 差了將近兩倍。GLM-5.3-Flash(320B-A18B)的 UD-Q2_K_XL 是 108.72 GB,載入後 used 107 GB,還留得下 262K 的 KV cache。
- GLM-5.3-Flash 在 DGX Spark 上多快?
- 用 llama.cpp + UD-Q2_K_XL + MTP 投機解碼,英文散文 decode 15.40 tok/s、中文散文 16.23 tok/s、生成 Three.js 程式碼 23.64 tok/s。同一台機器上 DeepSeek-V4-Flash 是 24.95、Qwen3.8-Flash-Next IQ1_S 是 32.27,所以它強的地方不是速度。
- 為什麼掛上 mmproj 送圖片會回 HTTP 500?
- 因為同時開了投機解碼。llama.cpp 的投機把 draft 放在第二個 llama_context,而圖片是以 embedding 進入主 context 的,draft 那邊的 KV 位置追不上,批次建構時的連續性檢查就會失敗。拿掉 --spec-type 之後圖片請求全部回 200。
接著讀
- 2026-08-28[DGX Spark] 1770 億參數 + 262K context 一起開:Spark 上不用二選一
Qwen3.8-Flash-Next 在單台 DGX Spark 上跑 UD-Q4_K_XL,原生 262,144 context 全開,改檔案 76.65 tok/s。完整設定、四格速度、記憶體怎麼分配。
- 2026-08-23[Benchmark] DGX Spark 跑 Qwen3.8-27B 到 65 tok/s:無投機只有 12.3,差別全在草稿預算
GB10 的頻寬 273 GB/s、語言主幹 18.77 GB,每個 token 都要整份讀過,上限 14.54 tok/s。實測無投機 12.32,吃掉 85%,換 kernel 撈不回來。投機解碼把它拉到 5.28 倍,而關鍵不是換方法,是把草稿預算從 8 調到 12。
- 2026-08-07[Benchmark] 在 DGX Spark 上跑 MiniMax-H3!可惜現在沒辦法用 NVIDIA VSR 放大
從零把 33B 影音同步模型跑在 GB10 上。哪些參數非設不可、時間到底花在哪、為什麼 NVIDIA 自家的放大器在這台裝不上,以及換成 4.3 MB 的開源 SPAN 之後省了 22%。
- 2026-07-07DGX Spark 2026 現況:哪些還能跑、哪些已經過時、我現在會怎麼配
DGX Spark 2026 年中現況整理:現在該用 vLLM、官方 Gemma 4 NVFP4 權重、MTP、長 context 多模態,以及仍然會咬人的坑。
不想錯過新文章?
訂閱我確保不漏接!
隨時一鍵退訂。