~/blog/qwen38-27b-ud-on-one-2080ti

洋垃圾跑大模型 · part 5

[洋垃圾跑大模型 #5] 一張 22G 老卡跑 Qwen3.8-27B:30 tok/s,還能一次寫出會動的 3D 場景

cat --toc
一張 2018 年的改裝 RTX 2080 Ti 22G 顯卡擬人化坐在桌前,畫面另一側是它一次生成出來的體素風五重塔庭園。

先看它能做到什麼。

下面這座浮空體素庭園——三層紅色塔身、灰瓦飛簷、相輪、鳥居、櫻花樹、兩萬多個方塊——是這張 2018 年的顯卡一次生成出來的單一 HTML 檔,中間沒有人改過任何一行:

Qwen3.8-27B 一次生成的體素庭園:三層紅色塔身配灰瓦飛簷,塔頂立著相輪,島上有櫻花樹、鳥居與草地,左上角的說明卡寫著 20,506 voxels

👉 開起來玩玩看(可以拖曳轉視角、滾輪縮放)

提示詞只有一句話,55 個英文字,連用什麼函式庫都沒指定:

Design and create a very creative, elaborate, and detailed voxel art scene of a pagoda in a beautiful garden with trees, including some cherry blossoms. Make the scene impressive and varied and use colorful voxels. Use whatever libraries to get this done but make sure I can paste it all into a single HTML file.

它自己選了 Three.js、自己決定要做浮空島、自己加了日夜切換跟花瓣風暴的按鈕。430 秒、13,513 個 token。

你需要什麼

  • 一張 22GB 以上的顯卡。 我這張是改裝的 2080 Ti 22G(sm_75、Turing、22,528 MiB)。24GB 的卡當然也行,而且會更寬鬆。
  • llama.cpp 的 CUDA build。 我用的是 b10064不用為了這顆模型重編——現成的 binary 直接吃。⚠️ 順帶一個會浪費你十分鐘的坑:這份 GGUF 的 metadata key 前綴是 qwen35. 不是 qwen38,拿 qwen38 去 grep 檔頭會什麼都找不到。
  • 17 GB 的磁碟空間放權重。

第一步:抓權重

要抓的是 unsloth 那份 GGUF 裡的 UD-Q4_K_XL——它是動態量化,不同層用不同精度,同樣大小下品質比一般 Q4_K 好。

huggingface-cli download unsloth/Qwen3.8-27B-GGUF \
  Qwen3.8-27B-UD-Q4_K_XL.gguf \
  --local-dir ~/models/qwen38-27b-ud

抓下來是 16.7 GiB(17,923,394,624 bytes)。同個 repo 裡還有一個 mmproj-F16.gguf(884 MiB),那是看圖用的投影層,只跑文字的話可以不抓。

第二步:起服務

CUDA_VISIBLE_DEVICES=0 \
llama-server -m ~/models/qwen38-27b-ud/Qwen3.8-27B-UD-Q4_K_XL.gguf \
  --alias qwen38-27b-ud --host 0.0.0.0 --port 8082 \
  -ngl 99 -c 131072 -ctk q4_0 -ctv q4_0 \
  --parallel 1 --jinja -fa on --metrics \
  --spec-type draft-mtp --spec-draft-n-max 2 \
  --chat-template-kwargs '{"enable_thinking":false}' \
  --temp 0.7 --top-p 0.80 --top-k 20 --min-p 0.0 \
  --presence-penalty 1.5 --repeat-penalty 1.0

載入完 VRAM 是 20,788 / 22,528 MiB,還剩 1.7 GB。

第三步:驗它真的載對了

curl -s http://127.0.0.1:8082/props | python3 -c \
  "import json,sys; d=json.load(sys.stdin); \
   print(d['model_path'].split('/')[-1], d['default_generation_settings']['n_ctx'])"

要看到檔名跟 131072

⚠️ 只信 -m 指到的檔案,不要信服務的描述字串。 我這台 systemd unit 的描述還停在三個月前的模型名,但 -m 早就換過兩次了——想知道一台服務當下到底在跑什麼模型,描述字串是最不可信的來源。

每個參數在做什麼

參數為什麼
-ngl 9927B 的層全部上卡。這顆模型剛好塞得下,不用像跑 MoE 那樣算要搬幾層
-c 131072128K context。再往上開到 192K 也還裝得下,但那是給別的用途的,一般夠用
-ctk q4_0 -ctv q4_0KV cache 量化成 4-bit。128K 的 KV 不壓的話裝不下
-fa onFlash Attention。Turing 也吃得到
--spec-type draft-mtp
--spec-draft-n-max 2
這顆模型本身就有 MTP 頭,可以自己猜下一批 token 再一次驗證。n=2 是實測的甜蜜點,開到 3 反而變慢
--parallel 1一次只服務一個請求。單卡本來就跑滿了,同時接多個請求只會讓大家一起卡著排隊
--temp 0.7 --top-p 0.80
--presence-penalty 1.5
官方給的非思考模式取樣值,照抄
--metrics/metrics,之後要量 tok/s 才有數字可讀

速度

同一題跑三次:

秒數完成 tokentok/s
第一次430.513,51331.4
第二次382.811,63030.4
第三次421.613,15631.2

30-31 tok/s,三發之間差不到 1。這個穩定度比數字本身更值得記——同一張卡上,我量到的變異幾乎都來自題目,不是來自機器。

最重要的那個參數不在啟動指令裡

上面那行啟動指令有 --chat-template-kwargs '{"enable_thinking":false}',預設是不思考的

那個預設是為了 agent 的短迴圈設的:看板上一個一百多字的小任務,如果讓它先想個五分鐘再回答,整條流程會塞住。

要它一次寫出兩萬多字的可執行程式碼,關掉思考就做不出來。它會照樣寫、照樣寫得很長,然後在某個地方悄悄散掉——變數名接不上、迴圈條件變成亂碼、或者東西都建好了但相機擺在看不到的地方。

解法是每次請求自己把思考打開,但給它上限:

curl -s http://127.0.0.1:8082/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "qwen38-27b-ud",
    "messages": [{"role": "user", "content": "……"}],
    "max_tokens": 40960,
    "chat_template_kwargs": {"enable_thinking": true},
    "thinking_budget_tokens": 2048
  }'

thinking_budget_tokens 會讓推理硬停在 2048,然後正文完整寫完。不設這個上限的話它會把 token 全部燒在推理上,最後回一份空白的正文——我看過一發燒掉三萬多個 token 然後 finish_reasonlength,正文一個字都沒有。

上面那座塔就是這樣生出來的:推理用掉約 2,000 個 token,正文 13,513 個。

⚠️ 三發只成功一發

這題不是每次都做得出來。 同樣的組態、同樣的提示詞,我今天跑三次只有一次成功——另外兩次程式碼跑得起來、瀏覽器不報語法錯,但卡在它自己寫的載入畫面上,因為動畫迴圈裡有一行會每幀拋例外。

所以「一次生成一個能跑的 3D 場景」在這個尺寸上還是擲骰子,不是穩定能力。這篇秀的是它做得到的樣子,不是它每次都會這樣。真的要用,就多跑幾次挑一個好的,或者把它當草稿,接受剩下的 bug 要你自己修。

而這也是為什麼驗收一定要真的把瀏覽器打開:那兩發失敗的產物,靜態檢查全部過關、node --check 也過,語法完全合法。是開起來才看得出來它沒動。


這個系列的其他文章:

常見問題

一張 22G 的顯卡跑得動 Qwen3.8-27B 嗎?
跑得動。unsloth 的 UD-Q4_K_XL 量化是 16.7 GiB,全部 27B 的層都上得了一張改裝 2080 Ti 22G,開到 128K context 之後 VRAM 用掉 20,788 / 22,528 MiB。實測 30-31 tok/s。
Qwen3.8 需要重新編 llama.cpp 嗎?
不用。我用的是 2026-08 的 b10064 build,現成的 binary 直接就跑起來了,沒有 patch、沒有 branch、沒有重編。⚠️ 這裡有個坑:這份 GGUF 的 metadata key 前綴是 qwen35 不是 qwen38,拿 qwen38 去 grep 檔頭會什麼都找不到。
要它一次寫出一大段程式碼,該開思考還是關思考?
要開,但要給上限。關掉思考的話單發最快,可是長程生成容易在中段散掉;完全不設上限它會把 token 全部燒在推理上,最後回一份空白的正文。實務上是每次請求帶 thinking_budget_tokens: 2048,推理硬停在上限、正文完整寫完。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。