README.md
Embeddings 模块
请求示例见 docs/QUICKSTART.md §3.3。
专项文档:
../docs/TEI_SERVICE说明文档.md../docs/CNCLIP_SERVICE说明文档.md
请求日志串联(reqid / uid):统一实现在仓库根目录的 request_log_context.py(勿放到 utils/ 下,以免 .venv-embedding 因 utils/__init__.py 拉取数据库依赖)。Uvicorn 日志配置见 config/uvicorn_embedding_logging.json。
这个目录是一个完整的“向量化模块”,包含:
- HTTP 客户端:
text_encoder.py/image_encoder.py(供搜索/索引模块调用) - 本地模型实现:
text_embedding_sentence_transformers.py/clip_model.py - clip-as-service 客户端:
clip_as_service_encoder.py(图片向量,推荐) - 向量化服务(FastAPI):
server.py - 统一配置:
config.py - 接口契约:
protocols.ImageEncoderProtocol(encode_image_urls+encode_clip_texts;本地 CN-CLIP 与 clip-as-service 均实现)
说明:历史上的云端 embedding 试验实现(DashScope)已从主仓库移除。当前默认部署为文本服务 6005 与图片服务 6008 两条独立链路;all 模式仅作为单进程调试入口。
文本向量后端(默认)
- 6005 文本向量服务默认后端:
TEI(Text Embeddings Inference) - 默认模型:
Qwen/Qwen3-Embedding-0.6B - 后端配置来源:
config/config.yaml -> services.embedding.backend/backends - 环境变量覆盖:
EMBEDDING_BACKEND、TEI_BASE_URL、TEI_TIMEOUT_SEC
服务接口
- 文本服务(默认
6005)POST /embed/text- 请求体:
["文本1", "文本2", ...] - 可选 query 参数:
normalize=true|false、priority=0|1 - 返回:
[[...], [...], ...] - 健康接口:
GET /health、GET /ready
- 图片服务(默认
6008)POST /embed/image:图片 URL 或本地路径POST /embed/clip_text:自然语言(CN-CLIP 文本塔,与/embed/image同向量空间;勿传http://图 URL)- 请求体:
["...", ...]字符串数组 - 可选 query 参数:
normalize=true|false、priority=0|1 - 返回:
[[...], [...], ...] - 健康接口:
GET /health、GET /ready
Redis 向量缓存
- Value 格式没有变化,仍然是 BF16 bytes:
- 写入:
float32 -> BF16 -> bytes - 读取:
bytes -> BF16 -> float32
- 写入:
- 现在是双层缓存:
- client 侧:
text_encoder.py/image_encoder.py - service 侧:
server.py
- client 侧:
- 当前主 key 格式(
model_name见CONFIG.MULTIMODAL_MODEL_NAME,与services.embedding.image_backends一致):- 文本(TEI):
embedding:embed:norm{0|1}:{text_or_sha256_digest} - CN-CLIP 图片:
embedding:image:embed:{model_name}:txt:norm{0|1}:{url_or_sha256_digest} - CN-CLIP 文本塔:
embedding:clip_text:embed:{model_name}:img:norm{0|1}:{text_or_sha256_digest}
- 文本(TEI):
- 尾部负载:长度 ≤
CACHE_KEY_RAW_BODY_MAX_CHARS(默认 256,见embeddings/cache_keys.py)用原文;更长用h:sha256:<hex>(TEI 与多模态共用同一辅助函数)。 - 切换多模态模型会自然换 key 空间;旧键需自行清理或等待过期。
压力隔离与拒绝策略
- 文本与图片各自有独立 admission control:
TEXT_MAX_INFLIGHTIMAGE_MAX_INFLIGHT
- 图片服务可以配置得比文本更严格。
- 请求若是 full-cache-hit,会在服务端直接返回,不占用模型并发槽位。
- 超过处理能力时直接拒绝,比无限排队更稳定。
- 文本服务支持
priority:priority=0(默认,适合离线索引)仍受TEXT_MAX_INFLIGHT限制,超限直接返回 overload。priority>0(建议在线 query 用1)不会因 admission control 被拒绝,但仍会计入 inflight。- 文本服务内部使用双队列调度,处理时会优先消费高优先级请求,避免在线请求长期排在离线批量任务后面。
- 图片服务同样支持
priority(语义与文本一致,按IMAGE_MAX_INFLIGHT计数;不做队列插队,仅 admission 规则不同)。
图片向量:clip-as-service(推荐)
默认使用 third-party/clip-as-service 的 Jina CLIP 服务生成图片向量。
安装 embedding 专用环境(首次使用):
./scripts/setup_embedding_venv.sh如需使用本地
local_st文本后端,再执行:INSTALL_LOCAL_ST=1 ./scripts/setup_embedding_venv.sh启动 CN-CLIP 服务(独立 gRPC 服务,默认端口 51000,详见
../docs/CNCLIP_SERVICE说明文档.md):./scripts/start_cnclip_service.sh配置(
embeddings/config.py或环境变量):USE_CLIP_AS_SERVICE=true(默认)CLIP_AS_SERVICE_SERVER=grpc://127.0.0.1:51000CLIP_AS_SERVICE_MODEL_NAME=CN-CLIP/ViT-H-14(与config/config.yaml中services.embedding.image_backends一致;换 ViT-L 时为 768 维,须同步改 ES 映射)scripts/start_cnclip_service.sh默认会读取同一个CLIP_AS_SERVICE_MODEL_NAME,也可用CNCLIP_MODEL_NAME或--model-name临时覆盖
性能与压测(沿用仓库脚本)
- 接口级压测(与
perf_reports/2026-03-12/matrix_report/等方法一致):benchmarks/perf_api_benchmark.py- 示例:
python benchmarks/perf_api_benchmark.py --scenario embed_text --duration 30 --concurrency 20 - 文本/图片向量可带
priority(与线上 admission 语义一致):--embed-text-priority 1、--embed-image-priority 1 - 自定义请求模板:
--cases-file benchmarks/perf_cases.json.example
- 示例:
- 历史矩阵结果与说明见
perf_reports/2026-03-12/matrix_report/summary.md。
启动服务
使用仓库脚本启动:
# GPU(需 nvidia-container-toolkit)
TEI_DEVICE=cuda ./scripts/start_tei_service.sh
# CPU
TEI_DEVICE=cpu ./scripts/start_tei_service.sh
./scripts/start_embedding_text_service.sh
./scripts/start_embedding_image_service.sh
修改配置
编辑 embeddings/config.py:
PORT:all模式单进程端口(默认 6005)TEXT_MODEL_ID,TEXT_DEVICE,TEXT_BATCH_SIZE,TEXT_NORMALIZE_EMBEDDINGSIMAGE_NORMALIZE_EMBEDDINGS(默认 true)USE_CLIP_AS_SERVICE,CLIP_AS_SERVICE_SERVER,CLIP_AS_SERVICE_MODEL_NAME:图片向量(clip-as-service)IMAGE_MODEL_NAME,IMAGE_DEVICE:本地 CN-CLIP(当USE_CLIP_AS_SERVICE=false时)- TEI 相关:
TEI_DEVICE、TEI_VERSION、TEI_MAX_BATCH_TOKENS、TEI_MAX_CLIENT_BATCH_SIZE、TEI_HEALTH_TIMEOUT_SEC - 分流/限流相关:
EMBEDDING_SERVICE_KIND=all|text|imageEMBEDDING_TEXT_PORTEMBEDDING_IMAGE_PORTTEXT_MAX_INFLIGHTIMAGE_MAX_INFLIGHT