一、先给结论

在真实的企业 RAG 项目中,Embedding 服务通常处理内部制度、合同、工单、代码、页面截图、图表和用户问题。数据不能随意出网,文档入库量大且需要反复重建,因此本文默认采用本地模型和私有化推理服务。线上 Embedding API 只作为特定合规场景下的补充,不再作为主要选型方向。

生产设计首先要判断检索对象:

  • 可解析正文、FAQ、制度条款、代码和日志,优先使用文本 Embedding;
  • 图表、流程图、页面布局、商品图片和扫描件视觉结构,增加多模态 Embedding;
  • 复杂 PDF 同时保留解析文本和页面图像,分别建索引后融合召回;
  • 视频只有在确实需要画面检索时才抽帧编码,不能把完整视频直接当作普通文档处理。

如果需要一组可落地的候选模型,可以从下面几类开始:

业务场景 首批候选 原生输出 选择原因
中文短文本、FAQ、制度条款,资源有限 bge-base-zh-v1.5bge-large-zh-v1.5 Dense 模型相对轻量,中文检索成熟,适合建立低成本基线
中英混合、长文档,或准备做稠密与稀疏混合检索 bge-m3 Dense、Sparse、Multi-vector 一个模型提供三种检索表示,最长输入为 8192 Token
中文、跨语言或代码检索,对效果要求更高 Qwen3-Embedding-0.6B4B Dense 支持任务指令和可变输出维度,模型规模覆盖轻量到高质量场景
需要长文本、多语言或 Dense + Sparse 的轻量方案 gte-multilingual-base Dense、Sparse Encoder-only,768 维,推理成本低于数十亿参数模型
中文和中英知识库,希望配套 Reranker bce-embedding-base_v1 Dense 接入成熟,可作为独立中文基线
页面、截图、图片和视频跨模态检索 Qwen3-VL-Embedding-2B 多模态 Dense 支持文本、图像、截图、视频及混合输入
轻量图文检索或商品以图搜图 BGE-VL-baseBGE-VL-large 多模态 Dense CLIP 路线较轻,适合图文共享空间

这张表只是候选集,不是最终答案。生产选型必须满足以下条件:

  1. 在自己的文档和问题上评测,而不是只看公开榜单;
  2. 在目标推理引擎、精度和并发参数下压测,而不是只比较参数量;
  3. 明确模型是只输出稠密向量,还是原生输出稀疏向量;外接 BM25 不能算成模型具备稀疏输出;
  4. 把模型、输出类型、指令、维度、图像预处理和索引当成同一个版本发布,而不是允许运行时随意切换;
  5. 稠密、稀疏与视觉通道分别评测,证明融合召回带来收益后再承担额外计算、存储和运维成本。

二、原有选型思路为什么不贴合生产

2.1 生成模型不等于 Embedding 模型

qwen3:4b 是生成模型,qwen3-embedding:4b 才是专门用于向量表示的模型。Mistral、Qwen 等名称描述的是模型家族,不能因为推理框架能加载它们,就默认它们都适合生成 Embedding。

模型服务和模型本身也不是一回事:

  • Ollama、vLLM、Text Embeddings Inference 是推理或服务工具;
  • Qwen3-Embedding、BGE-M3 才是决定向量空间的模型;
  • LangChain、LlamaIndex 等框架只是调用方,不应决定底层模型契约。

2.2 向量维度越高不代表检索一定越准

维度首先影响存储、内存、网络传输和相似度计算成本。模型训练方式、业务语料、指令和分块质量通常比单纯的维度更重要。

以一千万条向量、Float32、不计算索引和副本开销为例:

维度 原始向量数据量
768 约 30.72 GB
1024 约 40.96 GB
2560 约 102.40 GB
4096 约 163.84 GB

真实容量还要叠加向量索引、Payload、元数据、WAL、分片和副本。选择 4096 维不仅是模型推理问题,也可能把向量数据库的成本放大数倍。

Qwen3-Embedding 支持 Matryoshka Representation Learning(MRL),可以输出较低维度,但低维度仍然要经过业务评测,不能把“支持裁剪”理解为“裁剪无损”。其他不支持 MRL 的模型更不能直接截断向量。

2.3 “支持混合检索”不等于“模型输出稀疏向量”

稠密向量通常是固定维度的浮点数组,主要表达整体语义;稀疏向量通常是少量 Token ID 与权重的映射,主要保留产品名、错误码、版本号等词项信号。两者解决的问题不同,选型时不能只记录一个笼统的“支持向量检索”。

还要区分两种常见的混合检索:

  • Dense + BM25:Embedding 模型只输出稠密向量,关键词分数由检索引擎独立计算;
  • Dense + Model Sparse:同一个模型同时输出稠密向量和学习得到的稀疏词项权重,例如 BGE-M3、gte-multilingual-base

因此,“可以与 BM25 组合”不是模型能力指标,因为任何稠密模型都能在系统层与 BM25 组合。真正需要记录的是:模型官方推理接口能否输出稀疏表示、当前服务框架能否返回该输出、检索后端能否建立相应索引。

2.4 最大上下文长度不等于推荐 Chunk 长度

Qwen3-Embedding 的模型规格支持 32K 输入,BGE-M3 支持 8192 Token,但这只是模型可以接收的上限。把整章甚至整份文档直接编码,通常会稀释局部证据,也会显著降低吞吐。

Chunk 应先保持标题、段落、表格和代码结构,再通过真实问题评测长度与重叠。模型的最大输入长度只负责设置安全上限,不能替代分块策略。

2.5 “切换模型”不是修改一个配置项

只要模型、模型修订版本、输出类型、向量维度、归一化方式或指令模板发生变化,查询向量与旧文档向量就可能不再处于同一空间。即使新旧模型输出维度恰好相同,也不能把两者混在一个索引中搜索;稀疏词项权重的生成方式变化后,同样需要重建稀疏索引。

正确做法是创建新索引、重新生成文档向量、验证后切换读流量,并保留旧索引用于回滚。

2.6 云端模型并不天然更适合生产

线上 API 省去了模型部署,但引入了数据出境、供应商锁定、网络抖动、调用限额和持续费用。对于内部知识库,大规模离线入库往往比在线查询消耗更多 Token,本地部署的成本和可控性通常更符合实际。

只有在数据允许出网、本地资源无法满足需求,并且已经完成供应商、成本和可用性评估时,才需要把线上 API 纳入候选。

2.7 多模态 Embedding 不是 OCR 的替代品

OCR 和文档解析负责产生可阅读、可引用、可审计的文字;多模态 Embedding 负责发现版面、图形、颜色、空间关系等视觉相似性。只保留页面向量会失去精确文字、页码和引用位置,只保留 OCR 文本又可能漏掉流程图、图例和布局信息。

生产上应根据内容类型保留两条证据链:

  • 文本链:解析或 OCR → 结构化 Chunk → 文本向量;
  • 视觉链:页面或区域截图 → 图像预处理 → 多模态向量。

两条链路通过同一个 document_idpage_no 和区域坐标关联,但使用独立模型指纹和索引。

2.8 “支持多模态”不等于适合所有媒体

图文 CLIP 类模型通常适合文本搜图、以图搜图和商品检索;视觉语言模型路线可以处理截图、视觉文档和图文混合输入,但计算更重。视频检索还涉及抽帧率、镜头切分和时间戳,音频检索则需要独立的音频编码或 ASR 文本链路。

因此,“文本、图像、视频都塞进一个模型”不是生产架构。应先明确需要解决的是文字检索、视觉文档检索、图片检索还是视频片段检索。


三、文本 Embedding 怎么选

3.1 先统一选型指标

文本 Embedding 不能只比较公开榜单和稠密向量维度。进入候选集前,至少记录以下指标:

指标 要回答的问题 生产影响
业务召回质量 在真实问题上,Dense、Sparse 及融合结果的 Recall@K、nDCG@K 是否达标 决定模型是否真的解决业务问题
稀疏向量输出 官方推理接口能否返回 Token ID 与权重,而不只是能否外接 BM25 决定能否使用模型原生词项召回
稠密向量规格 默认维度、是否支持 MRL 或弹性维度、是否归一化 影响索引 Schema、存储和距离度量
输入契约 最大 Token、查询指令、文档模板、截断规则 输入不一致会直接破坏检索效果
语言与任务 中文、多语言、跨语言、代码和长文档是否经过对应评测 决定公开能力能否迁移到业务语料
服务兼容性 目标引擎能否返回模型所需的全部输出 “能加载模型”不代表能提供 Sparse 或 Multi-vector
性能与资源 吞吐、P95/P99 延迟、显存、CPU 与全量重建时间 决定容量和部署成本
许可证与维护 权重许可、商用条件、Remote Code 和版本维护状态 决定能否在企业内长期运行

其中,“稀疏向量输出”应记录为模型级指标和服务级指标。模型支持 Sparse,但服务接口只返回 Dense,当前部署仍然不能算支持稀疏检索。

3.2 文本模型能力对比

下面的“稀疏输出”以模型官方推理接口为准,不把外接 BM25 计入模型能力:

模型 Dense 默认维度 最大输入 稀疏输出 可变 Dense 维度 Query 指令 核心定位
Qwen3-Embedding-0.6B / 4B / 8B 1024 / 2560 / 4096 32K 不支持 MRL 推荐使用 多语言、代码与复杂语义检索
BGE-M3 1024 8192 支持 不支持 默认不需要 Dense、Sparse、Multi-vector 一体化检索
BGE v1.5 中文系列 512 / 768 / 1024 512 不支持 不支持 可选 中文短文本与低成本基线
gte-multilingual-base 768 8192 支持 Elastic Dense 默认不需要 轻量、多语言、长文本与混合检索
bce-embedding-base_v1 768 512 不支持 不支持 默认不需要 中英知识库与 BCE Reranker 配套
multilingual-e5-large-instruct 1024 512 不支持 不支持 需要 多语言和跨语言独立基线
jina-embeddings-v3 1024 8192 不支持 Matryoshka 使用任务参数 多语言、长文本与任务适配;注意商用许可

“不支持”表示该模型当前官方用法只提供稠密表示,不表示它不能与 BM25 组成混合检索系统。模型版本和接口会变化,落地时仍应固定 Revision,并用一次真实推理检查返回字段,而不是只读取服务的模型列表。

3.3 Qwen3-Embedding

Qwen3-Embedding 官方仓库给出的模型规格如下:

模型 参数量 最大输入 默认向量维度 稀疏输出 MRL 任务指令
Qwen3-Embedding-0.6B 0.6B 32K 1024 不支持 支持 支持
Qwen3-Embedding-4B 4B 32K 2560 不支持 支持 支持
Qwen3-Embedding-8B 8B 32K 4096 不支持 支持 支持

Qwen3-Embedding 更适合以下场景:

  • 中文与多语言混合检索;
  • 代码、错误日志、技术文档等语义较复杂的内容;
  • 需要用任务指令区分知识库问答、代码检索、相似问题匹配等任务;
  • 希望通过 MRL 在效果和向量存储之间寻找平衡。

生产上不建议直接从 8B 起步。更稳妥的顺序是用 0.6B 建立吞吐和质量基线,再评测 4B;只有 8B 的业务收益足以覆盖 GPU、延迟和存储增量时才升级。

Qwen3-Embedding 的查询侧应带任务指令,文档侧不加同样的查询指令。例如知识库检索可以固定为:

1
2
Instruct: Given a user question, retrieve relevant passages from the enterprise knowledge base
Query: 如何申请生产数据库权限?

指令应该由 Embedding Gateway 根据 profile_id 统一添加,不能散落在各业务系统中。指令内容一旦变化,就应产生新的配置版本并重新评测。

Qwen3-Embedding 当前输出稠密向量。若业务还需要错误码、产品型号等精确词项召回,应在检索层增加 BM25 或选择原生输出 Sparse 的模型,不能把 MRL 的低维稠密向量误认为稀疏向量。

3.4 BGE-M3

BGE-M3 官方模型说明中的 M3 分别代表:

  • Multi-Linguality:支持多语言;
  • Multi-Granularity:支持短句到最长 8192 Token 的文本;
  • Multi-Functionality:同时提供 Dense、Sparse 和 Multi-vector 表示。

BGE-M3 的 Dense 向量维度为 1024。它适合中英混合、长文本和混合检索,但要注意:模型具备三种输出能力,不代表生产环境必须全部启用。

输出 用途 生产代价
Dense 常规语义召回 接入最简单,适合作为第一阶段基线
Sparse 关键词和术语匹配 需要向量库或检索引擎支持稀疏向量
Multi-vector Token 级细粒度交互 存储和检索成本高,需专项评测后再启用

如果当前向量数据库只支持单个稠密向量,就先使用 BGE-M3 Dense,不要为了“用满模型能力”增加一套无法运维的检索链路。需要混合检索时,再比较 Dense + BM25Dense + BGE Sparse 的实际收益。

BGE-M3 在检索场景下不要求给查询额外添加指令。不要复用 Qwen3-Embedding 的查询模板,否则已经不是官方推荐的输入方式。

3.5 BGE v1.5 中文系列

BGE v1.5 仍然适合作为中文短文本检索的工程基线:

模型 向量维度 最大输入 稀疏输出 典型定位
bge-small-zh-v1.5 512 512 Token 不支持 CPU、边缘设备或低吞吐服务
bge-base-zh-v1.5 768 512 Token 不支持 资源与效果平衡
bge-large-zh-v1.5 1024 512 Token 不支持 中文检索质量优先

BGE v1.5 不带查询指令也能工作,检索任务中使用官方中文指令可能获得更好的效果。是否启用仍应作为一个独立实验变量,不能在上线后随意变化。

3.6 GTE / mGTE

gte-multilingual-base 是值得加入生产候选集的 Encoder-only 模型:约 305M 参数、768 维、最长 8192 Token,并能生成 Dense 和 Sparse 表示。官方接口可通过 return_dense=Truereturn_sparse=True 显式选择输出,也支持弹性 Dense 表示。相较数十亿参数的 Decoder-only Embedding,它更适合资源有限但需要多语言、长文本或混合检索的环境。

GTE 家族中也有基于 Qwen 的型号。需要比较不同模型架构时,应把 gte-multilingual-basegte-Qwen2-* 分开记录,不能只写“GTE”。

3.7 BCE、E5 与存量中文模型

模型 稀疏输出 适用场景 生产判断
bce-embedding-base_v1 不支持 中英文知识库,可搭配 BCE Reranker 中文 RAG 的独立候选,仍需业务评测
multilingual-e5-large-instruct 不支持 多语言和跨语言检索 适合作为非国产独立基线,注意 Query 指令格式
text2vec-base-chinese 不支持 中文短句、相似度和存量系统 模型轻,但长文本和复杂检索能力有限
Piccolo 不支持 中文短文本或存量项目 新项目需检查维护状态和业务收益
M3E 不支持 中文及少量英文的旧项目 官方模型卡说明权重受训练数据限制,仅供研究,商业生产需重新确认授权
jina-embeddings-v3 不支持 多语言、长文本、可变维度 本地商业使用涉及额外授权,不应未经审查直接上线

这些模型的意义是提供独立基线和迁移选择,不是让每个项目都维护十套模型。通常选择 2~4 个代表性候选完成同条件评测即可。

模型升级也不是解决所有召回问题的万能手段。如果正确答案根本没有被解析进 Chunk,或者表格被错误拆分,换更大的 Embedding 模型不会修复数据链路。


四、多模态 Embedding 怎么落地

4.1 先判断是否真的需要视觉检索

内容 默认处理 何时增加多模态向量
普通 DOCX、Markdown、网页 解析文本并使用文本 Embedding 页面布局本身具有业务含义时
可搜索 PDF 解析文字、表格和标题 流程图、复杂表格、印章或版式需要召回时
扫描 PDF OCR 文本 + 页面来源信息 OCR 质量不稳定或视觉结构重要时
商品图、设计稿、截图 多模态 Embedding 默认需要,同时保留标题和描述文本
图表、流程图 图像向量 + OCR/说明文字 通常两条链都需要
视频 ASR、字幕和镜头切分 需要按画面或时间片检索时才增加视频向量

如果用户始终通过文字搜索,文档也能被可靠解析,先把文本链路做好通常更经济。多模态检索主要解决文本解析无法表达的视觉证据,不是所有 RAG 的必选项。

4.2 当前可私有化的多模态候选

模型 规模与输出 输入能力 生产定位
Qwen3-VL-Embedding-2B 2B、2048 维、32K、支持 MRL 文本、图像、截图、视频及混合输入 视觉文档和跨模态检索的首批候选
Qwen3-VL-Embedding-8B 8B、4096 维、32K、支持 MRL 同上 质量优先且 GPU、延迟与存储预算充足
BGE-VL-base 约 149M、512 维 文本、图像、图文组合 轻量文本搜图、以图搜图和商品检索
BGE-VL-large 768 维 文本、图像、图文组合 比 Base 更高容量的 CLIP 路线
BGE-VL-MLLM / BGE-VL-v1.5 数十亿参数路线 更通用的视觉语义任务 能力更广但部署更重,中文视觉文档需专项验证
GME-Qwen2-VL-2B/7B 1536 / 3584 维、32K 文本、图像、图文组合 已有 GME 系统的迁移基线;新项目优先同时评测 Qwen3-VL

Qwen3-VL-Embedding 官方仓库同时提供 Embedding 和多模态 Reranker。Embedding 用于大规模召回,Reranker 接收查询与候选对做精排;不能用 Reranker 代替全库向量检索。

BGE-VL包含较轻的 CLIP 路线和更重的 MLLM 路线。CLIP 路线适合图片检索,但短文本编码器不应替代正文知识库的长文本模型。

4.3 按输出通道独立建索引

flowchart TD
    Source["原始文档 / 图片 / 视频"] --> Parse["解析、OCR、字幕"]
    Source --> Visual["页面渲染、图片区域、视频镜头"]

    Parse --> TextChunk["结构化文本 Chunk"]
    TextChunk --> TextEmbed["文本 Embedding"]
    TextEmbed --> DenseIndex["Dense 文本索引"]
    TextEmbed -->|"模型原生支持"| SparseIndex["Model Sparse 索引"]
    TextChunk --> BM25Index["BM25 词项索引"]

    Visual --> VisualPre["缩放、裁剪、抽帧与质量门禁"]
    VisualPre --> MMEmbed["多模态 Embedding"]
    MMEmbed --> VisualIndex["视觉向量索引"]

    Query["文本 / 图片查询"] --> Route{"查询路由"}
    Route -->|"文本查询"| TextQuery["文本查询"]
    TextQuery --> QueryEmbed["Query Embedding"]
    QueryEmbed --> DenseIndex
    QueryEmbed -->|"模型原生支持"| SparseIndex
    TextQuery --> BM25Index
    Route -->|"文本 / 图片查询"| MMQuery["多模态 Query Embedding"]
    MMQuery --> VisualIndex
    DenseIndex --> Fuse["RRF 或标定后融合"]
    SparseIndex --> Fuse
    BM25Index --> Fuse
    VisualIndex --> Fuse
    Fuse --> Rerank["文本或多模态 Rerank"]
    Rerank --> Evidence["原文、页码、区域和时间戳"]

Dense、Model Sparse、BM25 和视觉索引是不同的检索通道,可以使用不同的数据结构、距离度量和 Collection。默认先建立 Dense 基线;只有精确术语样本证明存在缺口时,才增加 BM25 或 Model Sparse。融合时优先使用 RRF 等基于名次的方法;如果要加权原始分数,必须先用标注数据校准各通道的分数分布。

4.4 多模态配置也必须版本化

除文本模型已有的配置外,多模态指纹至少还应包含:

  • 模型和 Processor Revision;
  • 图像缩放、裁剪、颜色空间和像素上下限;
  • PDF 页面渲染 DPI、区域切分算法和版本;
  • 视频镜头切分、抽帧率、最大帧数和时间片长度;
  • 查询指令、输入模态组合和输出维度;
  • 是否使用 OCR 文本、标题或其他文字与图像组成混合输入。

同一张图片经过不同裁剪或缩放后可能得到不同向量,因此缓存键不能只使用原文件哈希,还要包含视觉预处理指纹。


五、用业务评测决定模型

5.1 构造黄金评测集

评测数据应该来自真实搜索日志、客服问题、制度问答和专家补充,至少覆盖:

样本类型 要验证的问题
直接问法 正确段落能否进入 Top K
同义改写、口语和缩写 语义变化后能否稳定召回
产品名、错误码、单号和版本号 精确术语是否被纯语义检索漏掉
跨语言问题 中文问题能否召回英文材料,反之亦然
长文档和表格 局部证据会不会被长上下文稀释
页面截图和扫描件 文本问题能否召回正确页面和区域
图表和流程图 视觉关系能否被召回,OCR 文本是否形成互补
图片与图片 相似主体、布局或商品能否被正确区分
视频片段 正确镜头能否命中,时间边界是否准确
相似但错误的难负例 模型能否区分容易混淆的制度或产品
无答案问题 系统是否会召回看似相关但不支持答案的内容

初期可以先整理数百条高质量问题作为起点,但数量不是质量标准。每条问题都要标注相关 Chunk 或文档、相关等级、业务域和难例类型,并保留独立测试集,避免反复调参后只对当前样本有效。

多模态评测不能只标注文档级相关性。页面、区域和视频检索应标注 page_no、边界框或时间区间,否则无法判断模型找对了文档还是找对了证据。

5.2 同时测质量和成本

维度 建议指标
召回 Recall@K、Hit Rate@K
词项召回 产品名、错误码、编号和版本号子集的 Recall@K、零结果率
排序 MRR、nDCG@K
端到端 引用正确率、可回答率、无依据回答率
跨模态 Text→Image、Image→Image、Text→Page 的 Recall@K 和 nDCG
视觉定位 页面命中率、区域命中率、视频时间片 IoU
在线性能 P50/P95/P99 延迟、超时率、排队时延
离线性能 Tokens/s、每小时 Chunk 数、全量重建时间
资源 GPU 利用率、显存峰值、CPU、内存和网络流量
稳定性 OOM、空向量、NaN、维度错误和重试率
存储 单向量字节数、索引体积、构建时间和副本成本

稀疏能力不能只看“支持/不支持”这一列。对于需要混合检索的候选,至少比较以下实验组:

实验组 目的
Dense Only 建立语义召回基线
BM25 Only 判断业务对原词、编号和术语的依赖程度
Model Sparse Only 验证模型学习到的词项权重是否优于传统词频信号
Dense + BM25 衡量通用混合检索收益
Dense + Model Sparse 衡量模型原生双路输出的收益与成本

如果模型不支持 Sparse,就不运行对应实验组,不能用 BM25 结果冒充模型 Sparse。不要只报平均延迟;输入长度分布和批量大小会显著影响结果,应按输出通道、短中长文本以及在线查询、离线文档分别统计。

5.3 保证对比公平

一次实验只改变一个主要变量,并记录完整配置:

  • 固定文档版本、分块结果和评测问题;
  • 使用模型对应的 Tokenizer,并显式记录是否截断;
  • 分别固定 Dense、Sparse 和 BM25 的索引参数、候选数、过滤条件及最终 Rerank 预算;
  • 查询与文档使用各自正确的指令格式;
  • 明确记录模型返回的输出类型、稀疏词项数量、融合方法和权重;
  • 固定页面渲染、图片尺寸、裁剪和视频抽帧策略;
  • 在相同精度、相同硬件和目标并发下压测;
  • 每个模型重新生成完整文档向量,禁止用新查询向量搜索旧索引。

量化权重也要作为新的实验候选。Ollama 中的 Q4/Q8 模型、官方 FP16/BF16 权重和其他量化格式可能具有不同的延迟、显存和召回表现,不能只对比模型名称。

公开榜单只适合筛选候选模型,不能直接代替这组实验。


六、生产架构:在线与离线必须分开

文档入库追求吞吐,用户查询追求低延迟。两者共享同一模型实例时,一次全量重建就可能拖慢所有在线请求。

flowchart LR
    subgraph Offline["离线入库平面"]
        TextQueue["文本 Chunk 队列"] --> TextBatch["按 Token 动态合批"]
        VisualQueue["页面 / 图片 / 视频队列"] --> VisualBatch["按像素与帧数合批"]
        TextBatch --> OfflineText["离线文本 Embedding 池"]
        TextBatch --> BM25Staging["BM25 STAGING 索引"]
        VisualBatch --> OfflineMM["离线多模态 Embedding 池"]
        OfflineText --> DenseStaging["Dense STAGING 索引"]
        OfflineText -->|"Profile 启用 Sparse"| SparseStaging["Sparse STAGING 索引"]
        OfflineMM --> VisualStaging["视觉 STAGING 索引"]
        BM25Staging --> Validate["完整性与黄金集验证"]
        DenseStaging --> Validate
        SparseStaging --> Validate
        VisualStaging --> Validate
    end

    subgraph Online["在线查询平面"]
        Query["用户问题"] --> Gateway["Embedding Gateway"]
        Gateway --> OnlineText["在线文本 Embedding 池"]
        Gateway --> OnlineMM["在线多模态 Embedding 池"]
        Gateway --> BM25Active["BM25 ACTIVE 索引"]
        OnlineText --> DenseActive["Dense ACTIVE 索引"]
        OnlineText -->|"Profile 启用 Sparse"| SparseActive["Sparse ACTIVE 索引"]
        OnlineMM --> VisualActive["视觉 ACTIVE 索引"]
        BM25Active --> Fusion["结果融合"]
        DenseActive --> Fusion
        SparseActive --> Fusion
        VisualActive --> Fusion
    end

    Registry["模型注册表 / 配置指纹"] --> Gateway
    Registry --> TextBatch
    Registry --> VisualBatch
    Validate --> Release["CAS 发布索引集合"]
    Release --> BM25Active
    Release --> DenseActive
    Release --> SparseActive
    Release --> VisualActive
    Metrics["指标、日志、Trace"] -.-> Gateway
    Metrics -.-> OnlineText
    Metrics -.-> OnlineMM
    Metrics -.-> OfflineText
    Metrics -.-> OfflineMM

至少要做到:

  • 在线和离线使用独立队列、并发配额和资源池;
  • 文本与多模态任务也要隔离,避免页面批处理占满文本查询资源;
  • 在线服务优先保证延迟,离线任务允许暂停和断点续跑;
  • 新向量先写入 STAGING 索引,验证通过后再切换 ACTIVE;
  • Dense、Sparse、BM25 与视觉索引由发布清单按启用通道原子绑定,禁止只切换其中一部分;
  • 模型不可用时只切换到同一配置指纹的副本,不能临时换另一个模型;
  • 多模态服务故障时可以关闭视觉通道保留文本检索;文本 Embedding 故障时可以降级到 BM25;
  • 任何情况下都不能用其他模型生成的查询向量搜索当前索引。

七、Embedding Gateway 要固定什么

业务系统不应该直接依赖某个推理框架的私有参数。统一 Gateway 至少要区分查询和文档:

1
2
3
4
5
6
7
{
"profile_id": "kb-qwen3-06b-v3",
"input_type": "query",
"inputs": ["如何申请生产数据库权限?"],
"truncate": "reject",
"request_id": "req-20260811-001"
}

input_type 决定是否添加查询指令;profile_id 指向不可变配置。客户端不能直接传任意模型名、维度或 Prompt,避免同一索引出现不同编码方式。

多模态请求使用受控资产标识,而不是允许推理服务下载任意 URL:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"profile_id": "kb-qwen3-vl-2b-v1",
"input_type": "visual_document",
"items": [
{
"asset_id": "asset-8f32",
"page_no": 12,
"region_id": "figure-3",
"text": "数据库权限申请流程图"
}
],
"request_id": "req-20260811-002"
}

Gateway 从内部对象存储读取 asset_id,并校验租户、ACL、MIME、像素、文件大小和解码结果。外部 URL、Data URI 和本地路径不应直接透传给模型 Worker。

一个启用 BGE-M3 原生 Dense + Sparse 输出的配置指纹至少包含:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
profile_id: kb-bge-m3-hybrid-v1
modality: text
model_id: BAAI/bge-m3
model_revision: <固定 commit 或内部制品版本>
tokenizer_revision: <固定 commit 或内部制品版本>
precision: fp16
output_types:
- dense
- sparse
dense:
dimension: 1024
normalize: l2
distance_metric: inner_product
sparse:
format: token_id_weight
score_metric: inner_product
max_input_tokens: 1024
query_instruction_version: none
document_template_version: title-section-content-v1

Qwen3-Embedding 等只输出 Dense 的模型,其 output_types 只能配置为 [dense]。Profile 不能声明模型或当前服务接口无法返回的输出。多模态 Profile 还需要记录 processor_revisionimage_preprocess_versionpage_render_versionframe_sampling_version 和允许的输入模态。Dense、Sparse 与视觉索引分别绑定具体 Profile,不能共用一个模糊的 embedding_model 配置项。

还要把推理引擎及其版本记录到部署清单中。即使模型配置不变,升级推理引擎后也应运行一致性测试,检查输出维度、归一化、截断和数值漂移。

Gateway 返回结果时应附带 profile_id、配置指纹、实际 Token 数、是否截断和实际输出类型。写入索引前再次校验:

  • 数量是否与输入一致;
  • Dense 维度是否符合索引 Schema,是否存在空向量、NaN 或 Infinity;
  • Dense 的 L2 范数是否符合归一化约定;
  • Sparse 的 Token ID、权重类型、非零项数量和数值范围是否有效;
  • Profile 要求的 Dense、Sparse 输出是否完整,未启用的输出是否被意外写入;
  • 模型指纹是否与目标索引一致;
  • 多模态结果是否能追溯到资产、页码、区域或视频时间片。

八、输入处理比调用 API 更容易出错

8.1 查询和文档不能使用同一模板

不同模型的输入约定不同:

模型 Query Document
Qwen3-Embedding 添加稳定的任务指令 不添加查询指令
BGE-M3 默认不加查询指令 原文或受控增强文本
BGE v1.5 可评测官方检索指令 不添加查询指令

这也是模型配置必须版本化的原因。模型名相同但查询模板不同,检索结果仍可能变化。

8.2 保存两份文本

建议区分:

  • display_text:接近原文,用于答案上下文与引用;
  • embedding_text:可以在正文前补充文档标题、章节路径和必要的字段名,用于生成向量。

补充元数据有助于召回,但不能把未出现在原文中的增强文本当成引用证据。租户、权限、时间和标签等过滤条件应保存为向量 Payload,不要全部拼进 Embedding 文本。

视觉记录还应保存 asset_id、原始文件哈希、页面号、区域坐标、视频起止时间、渲染产物地址和预处理指纹。每条视觉向量必须继承原文档的租户与 ACL,删除原文档时同步删除文本和视觉索引数据。

8.3 禁止静默截断

调用前必须使用目标模型的 Tokenizer 计数。超过 max_input_tokens 时,应返回明确错误或重新分块,不能默认截掉尾部后继续写入索引。

max_input_tokens 应是经过压测的服务上限,通常低于模型理论上下文长度。较短的上限能减少长尾延迟、显存波动和单个超长请求对整个 Batch 的拖累。

8.4 图像与视频也不能静默降质

图片超过像素预算时应按固定策略缩放或分区,不能由不同 Worker 随机处理。扫描页需要检测空白页、旋转、模糊和极端长宽比;视频需要先做镜头或时间片切分,再按固定策略抽帧,并保留帧到原视频时间戳的映射。

视觉预处理失败必须显式进入隔离队列。生成一张全黑缩略图后继续写入向量,会形成很难通过普通日志发现的静默错误。

8.5 相似度与归一化必须匹配

如果向量经过 L2 归一化,内积与余弦相似度的排序等价;如果没有归一化,两者含义不同。模型输出、Gateway 处理方式和向量库距离度量必须写入同一个配置指纹。

相似度阈值也不能从其他模型照搬。换模型、换维度或换指令后,要根据正负样本的分数分布重新标定。


九、吞吐、显存和批处理

9.1 按 Token、像素和帧数合批

“每 64 条一批”不是稳定策略,因为 64 条 FAQ 和 64 个长 Chunk 的计算量完全不同。生产合批应同时限制:

  • max_batch_items:单批最大条数;
  • max_batch_tokens:单批总 Token;
  • max_input_tokens:单条最大 Token;
  • max_wait_ms:在线请求等待合批的最长时间。

多模态批次还要限制 max_image_pixelsmax_batch_pixelsmax_framesmax_batch_frames。只限制条数时,一批缩略图和一批高分辨率页面的显存占用可能完全不同。

可以按输入长度分桶,避免短查询被长文档 Padding 拖慢。离线任务优先提高 GPU 利用率,在线任务优先控制排队时间,两者使用不同参数。

9.2 不要照抄显存表

模型能否部署在某张 GPU 上,取决于模型规模、权重精度、输入长度、批量、推理引擎和并行方式。网上单请求得到的显存数字不能直接作为生产容量。

正确流程是:

  1. 使用线上真实 Token、图片分辨率和视频帧数分布回放;
  2. 从低并发逐步增加,记录吞吐、P95/P99 延迟和显存峰值;
  3. 注入超长文本和突发流量,观察是否 OOM;
  4. 预留故障迁移容量,验证少一个副本时仍能服务;
  5. 根据排队 Token、延迟和 GPU 利用率共同扩缩容。

只按请求数扩缩容会误判负载,因为不同请求的 Token、图片像素和视频帧数可能相差几十倍。

多模态容量不能只计算向量本身,还要计算页面渲染图、区域裁剪图、视频关键帧和缩略图。若一份文档同时生成页级与区域级向量,向量数量也不再等于 Chunk 数,应分别按 N_textN_pageN_regionN_frame 估算。

9.3 缓存要带配置指纹

文档向量缓存键至少包含:

1
hash(embedding_text + embedding_config_fingerprint)

只使用文本哈希会在模型升级后错误复用旧向量。查询缓存还要考虑租户、规范化结果、查询指令版本和过期时间,不能缓存或记录不必要的敏感原文。

视觉向量缓存使用原始资产哈希、页码或时间片、区域坐标、预处理指纹和模型指纹。页面重新渲染、裁剪规则改变或抽帧策略改变,都必须生成新缓存键。


十、推理服务怎么选

方案 当前应按什么输出验收 适合阶段 注意事项
Sentence Transformers Dense 评测、离线任务、稠密基线 能加载 BGE-M3 不代表调用路径会返回其 Sparse 和 Multi-vector
FlagEmbedding / BGE-M3 官方实现 Dense、Sparse、Multi-vector BGE-M3 完整能力验证 显式设置返回类型,并核对每批结果字段
GTE 官方实现 Dense、Sparse gte-multilingual-base 混合检索验证 需要相应 Remote Code,必须固定 Revision 并审查代码
Ollama /api/embed Dense 本地开发、小规模内网应用、快速验证 当前文档返回归一化向量数组;不能据此暴露 BGE-M3 Sparse
Hugging Face Text Embeddings Inference 按标准 Embedding 接口验收 Dense 标准化 Embedding 服务 支持某个模型架构不等于暴露该模型的全部自定义输出
vLLM Pooling 按实际 Pooling 接口验收 已使用 vLLM、需要统一服务体系 先检查模型实现与返回 Schema,再在目标硬件压测
Qwen3-VL-Embedding 官方实现 多模态 Dense 图像、视觉文档和视频检索 功能完整,但需要自行补齐网关、动态批处理、监控和高可用
Sentence Transformers 多模态模型 多模态 Dense BGE-VL、GME 等评测与服务封装 核对自定义代码、Processor 和图片输入格式,不能只验证纯文本 encode

推理引擎的选择是工程决策,不是模型质量决策。同一个模型在不同引擎下仍要验证输出一致性和性能,不能仅凭“支持加载”就上线。

生产部署还应具备:

  • 模型权重从内部制品库加载,固定 Revision 和校验和;
  • 记录模型来源、许可证和安全审查结果,升级时重新核对;
  • 启动时完成模型预热,Readiness 通过后才接收流量;
  • 至少两个副本,支持滚动升级和优雅下线;
  • 请求体、输入条数、Token 和并发均有限额;
  • 离线环境默认禁止推理容器访问公网;
  • 图片和视频由独立解码沙箱处理,限制格式、像素、帧数、时长、CPU、内存和超时;
  • 使用 trust_remote_code 的模型必须固定代码 Revision,并经过代码与依赖审查;
  • 日志记录哈希、长度和版本,不记录完整敏感文本;
  • 模型加载失败、GPU 故障和队列堆积均有告警。

十一、失败处理与可观测性

11.1 错误不能全部重试

错误 处理方式
网络闪断、临时不可用 有上限的指数退避,重试仍计入并发与预算
OOM 拆分 Batch、降低 Token 预算;持续发生时隔离实例
输入超长 重新分块或拒绝,禁止静默截断后重试
图片损坏、像素超限、视频解码失败 拒绝或隔离,记录资产与预处理版本
Dense 维度不符、NaN、空向量 阻止写入并告警,不可作为临时错误重试
Sparse 缺失、Token ID 非法、权重异常 阻止写入对应稀疏索引,检查模型接口和 Profile
模型或指纹不匹配 阻止请求,检查路由与发布配置
单条坏数据 隔离该条并记录原因,避免阻塞整个离线批次

文本任务使用 chunk_id + embedding_config_fingerprint 作为幂等键;视觉任务使用 asset_id + page/region/time_range + visual_config_fingerprint。Worker 崩溃后可以重新领取任务,但同一配置不能重复写出多份有效向量。

11.2 至少监控这些指标

  • 请求量、输入条数和输入 Token 分布;
  • 排队时延、推理时延和端到端 P50/P95/P99;
  • Batch Item、Batch Token 和 Padding 比例;
  • 图片像素、页面数、视频帧数、解码与预处理耗时;
  • GPU 利用率、显存、功耗,CPU 和内存;
  • Tokens/s、Chunk/s、缓存命中率;
  • 超时、OOM、重试、截断拒绝、无效向量;
  • Dense 与 Sparse 输出成功率、Sparse 非零项数量和生成耗时;
  • 按模型指纹和输出类型统计的索引写入量及查询量;
  • Dense、Sparse、BM25、视觉和融合通道各自的候选量、命中率及零结果率;
  • 在线 SLO 与离线全量重建剩余时间。

Trace 应串联业务请求、Gateway、预处理 Worker、模型副本和向量检索,但只记录必要元数据。发生召回异常时,要能还原“哪个模型版本、哪条指令、是否截断、如何渲染或抽帧、搜索了哪个索引集合”。


十二、模型升级与回滚

模型升级应走完整的索引发布流程:

flowchart LR
    Candidate["候选模型与配置"] --> OfflineEval["离线黄金集评测"]
    OfflineEval --> LoadTest["目标硬件压测"]
    LoadTest --> Build["创建 Dense / Sparse / BM25 / 视觉新索引并全量回填"]
    Build --> Check["数量、输出类型、维度、词项权重与资产关联校验"]
    Check --> Shadow["影子流量 / 双路对比"]
    Shadow --> Canary["小流量灰度"]
    Canary --> Switch["原子切换 ACTIVE 别名"]
    Switch --> Observe["观察业务指标"]
    Observe -->|"异常"| Rollback["切回旧索引"]
    Observe -->|"稳定"| Retain["保留观察期后清理旧索引"]

影子阶段可以分别搜索新旧索引并比较结果,但不要直接混合不同模型的相似度分数。不同向量空间的分数分布未必可比,需要融合时应使用排序名次或经过标定的分数。

发布前应核对:

  • Dense、Sparse 与 BM25 新索引记录数和有效 Chunk Manifest 一致;
  • 每条 Dense 向量的维度和指纹一致;
  • 启用 Sparse 时,每条记录的词项权重有效且查询侧使用同一模型与 Revision;
  • 页面、区域和视频时间片能够回溯到原始资产;
  • 删除文档、租户和 ACL 过滤在新索引中生效;
  • 文本、视觉和融合检索分别达到项目门槛;
  • 在线延迟和离线吞吐满足容量窗口;
  • 灰度与回滚都经过演练;
  • 旧索引未在切换后立即删除。

十三、推荐的落地顺序

第一阶段:建立可信基线

  1. 选择 bge-base-zh-v1.5Qwen3-Embedding-0.6B,先建立 Dense 基线;
  2. 固定分块、输出类型、指令、归一化和向量库参数;
  3. 建立黄金问题与难负例;
  4. 跑通离线入库、在线查询、监控和索引版本发布。

这一阶段先使用文本检索。除非核心业务就是图片搜索,否则不要在基线尚未稳定时同时引入视觉链路。

第二阶段:解决明确问题

  • 中文短文本质量不足:比较 BGE Large 与 Qwen3 0.6B/4B;
  • 中英跨语言或长文档:加入 BGE-M3;
  • 专有名词、编号召回差:比较 Dense + BM25BGE-M3 Dense + SparseGTE Dense + Sparse,不要默认原生 Sparse 一定优于 BM25;
  • Top K 中有答案但首位不准:优先增加 Reranker,而不是盲目增大 Embedding 模型;
  • 向量库存储压力大:评测 Qwen MRL 低维输出,或选择较低维模型;
  • 领域表达特殊:先扩充难负例,再考虑领域微调。

第三阶段:按需增加多模态

  1. 从流程图、扫描页、商品图片等文本链路的明确失败样本开始;
  2. 使用 Qwen3-VL-Embedding-2BBGE-VL-base/large 建立视觉基线;
  3. 分别评测文本、视觉以及融合结果,确认增量收益;
  4. 建立页面、区域和时间片来源定位;
  5. 完成视觉索引的灰度、回滚与资源隔离后再扩大覆盖范围。

第四阶段:规模化

完成在线与离线资源隔离、多副本、限流、断点续跑、模型制品管理、影子评测、灰度和回滚。只有这些能力闭环,模型在测试集上的提升才真正具备生产价值。


十四、总结

生产环境中的 Embedding 选型,不是 OpenAI、Ollama、Qwen 和 BGE 之间的简单品牌比较。更准确的拆分是:

  • Qwen3-Embedding、BGE、GTE、BCE 等文本模型决定文字检索的向量质量、输出类型和输入约定;
  • Qwen3-VL-Embedding、BGE-VL 和 GME 等模型补充页面、图像和视频的视觉召回;
  • Ollama、TEI、vLLM、FlagEmbedding 决定模型如何被服务;
  • 稀疏输出是独立选型指标:BGE-M3 与 gte-multilingual-base 可原生输出 Sparse,Qwen3-Embedding、BGE v1.5、BCE 和 E5 等候选需要外接 BM25 才能形成稀疏词项通道;
  • 输出类型、指令、维度、归一化、距离度量和视觉预处理共同定义索引契约;
  • 分块、Dense、Sparse、BM25、融合和 Rerank 共同决定最终召回效果;
  • 版本化、容量、监控、灰度和回滚决定系统能否长期运行。

对多数企业内部知识库,合理的起点不是线上 API,也不是直接部署最大的文本或多模态模型,而是先建立可复现的文本基线。只有真实失败样本证明文字无法表达页面、图表或画面证据时,才增加独立的多模态索引并进行受控融合。

参考资料