**这次跑 `gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf`,走的是 `llama.cpp + HIP + GGUF` 这条路线,不是 vLLM。**
下面这份教程按“**新电脑只装好了系统、驱动、DCU/DTK**”来写,重点是**思路和关键决策**,同时给出能直接用的命令。
**目标**
在一台新 Linux 机器上,把 `4 x Z100L` 跑成一台可直接提供服务的 `llama.cpp` 推理机,稳定运行:
- 模型:`gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf`
- 运行方式:`llama.cpp`
- 后端:`HIP / DTK`
- 多卡方式:`layer split`
- 最大真实 prompt:约 `262140 tokens`
---
## 一、总体思路
这条路线的核心,不是把 Z100L“伪装成 AMD”,而是:
1. **接受底层还是海光 DTK**
2. **上层尽量使用通用开源栈**
3. 对 `gfx906/Z100L` 只做**最小必要修正**
这次最终稳定跑通的栈是:
- 宿主系统:Ubuntu 22.04
- 驱动:海光已安装驱动
- DCU/DTK:`/opt/dtk-26.04`
- 推理框架:`llama.cpp`
- 模型格式:`GGUF`
- 多卡策略:`-sm layer`
- KV cache 压缩:`-ctk q8_0`
为什么选这条路:
- `llama.cpp` 对 GGUF 支持成熟
- 31B 这种模型配 `Q8_0` 很适合 4 卡 32G 这类机器
- 相比继续硬推 `vLLM + Triton + 31B uncensored + DFlash`,这条更稳、更直接
---
## 二、前置条件
至少满足这些:
- Ubuntu 22.04.x
- 驱动已安装并能识别 4 张卡
- DTK 已安装,路径是 `/opt/dtk-26.04`
- `hipcc` 可用
- `rocminfo` 可识别 `gfx906`
- 4 张卡都正常
- 磁盘至少有 80GB 以上空闲
- 内存建议 128GB 以上更舒服,64GB 也能干
先确认环境:
```bash
hostname
uname -a
cat /etc/os-release
ls -ld /opt/dtk /opt/dtk-26.04
/opt/dtk-26.04/bin/hipcc --version
export LD_LIBRARY_PATH=/opt/dtk-26.04/lib:/opt/dtk-26.04/hip/lib:/opt/dtk-26.04/hsa/lib:/opt/dtk-26.04/.hyhal/lib:/opt/dtk-26.04/.hyhal/rocm_smi/lib:/opt/dtk-26.04/dcc/lib:$LD_LIBRARY_PATH
/opt/dtk-26.04/bin/rocminfo | egrep -i 'Name:|Marketing Name:|Vendor Name:|gfx'
```
如果这里不通,不要继续。
---
## 三、先固化环境脚本
建议先做一个固定环境脚本,不要每次手敲。
例如:
`/home/muyi/envs/dtk26-z100l.sh`
```bash
#!/usr/bin/env bash
export ROCM_SOURCE_DIR=/opt/dtk-26.04
export ROCM_PATH=/opt/dtk-26.04
export HIP_PATH=/opt/dtk-26.04/hip
export HSA_PATH=/opt/dtk-26.04/hsa
export PATH=/opt/dtk-26.04/bin:/opt/dtk-26.04/llvm/bin:/opt/dtk-26.04/dcc/bin:$PATH
export LD_LIBRARY_PATH=/opt/dtk-26.04/lib:/opt/dtk-26.04/hip/lib:/opt/dtk-26.04/hsa/lib:/opt/dtk-26.04/.hyhal/lib:/opt/dtk-26.04/.hyhal/rocm_smi/lib:/opt/dtk-26.04/dcc/lib:$LD_LIBRARY_PATH
```
以后都先执行:
```bash
source /home/muyi/envs/dtk26-z100l.sh
```
---
## 四、先做最小 GPU 验证
在新机器上,不要上来就编大项目。先确认 GPU 计算链路是真的通。
最少要确认:
- `rocminfo` 能看到 4 张卡
- `hipcc` 能编译简单程序
- 4 张卡都能被 HIP runtime 看到
最小 Python 验证也可以:
```python
import ctypes
hip = ctypes.CDLL("/opt/dtk-26.04/lib/libamdhip64.so")
count = ctypes.c_int()
rc = hip.hipGetDeviceCount(ctypes.byref(count))
print("rc =", rc, "count =", count.value)
```
如果这里都不通,后面别继续。
---
## 五、准备 `llama.cpp`
### 1. 拉源码
```bash
cd /home/muyi/src
git clone https://github.com/ggml-org/llama.cpp.git llama.cpp-z100l
cd /home/muyi/src/llama.cpp-z100l
```
### 2. 为什么不能直接原样编
这台机器不是标准 AMD ROCm 机器,直接编通常会遇到三类问题:
- DTK 的 HIP CMake 元信息不标准
- `gfx906` 上某些 HIP kernel 的 launch bounds 不适配
- 长 prompt 时 softmax / norm 相关 kernel 容易出错或输出异常
所以这条路要接受一个现实:
**需要极小补丁,但补丁应尽量只修 `gfx906/DTK` 边界,不改模型逻辑。**
### 3. 关键修正点
这次最终稳定运行用到的关键修正有三类:
1. `ggml/src/ggml-hip/CMakeLists.txt`
- 修正 DTK 返回的 HIP 版本信息
- 否则构建阶段会把 HIP 识别错
2. `ggml/src/ggml-cuda/norm.cu`
- 在 `HIP + gfx906` 下,把容易出问题的高线程分支收窄
- 否则 4 卡 GPU 路径可能出现错误输出
3. `ggml/src/ggml-cuda/softmax.cu`
- 在 `HIP + gfx906` 下限制 softmax 的 block/thread 选择
- 否则长 prompt prefill 不稳定
如果你手头有我之前整理的资源包,**优先直接复用那套 patched 源码**。
从零编也可以,但你要自己把这三类修正带上。
### 4. 编译
```bash
source /home/muyi/envs/dtk26-z100l.sh
cd /home/muyi/src/llama.cpp-z100l
cmake -S . -B build-hip-no-fa \
-DGGML_HIP=ON \
-DCMAKE_BUILD_TYPE=Release
cmake --build build-hip-no-fa -j 32
```
编完后至少要有:
```bash
/home/muyi/src/llama.cpp-z100l/build-hip-no-fa/bin/llama-cli
/home/muyi/src/llama.cpp-z100l/build-hip-no-fa/bin/llama-server
```
---
## 六、下载模型
这次路线用的是:
- 仓库:`hf-mirror.com/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF`
- 主模型:
`gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf`
建议目录:
```bash
mkdir -p /home/muyi/models/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF
cd /home/muyi/models/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF
```
如果镜像站支持 `resolve/main`,直接断点续传:
```bash
wget -c "https://hf-mirror.com/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF/resolve/main/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf"
```
如果不支持,就直接去页面里复制文件直链。
---
## 七、为什么最终参数是这一组
这条路线不是随便试出来的,是经过很多轮收敛后的稳定点:
```bash
-sm layer
-ts 1,1,1,1
-ctk q8_0
-c 262144
-b 1024
-ub 256
-ngl 999
-t 32
-tb 32
```
每个参数的含义:
- `-sm layer`
- 用分层流水线切模型
- 这是当前最稳定的多卡模式
- `-ts 1,1,1,1`
- 四卡等比例分层
- 虽然显存不完全均衡,但在满配置下最稳定
- `-ctk q8_0`
- K cache 用 `q8_0`
- 这是把上下文推到 `262140` 的关键之一
- `-c 262144`
- 开满模型上下文窗口
- `-b 1024 -ub 256`
- 这是满窗口下当前稳定点
- 再往上很容易 OOM
- `-ngl 999`
- 全层尽量上 GPU
- `-t 32 -tb 32`
- 这台双路机器上是一个比较合理的 CPU 线程档位
---
## 八、先用 `llama-cli` 验证
先别急着起服务,先确认命令行单次推理通。
```bash
source /home/muyi/envs/dtk26-z100l.sh
/home/muyi/src/llama.cpp-z100l/build-hip-no-fa/bin/llama-cli \
-m /home/muyi/models/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf \
-ngl 999 \
-sm layer -ts 1,1,1,1 \
-ctk q8_0 \
-c 262144 \
-t 32 -tb 32 \
-b 1024 -ub 256 \
-cnv -st \
--reasoning-budget 0 \
-p "你好,用一句中文介绍你自己。"
```
注意两点:
- `llama-cli` 和 `llama-server` 不要同时跑
- 这个 31B 模型会把 4 卡显存吃得比较满
---
## 九、正式起服务
推荐服务命令:
```bash
source /home/muyi/envs/dtk26-z100l.sh
/home/muyi/src/llama.cpp-z100l/build-hip-no-fa/bin/llama-server \
-m /home/muyi/models/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf \
-a gemma4-heretic-q8 \
-ngl 999 \
-sm layer -ts 1,1,1,1 \
-ctk q8_0 \
-c 262144 \
-t 32 -tb 32 \
-b 1024 -ub 256 \
-np 4 \
--kv-unified \
--host 127.0.0.1 \
--port 18080 \
--timeout 1800 \
--metrics \
--slots \
-rea off \
--reasoning-budget 0
```
为什么加这些:
- `-np 4`
- 开 4 个服务槽位,支持并发
- `--kv-unified`
- 让服务的 slot/KV 管理更适合这类长上下文场景
- `-rea off --reasoning-budget 0`
- 直接关思考输出
- 否则很容易拿到空 `content` 和一堆 `reasoning_content`
---
## 十、如何调用
### 1. 本机 curl
```bash
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gemma4-heretic-q8",
"messages": [
{"role": "user", "content": "Say hello in one short sentence."}
],
"max_tokens": 64,
"temperature": 0
}'
```
### 2. 本地电脑通过 SSH 隧道调用
在你本地电脑上:
```bash
ssh -L 18080:127.0.0.1:18080 muyi@192.168.147.248
```
然后本地调:
```bash
curl http://127.0.0.1:18080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gemma4-heretic-q8",
"messages": [
{"role": "user", "content": "你好,介绍一下你自己。"}
],
"max_tokens": 128,
"temperature": 0
}'
```
### 3. Python 调用
```python
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:18080/v1",
api_key="dummy",
)
resp = client.chat.completions.create(
model="gemma4-heretic-q8",
messages=[{"role": "user", "content": "你好,介绍一下你自己。"}],
max_tokens=128,
temperature=0,
)
print(resp.choices[0].message.content)
```
---
## 十一、这条路线当前能做到什么
当前这条 `4x Z100L + llama.cpp + GGUF Q8_0` 路线,已经实测到:
- **最大真实 prompt**
- `262140 tokens`
- **满窗长 prompt 吞吐**
- 约 `22.47 tok/s`
- **约 131k prompt**
- 约 `34.03 tok/s`
- **短输出 decode**
- 大致 `11 tok/s` 左右
- **服务并发**
- `1` 路时延最好
- `4` 路时总吞吐更高
---
## 十二、为什么不是每张 GPU 同时满负荷
这是很多人第一次看监控时最容易误判的点。
当前稳定路线是:
- `-sm layer`
- `-ts 1,1,1,1`
这不是“4 卡同时干同一件事”的纯并行,而是:
**layer split + pipeline parallelism**
所以会出现:
- 显存 4 张卡都占着
- 但某个瞬间只有 1 张或 2 张 `HCU=100%`
- 另外几张在等流水线前段/后段
这是正常现象,不代表策略坏了。
如果想让 4 张卡更像“同时一起满载”,理论上要走:
- `-sm row`
- 或 `-sm tensor`
但这台机器上,这两条当前都不稳定或不可用。
所以**当前最实用的办法不是改 split mode,而是提高并发请求数。**
---
## 十三、为什么不建议锁频
我实际测试过:
- 最高能锁到 `1600 MHz`
- 但锁频后:
- 烤机总 TFLOPS 反而下降
- 温度更高
- 模型推理收益几乎没有
所以当前结论是:
**保持 `auto` 比锁高频更合理。**
---
## 十四、常见坑
### 1. `rocminfo` 能看到卡,但程序跑不起来
通常是 `LD_LIBRARY_PATH` 没配完整。一定要带上:
- `/opt/dtk-26.04/lib`
- `/opt/dtk-26.04/hip/lib`
- `/opt/dtk-26.04/hsa/lib`
- `/opt/dtk-26.04/.hyhal/lib`
- `/opt/dtk-26.04/.hyhal/rocm_smi/lib`
- `/opt/dtk-26.04/dcc/lib`
### 2. `llama-cli` / `llama-server` 同时开,报 OOM
正常。
这个 31B Q8_0 会把 4 卡吃得很满,**服务和 CLI 二选一**。
### 3. 改 `-ts` 以后显存更均衡了,但服务反而起不来
我已经实测过。轻微非对称 `-ts` 在小配置下更均衡,但回到:
- `262144 ctx`
- `np 4`
- `kv-unified`
这组真实服务配置时,会变得不稳定。
所以正式配置还是建议:
```bash
-ts 1,1,1,1
```
### 4. 想用 `-sm tensor`
当前不建议。
这条路线和当前 `KV q8_0` / 4 卡配置不兼容。
### 5. 想开 DFlash
当前这条 `GGUF + llama.cpp` 路线**不能直接用 DFlash**。
它不是一个本地开关。
---
## 十五、推荐最终配置
**命令行单次推理**
```bash
/home/muyi/src/llama.cpp-z100l/build-hip-no-fa/bin/llama-cli \
-m /home/muyi/models/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf \
-ngl 999 \
-sm layer -ts 1,1,1,1 \
-ctk q8_0 \
-c 262144 \
-t 32 -tb 32 \
-b 1024 -ub 256 \
-cnv -st \
--reasoning-budget 0
```
**服务模式**
```bash
/home/muyi/src/llama.cpp-z100l/build-hip-no-fa/bin/llama-server \
-m /home/muyi/models/mradermacher/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking-GGUF/gemma-4-31B-it-Mystery-Fine-Tune-HERETIC-UNCENSORED-Thinking.Q8_0.gguf \
-a gemma4-heretic-q8 \
-ngl 999 \
-sm layer -ts 1,1,1,1 \
-ctk q8_0 \
-c 262144 \
-t 32 -tb 32 \
-b 1024 -ub 256 \
-np 4 \
--kv-unified \
--host 127.0.0.1 \
--port 18080 \
--timeout 1800 \
--metrics \
--slots \
-rea off \
--reasoning-budget 0
```
---
## 十六、最后一句话总结
如果你把这份教程压成一句话,就是:
**这次不是把 Z100L 伪装成 AMD,也不是继续走海光 demo,而是保留 DTK 底层,用 patched `llama.cpp + GGUF` 在 4 张 Z100L 上稳定跑通了 `Gemma 4 31B uncensored Q8_0`,并把上下文压到了 `262140`。**