搜索API对接指南-07-微服务接口(Embedding-Reranker-Translation).md 17.5 KB

搜索API对接指南-07-微服务接口(Embedding-Reranker-Translation)

本篇覆盖向量服务(Embedding)、重排服务(Reranker)、翻译服务(Translation)以及 Indexer 服务内的内容理解字段生成(原文第 7 章)。

7. 微服务接口(向量、重排、翻译)

以下三个微服务独立部署,外部系统可直接调用。它们被搜索后端(6002)和索引服务(6004)内部使用,也可供其他业务系统直接对接。

服务 默认端口 Base URL 说明
向量服务(文本) 6005 http://localhost:6005 文本向量化,用于 query/doc 语义检索
向量服务(图片 / 多模态 CN-CLIP) 6008 http://localhost:6008 图片向量 /embed/image;同空间文本向量 /embed/clip_text(以文搜图等)
翻译服务 6006 http://localhost:6006 多语言翻译(云端与本地模型统一入口)
重排服务 6007 http://localhost:6007 对检索结果进行二次排序

生产环境请将 localhost 替换为实际服务地址。 服务管理入口与完整启停规则见:docs/Usage-Guide.md -> 服务管理总览

7.1 向量服务(Embedding)

  • Base URL:
    • 文本:http://localhost:6005(可通过 EMBEDDING_TEXT_SERVICE_URL 覆盖)
    • 图片:http://localhost:6008(可通过 EMBEDDING_IMAGE_SERVICE_URL 覆盖)
  • 启动:
    • 文本:./scripts/start_embedding_text_service.sh
    • 图片:./scripts/start_embedding_image_service.sh
  • 依赖:
    • 文本向量后端默认走 TEI(http://127.0.0.1:8080
    • 图片向量依赖 cnclipgrpc://127.0.0.1:51000
    • TEI 默认使用 GPU(TEI_DEVICE=cuda);当配置为 GPU 且不可用时会启动失败(不会自动降级到 CPU)
    • cnclip 默认使用 cuda;若配置为 cuda 但 GPU 不可用会启动失败(不会自动降级到 cpu
    • 当前单机部署建议保持单实例,通过文本/图片拆分 + 独立限流隔离压力

补充说明:

  • 文本和图片现在已经拆成不同进程 / 不同端口,避免图片下载与编码波动影响文本向量化。
  • 服务端对 text / image 有独立 admission control
    • TEXT_MAX_INFLIGHT
    • IMAGE_MAX_INFLIGHT
  • 当超过处理能力时,服务会直接返回过载错误,而不是无限排队。
  • 文本与图片服务均支持 priority query 参数(图片不做队列插队,仅 admission 规则与文本一致):
    • priority=0(默认):适合离线索引,仍分别受 TEXT_MAX_INFLIGHT / IMAGE_MAX_INFLIGHT admission control 约束。
    • priority>0(建议在线请求用 1):不会因 admission control 被拒绝,但仍会占用对应 text/image 的 inflight。
    • 文本服务端会优先处理高优先级文本请求;图片端不实现插队,顺序按请求到达处理即可。
  • GET /health 会返回各自的 limitsstatscache_enabled 等状态;GET /ready 用于就绪探针。

7.1.1 POST /embed/text — 文本向量化

将文本列表转为 1024 维向量,用于语义搜索、文档索引等。

请求体(JSON 数组):

["文本1", "文本2", "文本3"]

响应(JSON 数组,与输入一一对应):

[[0.01, -0.02, ...], [0.03, 0.01, ...], ...]

完整 curl 示例:

curl -X POST "http://localhost:6005/embed/text?normalize=true&priority=1" \
  -H "Content-Type: application/json" \
  -d '["芭比娃娃 儿童玩具", "纯棉T恤 短袖"]'

说明:

  • 在线 query / 实时请求:建议显式传 priority=1
  • 离线索引 / 批量回填:保持默认 priority=0 即可

7.1.2 POST /embed/image — 图片向量化

将图片 URL 或路径转为向量,用于以图搜图。

前置条件:cnclip 服务已启动(默认端口 51000)。若未启动,图片 embedding 服务启动会失败或请求返回错误。

请求体(JSON 数组):

["https://example.com/image1.jpg", "https://example.com/image2.jpg"]

响应(JSON 数组,与输入一一对应):

[[0.01, -0.02, ...], [0.03, 0.01, ...], ...]

完整 curl 示例:

curl -X POST "http://localhost:6008/embed/image?normalize=true&priority=1" \
  -H "Content-Type: application/json" \
  -d '["https://oss.essa.cn/98532128-cf8e-456c-9e30-6f2a5ea0c19f.jpg"]'

在线以图搜图等实时场景可传 priority=1;离线索引回填保持默认 priority=0

7.1.3 POST /embed/clip_text — CN-CLIP 文本多模态向量(与图片同空间)

自然语言短语编码为向量,与 POST /embed/image 输出的图向量处于同一向量空间(Chinese-CLIP 文本塔 / 图塔),用于 以文搜图、与 ES image_embedding 对齐的 KNN 等。默认配置为 ViT-H-14,向量长度 1024(与 mappings/search_products.jsonimage_embedding.vector.dims 一致);若改为 ViT-L-14 则为 768 维,须同步索引映射与全量重索引。

7.1.1POST /embed/text(TEI/BGE,语义检索)不是同一模型、不是同一空间,请勿混用。

请求体(JSON 数组,每项为字符串;不要传入 http:// / https:// 图片 URL,图片请用 /embed/image):

["纯棉短袖T恤", "芭比娃娃连衣裙"]

响应(JSON 数组,与输入一一对应):

[[0.01, -0.02, ...], [0.03, 0.01, ...], ...]

curl 示例:

curl -X POST "http://localhost:6008/embed/clip_text?normalize=true&priority=1" \
  -H "Content-Type: application/json" \
  -d '["纯棉短袖", "street tee"]'

说明:与 /embed/image 共用图片侧限流与 IMAGE_MAX_INFLIGHT;Redis 缓存键 namespace 为 clip_text,与 TEI 文本缓存区分。

7.1.4 GET /health — 健康检查

curl "http://localhost:6005/health"
curl "http://localhost:6008/health"

返回中会包含:

  • service_kindtext / image / all
  • cache_enabled:text/image/clip_text Redis 缓存是否可用
  • limits:当前 inflight limit、active、rejected_total 等
  • stats:request_total、cache_hits、cache_misses、avg_latency_ms 等

7.1.5 GET /ready — 就绪检查

curl "http://localhost:6005/ready"
curl "http://localhost:6008/ready"

7.1.6 缓存与限流说明

  • 文本与图片都会先查 Redis 向量缓存。
  • Redis 中 value 仍是 BF16 bytes,读取后恢复成 float32 返回。
  • cache key 已区分 normalize=true/false,避免不同归一化策略命中同一条缓存。
  • 当服务端发现请求是 full-cache-hit 时,会直接返回,不占用模型并发槽位。
  • 当服务端发现超过 TEXT_MAX_INFLIGHT / IMAGE_MAX_INFLIGHT 时,会直接拒绝,而不是无限排队。
  • 其中 POST /embed/textpriority=0 会按上面的 inflight 规则直接拒绝;priority>0 不会被 admission 拒绝,但仍计入 inflight,并在服务端排队时优先于 priority=0 请求。
  • POST /embed/imagepriority=0IMAGE_MAX_INFLIGHT 约束;priority>0 不会被 admission 拒绝,但仍计入 inflight(无插队)。
  • POST /embed/clip_text/embed/image 共用同一后端与 IMAGE_MAX_INFLIGHT(计入图片侧并发)。

7.1.7 TEI 统一调优建议(主服务)

使用单套主服务即可同时兼顾:

  • 在线 query 向量化(低延迟,常见 batch=1~4
  • 索引构建向量化(高吞吐,常见 batch=15~20

统一启动(主链路):

./scripts/start_tei_service.sh
./scripts/service_ctl.sh restart embedding

默认端口:

  • TEI: http://127.0.0.1:8080
  • 文本向量服务(/embed/text): http://127.0.0.1:6005
  • 图片向量服务(/embed/image/embed/clip_text): http://127.0.0.1:6008

当前主 TEI 启动默认值(已按 T4/短文本场景调优):

  • TEI_MAX_BATCH_TOKENS=4096
  • TEI_MAX_CLIENT_BATCH_SIZE=24
  • TEI_DTYPE=float16

7.2 重排服务(Reranker)

  • Base URL: http://localhost:6007(可通过 RERANKER_SERVICE_URL 覆盖)
  • 启动: ./scripts/start_reranker.sh

说明:默认后端为 qwen3_vllmQwen/Qwen3-Reranker-0.6B),需要可用 GPU 显存。

补充:若切换到 jina_reranker_v3,在当前 Tesla T4 上建议使用:

  • dtype: float16
  • batch_size: 64
  • max_doc_length: 160
  • max_query_length: 64
  • sort_by_doc_length: true

原因:jina_reranker_v3auto 在当前机器上会落到 bfloat16,性能明显差于 float16;而它的 listwise 架构在 T4 上对上下文长度更敏感,过大的 batch 会显著拉长延迟。

补充:docs 的请求大小与模型推理 batch size 解耦。即使一次传入 1000 条文档,服务端也会按 services.rerank.backends.qwen3_vllm.infer_batch_size 自动拆分。

7.2.1 POST /rerank — 结果重排

根据 query 与 doc 的相关性对文档列表重新打分排序。

请求体:

{
  "query": "玩具 芭比",
  "docs": [
    "12PCS 6 Types of Dolls with Bottles",
    "纯棉T恤 短袖 夏季"
  ],
  "normalize": true
}
参数 类型 必填 说明
query string Y 搜索查询
docs array[string] Y 待重排的文档列表(单次最多由服务端配置限制)
normalize boolean N 是否对分数做 sigmoid 归一化,默认 true

响应:

{
  "scores": [0.92, 0.15],
  "meta": {
    "service_elapsed_ms": 45.2,
    "input_docs": 2,
    "unique_docs": 2
  }
}

完整 curl 示例:

curl -X POST "http://localhost:6007/rerank" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具 芭比",
    "docs": ["12PCS 6 Types of Dolls with Bottles", "纯棉T恤 短袖"],
    "top_n":386,
    "normalize": true
  }'

7.2.2 GET /health — 健康检查

curl "http://localhost:6007/health"

7.3 翻译服务(Translation)

  • Base URL: http://localhost:6006(以 config/config.yaml -> services.translation.service_url 为准)
  • 启动: ./scripts/start_translator.sh

7.3.1 POST /translate — 文本翻译

支持 translator service 内所有已启用 capability,适用于商品名称、描述、query 等电商场景。当前可配置能力包括 qwen-mtllmdeepl 以及本地模型 nllb-200-distilled-600mopus-mt-zh-enopus-mt-en-zh

请求体(支持单条字符串或字符串列表):

{
  "text": "商品名称",
  "target_lang": "en",
  "source_lang": "zh",
  "model": "qwen-mt",
  "scene": "sku_name"
}

也支持批量列表形式:

{
  "text": ["商品名称1", "商品名称2"],
  "target_lang": "en",
  "source_lang": "zh",
  "model": "qwen-mt",
  "scene": "sku_name"
}
参数 类型 必填 说明
text string \ string[] Y
target_lang string Y 目标语言:zhenru
source_lang string N 源语言。云端模型可不传;nllb-200-distilled-600m 建议显式传入
model string N 已启用 capability 名称,如 qwen-mtllmdeeplnllb-200-distilled-600mopus-mt-zh-enopus-mt-en-zh
scene string N 翻译场景参数,与 model 配套使用;当前标准值为 sku_nameecommerce_search_querygeneral

说明:

  • 外部接口不接受 prompt;LLM prompt 由服务端按 scene 自动生成。
  • 传入未定义的 scene 或未启用的 model 会返回 400

SKU 名称场景选型建议:

  • 批量 SKU 名称翻译,优先考虑本地大吞吐方案时,可使用 "model": "nllb-200-distilled-600m"(该模型"scene":参数无效)。
  • 如果目标是更高质量,且可以接受更慢速度与额外 LLM API 费用,可使用 "model": "llm" + "scene": "sku_name"
  • 如果是en-zh互译、期待更高的速度,可以考虑opus-mt-zh-en / opus-mt-en-zh。(质量未详细评测,一些文章说比blib-200-600m更好,但是我看了些case感觉要差不少)

实时翻译选型建议:

  • 在线 query 翻译如果只是 en/zh 互译,优先使用 opus-mt-zh-enopus-mt-en-zh
  • 如果涉及其他语言,或对质量要求高于本地轻量模型,优先考虑 deepl
  • nllb-200-distilled-600m 不建议作为在线 query 翻译默认方案;我们在 Tesla T4 上测到 batch_size=1 时,根据query长短,耗时大概在70-150ms之间。

Batch Size / 调用方式建议:

  • 本接口支持 text: string[];离线或批量索引翻译时,应尽量合并请求,让底层 backend 发挥批处理能力。
  • nllb-200-distilled-600m 在当前 Tesla T4 压测中,推荐配置是 batch_size=16max_new_tokens=64attn_implementation=sdpa;继续升到 batch_size=32 虽可能提高吞吐,但 tail latency 会明显变差。
  • 在线 query 场景可直接把“单条请求”理解为 batch_size=1;更关注 request latency,而不是离线吞吐。
  • opus-mt-zh-en / opus-mt-en-zh 当前生产配置也是 batch_size=16,适合作为中英互译的低延迟本地默认值;若走在线单条调用,同样按 batch_size=1 理解即可。
  • llm 按单条请求即可。

响应:

{
  "text": "商品名称",
  "target_lang": "en",
  "source_lang": "zh",
  "translated_text": "Product name",
  "status": "success",
  "model": "qwen-mt",
  "scene": "sku_name"
}

当请求为列表形式时,texttranslated_text 均为等长数组:

{
  "text": ["商品名称1", "商品名称2"],
  "target_lang": "en",
  "source_lang": "zh",
  "translated_text": ["Product name 1", "Product name 2"],
  "status": "success",
  "model": "qwen-mt",
  "scene": "sku_name"
}

失败语义(批量):当 text 为列表时,如果其中某条翻译失败,对应位置返回 null(即 translated_text[i] = null),并保持数组长度与顺序不变;接口整体仍返回 status="success",用于避免“部分失败”导致整批请求失败。

实现提示(可忽略):服务端会尽可能使用底层 backend 的批量能力(若支持),否则自动拆分逐条翻译;无论采用哪种方式,上述批量契约保持一致。

完整 curl 示例:

中文 → 英文:

curl -X POST "http://localhost:6006/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "商品名称",
    "target_lang": "en",
    "source_lang": "zh"
  }'

俄文 → 英文:

curl -X POST "http://localhost:6006/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Название товара",
    "target_lang": "en",
    "source_lang": "ru"
  }'

使用 DeepL 模型:

curl -X POST "http://localhost:6006/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "商品名称",
    "target_lang": "en",
    "source_lang": "zh",
    "model": "deepl"
  }'

使用本地 OPUS 模型(中文 → 英文):

curl -X POST "http://localhost:6006/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "蓝牙耳机",
    "target_lang": "en",
    "source_lang": "zh",
    "model": "opus-mt-zh-en",
    "scene": "sku_name"
  }'

使用本地 NLLB 做 SKU 名称批量翻译:

curl -X POST "http://localhost:6006/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": ["商品名称1", "商品名称2", "商品名称3"],
    "target_lang": "en",
    "source_lang": "zh",
    "model": "nllb-200-distilled-600m",
    "scene": "sku_name"
  }'

使用 LLM 做高质量 SKU 名称翻译:

curl -X POST "http://localhost:6006/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "男士偏光飞行员太阳镜",
    "target_lang": "en",
    "source_lang": "zh",
    "model": "llm",
    "scene": "sku_name"
  }'

7.3.2 GET /health — 健康检查

curl "http://localhost:6006/health"

典型响应:

{
  "status": "healthy",
  "service": "translation",
  "default_model": "llm",
  "default_scene": "general",
  "available_models": ["qwen-mt", "llm", "opus-mt-zh-en"],
  "enabled_capabilities": ["qwen-mt", "llm", "opus-mt-zh-en"],
  "loaded_models": ["llm"]
}

7.4 内容理解字段生成(Indexer 服务内)

内容理解字段生成接口部署在 Indexer 服务(默认端口 6004)内,与「翻译、向量化」等独立端口微服务并列,供采用微服务组合方式的 indexer 调用。

  • Base URL: Indexer 服务地址,如 http://localhost:6004
  • 路径: POST /indexer/enrich-content
  • 说明: 根据商品标题批量生成 qanchorsenriched_attributesenriched_tagsenriched_taxonomy_attributes,用于拼装 ES 文档。支持通过 enrichment_scopes 选择执行 generic / category_taxonomy,并通过 category_taxonomy_profile 选择对应大类的 taxonomy prompt/profile;默认执行 generic + category_taxonomy(apparel)。当前支持的 taxonomy profile 包括 apparel3cbagspet_supplieselectronicsoutdoorhome_applianceshome_livingwigsbeautyaccessoriestoysshoessportsothers。所有 profile 的 taxonomy 输出都统一返回 zh + encategory_taxonomy_profile 只决定字段集合。内部使用大模型(需配置 DASHSCOPE_API_KEY),支持多语言与 Redis 缓存;单次最多 50 条,建议批量调用以提升效率。

请求/响应格式、示例及错误码见 -05-索引接口(Indexer)