# Reranker 模块 **请求示例**见 `docs/QUICKSTART.md` §3.5。扩展规范见 `docs/DEVELOPER_GUIDE.md` §7。部署与调优实战见 `reranker/DEPLOYMENT_AND_TUNING.md`。`ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF` 的专项接入与调优结论见 `reranker/GGUF_0_6B_INSTALL_AND_TUNING.md`。 --- Reranker 服务提供统一的 `/rerank` API,支持可插拔后端(BGE、Jina Reranker v3、Qwen3-vLLM、Qwen3-Transformers、Qwen3-GGUF、DashScope 云重排)。调用方通过 HTTP 访问,不关心具体后端。 ## 当前结论 在当前项目的线上形态里,**首选后端是 `qwen3_vllm_score`**,**次选后端是 `qwen3_vllm`**。 原因不是“`LLM.score()` 理论上更高级”,而是这轮优化后,`qwen3_vllm_score` 在当前硬件和依赖栈上形成了一套更干净、更稳定、也更快的组合: - 模型:`Qwen/Qwen3-Reranker-0.6B` - GPU:Tesla T4 16GB - CUDA:12.8 - PyTorch:`2.10.0+cu128` - vLLM-score 环境:`vllm==0.18.0` - attention:**由 vLLM 运行时自动选择**后端实现;在已验证的 T4 栈上日志可见 **`FLASHINFER`** ## 后端总览 | 后端 | 当前定位 | 结论 | |------|----------|------| | `qwen3_vllm_score` | 主推荐 | 走 vLLM **`LLM.score()`** 的 **pooling / classify** 路径:对每条 (query, doc) **直接产出相关分**,不经 causal LM 的整步 **generate**。相对 **`qwen3_vllm`**(`generate(max_tokens=1)` + **yes/no** 的 logprob 推导),**省去**每对样本上**大词表 softmax / 采样约束**那一层的常规开销,语义与 cross-encoder 式 rerank 更一致;在当前栈与 T4 上延迟表现最好 | | `qwen3_vllm` | 次推荐 | 稳定、成熟、好排障,是很好的 fallback 和对照组 | | `jina_reranker_v3` | 新增本地方案 | 按官方推荐使用 `AutoModel(..., trust_remote_code=True)` + `model.rerank(query, docs)`,更接近 Jina 原生 listwise rerank 用法 | | `qwen3_transformers` | 兼容方案 | | | `qwen3_transformers_packed` | 特定场景方案 | T可能实现还有问题,没调好 | | `qwen3_gguf` / `qwen3_gguf_06b` | 低显存 / 功能兜底 | 更适合资源受限场景,不适合作为当前主在线方案 | | `dashscope_rerank` | 云服务方案 | 运维简单,但依赖外部服务和网络 | ## 目录与入口 - `reranker/server.py`:FastAPI 服务,启动时按配置加载一个后端 - `reranker/backends/`:后端实现与工厂 - `backends/__init__.py`:`get_rerank_backend(name, config)` - `backends/jina_reranker_v3.py`:Jina 官方 `model.rerank(...)` 接法 - `backends/qwen3_vllm_score.py`:当前最优的本地 GPU reranker - `backends/qwen3_vllm.py`:次优的本地 GPU reranker - `backends/qwen3_transformers.py`:Transformers 基线实现 - `backends/qwen3_transformers_packed.py`:packed 推理实现 - `backends/qwen3_gguf.py`:GGUF + llama.cpp 后端 - `backends/dashscope_rerank.py`:DashScope 云端重排后端 - `scripts/setup_reranker_venv.sh`:按后端创建独立 venv - `scripts/start_reranker.sh`:启动 reranker 服务 - `scripts/smoke_qwen3_vllm_score_backend.py`:`qwen3_vllm_score` 本地 smoke - `scripts/benchmark_reranker_random_titles.py`:随机标题压测脚本 - `scripts/run_reranker_vllm_instruction_benchmark.sh`:历史矩阵脚本 ## 环境基线 当前验证环境: - GPU:`Tesla T4 16GB` - Driver / CUDA:`570.158.01 / 12.8` - Python:`3.12.3` - `torch`:`2.10.0+cu128` - `transformers`:`4.51+` - `qwen3_vllm_score` 环境:`vllm==0.18.0` - `qwen3_vllm` 环境:`vllm>=0.8.5` 独立 venv 约定: - `qwen3_vllm` -> `.venv-reranker` - `qwen3_vllm_score` -> `.venv-reranker-score` - `jina_reranker_v3` -> `.venv-reranker-jina` - `qwen3_transformers` -> `.venv-reranker-transformers` - `qwen3_transformers_packed` -> `.venv-reranker-transformers-packed` - `qwen3_gguf` -> `.venv-reranker-gguf` - `qwen3_gguf_06b` -> `.venv-reranker-gguf-06b` - `bge` -> `.venv-reranker` - `dashscope_rerank` -> `.venv-reranker-dashscope` - 不同后端的 CUDA / vLLM / llama.cpp 依赖耦合很深,混装后更难定位性能和兼容性问题 - qwen3_vllm_score 和 qwen3_vllm 分了两个环境,是因为qwen3_vllm_score使用了vllm 0.18,但是后面经过测试两者性能相同。所以其实可以共用一个环境。不过没有动力合并回去。 ## 安装与部署 ### 1. 创建后端环境 `qwen3_vllm_score`: ```bash ./scripts/setup_reranker_venv.sh qwen3_vllm_score ``` `qwen3_vllm`: ```bash ./scripts/setup_reranker_venv.sh qwen3_vllm ``` `jina_reranker_v3`: ```bash ./scripts/setup_reranker_venv.sh jina_reranker_v3 ``` ### 2. 基础检查 ```bash nvidia-smi ./.venv-reranker-score/bin/python -c "import torch, vllm; print(torch.cuda.is_available(), torch.cuda.get_device_name(0), vllm.__version__)" ./.venv-reranker/bin/python -c "import torch, vllm; print(torch.cuda.is_available(), torch.cuda.get_device_name(0), vllm.__version__)" ``` ### 3. 启动服务 ```bash ./scripts/start_reranker.sh ``` ### 4. Smoke ```bash PYTHONPATH=. ./.venv-reranker-score/bin/python scripts/smoke_qwen3_vllm_score_backend.py --gpu-memory-utilization 0.2 ``` ## `jina_reranker_v3` 该后端参考 Jina 官方模型卡接入,使用: ```python from transformers import AutoModel model = AutoModel.from_pretrained( "jinaai/jina-reranker-v3", dtype="auto", trust_remote_code=True, ) results = model.rerank(query, documents) ``` 服务内实现补了几件工程化工作: - 统一适配 `/rerank` 协议,返回与输入 docs 对齐的 `scores` - 对空文档与重复文档做预处理,避免重复推理 - 支持 `top_n` hint,并保留原始输入顺序输出 - 保留 `cache_dir` / `device` / `dtype` / `batch_size` 等配置项 推荐配置: ```yaml services: rerank: backends: jina_reranker_v3: model_name: "jinaai/jina-reranker-v3" device: null dtype: "float16" batch_size: 64 max_doc_length: 160 max_query_length: 64 sort_by_doc_length: true cache_dir: "./model_cache" trust_remote_code: true ``` T4 实测建议: - `dtype` 优先使用 `float16`;在当前机器上 `auto` 会加载成 `bfloat16`,明显更慢 - 在线短文本商品重排建议从 `batch_size: 64` 起步;它比更大的 listwise block 更快,但会牺牲一部分“完整 listwise”排序一致性 - 若你更看重接近完整 listwise 的排序结果,可提高到 `batch_size: 125`,代价是延迟明显上升 - `max_doc_length: 160`、`max_query_length: 64` 更适合当前商品标题 / 短 query 场景 ## 当前最优方案:`qwen3_vllm_score` ### 关键实现点 `qwen3_vllm_score.py` 里值得关注的地方: - `runner` / `convert` 保持 **auto**:走 **pooling / classify** 与 **`LLM.score()`** 的推荐接法(vLLM 0.17+) - `hf_overrides`:把原始 Qwen3 reranker 权重按官方要求映射到 `Qwen3ForSequenceClassification` - `LLM(...)` 仅使用本后端所需的模型与并行等参数;**attention 后端由 vLLM 内部按运行环境选用** - `deduplicate_with_positions(...)`:先去重,再回填原始顺序 - `sort_by_doc_length`:减少 padding 浪费 - `infer_batch_size`:控制服务层分批 - `enable_prefix_caching`:(作用每检验过) - `self._infer_lock`:避免当前进程模型下并发调用破坏 vLLM engine 稳定性 ### Attention 与算力路径(现状) - **vLLM** 根据 **GPU 算力架构**与**当前 wheel 中的实现**(如随发行版提供的 **flashinfer** 等)自动选用 attention 路径。 - 在 **Tesla T4(`sm_75`)** + **vLLM 0.18.x** 的已验证环境中,服务日志中可见选用 **`FLASHINFER`**。 #### attention后端对比 | 后端 | 计算能力要求 | 特点 | 适用场景 | | ----------------------------- | --------------- | ---------------- | ----------------------- | | **FLASH\_ATTN (FA2/FA3/FA4)** | ≥ 8.0 (Ampere+) | 最高性能,手写 CUDA 内核 | A100/H100 等高端卡 | | **FLASHINFER** | 7.x-9.x (JIT) | 灵活定制,支持多种变体 | 需要特殊 attention mask | | **TRITON\_ATTN** | 任意 | 纯 Triton,跨平台,零依赖 | 旧 GPU / AMD / fallback | | **XFORMERS** | 任意 | 替代方案,灵活性高 | 兼容性优先 | ### 推荐配置 当前项目统一使用 `standard`,README 也按这个基线描述: ```yaml services: rerank: backend: "qwen3_vllm_score" backends: qwen3_vllm_score: model_name: "Qwen/Qwen3-Reranker-0.6B" use_original_qwen3_hf_overrides: true engine: "vllm" max_model_len: 256 tensor_parallel_size: 1 gpu_memory_utilization: 0.20 dtype: "float16" enable_prefix_caching: true enforce_eager: false infer_batch_size: 100 sort_by_doc_length: true instruction_format: standard instruction: "Rank products by query with category & style match prioritized" ``` ### 关键实现点 - `AutoTokenizer.apply_chat_template(...)` - `SamplingParams(max_tokens=1, allowed_token_ids=[yes, no])` - `generate(...)` 后从最后一步 logprobs 计算 yes/no 概率 - 同样具备去重、按长度排序、分批推理、前缀缓存、单进程锁等优化 ### 推荐配置 ```yaml services: rerank: backends: qwen3_vllm: model_name: "Qwen/Qwen3-Reranker-0.6B" engine: "vllm" max_model_len: 256 tensor_parallel_size: 1 gpu_memory_utilization: 0.20 dtype: "float16" enable_prefix_caching: true enforce_eager: false infer_batch_size: 100 sort_by_doc_length: true instruction_format: standard instruction: "Rank products by query with category & style match prioritized" ``` ## benchmark 建议流程 推荐流程: 1. 确认目标 backend 已切换到正确配置 2. `./scripts/start_reranker.sh` 3. `curl http://127.0.0.1:6007/health` 4. 跑 benchmark 脚本 5. 保存 JSON 和 Markdown 结果 6. 记录当时的 GPU 占用情况和 `nvidia-smi` ## 常见问题 ### 1. 为什么第一次启动很慢 - 模型加载 - torch.compile - CUDA graph capture - flashinfer / triton JIT ### 3. `qwen3_vllm_score` 的 attention 要在哪里调 **由 vLLM 在运行时按 GPU 与版本自动选择**;与延迟和稳定性更直接相关、且建议在仓库里动的,是 **`max_model_len`**、**`infer_batch_size`**、**`gpu_memory_utilization`**、去重、排序分批、prefix cache 等。 ## 代码阅读建议 1. `reranker/backends/qwen3_vllm_score.py` 2. `reranker/backends/qwen3_vllm.py` 3. `scripts/start_reranker.sh` 4. `scripts/setup_reranker_venv.sh` 5. `config/config.yaml` 里的 `services.rerank.backends.*` ## 性能测试、对比 ```bash ll tests/reranker_performance/ curl1.sh curl1_simple.sh rerank_performance_compare.sh ```