Commit fb973d19cdee6ce7db1611c9b7a306e3fab08628
1 parent
00c8ddb9
configs
Showing
13 changed files
with
50 additions
and
63 deletions
Show diff stats
.gitignore
@ deleted
| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | - | |
| 2 | -# Please enter the commit message for your changes. Lines starting | |
| 3 | -# with '#' will be ignored, and an empty message aborts the commit. | |
| 4 | -# | |
| 5 | -# On branch master | |
| 6 | -# Your branch is ahead of 'origin/master' by 3 commits. | |
| 7 | -# (use "git push" to publish your local commits) | |
| 8 | -# | |
| 9 | -# Changes to be committed: | |
| 10 | -# modified: README.md | |
| 11 | -# modified: docs/Usage-Guide.md | |
| 12 | -# modified: scripts/service_ctl.sh | |
| 13 | -# new file: status.sh | |
| 14 | -# | |
| 15 | -# Changes not staged for commit: | |
| 16 | -# modified: third-party/clip-as-service (untracked content) | |
| 17 | -# |
] deleted
| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | -docs | |
| 2 | -# Please enter the commit message for your changes. Lines starting | |
| 3 | -# with '#' will be ignored, and an empty message aborts the commit. | |
| 4 | -# | |
| 5 | -# On branch master | |
| 6 | -# Your branch is ahead of 'origin/master' by 5 commits. | |
| 7 | -# (use "git push" to publish your local commits) | |
| 8 | -# | |
| 9 | -# Changes to be committed: | |
| 10 | -# modified: config/config.yaml | |
| 11 | -# modified: docs/TODO.txt | |
| 12 | -# modified: "docs/\346\220\234\347\264\242API\345\257\271\346\216\245\346\214\207\345\215\227-07-\345\276\256\346\234\215\345\212\241\346\216\245\345\217\243\357\274\210Embedding-Reranker-Translation\357\274\211.md" | |
| 13 | -# modified: "docs/\347\233\270\345\205\263\346\200\247\346\243\200\347\264\242\344\274\230\345\214\226\350\257\264\346\230\216.md" | |
| 14 | -# | |
| 15 | -# Changes not staged for commit: | |
| 16 | -# modified: third-party/clip-as-service (untracked content) | |
| 17 | -# |
config/config.yaml
| ... | ... | @@ -131,7 +131,7 @@ function_score: |
| 131 | 131 | # 重排配置(provider/URL 在 services.rerank) |
| 132 | 132 | rerank: |
| 133 | 133 | enabled: true |
| 134 | - rerank_window: 384 | |
| 134 | + rerank_window: 400 | |
| 135 | 135 | timeout_sec: 15.0 |
| 136 | 136 | weight_es: 0.4 |
| 137 | 137 | weight_ai: 0.6 |
| ... | ... | @@ -275,7 +275,7 @@ services: |
| 275 | 275 | max_docs: 1000 |
| 276 | 276 | normalize: true |
| 277 | 277 | # 服务内后端(reranker 进程启动时读取) |
| 278 | - backend: "qwen3_transformers" # bge | qwen3_vllm | qwen3_transformers | dashscope_rerank | |
| 278 | + backend: "qwen3_vllm" # bge | qwen3_vllm | qwen3_transformers | dashscope_rerank | |
| 279 | 279 | backends: |
| 280 | 280 | bge: |
| 281 | 281 | model_name: "BAAI/bge-reranker-v2-m3" |
| ... | ... | @@ -296,15 +296,18 @@ services: |
| 296 | 296 | enforce_eager: false |
| 297 | 297 | infer_batch_size: 100 |
| 298 | 298 | sort_by_doc_length: true |
| 299 | - length_sort_mode: "char" # char | token | |
| 300 | - instruction: "rank products by given query" | |
| 299 | + # "rank products by given query" 比 “Given a query, score the product for relevance” 更好点 | |
| 300 | + instruction: "rank products by given query" | |
| 301 | + # instruction: "Given a query, score the product for relevance" | |
| 301 | 302 | qwen3_transformers: |
| 302 | 303 | model_name: "Qwen/Qwen3-Reranker-0.6B" |
| 303 | 304 | instruction: "rank products by given query" |
| 305 | + # instruction: "Score the product’s relevance to the given query" | |
| 304 | 306 | max_length: 8192 |
| 305 | 307 | batch_size: 64 |
| 306 | 308 | use_fp16: true |
| 307 | - attn_implementation: "flash_attention_2" | |
| 309 | + # sdpa:默认无需 flash-attn;若已安装 flash_attn 可改为 flash_attention_2 | |
| 310 | + attn_implementation: "sdpa" | |
| 308 | 311 | dashscope_rerank: |
| 309 | 312 | model_name: "qwen3-rerank" |
| 310 | 313 | # 按地域选择 endpoint: | ... | ... |
docs/DEVELOPER_GUIDE.md
| ... | ... | @@ -360,7 +360,7 @@ services: |
| 360 | 360 | ### 7.6 新增后端清单(以 Qwen3-Reranker 为例) |
| 361 | 361 | |
| 362 | 362 | 1. **实现协议**:在 `reranker/backends/qwen3_vllm.py` 中实现类,提供 `score_with_meta(query, docs, normalize) -> (scores, meta)`,输出与 docs 等长且顺序一致。 |
| 363 | -2. **配置**:在 `config/config.yaml` 的 `services.rerank.backends` 下增加 `qwen3_vllm` 块(model_name、engine、max_model_len、gpu_memory_utilization、`infer_batch_size`、`sort_by_doc_length`、`length_sort_mode` 等);支持环境变量 `RERANK_BACKEND=qwen3_vllm`。 | |
| 363 | +2. **配置**:在 `config/config.yaml` 的 `services.rerank.backends` 下增加 `qwen3_vllm` 块(model_name、engine、max_model_len、gpu_memory_utilization、`infer_batch_size`、`sort_by_doc_length`等);支持环境变量 `RERANK_BACKEND=qwen3_vllm`。 | |
| 364 | 364 | 3. **注册**:在 `reranker/backends/__init__.py` 的 `get_rerank_backend(name, config)` 中增加 `qwen3_vllm` 分支。 |
| 365 | 365 | 4. **服务启动**:`reranker/server.py` 启动时根据配置调用 `get_rerank_backend(backend_name, backend_cfg)` 得到实例。 |
| 366 | 366 | 5. **调用方**:无需修改;仅部署时启动使用新后端的 reranker 服务即可。 | ... | ... |
docs/TODO.txt
| ... | ... | @@ -21,6 +21,15 @@ |
| 21 | 21 | 如果有: 先做sku筛选,然后把最优的拼接到名称中,参与reranker。 |
| 22 | 22 | |
| 23 | 23 | |
| 24 | +现在在reranker、分页之后、做填充的时候,已经有做sku的筛选。 | |
| 25 | +需要优化: | |
| 26 | +现在是,先做包含的判断,找到第一个 option_value被query包含的,则直接认为匹配。改为 | |
| 27 | +1. 第一轮:遍历完,如果有且仅有一个才这样。 | |
| 28 | +2. 第二轮:如果有多个,跳到3。如果没有,对每个词都走泛化词表进行匹配。 | |
| 29 | +3. 第三轮:如果有多个,那么对这多个,走embedding相关性取最高的。如果一个也没有,则对所有的走embedding相关性取最高的 | |
| 30 | +这个sku筛选也需要提取为一个独立的模块 | |
| 31 | + | |
| 32 | + | |
| 24 | 33 | |
| 25 | 34 | 2026-03-21 10:29:23,698 - elastic_transport.transport - INFO - POST http://localhost:9200/search_products_tenant_163/_search?include_named_queries_score=false [status:200 duration:0.009s] |
| 26 | 35 | 2026-03-21 10:29:23,700 - request_context - INFO - 分页详情回填 | ids=20 | filled=20 | took=7ms | ... | ... |
docs/工作总结-微服务性能优化与架构.md
| ... | ... | @@ -41,7 +41,7 @@ |
| 41 | 41 | - **精度**:`dtype: "float16"`,降低显存与计算量。 |
| 42 | 42 | - **Prefix Caching**:`enable_prefix_caching: true`,对重复前缀(如相同 query)做缓存,减少重复计算。 |
| 43 | 43 | - **CUDA 图**:`enforce_eager: false`(默认),利用 vLLM 的 CUDA graph 降低 kernel 启动开销。 |
| 44 | -- **按文档长度分批**:`sort_by_doc_length: true`,请求内先按文档长度排序再按 `infer_batch_size` 分批推理,减少 padding 浪费;`length_sort_mode: "char"`(更快,短文本推荐)或 `"token"`(更精确)。 | |
| 44 | +- **按文档长度分批**:`sort_by_doc_length: true`,请求内先按文档长度排序再按 `infer_batch_size` 分批推理,减少 padding 浪费。 | |
| 45 | 45 | - **参数搜索结论**:在 T4、1000-doc 口径下对 `infer_batch_size` 做了 24/32/48/64 对比;**单请求延迟(c=1)** 上 `infer_batch_size=64` 最优,故当前默认 `infer_batch_size: 64`;`max_model_len: 256` 满足 query+doc 短文本场景;`gpu_memory_utilization: 0.36` 与 T4 16GB 匹配。 |
| 46 | 46 | |
| 47 | 47 | **具体配置**(`config/config.yaml` → `services.rerank.backends.qwen3_vllm`): |
| ... | ... | @@ -56,7 +56,6 @@ enable_prefix_caching: true |
| 56 | 56 | enforce_eager: false |
| 57 | 57 | infer_batch_size: 64 |
| 58 | 58 | sort_by_doc_length: true |
| 59 | -length_sort_mode: "char" | |
| 60 | 59 | instruction: "Given a shopping query, rank product titles by relevance" |
| 61 | 60 | ``` |
| 62 | 61 | 环境变量覆盖:`RERANK_BACKEND`、`RERANKER_SERVICE_URL`、`RERANK_VLLM_INFER_BATCH_SIZE`、`RERANK_VLLM_SORT_BY_DOC_LENGTH` 等。启停:`./scripts/service_ctl.sh start reranker`,健康:`curl -sS http://127.0.0.1:6007/health`。 | ... | ... |
docs/搜索API对接指南-07-微服务接口(Embedding-Reranker-Translation).md
| ... | ... | @@ -161,7 +161,7 @@ curl "http://localhost:6008/ready" |
| 161 | 161 | |
| 162 | 162 | 说明:默认后端为 `qwen3_vllm`(`Qwen/Qwen3-Reranker-0.6B`),需要可用 GPU 显存。 |
| 163 | 163 | |
| 164 | -补充:`docs` 的请求大小与模型推理 `batch size` 解耦。即使一次传入 1000 条文档,服务端也会按 `services.rerank.backends.qwen3_vllm.infer_batch_size` 自动拆分;若 `sort_by_doc_length=true`,会先按文档长度排序后分批,减少 padding,再按原输入顺序返回分数。`length_sort_mode` 可选 `char`(更快)或 `token`(更精确)。 | |
| 164 | +补充:`docs` 的请求大小与模型推理 `batch size` 解耦。即使一次传入 1000 条文档,服务端也会按 `services.rerank.backends.qwen3_vllm.infer_batch_size` 自动拆分。 | |
| 165 | 165 | |
| 166 | 166 | #### 7.2.1 `POST /rerank` — 结果重排 |
| 167 | 167 | ... | ... |
docs/相关性检索优化说明.md
| ... | ... | @@ -267,3 +267,17 @@ python ./scripts/eval_search_quality.py |
| 267 | 267 | 3. 源语种不在索引语言,翻译全部失败(验证多目标 fallback) |
| 268 | 268 | 4. 自定义 `original_query_fallback_boost_when_translation_missing` 生效 |
| 269 | 269 | 5. 非 `zh/en` 语种字段动态拼接(如 `de/fr/es`) |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | +## reranker方面: | |
| 274 | +BAAI/bge-reranker-v2-m3的一个严重badcase: | |
| 275 | +q=黑色中长半身裙 | |
| 276 | + | |
| 277 | +Rerank score: 0.0785 | |
| 278 | +title.zh: 2026款韩版高腰显瘦雪尼尔包臀裙灯芯绒开叉中长款咖啡色半身裙女 | |
| 279 | +title.en: 2026 Korean-style High-waisted Slimming Corduroy Skirt with Slit, Mid-Length Coffee-colored Skirt for Women | |
| 280 | + | |
| 281 | +Rerank score: 0.9643 | |
| 282 | +title.en: Black Half-high Collar Base Shirt Women's Autumn and Winter fleece-lined Contrast Color Pure Desire Design Sense Horn Sleeve Ruffled Inner Top | |
| 283 | +title.zh: 黑色高领半高领女士秋冬内搭加绒拼色纯欲设计荷叶边袖内衬上衣 | ... | ... |
reranker/DEPLOYMENT_AND_TUNING.md
| ... | ... | @@ -93,19 +93,14 @@ curl -sS http://127.0.0.1:6007/health |
| 93 | 93 | |
| 94 | 94 | - 调用方一次可传入 1000 docs(业务需求) |
| 95 | 95 | - 服务端按 `infer_batch_size` 自动拆批推理(模型效率需求) |
| 96 | - | |
| 97 | -### 4.2 先排序再分批,降低 padding 浪费 | |
| 98 | - | |
| 99 | 96 | - `sort_by_doc_length: true`:按长度排序后再分批 |
| 100 | -- `length_sort_mode: "char"`:短文本场景下开销更低,默认推荐 | |
| 101 | -- `length_sort_mode: "token"`:长度估计更精确,但有额外 tokenizer 开销 | |
| 102 | 97 | |
| 103 | -### 4.3 全局去重后回填 | |
| 98 | +### 4.2 全局去重后回填 | |
| 104 | 99 | |
| 105 | 100 | - 对 docs 进行全局去重(非“仅相邻去重”) |
| 106 | 101 | - 推理后按原请求顺序回填 scores,保证接口契约稳定 |
| 107 | 102 | |
| 108 | -### 4.4 启动稳定性修复 | |
| 103 | +### 4.3 启动稳定性修复 | |
| 109 | 104 | |
| 110 | 105 | - `service_ctl.sh` 对 reranker 使用独立启动路径 |
| 111 | 106 | - 增加“稳定健康检查”(连续健康探测)避免“刚 healthy 即退出”的假阳性 |
| ... | ... | @@ -159,7 +154,7 @@ curl -sS http://127.0.0.1:6007/health |
| 159 | 154 | |
| 160 | 155 | ## 7. 生产建议 |
| 161 | 156 | |
| 162 | -- 默认保持:`infer_batch_size: 64`、`sort_by_doc_length: true`、`length_sort_mode: "char"` | |
| 157 | +- 默认保持:`infer_batch_size: 64`、`sort_by_doc_length: true` | |
| 163 | 158 | - 满足以下条件时可考虑提高到 `96`:业务以吞吐优先、可接受更高单请求延迟、已通过同机同数据压测验证收益 |
| 164 | 159 | - 每次改动后都必须复跑 `benchmark_reranker_1000docs.sh` 并归档结果 |
| 165 | 160 | ... | ... |
reranker/README.md
| ... | ... | @@ -24,7 +24,7 @@ Reranker 服务提供统一的 `/rerank` API,支持可插拔后端(BGE、Qwe |
| 24 | 24 | - `reranker/config.py`:服务端口、MAX_DOCS、NORMALIZE 等(后端参数在 config.yaml) |
| 25 | 25 | |
| 26 | 26 | ## 依赖 |
| 27 | -- 通用:`torch`、`modelscope`、`fastapi`、`uvicorn`(见项目 `requirements.txt` / `requirements_ml.txt`) | |
| 27 | +- 通用:`torch`、`transformers`、`fastapi`、`uvicorn`(隔离环境见 `requirements_reranker_service.txt`;全量 ML 环境另见 `requirements_ml.txt`) | |
| 28 | 28 | - **Qwen3-vLLM 后端**:`vllm>=0.8.5`、`transformers>=4.51.0`(仅当使用 `backend: qwen3_vllm` 时需 vLLM) |
| 29 | 29 | - **Qwen3-Transformers 后端**:`transformers>=4.51.0`、`torch`(无需 vLLM,适合 CPU 或小显存) |
| 30 | 30 | ```bash |
| ... | ... | @@ -53,7 +53,6 @@ services: |
| 53 | 53 | max_model_len: 256 |
| 54 | 54 | infer_batch_size: 64 |
| 55 | 55 | sort_by_doc_length: true |
| 56 | - length_sort_mode: "char" # char | token | |
| 57 | 56 | enable_prefix_caching: true |
| 58 | 57 | enforce_eager: false |
| 59 | 58 | instruction: "Given a shopping query, rank product titles by relevance" |
| ... | ... | @@ -157,7 +156,7 @@ uvicorn reranker.server:app --host 0.0.0.0 --port 6007 --log-level info |
| 157 | 156 | ## Notes |
| 158 | 157 | - 无请求级缓存;输入按字符串去重后推理,再按原始顺序回填分数。 |
| 159 | 158 | - 空或 null 的 doc 跳过并计为 0。 |
| 160 | -- **Qwen3-vLLM 分批策略**:`docs` 请求体可为 1000+,服务端会按 `infer_batch_size` 拆分;当 `sort_by_doc_length=true` 时,会先按文档长度排序后分批,减少 padding 开销,最终再按输入顺序回填分数。`length_sort_mode` 支持 `char`(默认,更快)与 `token`(更精确)。 | |
| 159 | +- **Qwen3-vLLM 分批策略**:`docs` 请求体可为 1000+,服务端会按 `infer_batch_size` 拆分;当 `sort_by_doc_length=true` 时,会先按文档长度排序后分批,减少 padding 开销,最终再按输入顺序回填分数。 | |
| 161 | 160 | - 运行时可用环境变量临时覆盖批量参数:`RERANK_VLLM_INFER_BATCH_SIZE`、`RERANK_VLLM_SORT_BY_DOC_LENGTH`。 |
| 162 | 161 | - **Qwen3-vLLM**:参考 [Qwen3-Reranker-0.6B](https://huggingface.co/Qwen/Qwen3-Reranker-0.6B),需 GPU 与较多显存;与 BGE 相比适合长文本、高吞吐场景(vLLM 前缀缓存)。 |
| 163 | -- **Qwen3-Transformers**:官方 Transformers Usage 方式,无需 vLLM;适合 CPU 或小显存,可选 `attn_implementation: "flash_attention_2"` 加速。 | |
| 162 | +- **Qwen3-Transformers**:官方 Transformers Usage 方式,无需 vLLM;适合 CPU 或小显存。默认 `attn_implementation: "sdpa"`;若已安装 `flash_attn` 可设 `flash_attention_2`(未安装时服务会自动回退到 sdpa)。 | ... | ... |
reranker/backends/qwen3_vllm.py
| ... | ... | @@ -76,7 +76,7 @@ class Qwen3VLLMRerankerBackend: |
| 76 | 76 | dtype = str(self._config.get("dtype", "float16")).strip().lower() |
| 77 | 77 | self._instruction = str( |
| 78 | 78 | self._config.get("instruction") |
| 79 | - or "Given a shopping query, rank product titles by relevance" | |
| 79 | + or "Given a query, score the product for relevance" | |
| 80 | 80 | ) |
| 81 | 81 | infer_batch_size = os.getenv("RERANK_VLLM_INFER_BATCH_SIZE") or self._config.get("infer_batch_size", 64) |
| 82 | 82 | sort_by_doc_length = os.getenv("RERANK_VLLM_SORT_BY_DOC_LENGTH") | ... | ... |
reranker/bge_reranker.py
| ... | ... | @@ -170,13 +170,14 @@ class BGEReranker: |
| 170 | 170 | output_scores[orig_idx] = float(unique_scores[unique_idx]) |
| 171 | 171 | |
| 172 | 172 | # Log per-doc scores (aligned to original docs order) |
| 173 | - try: | |
| 174 | - lines = [] | |
| 175 | - for i, d in enumerate(docs[:100]): | |
| 176 | - lines.append(f"{output_scores[i]},{'' if d is None else str(d)}") | |
| 177 | - logger.info("[BGE_RERANKER] query:%s Scores (score,doc):\n%s", query, "\n".join(lines)) | |
| 178 | - except Exception: | |
| 179 | - pass | |
| 173 | + if 0: | |
| 174 | + try: | |
| 175 | + lines = [] | |
| 176 | + for i, d in enumerate(docs[:100]): | |
| 177 | + lines.append(f"{output_scores[i]},{'' if d is None else str(d)}") | |
| 178 | + logger.info("[BGE_RERANKER] query:%s Scores (score,doc):\n%s", query, "\n".join(lines)) | |
| 179 | + except Exception: | |
| 180 | + pass | |
| 180 | 181 | |
| 181 | 182 | elapsed_ms = (time.time() - start_ts) * 1000.0 |
| 182 | 183 | dedup_ratio = 0.0 | ... | ... |