我跑的是 Qwen3.8 27B(FP8 quantized),兩張 AMD R9700 32GB(RDNA4 架構),用 vLLM serving。這篇記錄我踩過的坑和最終設定。
為什麼本地推理
- 隱私:我的對話、記憶、文件都不經過 OpenAI/Anthropic 的 server
- 成本:27B 模型一次下載,之後免費(vs API 按 token 計費)
- 延遲可控:不用等網路 round-trip,TTFT 280ms
- 永遠在線:不擔心 API 停機、rate limit、區域限制
模型與來源
| 項目 | 來源 |
|------|------|
| 模型 | Qwen3.8-27B-Instruct-FP8(HuggingFace) |
| vLLM | vLLM 0.28.0(RDNA4 community image) |
| Docker image | capicua25x/vllm-rocm-rdna4:0.28.0-rdna4-rc13 |
| ROCm | ROCm 7.0(AMD GPU compute platform) |
| GPU | AMD Radeon R9700 32GB(RDNA4) |
硬體
- 2× AMD Radeon R9700 32GB(RDNA4,PCIe 4.0 x16)
- 48GB RAM(LXC 分配)
- ROCm 7.0(AMD 的 CUDA 等效物)
為什麼 vLLM 不是 llama.cpp
| | vLLM | llama.cpp |
|---|---|---|
| throughput | Paged attention + continuous batching,高併發快 | 單 request 快,多 request 排隊 |
| API | 原生 OpenAI-compatible(/v1/chat/completions) | 也有,但穩定度差一些 |
| 長 context | 262K token(我的設定) | 受限於 RAM/GPU 分配 |
| AMD 支援 | ROCm build(有 community RDNA4 image) | Vulkan / HIP,穩定但慢 |
| speculative decoding | MTP(Multi-Token Prediction) | 也支援,但整合較少 |
我的 agent 同時有多個 auxiliary 任務(vision、STT、memory extraction),需要高併發。vLLM 贏。
我的 vLLM 設定
docker run -d --name qwen38-vllm \
--gpus all \
--ipc=host \
-p 8080:8080 \
-v /models:/models \
capicua25x/vllm-rocm-rdna4:0.28.0-rdna4-rc13 \
--model /models/vision \
--tensor-parallel-size 2 \
--max-model-len 262144 \
--kv-cache-dtype fp8 \
--attention-backend TRITON_ATTN \
--speculative-config '{"method":"mtp","num_speculative_tokens":5}' \
--max-num-seqs 8
關鍵參數解釋:
- TP=2:兩張卡各跑一半模型(tensor parallel)
- max-model-len 262144:262K context(夠長,可以一次丟整個 codebase)
- kv-cache-dtype fp8:省 50% VRAM(代價:極微精度損失)
- TRITON_ATTN:RDNA4 上最快(我 A/B 測過 ROCM_ATTN 和 FLASH_ATTENTION)
- MTP n=5:每步預測 5 個 token,實際接受率 ~68%(decode 加速 ~50%)
踩過的坑
1. ROCm 版本對不上
AMD 的 ROCm 跟 GPU 架構綁死。RDNA4 需要 ROCm 7.0+,官方 vLLM image 沒 RDNA4 build。我用 community image(capicua25x/vllm-rocm-rdna4)。
2. FP8 KV cache 在 RDNA4 上要對齊
head_dim=256(Qwen3.8)+ FP8 KV 會走 Triton kernel 而非原生 fast path。速度仍可接受,但不是理論最優。
3. 冷啟動 garbled
vLLM 第一次 decode 會有 2-3 個 token 亂碼(GPU 還沒 warm up)。我加了個 canary gate:收到請求先發一個 8-token 的 canary,確認 decode 正常才放真流量。
4. 兩卡溫度不均
GPU 0 跑 compute-heavy 的 layer 比較多,溫度比 GPU 1 高 5-8°C。用 --tensor-parallel-size 2 是自動均衡的,但物理上 GPU 0 位置通風較差。解法:換風扇轉向。
效能(實測)
- decode:60-64 tok/s(1024 token 輸出、concurrency=1)
- TTFT:288ms(1024 token input)
- VRAM 使用:每卡 ~30.7GB / 32GB
- MTP 接受率:67-69%(穩定)
下一步
模型跑起來了,但 agent 沒有「記憶」。下一篇:怎麼接 Hindsight 讓它跨 session 記得事情。