开发与配置指南
新人入口:环境、服务、模块、请求示例、基础配置、Provider 架构、模块扩展规范,一文档搞定。
建议:首次参与开发请先阅读 DEVELOPER_GUIDE.md 建立项目全貌与协作规范,再使用本文做环境与配置速查。
为什么这样整合
以下文档已删除,其核心内容已并入本文与 DEVELOPER_GUIDE.md §7:原 PROVIDER_ARCHITECTURE.md、MODULE_EXTENSION_SPEC.md、基础配置指南.md。本文保留环境、服务、基础配置、Provider 与模块扩展的速查;协议与新增后端清单见 DEVELOPER_GUIDE §7。
关于 docs/Usage-Guide.md:保留为运行/运维手册更清晰(日志、故障排查、多环境切换、建议索引运行细节),本文只保留开发常用且高频的信息,避免一个文档同时承担“开发规范 + 运维 runbook”导致冗长和混乱。
目录
- 快速上手
- 1.1 环境准备 / 1.2 服务与端口 / 1.3 常用 API / 1.4 系统要求 / 1.5 Python 运行环境 / 1.6 外部服务与 .env / 1.7 店匠数据源 / 1.8 相关脚本 / 1.9 配置入口总览
- 基础配置与搜索行为
- Provider 架构
- 模块扩展规范(Embedding / Rerank)
- 验证、日志与常见排障入口
- 相关文档
- 持续集成测试(最小可维护方案)
1. 快速上手
1.1 环境准备
source activate.sh
# 首次创建环境:
./scripts/create_venv.sh
# embedding 服务独立环境(推荐)
./scripts/setup_embedding_venv.sh
# reranker 服务独立环境(Qwen3-vLLM)
./scripts/setup_reranker_venv.sh
# CN-CLIP 独立环境
./scripts/setup_cnclip_venv.sh
依赖:Python 3.8+、Elasticsearch 8.x、MySQL、Redis(可选,缓存用途)。
更详细的系统要求、Python 环境、外部服务与生产凭证见 1.4–1.8。
1.2 服务与端口
| 服务 | 端口 | 默认启动 | 说明 |
|---|---|---|---|
| backend | 6002 | ✓ | 搜索 API(/search/*)+ 管理接口(/admin/*) |
| indexer | 6004 | ✓ | 索引 API(/indexer/*) |
| frontend | 6003 | ✓ | 调试 UI |
| eval-web | 6010 | ✓ | 搜索评估 Web(scripts/evaluation/,依赖 backend 联调) |
| embedding | 6005 | - | 文本向量服务(/embed/text) |
| embedding-image | 6008 | - | 图片向量服务(/embed/image) |
| translator | 6006 | - | 翻译服务(/translate) |
| reranker | 6007 | - | 重排服务(/rerank) |
启动与停止:
./run.sh all
# 仅为薄封装:等价于 ./scripts/service_ctl.sh up all
# 说明:
# - all = tei cnclip embedding embedding-image translator reranker reranker-fine backend indexer frontend eval-web
# - up 会同时启动 monitor daemon(运行期连续失败自动重启)
# - reranker 为 GPU 强制模式(资源不足会直接启动失败)
# - TEI 默认使用 GPU;当 TEI_DEVICE=cuda 且 GPU 不可用时会直接失败(不会自动降级到 CPU)
# - cnclip 默认使用 cuda;若显式配置为 cuda 且 GPU 不可用会直接失败(不会自动降级到 cpu)
./restart.sh all
# 仅为薄封装:等价于 ./scripts/service_ctl.sh restart all
./scripts/service_ctl.sh status
./scripts/stop.sh all # 仅为薄封装:等价于 ./scripts/service_ctl.sh down all
服务管理方式(入口职责、默认行为、全量拉起顺序)见:
docs/Usage-Guide.md->服务管理总览
1.3 常用 API 请求示例
搜索 API(backend 6002)
# 文本搜索
curl -X POST http://localhost:6002/search/ \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 162" \
-d '{"query": "玩具", "size": 10}'
# 图片搜索
curl -X POST http://localhost:6002/search/image \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 162" \
-d '{"image_url": "https://example.com/img.jpg", "size": 10}'
# Suggestion
curl "http://localhost:6002/search/suggestions?q=玩&size=5" \
-H "X-Tenant-ID: 162"
# 健康与统计
curl http://localhost:6002/admin/health
curl http://localhost:6002/admin/stats -H "X-Tenant-ID: 162"
API 文档:http://localhost:6002/docs
索引 API(indexer 6004)
# 创建租户索引
./scripts/create_tenant_index.sh 162
# 全量重建(更新/写入,不删除旧索引)
curl -X POST http://localhost:6004/indexer/reindex \
-H "Content-Type: application/json" \
-d '{"tenant_id": "162", "batch_size": 500}'
# 增量索引
curl -X POST http://localhost:6004/indexer/index \
-H "Content-Type: application/json" \
-d '{"tenant_id": "162", "spu_ids": ["1001", "1002"]}'
# 构建文档(不写 ES)
curl -X POST http://localhost:6004/indexer/build-docs \
-H "Content-Type: application/json" \
-d '{"tenant_id":"162","items":[{"spu":{},"skus":[],"options":[]}]}'
API 文档:http://localhost:6004/docs
Embedding 服务(文本 6005 / 图片 6008)
# TEI(文本向量后端,默认)
# GPU(需 nvidia-container-toolkit)
TEI_DEVICE=cuda ./scripts/start_tei_service.sh
# Embedding API(text 会校验 TEI /health)
./scripts/start_embedding_text_service.sh
./scripts/start_embedding_image_service.sh
curl -X POST http://localhost:6005/embed/text \
-H "Content-Type: application/json" \
-d '["衣服", "Bohemian Maxi Dress"]'
curl -X POST http://localhost:6008/embed/image \
-H "Content-Type: application/json" \
-d '["https://example.com/img.jpg"]'
说明:
- TEI 默认镜像按
TEI_VERSION组装:cuda-<version>(默认1.9)。 TEI_DEVICE=cuda时会严格校验 Docker GPU runtime;未配置会直接报错退出。/embed/image依赖cnclip(grpc://127.0.0.1:51000),未启动时图片 embedding 服务会启动失败。
Translator 服务(6006)
./scripts/setup_translator_venv.sh
./.venv-translator/bin/python scripts/download_translation_models.py --all-local # 如需本地模型
./scripts/start_translator.sh
curl -X POST http://localhost:6006/translate \
-H "Content-Type: application/json" \
-d '{"text":"商品名称","target_lang":"en","source_lang":"zh","model":"qwen-mt","scene":"sku_name"}'
说明:
- translator service 是翻译统一入口,业务侧不再直接选择翻译 provider。
- 本地模型默认关闭;需先在
config/config.yaml -> services.translation.capabilities中启用,再通过model指定。
Reranker 服务(6007)
# 默认后端 qwen3_vllm(Qwen3-Reranker-0.6B)
./scripts/start_reranker.sh
curl -X POST http://localhost:6007/rerank \
-H "Content-Type: application/json" \
-d '{"query":"wireless mouse","docs":["logitech mx master","usb cable"]}'
1.4 系统要求
- 操作系统:Linux(推荐 Ubuntu 18.04+)
- Python:3.10(由 venv 提供)
- 内存:建议 8GB+(含模型与 ES)
- 磁盘:10GB+(含模型与索引)
1.5 Python 运行环境(详细)
项目根目录的 activate.sh 激活 .venv 并加载当前目录 .env。
cd /data/saas-search
./scripts/create_venv.sh
source activate.sh
主程序 .venv 与模型服务环境隔离:
- 主程序:
.venv(./scripts/create_venv.sh) - embedding 服务:
.venv-embedding(./scripts/setup_embedding_venv.sh) - reranker 服务:
.venv-reranker(./scripts/setup_reranker_venv.sh) - cnclip:
.venv-cnclip(./scripts/setup_cnclip_venv.sh) - TEI:Docker 容器(
./scripts/start_tei_service.sh)
1.6 外部服务与 .env(含生产凭证)
以下为 AI 生产环境 统一使用的地址与凭证(Redis / ES / MySQL 均以此为准)。本地开发可将 DB_HOST/ES_HOST/REDIS_HOST 改为 localhost(服务在本机时)。
| 服务 | 地址(生产) | 端口 | 说明 |
|---|---|---|---|
| MySQL | 10.200.16.14 / localhost | 3316 | 店匠 SPU/SKU 数据 |
| Redis | 10.200.16.14 / localhost | 6479 | Embedding/翻译缓存 |
| Elasticsearch | 10.200.16.14 / localhost | 9200 | 搜索索引 |
MySQL(AI 生产推荐使用 root,3 个用户均可远程登录):
| 用户 | 密码 | 说明 |
|---|---|---|
| root | qY8tgodLoA&KT#yQ | AI 生产推荐 |
| saas | 6dlpco6dVGuqztl | 业务用户 |
| sa | C#HU!GPps7ck8tsM | 备用 |
创建远程用户(如尚未创建):
mysql -uroot -p'qY8tgodLoA&KT#yQ'
CREATE USER 'saas'@'%' IDENTIFIED BY '6dlpco6dVGuqzt^l';
CREATE USER 'sa'@'%' IDENTIFIED BY 'C#HU!GPps7ck8tsM';
Redis:
- 地址:
10.200.16.14:6479 - 密码:
dxEkegEZ@C5SXWKv - 远程登录示例:
redis-cli -h 10.200.16.14 -p 6479 -a 'dxEkegEZ@C5SXWKv' --no-auth-warning
Elasticsearch:
- 用户名/密码:
saas/4hOaLaf41y2VuI8y - 访问示例:
curl -u 'saas:4hOaLaf41y2VuI8y' \
-X GET 'http://localhost:9200/search_products_tenant_111/_search?pretty' \
-H 'Content-Type: application/json' \
-d '{
"size": 11,
"_source": ["title"],
"query": {
"bool": {
"filter": [
{ "term": {"spu_id" : 206150} }
]
}
}
}'
注意(Kibana 运维):应用侧
.env的ES_USERNAME/ES_PASSWORD仅用于业务服务访问 ES;Kibana 不应复用该账号。Kibana 推荐在/etc/kibana/kibana.yml使用elasticsearch.serviceAccountToken,否则在.kibana_*受限索引迁移阶段可能出现security_exception并导致 5601 长时间无响应。
在项目根目录创建 .env:
./scripts/init_env.sh # 从 .env.example 复制(若 .env 不存在)
然后按环境修改 .env。含特殊字符(#、$、&、空格)的密码需加引号,例如:
# MySQL(AI 生产 10.200.16.14:3316,推荐 root)
DB_HOST=10.200.16.14
DB_PORT=3316
DB_DATABASE=saas
DB_USERNAME=root
DB_PASSWORD="qY8tgodLoA&KT#yQ"
# Elasticsearch
ES_HOST=http://10.200.16.14:9200
ES_USERNAME=saas
ES_PASSWORD="4hOaLaf41y2VuI8y"
# Redis(可选)
REDIS_HOST=10.200.16.14
REDIS_PORT=6479
REDIS_PASSWORD="dxEkegEZ@C5SXWKv"
# DeepL 翻译(按需)
DEEPL_AUTH_KEY=your-key
# API
API_HOST=0.0.0.0
API_PORT=6002
EVAL_WEB_PORT=6010
生产环境请妥善保管凭证;本地/测试可改用上述值或自建实例。
1.7 店匠数据源说明
saas-search 以 MySQL 中的店匠标准表为权威数据源:
shoplazza_product_spu:SPU 商品主表shoplazza_product_sku:SKU 变体表
shoplazza_product_sku 字段节选:id, spu_id, shop_id, title, sku, price, compare_at_price, option1/2/3, inventory_quantity, image_src, tenant_id, create_time, update_time, deleted 等。完整字段与 ES 对应关系见 INDEX_FIELDS_DOCUMENTATION.md(若有)。
1.8 相关脚本
activate.sh(项目根目录):激活 Python 环境并加载.env,日常开发/部署以本脚本为准。scripts/create_venv.sh:创建主程序 venv(.venv)scripts/setup_embedding_venv.sh:创建 embedding 服务 venv(.venv-embedding)scripts/setup_reranker_venv.sh:创建 reranker 服务 venv(.venv-reranker)scripts/start_tei_service.sh:启动 TEI 容器(文本向量后端)scripts/mock_data.sh:生成 Tenant1 Mock + Tenant2 CSV 并导入 MySQLscripts/create_tenant_index.sh <tenant_id>:创建租户 ES 索引结构POST /indexer/reindex:从 MySQL 全量导入到 ESrun.sh/restart.sh/scripts/stop.sh:推荐入口(对应 up/restart/down)scripts/service_ctl.sh:up/down/start/stop/restart/status/monitor/monitor-start/monitor-stop/monitor-status
更多脚本与验证命令见 docs/Usage-Guide.md。
1.9 配置入口总览
- 搜索行为配置:
config/config.yaml - 索引结构定义:
mappings/search_products.json - provider/服务配置:
config/config.yaml的services块 - 环境变量:
.env
---·
2. 基础配置与搜索行为
2.1 总体原则
- 统一索引结构:所有租户使用同一套 mapping(按租户数据分索引名 + 文档内
tenant_id隔离) - SPU 级索引:每个文档是一个 SPU,包含嵌套
skus、specifications - 配置文件驱动:搜索权重、动态多语言字段、重排融合、provider 全在
config/config.yaml,不再以“硬编码配置”为主
2.2 索引结构(Mapping)
文件:mappings/search_products.json
核心字段可分为:
- 标识字段:
tenant_id,spu_id - 多语言文本:
title.<lang>,brief.<lang>,description.<lang>,vendor.<lang>,category_path.<lang>,category_name_text.<lang> - 类目过滤:
category1_name,category2_name,category3_name等 - 规格/变体:
specifications(nested)、skus(nested) - 价格库存:
min_price,max_price,total_inventory等 - 向量:
title_embedding(dense vector)、image_embedding(nested)
2.3 查询、权重、排序(config/config.yaml)
field_boosts:字段权重(统一按字段基名配置,运行时按.{lang}动态组装)query_config.search_fields:动态多语言检索字段(multilingual/shared/core)query_config.text_query_strategy:文本召回策略参数(minimum_should_match、翻译boost、翻译失败原文兜底boost等)query_config:语言、embedding 开关、source_fields、knn_boost、翻译提示词等function_score:ES 层加权函数rerank:重排窗口、超时、ES/AI 融合权重
2.4 分面与返回字段
- 分面字段通常包括:
category1_name、category2_name、category3_name、specifications.* query_config.source_fields控制返回字段(null=全部,[]=不返回 source,列表=指定字段)- 多语言返回遵循请求 language 与字段回退策略
2.5 修改配置时怎么做
| 修改项 | 操作 |
|---|---|
| 索引结构(mapping) | 修改 mappings/search_products.json → ./scripts/create_tenant_index.sh <tenant_id> → 重新导入 |
| 搜索字段/权重/排序/重排 | 修改 config/config.yaml 对应块 |
| provider 与服务 URL | 修改 config/config.yaml 的 services 块;translation 的 service_url/default_model/default_scene 只认 YAML,embedding/rerank 仍可按需用环境变量覆盖 |
3. 能力接入架构
目标:调用方稳定、配置可切换、单一配置源。
3.1 当前代码结构
- 模块:
providers/+translation/ - 工厂:
translation.create_translation_client()、create_embedding_provider()、create_rerank_provider() - 配置解析:
config/services_config.py
| 能力 | 调用入口 | 服务内实现 |
|---|---|---|
| translation | translation/client.py |
translation/service.py + translation/backends/ |
| embedding | providers/embedding.py(http) |
embedding 服务内 backend |
| rerank | providers/rerank.py(http) |
reranker 服务内 backend |
3.2 配置与覆盖
统一在 config/config.yaml:
services:
translation:
service_url: "http://127.0.0.1:6006"
default_model: "llm"
default_scene: "general"
timeout_sec: 10.0
capabilities:
qwen-mt: { enabled: true, backend: "qwen_mt", model: "qwen-mt-flash", base_url: "https://dashscope-us.aliyuncs.com/compatible-mode/v1", timeout_sec: 10.0, use_cache: true }
llm: { enabled: true, backend: "llm", model: "qwen-flash", base_url: "https://dashscope-us.aliyuncs.com/compatible-mode/v1", timeout_sec: 30.0 }
deepl: { enabled: false, backend: "deepl", api_url: "https://api.deepl.com/v2/translate", timeout_sec: 10.0 }
nllb-200-distilled-600m: { enabled: false, backend: "local_nllb", model_id: "facebook/nllb-200-distilled-600M" }
opus-mt-zh-en: { enabled: false, backend: "local_marian", model_id: "Helsinki-NLP/opus-mt-zh-en" }
opus-mt-en-zh: { enabled: false, backend: "local_marian", model_id: "Helsinki-NLP/opus-mt-en-zh" }
embedding:
provider: "http"
backend: "tei"
providers:
http: { text_base_url: "http://127.0.0.1:6005", image_base_url: "http://127.0.0.1:6008" }
backends:
tei: { base_url: "http://127.0.0.1:8080", timeout_sec: 60, model_id: "Qwen/Qwen3-Embedding-0.6B" }
rerank:
provider: "http"
backend: "qwen3_vllm" # bge | qwen3_vllm | qwen3_transformers | dashscope_rerank
providers:
http: { base_url: "http://127.0.0.1:6007", service_url: "http://127.0.0.1:6007/rerank" }
环境变量覆盖(优先级更高):
EMBEDDING_TEXT_SERVICE_URLEMBEDDING_IMAGE_SERVICE_URLEMBEDDING_BACKENDTEI_BASE_URLRERANKER_SERVICE_URLRERANK_BACKEND(服务内后端)RERANK_DASHSCOPE_API_KEY_CN/RERANK_DASHSCOPE_API_KEY_US(dashscope_rerank后端鉴权)RERANK_DASHSCOPE_ENDPOINT(dashscope_rerank地域 endpoint 覆盖)
3.3 新增接入能力的最小步骤
- translation 新增能力:
在
translation/backends/实现 backend,在translation/service.py注册,并在services.translation.capabilities增加配置。 - embedding / rerank 新增调用方式:
在
providers/<capability>.py实现 provider 类,并在create_*_provider()注册。 - embedding / rerank 新增服务内模型:
在对应服务的
backends/下实现并注册,在services.<capability>.backends新增配置。
说明:
- translation 的 scene 规则、语言码映射、prompt 模板、模型方向约束位于
translation/内部,不再放到config/。 - 翻译公共接口只暴露
model + scene,不暴露prompt。 - translation 的
service_url、default_model、default_scene来自config/config.yaml -> services.translation,不再由环境变量静默覆盖。
4. 模块扩展规范(Embedding / Rerank)
这里重点区分两层:
- Provider 层(调用方式):调用方如何访问能力(http/direct)
- Backend 层(推理实现):服务进程内部具体模型实现(tei / local_st / qwen3_vllm / ...)
4.1 Rerank(重排)扩展
调用链:
search/rerank_client.py -> create_rerank_provider() -> HttpRerankProvider -> POST /rerank
服务实现:
reranker/server.pyreranker/backends/__init__.py(工厂)reranker/backends/bge.pyreranker/backends/qwen3_vllm.pyreranker/backends/qwen3_transformers.pyreranker/backends/dashscope_rerank.py
后端协议(服务内):
- 实现
score_with_meta(query, docs, normalize) -> (scores, meta) - 返回
scores与输入docs等长且顺序一致
配置位置:
config/config.yaml -> services.rerank.backend + services.rerank.backends.<name>
4.2 Embedding(向量化)扩展
调用链:
create_embedding_provider() -> POST /embed/text / POST /embed/image
服务实现:
embeddings/server.py(文本和图像可独立加载)- 文本后端默认
TEI(Qwen3-Embedding-0.6B) - 图像后端支持本地 CLIP 或 clip-as-service
扩展建议:
- 文本后端统一提供批量编码能力(与输入索引对齐)
- 图像后端实现
ImageEncoderProtocol(encode_image_urls) - 如后续后端增多,建议与 rerank 一样在
services.embedding.backend(s)统一配置
选型建议(Qwen3-Embedding-0.6B):
- 当前仓库默认:
TEI(Text Embeddings Inference) - 生产高并发优先:
TEI通常比 vLLM 更贴合 embedding-only 场景 vLLM更适合生成式/重排混合场景;若仅做文本 embedding,通常不作为首选
4.3 新增后端检查清单(以 qwen3_vllm 为例)
- 实现后端协议(服务内)
- 在后端工厂注册(如
get_rerank_backend) - 增加
config/config.yaml对应 backend 配置 - 提供健康检查中的 backend/model 可观测信息
- 保持外部 HTTP 契约不变,调用方无需改造
5. 验证、日志与常见排障入口
5.1 快速健康检查
curl http://localhost:6002/health
curl http://localhost:6002/admin/health
curl http://localhost:6004/health
curl http://localhost:6005/health
curl http://localhost:6008/health
curl http://localhost:6006/health
curl http://localhost:6007/health
# eval-web(若已启动):根路径可访问即正常
curl -sf -o /dev/null http://localhost:6010/ || true
5.2 常看日志
logs/<service>-YYYY-MM-DD.log(service_ctl.sh按天写入的真实文件)logs/<service>.log(指向当天文件的软链,推荐tail -F)logs/service-monitor.log(service_ctl.sh monitor运行期健康检查、失败计数、自动重启日志)logs/api.log(backend 进程内日志,按天轮转)logs/backend_verbose.log(backend 大对象详细日志,按天轮转)logs/indexer.log(索引结构化 JSON 日志,按天轮转)
5.3 常用排障命令
./scripts/service_ctl.sh status
curl http://localhost:9200
lsof -i :6002
lsof -i :6004
lsof -i :6010
更完整的运行排障(多环境切换、Suggestion 构建、FAQ)见 docs/Usage-Guide.md。
5.4 HanLP 与 transformers 版本(BertTokenizer.encode_plus)
若日志出现 AttributeError: BertTokenizer has no attribute encode_plus,通常是 同一 venv 里装了 transformers 5.x,与 HanLP 2.1.x 不兼容(HanLP 仍调用已移除的 encode_plus)。
处理: 将 transformers 固定到 4.x(例如 4.44+),然后重装/校验 HanLP:
source activate.sh
pip install -r requirements_hanlp.txt
python -c "from transformers import BertTokenizer; import transformers as t; print(t.__version__, hasattr(BertTokenizer, 'encode_plus'))"
# 期望:4.x 且 True
说明: 重排/TEI 等若使用 独立 venv(如 .venv-reranker),可与主 venv 的 transformers 版本分离;主 venv 只要装了 HanLP 做查询分词,就不要把 transformers 升到 5。
6. 相关文档
| 文档 | 用途 |
|---|---|
docs/DEVELOPER_GUIDE.md |
项目全貌、规范、协作方式 |
docs/Usage-Guide.md |
运行运维手册:日志、多环境、故障排查、Suggestion 运维 |
docs/搜索API速查表.md |
搜索 API 参数速查 |
docs/搜索API对接指南.md |
搜索 API 完整说明 |
indexer/README.md |
索引模块职责与接口 |
embeddings/README.md |
向量化服务说明 |
docs/TEI_SERVICE说明文档.md |
TEI 专项(安装、部署、GPU/CPU 模式、排障) |
docs/CNCLIP_SERVICE说明文档.md |
CN-CLIP/clip-as-service 专项(环境、GPU、运维) |
reranker/README.md |
重排服务说明 |
7. 持续集成测试(最小可维护方案)
目标:让后续开发者在不依赖真实 ES/MySQL/模型服务的前提下,快速验证核心服务契约不被破坏。
7.1 测试范围
tests/ci/test_service_api_contracts.py 覆盖:
- 搜索接口:
/search/、/search/image、/search/suggestions - 索引接口:
/indexer/reindex、/indexer/index、/indexer/build-docs - 向量服务:
/embed/text、/embed/image - 翻译服务:
/translate、/health - 重排服务:
/rerank、/health
7.2 运行方式
source activate.sh
python -m pytest tests/ci -q
7.3 设计取舍
- 使用 mock/stub 注入依赖,确保测试快且稳定
- 重点测“接口契约与参数行为”,而不是底层模型质量
- 作为 PR 级门禁;真实环境联调放在运维/预发布流程