# Qwen3 GGUF 安装与调优手册

本文档只覆盖 `qwen3_gguf` 后端，目标机器为当前项目实测环境：

- GPU: `Tesla T4 16GB`
- CUDA: `12.8`
- 模型: `DevQuasar/Qwen.Qwen3-Reranker-4B-GGUF`
- 量化: `Q8_0`

---

## 1. 结论先看

当前这套代码里，GGUF 后端的主要瓶颈不是“显存没吃满”，而是 **llama.cpp 按 doc 顺序逐条打分**。因此最有效的优化策略是：

- 让模型层尽可能全部 offload 到 GPU
- 打开 `flash_attn` / `offload_kqv`
- 把 `n_ctx / n_batch / n_ubatch` 调到一个对短标题重排更合适的高效点

本轮在当前机器上的推荐配置是：

```yaml
qwen3_gguf:
  n_ctx: 512
  n_batch: 512
  n_ubatch: 512
  n_gpu_layers: 999
  n_threads: 2
  n_threads_batch: 4
  flash_attn: true
  offload_kqv: true
  infer_batch_size: 8
  sort_by_doc_length: true
  length_sort_mode: "char"
```

说明：

- `n_gpu_layers: 999` 在 llama.cpp 中等价于“尽可能全部层都 offload”
- 这台 T4 上，**即使全量 offload，当前模型也只占到约 `4.5 GiB` GPU 显存**
- 所以“允许 8G 显存”并不会自动带来更高速度；这个模型/后端在当前工作负载下已经接近“该用到的权重都上 GPU 了”

---

## 2. 独立环境

`qwen3_gguf` 必须使用自己的独立 venv：

- `qwen3_vllm` -> `.venv-reranker`
- `qwen3_gguf` -> `.venv-reranker-gguf`

安装命令：

```bash
./scripts/setup_reranker_venv.sh qwen3_gguf
```

脚本现在会自动做两件事：

1. 安装 GGUF 后端所需 Python 依赖
2. 在检测到 `/usr/local/cuda/bin/nvcc` 时，把 `llama-cpp-python` **重编译成 CUDA 版**

---

## 3. GPU 版验证

必须验证不是 CPU-only 版：

```bash
./.venv-reranker-gguf/bin/python - <<'PY'
import llama_cpp
print("supports_gpu_offload =", llama_cpp.llama_supports_gpu_offload())
PY
```

正确结果应为：

```text
supports_gpu_offload = True
```

还可以看动态库：

```bash
ldd .venv-reranker-gguf/lib/python3.12/site-packages/llama_cpp/lib/libllama.so | rg 'cuda|cublas|ggml-cuda'
```

应能看到：

- `libggml-cuda.so`
- `libcudart.so`
- `libcublas.so`

---

## 4. 模型下载

当前使用本地文件优先策略，模型放在：

```text
models/reranker/qwen3-reranker-4b-gguf/Qwen.Qwen3-Reranker-4B.Q8_0.gguf
```

若本地文件存在，后端会直接加载本地 GGUF，不再依赖启动时在线下载。

为了避免当前机器上 Hugging Face Xet 下载的 `416 Range Not Satisfiable` 问题，`start_reranker.sh` 已对 `qwen3_gguf` 默认设置：

```bash
HF_HUB_DISABLE_XET=1
```

---

## 5. 本地调优脚本

新增本地基准脚本：

```bash
PYTHONPATH=/data/saas-search ./.venv-reranker-gguf/bin/python \
  benchmarks/reranker/benchmark_reranker_gguf_local.py --docs 64 --repeat 1
```

它会直接实例化 GGUF backend，输出：

- 模型加载耗时
- 当前进程 GPU 显存占用
- 单次 rerank 延迟

---

## 6. 本轮实测结果

测试条件：

- Query: `白色oversized T-shirt`
- Docs: `64` 条商品标题
- 本地脚本：`benchmarks/reranker/benchmark_reranker_gguf_local.py`
- 每组 1 次，重点比较相对趋势

结果：

### 6.1 保守配置

```text
n_ctx=384
n_batch=384
n_ubatch=128
n_gpu_layers=24
```

- GPU 显存：`2984 MiB`
- 64 docs 延迟：`74347.91 ms`

### 6.2 全量 offload

```text
n_ctx=384
n_batch=384
n_ubatch=128
n_gpu_layers=999
```

- GPU 显存：`4338 MiB`
- 64 docs 延迟：`51401.77 ms`

### 6.3 最优配置

```text
n_ctx=512
n_batch=512
n_ubatch=512
n_gpu_layers=999
```

- GPU 显存：`4564 MiB`
- 64 docs 延迟：`49116.10 ms`

### 6.4 其它尝试

`n_threads=4 / n_threads_batch=8`：

- GPU 显存：`4564 MiB`
- 64 docs 延迟：`49895.88 ms`
- 比推荐值略慢

`infer_batch_size=64`：

- GPU 显存：`4564 MiB`
- 64 docs 延迟：`50723.36 ms`
- 也略慢

### 6.5 API 级验证

在把推荐配置写入 `config/config.yaml` 并重启服务后，使用：

```bash
RERANK_BASE=http://127.0.0.1:6007 \
  ./.venv/bin/python benchmarks/reranker/benchmark_reranker_random_titles.py 64 --repeat 1 --query '白色oversized T-shirt'
```

得到：

- `64 docs`：`50177.22 ms`

再用：

```bash
RERANK_BASE=http://127.0.0.1:6007 \
  ./.venv/bin/python benchmarks/reranker/benchmark_reranker_random_titles.py 153 --repeat 1 --query '白色oversized T-shirt'
```

得到：

- `153 docs`：`115328.60 ms`

对比旧日志中的保守配置：

- 旧配置 `153 docs`：`153435.37 ms`
- 新配置 `153 docs`：`115328.60 ms`

改善幅度约：

- `24.8%`

---

## 7. 为什么没有吃到 8G

结论很重要：

- 当前最优配置已经是“尽可能全量层 offload”
- 该 `Q8_0` 模型在这套 llama.cpp / T4 / 短文本重排场景下，**实测只需要约 `4.5 GiB` GPU 显存**
- 继续为了“吃满 8G”去增大 `n_ctx`，不会明显提升吞吐，反而可能带来额外开销

所以本轮不是“显存太保守”，而是：

- 可 offload 的权重已经基本 offload 完了
- 真正拖慢响应的是 **逐 doc 顺序推理** 这一后端实现路径

---

## 8. 生产建议

### 8.1 当前建议

保留以下参数：

```yaml
n_ctx: 512
n_batch: 512
n_ubatch: 512
n_gpu_layers: 999
n_threads: 2
n_threads_batch: 4
flash_attn: true
offload_kqv: true
```

### 8.2 如果还嫌慢

优先级建议：

1. 缩小 `rerank_window`
2. 减少传入 doc 数
3. 若业务允许，切换到更适合高吞吐的后端

原因：

- 当前 GGUF 后端是本地单进程、逐 doc 打分
- 对长列表重排，它天然不如 vLLM / 云端 rerank API 擅长吞吐

---

## 9. 本轮落地文件

- `config/config.yaml`
- `scripts/setup_reranker_venv.sh`
- `scripts/start_reranker.sh`
- `benchmarks/reranker/benchmark_reranker_gguf_local.py`
- `reranker/GGUF_INSTALL_AND_TUNING.md`
