雙 5090 跑 Qwen3.8-27B BF16 140K 實測數據與優化心得
-
看到板上幾篇 5070 Ti / 3070 Ti 異構雙卡跑 Qwen3.8 的分享,數據都很紮實。我這邊條件好一點(雙 RTX 5090 32GB),把生產環境實際在跑的 Qwen3.8-27B 數據整理出來分享,重點是「哪些優化方向實測有效、哪些是白做工」,希望對其他雙卡玩家有參考價值。
1. 硬體與軟體
項目 配置 GPU 2× RTX 5090 32GB(SM120 Blackwell) CPU Ryzen 9 9950X3D(16C/32T) 記憶體 60GB DDR5 系統 Ubuntu 24.04.4 LTS 引擎 llama.cpp(LM Studio 2.29.0 CUDA12 binary) 模型 Qwen3.8-27B-BF16(兩片 GGUF 共 54.6GB)+ mmproj-F16(928MB,啟用 Vision) Context 140,000(對齊 Hermes context_length;原 200000 多出的 70K 純佔 VRAM,已縮小) KV q8_0 / q8_0 Split tensor 0.5,0.5 MTP 關閉(實測更慢,見 §4.1) 用途 Hermes Agent 主腦,長期單 slot 真實對話流量,非固定短 prompt benchmark 2. 生產啟動參數
llama-server -m Qwen3.8-27B-BF16-00001-of-00002.gguf \ --mmproj mmproj-F16.gguf \ --n-gpu-layers 99 \ --split-mode tensor --tensor-split 0.5,0.5 \ --ctx-size 140000 -fa on \ --batch-size 4096 --ubatch-size 4096 \ --cache-type-k q8_0 --cache-type-v q8_0 \ -np 1 --kv-unified \ --jinja --metrics --no-webui重點說明:
-np 1:單 slot 長 context,避免 KV 爆炸。--kv-unified保留著,之後開多 slot 時兩 slot 共享總 KV pool(按需分配,不靜態平分),目前單 slot 下無副作用。-fa on:長 context 下顯存與速度都受益,必開。--metrics:Prometheus endpoint,MTP 接受率、prefill/decode 總量都從這裡看,比翻 log 方便。--jinja:走模型官方 chat template,thinking 輸出行為才正確。
3. 實測數據(生產 log 為準)
以下全部取自 llama-server 自己的
print_timing與/metrics,不是 client 端量測(client 端 burst 量測會偏高 ~30%,這坑我踩过)。統計區間為本次啟動後 53 筆已完成任務,真實 Agent 工作流(含工具操作與上下文逐步累積):llamacpp:prompt_tokens_total 395739 llamacpp:prompt_seconds_total 341.57 → prefill 平均 1158.6 tok/s llamacpp:tokens_predicted_total 86194 llamacpp:tokens_predicted_seconds 1793.85 → decode 平均 48.05 tok/s llamacpp:n_tokens_max 99372 → 單 task 最大 context llamacpp:requests_deferred 0逐 task 抽樣(每 task 一個 session turn,* = 累計 context 已達 99.4K 的長任務):
task prompt prefill gen tok decode 68781 ~1.7K 1017 t/s 119 47.72 t/s 68902 ~0.2K 增量 393 t/s 455 47.44 t/s 69995 ~2.8K 1168 t/s 433 50.01 t/s 70430 ~0.5K 678 t/s 117 50.37 t/s 74156 ~0.9K 848 t/s 1312 49.18 t/s 75470 ~4.5K 1121 t/s 1038 49.13 t/s 70549 ~4.7K 1104 t/s 3604 49.35 t/s 76862 ~1.6K * 989 t/s 9517 48.29 t/s 86382 ~1.1K 924 t/s 2728 48.43 t/s觀察:
- decode 非常平穩:47.4–52.4 t/s,約 20.5 ms/token,從 1K 短 context 到 99.4K 長 context 幾乎不衰减——BF16 權重下 5090 的 1792GB/s 頻寬在 decode 端壓力還不大。
- 最長 task 一次生成 9517 tok(近 3.4 分鐘持續輸出),全程 0 OOM、0 pipeline fallback、0 deferred。
- prefill 在 0.5K–4.7K 增量下穩定 840–1170 tok/s(前綴快取命中時更高)。
- 峰值 99,372 tokens < 140K 上限,餘量健康。
- VRAM:GPU0 ~31.3GB / GPU1 ~30.2GB(各 32.6GB),BF16 雙卡各分 ~27GB 權重 + KV,headroom 約 1–2.3GB/卡。想再拉 ctx 就得降量化。
- 載入:54.6GB BF16 兩片 mmap,NVMe 上約 30–40 秒。
4. 實測過的優化方向:哪些有效、哪些放棄
4.1 MTP(投機解碼)——實測放棄
Qwen3.8-27B GGUF 內建 MTP draft 層(blk.64),理論上 decode 可以白賺一截。實際開
--spec-type draft-mtp實測後關閉:- 接受率約 40%(這模型的 draft head 偏弱,比 Qwen3.6 系的 62–71% 低一截),
--spec-draft-n-min調低變負優化; - draft 佔 VRAM + 配置複雜度上升;
- 雙卡 tensor split + MTP 實測比純 decode 還慢——跨卡同步開銷吃掉了投機解碼的收益。
驗證 MTP 確已關閉的方法:啟動 log 會有 15 行
model has unused tensor blk.64.* -- ignoring,合計約 810MB——這 15 行代表內建 MTP 層被丟棄,是「MTP 已關」的正面證據,不是異常。4.2 雙卡 split:同型號卡 tensor,異構卡 layer
- 同型號雙卡(我這台):
--split-mode tensor 0.5,0.5沒問題,每層雙卡各算一半。 - 異構卡(如 5070 Ti + 3070 Ti):layer split 更合理,tensor split 每層跨卡 all-reduce 會被最慢那張卡釘死。
- 雙 5090 走 PCIe 的 internal AllReduce(用 LM Studio binary 時 log 裡有 NCCL 行),沒另編 NCCL build——實測 NCCL 自編版沒有更快,維持現狀。
4.3 換引擎——SGLang / NInfer 都測過
- SGLang 0.5.17:載不動。對 unsloth Qwen3.8 GGUF 直接報
unknown architecture: qwen35(2026-08 新架構還沒進 transformers GGUF arch map);改載 HF 原生權重會反量化成 BF16 → 每卡 27GB OOM;--quantization ggufloader 仍找 safetensors。SM120 上 FP8/NVFP4 kernel 也不完整。結論:llama.cpp 是目前唯一完整支援 Qwen3.8 GGUF 的生產選項。 - NInfer(自 build):更快,但生態封閉。同一顆空 5090、同 ctx、同 prompt 對決:NInfer prefill ~8575 tok/s(llama.cpp ~2975,約 2.9×)、decode 180.6 vs 141.25 t/s(約 1.28×)、warm ttft 19ms vs 66ms;MTP 接受率兩邊都 ~62% 打平——差距來自引擎本體 kernel 效率,不是 MTP。NInfer 現在是我的備用腦/實驗場,生產主腦維持 llama.cpp(OpenAI 相容 API + 生態成熟 + 換模型零成本)。
4.4 有效的長期配置決策
- ctx 對齊实际需求:llama.cpp 啟動時預分配整塊
n_ctx的 KV buffer(不是按需長),200000 → 131072 一步直接省下 3–4GB/卡。 - KV 量化 q8_0:Qwen3.8-27B 是 GQA-4(head_count_kv=4,不是 30——早期用 30 heads 估 KV 會高估 7.5 倍),17 層 KV,q8_0 約 37KB/token:200K ctx ≈ 7.3GB、256K ≈ 9.7GB。KV 才是長 context 的大頭,不是權重。
- thinking 模型讀兩個欄位:長推理輸出落在
reasoning_content,content會是空的——用 API 驗證時別把空 content 當成失敗。 - 雙卡 VRAM 統計:
nvidia-smi --query-compute-apps裡 tensor split 的 PID 每張卡各出現一次,要加總,別只看一行。
5. 給雙卡玩家的參數建議(單 slot 長 context)
-tp 2 / --split-mode tensor --tensor-split 0.5,0.5 # 同型號卡 --split-mode layer --tensor-split 16,8 # 異構卡(按 VRAM 比例) -fa on # 必開 -ctk q8_0 -ctv q8_0 # KV 量化 -np 1 # 單 slot --ctx-size <對齊前端 context_length> # 別多開,KV 啟動即預分配 -b 4096 -ub 4096 # prefill 批大小(prefill 慢可降 ub) --jinja --metrics # 官方模板 + 可觀測性6. 結語
雙 5090 + BF16 140K 對我這種 7×24 單 slot agent 場景是「夠用且平穩」的配置:decode ~48 t/s 穩定、99K context 無衰减、零 fallback。最大的心得是:先測再優化——MTP、NCCL、SGLang 三個「理論上應該更快」的方向全數實測過,兩個更慢、一個載不動,最後贏的是最樸素的 tensor split + q8_0 KV + 合身的 ctx。
數據全部可重現:引擎端 log(
print_timing)+/metrics,啟動參數如上。有問題歡迎直接問,踩過的坑都寫在上面了。
附:所有數據以引擎端 log 為準;client 端量測(TTFT/burst)與引擎端 print_timing 計時窗不同,會偏高,引用時請註明口徑。