上一篇:文档解析与分块——检索失败的上游
上一篇把文档变成了带元数据的块。这一篇讲怎么把块存起来、怎么找回来:选哪个 embedding 模型、用什么索引结构、放在哪个向量库、怎么把 BM25(Best Matching 25)与向量的结果合起来、为什么 rerank 是整条流水线上性价比最高的一步、以及权限过滤为什么必须发生在这一步。
这一层的选型与 《模型作为组件(05):选型——榜单的失真、自己的评测集与供应商的弃用周期》的模型选型同构:榜单(MTEB,Massive Text Embedding Benchmark)只能缩范围,决定要在自己的查询集上做;并且它有一个模型选型没有的隐藏成本——换 embedding 模型意味着全量重建索引。2026 年的候选很多(Qwen3-Embedding 登顶 MMTEB(Massive Multilingual Text Embedding Benchmark)、Gemini Embedding、Voyage-3-large、Cohere Embed v4 支持 128K 与多模态、OpenAI text-embedding-3),而 MTEB 本身被指出用二元相关性抹平了模型之间的差异。选对模型之后,混合检索与 rerank 带来的提升常常比换模型大。
本篇要回答的核心问题是:
embedding 模型怎么选、MTEB 为什么不能直接用?1 向量索引与向量库怎么选,混合检索与 RRF(Reciprocal Rank Fusion)是什么,rerank 为什么性价比最高?2 权限为什么必须在检索时过滤,增量更新与删除怎么做?3
术语与缩写
| 缩写 | 全称 | 一句话解释 |
|---|---|---|
| embedding | — | 把文本变成向量,意思相近的文本向量也相近 |
| BM25 | Best Matching 25 | 按词频和文档长度打分的经典关键词检索算法 |
| rerank | — | 对召回的候选重新精排打分 |
| MTEB | Massive Text Embedding Benchmark | 文本 embedding 模型的综合榜单 |
| Qwen3-Embedding / Gemini Embedding / Voyage-3-large / Cohere Embed v4 / text-embedding-3 | — | 2026 年主要的 embedding 模型候选 |
| MMTEB | Massive Multilingual Text Embedding Benchmark | MTEB 的多语言扩展版 |
| RRF | Reciprocal Rank Fusion | 倒数排名融合:只按排名合并多路结果 |
| prompt | — | 发给模型的提示词与上下文 |
| cross-encoder | — | 把查询和文档拼在一起过模型打分,rerank 用它 |
| ANN | approximate nearest neighbor | 近似最近邻搜索,用一点精度换速度 |
| Apache 2.0 | Apache License 2.0 | 允许商用的宽松开源许可证 |
| Cohere Rerank / Qwen3-Reranker / BGE-reranker | — | 常用的 rerank 模型 |
| XOR-Retrieve | — | 跨语言检索基准 |
| token | — | 模型处理文本的基本单位 |
| Matryoshka | Matryoshka Representation Learning | 套娃式向量:只取前几维也能用 |
| int8 | 8-bit integer | 8 位整数,用来压缩向量 |
| BGE-M3 | BAAI General Embedding M3 | 同时输出稠密、稀疏、多向量的开源 embedding 模型 |
| nDCG | normalized discounted cumulative gain | 按位置打折、能用分级相关性的排序指标 |
| judge | — | 给结果打分的模型,即 LLM-as-judge |
| recall@k | — | 前 k 个结果里找回了多少相关块 |
| MRR | mean reciprocal rank | 第一个相关结果排名倒数的平均值 |
| HNSW | Hierarchical Navigable Small World | 分层的近邻图索引,多数向量库的默认结构 |
| IVF | inverted file index | 先聚类、只搜最近几个簇的向量索引 |
| PQ / SQ | product quantization / scalar quantization | 乘积量化 / 标量量化,压缩向量省内存 |
| DiskANN | — | 微软的磁盘驻留向量索引,适合亿级 |
| L2 | — | 应用地图第二层:Prompt 与上下文工程 |
| L1 | — | 应用地图第一层:模型作为组件 |
| top-k | — | 按分数取前 k 个结果 |
| pgvector | — | PostgreSQL 的向量检索扩展 |
| Elasticsearch / OpenSearch | — | 全文检索引擎,也支持向量 |
| Qdrant / Milvus / Weaviate | — | 专用的向量数据库 |
| turbopuffer / LanceDB | — | 基于对象存储的低成本向量库 |
| QPS | queries per second | 每秒查询数 |
| contextual retrieval | — | 给每个块前置一段模型写的上下文说明,再建索引 |
| SPLADE | SParse Lexical AnD Expansion model | 学出词权重的稀疏检索模型 |
| ColBERT | Contextualized Late Interaction over BERT | 按 token 存多向量、查询时晚交互的检索模型 |
| agentic | — | 由模型自己决定查什么、查几轮的做法 |
| ACL | access control list | 访问控制列表:记录谁能看这份文档 |
| SaaS | software as a service | 软件即服务,这里指多租户的在线产品 |
| A/B | A/B testing | 把流量分成两组、对比两个版本的实验 |
一、总览
1. 一次检索的路径
%%{init: {"flowchart": {"wrappingWidth": 200}}}%%
%% 图:一次检索的路径:两路召回 → RRF 融合 → rerank → top-5 进 prompt
flowchart TB
Q["查询 + 请求者的权限"] --> A["向量召回<br/>抓语义:同义 / 改述<br/>取 top-50"]
Q --> B["BM25 召回<br/>抓精确:型号 / 函数名 / 错误码<br/>取 top-50"]
P["权限与时间过滤<br/>在召回时就做,不能等到最后"] -.-> A & B
A & B --> R["RRF 融合<br/>两个排名合成一个(按名次不按分数)"]
R --> K["rerank(cross-encoder)<br/>对前 30–50 个逐一精排——整条线上性价比最高的一步"]
K --> O["top-5 进 prompt<br/>最相关的放末尾(位置效应)"]
查询
├─ embedding ─→ 向量索引(ANN)─→ top-50 ← 元数据过滤(权限、时间)
└─ 分词 ──────→ 倒排索引(BM25)─→ top-50 ← 元数据过滤
↓ 两路合并
RRF 融合 ─→ top-20
↓
rerank(cross-encoder)─→ top-5
↓
进入上下文
四段:两路召回(向量抓语义、BM25 抓精确)各取几十个候选,融合(RRF)合成一个列表,精排(rerank)对前几十个逐一打分取前几个,过滤在两路召回时就做(权限、时间)。每一段是本文一章。
2. 本文的章节安排
第二章 embedding 模型的选法;第三章向量索引与向量库;第四章混合检索与 RRF;第五章 rerank;第六章权限过滤与元数据;第七章增量更新、删除与重建;第八章实践建议。
二、embedding 模型
1. 候选(2026 年 9 月)
| 模型 | 类型 | 特点 |
|---|---|---|
| Qwen3-Embedding-8B / 4B / 0.6B | 开放(Apache 2.0) |
|
| Gemini Embedding 001 | 闭源 API |
|
| Voyage-3-large | 闭源 API(MongoDB 旗下) |
|
| Cohere Embed v4 | 闭源 API | 128K 上下文;多模态(PDF 里的图、幻灯片、商品图与文本同一空间) |
| OpenAI text-embedding-3-large | 闭源 API | 集成最广;Matryoshka——256 维仍胜旧的 ada-002 1,536 维 |
| BGE-M3、multilingual-e5、embeddinggemma-300m | 开放 | 生产基线:便宜、快、多语言;BGE-M3 同时输出稠密、稀疏、多向量 |
| KaLM-Embedding-Gemma3-12B | 开放(社区许可) | MMTEB 榜首量级的”天花板”模型;11.7B 参数、3,840 维,索引与服务成本高 |
2. MTEB 为什么不能直接用
与 《模型作为组件(05):选型——榜单的失真、自己的评测集与供应商的弃用周期》讲的 Arena 同一类问题:
- 版本不可比:MTEB 与 MMTEB、Multilingual v1 与 v2 的任务集不同,跨版本的分数不能横比。
- 二元相关性:MTEB 的检索数据集多用”相关 / 不相关”二值标注,nDCG(normalized discounted cumulative gain)这类指标在二值标签下退化——分不清”完美答案”与”勉强相关”。ZeroEntropy 2026 年用三个 judge 对 28 个 MTEB 检索数据集重标分级相关性,重评 16 个 embedding 模型与 7 个 rerank 模型,排名明显变化。
- 聚合分数掩盖任务方差:一个模型在分类上强、在检索上弱,平均分看不出来;你只关心检索。
- 领域与语言:中文法律文书、内部代码、医疗记录不在榜单的分布里。
用法与 《模型作为组件(05):选型——榜单的失真、自己的评测集与供应商的弃用周期》相同:榜单缩范围,自己的查询集决定。
3. 判据
| 判据 | 问什么 |
|---|---|
| 语言与领域 | 你的语料是中文为主?代码?法律?榜单第一在你的领域未必第一 |
| 上下文长度 | 块能多长——Gemini 的 2K 与 Cohere 的 128K 差 64 倍;长块能减少分块的影响 |
| 维度与 Matryoshka | 维度决定存储与检索成本;支持截断维度的模型让你事后调(先存 1,024 维,需要时截到 256) |
| 多模态 | 语料含图表、幻灯片、商品图时 Cohere Embed v4 一类是唯一主流选项 |
| 开放 vs API | 数据出域、成本(大规模自托管 Qwen3 便宜)、版本稳定性 |
| 版本稳定性 | 换模型 = 全量重建索引——选供应商承诺长期维护的版本,比选榜单第一重要 |
| 配套 rerank | 同家的 embedding + rerank 通常配合更好 |
4. 怎么评
从真实查询里采 50–200 条,人工标注每条的相关块(第七篇的检索评测集),对候选模型算 recall@5 / @20 与 MRR(mean reciprocal rank)。多数团队会发现:三个候选的差距小于”加 BM25 混合”或”加 rerank”带来的提升——模型选型不是这一层的主要杠杆。
%% 图:这一层各个杠杆的量级(示意,以纯 embedding 的 recall@5 = 70 为基线)——换一个榜单更高的 embedding 模型通常只动 2–3 个点;加 BM25 混合与 RRF 动 6–8 个点;加 rerank 再动 8–10 个点;把 embedding 选型当主要杠杆是这一层最常见的用力方向错误
%%{init: {"xyChart": {"width": 760, "height": 340, "plotReservedSpacePercent": 60}, "themeVariables": {"xyChart": {"plotColorPalette": "#c0392b, #5b8fd6, #4d9a5c"}}}}%%
xychart-beta
title "recall@5(示意):模型选型不是主要杠杆"
x-axis ["embedding A", "换 embedding B(榜单更高)", "+ BM25 混合 · RRF", "+ rerank"]
y-axis "recall@5(%)" 60 --> 95
bar [70, 73, 80, 89]
三、向量索引与向量库
1. 索引结构
精确最近邻在百万向量上太慢,用近似(ANN,approximate nearest neighbor):
| 结构 | 原理 | 适合 | 代价 |
|---|---|---|---|
| HNSW | 多层图,贪心导航 | 百万级、高召回、低延迟;多数向量库的默认 | 内存驻留(每向量几百字节到几 KB);构建慢 |
| IVF(倒排文件) | 聚类成若干桶,查最近的几个桶 | 千万到亿级、可放磁盘 | 召回随桶数权衡;聚类要重训 |
| 量化(PQ / SQ / 二值) | 压缩向量(int8、二值) | 降内存与带宽 4–32 倍 | 精度损失;配 rerank 弥补 |
| DiskANN 一类 | 图 + 磁盘 | 十亿级单机 | 延迟比内存 HNSW 高 |
多数应用在百万块以下,HNSW(Hierarchical Navigable Small World)加标量量化足够;亿级才需要 IVF(inverted file index)与磁盘方案。带过滤的搜索是一个专门的问题:先过滤再搜(候选少时准但慢)还是先搜再过滤(快但可能过滤后不够 k 个)——向量库对此有各自的实现(过滤下推到图遍历),选库时要测你的过滤选择性下的召回。
%% 图:HNSW 的多层图与贪心导航——上层稀疏、下层稠密,查询从顶层一个入口点开始,每层贪心走到离查询最近的节点再下一层,到底层做局部精搜;百万向量几次跳转就能到,代价是整张图驻留内存、构建慢
flowchart TB
Q["查询向量"] --> L2["第 2 层:几十个节点,稀疏长边<br/>从入口点贪心走到最近的节点"]
L2 --> L1["第 1 层:几千个节点<br/>从上一层落点继续贪心"]
L1 --> L0["第 0 层:全部 100 万个节点,稠密短边<br/>局部精搜,返回 top-k"]
L0 --> R["top-50 候选"]
F["元数据过滤(权限 · 时间)<br/>下推到图遍历:走图时跳过不满足的节点<br/>而不是搜完 50 个再过滤剩 3 个"] -.-> L0
classDef q fill:#eef6ff,stroke:#5b8fd6,color:#222
classDef layer fill:#fff7e0,stroke:#c98a00,color:#222
classDef ok fill:#eefaf0,stroke:#4d9a5c,color:#222
class Q q
class L2,L1,L0 layer
class R,F ok
2. 向量库
| 选项 | 适合 | 备注 |
|---|---|---|
| pgvector(+ pgvectorscale) | 已有 PostgreSQL、百万级以下 | 先用现有基础设施;事务、权限、备份现成 |
| Elasticsearch / OpenSearch | 已有全文索引、要混合检索 | BM25 与向量在同一系统,混合最方便 |
| Qdrant、Milvus、Weaviate | 专用、千万级以上、丰富的过滤 | 独立运维 |
| turbopuffer、LanceDB 一类 | 对象存储后端、成本敏感的大规模 | Cursor 用 turbopuffer 存代码索引 |
| 云托管(各云的向量服务) | 不想运维 | 锁定 |
原则:数据量小时用你已有的数据库。pgvector 在百万级以下完全够用,且把块、元数据、权限、事务放在一个系统里比跨系统同步简单得多。到了千万级、或需要复杂过滤与高 QPS(queries per second),再上专用库。
四、混合检索
1. 为什么要两路
向量抓语义,抓不住精确:型号 “X-200” 与 “X-2000”、函数名、错误码、人名、日期在向量空间里靠得很近。BM25 抓精确,抓不住语义:同义、改述、跨语言。两路各取几十个候选合并,覆盖对方的盲区——这是 2024 年之后企业检索的默认配置,Anthropic 的 contextual retrieval 实验里”embedding + BM25”比纯 embedding 的失败率再降一截。
2. RRF:不用调权重的融合
两路的分数不在同一尺度(余弦相似度 0–1 与 BM25 的无界分数),直接加权要调参且不稳定。倒数排名融合(Reciprocal Rank Fusion)只用排名:
\[\text{RRF}(d) = \sum_{r \in \text{路}} \frac{1}{k + \text{rank}_r(d)}\]\(k\) 通常取 60。一个文档在两路都靠前,分数最高;只在一路出现,也有分数。不需要归一化、不需要调权重、对两路的分数分布不敏感——这是它成为默认的原因。Elasticsearch、OpenSearch、多数向量库都内置。
%% 图:RRF 的一个算例(k = 60)——文档 D1 向量路第 1、BM25 路第 3:1/61 + 1/63 = 0.0323;D2 只在向量路第 2:1/62 = 0.0161;D3 只在 BM25 路第 1(精确命中型号 X-200):1/61 = 0.0164;两路都靠前的 D1 排第一,只在一路出现的也有分,两路的原始分数(余弦 0.83 与 BM25 的 12.7)根本不用比
flowchart LR
subgraph V["向量路(余弦相似度)"]
direction TB
V1["#1 D1(0.83)"] ~~~ V2["#2 D2(0.81)"] ~~~ V3["#3 D5(0.79)"]
end
subgraph B["BM25 路(无界分数)"]
direction TB
B1["#1 D3(12.7)精确命中 X-200"] ~~~ B2["#2 D7(9.1)"] ~~~ B3["#3 D1(8.4)"]
end
V --> R["RRF:Σ 1 / (60 + 名次)"]
B --> R
R --> O1["D1:1/61 + 1/63 = 0.0323 ← 两路都靠前"]
R --> O2["D3:1/61 = 0.0164"]
R --> O3["D2:1/62 = 0.0161"]
classDef v fill:#eef6ff,stroke:#5b8fd6,color:#222
classDef b fill:#fff7e0,stroke:#c98a00,color:#222
classDef r fill:#eefaf0,stroke:#4d9a5c,color:#222
class V1,V2,V3 v
class B1,B2,B3 b
class R,O1,O2,O3 r
3. 三路
BGE-M3 一类模型同时输出稠密向量、稀疏(学习到的词权重,类似 SPLADE(SParse Lexical AnD Expansion model))与多向量(ColBERT(Contextualized Late Interaction over BERT)式);三路 RRF 在多语言语料上常再提一截。代价是索引与查询成本三倍。
五、rerank
1. 为什么双塔不够
embedding 检索是双塔:查询与文档各自独立编码成向量,相似度是两个向量的点积——文档向量在索引时就算好了,查询来了只算一次,所以快。代价是查询与文档没有交互:模型没有机会”读着查询看文档”。cross-encoder 把(查询,文档)拼在一起过一遍模型,输出一个相关性分数——有交互,精确得多,但每个候选都要算一次,不能预计算,只能用在 top-k 之后。
%% 图:双塔与 cross-encoder——双塔把查询和文档各自独立编码成向量,文档向量在索引时预先算好,查询来了只算一次点积,快但查询与文档没有交互;cross-encoder 把(查询,文档)拼在一起过模型输出一个分数,有交互、精确,但每个候选都要算一次,所以只能用在 top-k 之后
flowchart TB
subgraph BI["双塔(embedding 检索):快,无交互"]
direction LR
Q1["查询"] --> E1["编码器"] --> QV["查询向量"]
D1["文档(索引时已编码)"] --> DV["文档向量"]
QV --> DOT["点积 → 相似度<br/>百万文档毫秒级"]
DV --> DOT
end
subgraph CE["cross-encoder(rerank):精确,逐个算"]
direction LR
P["(查询,文档)拼在一起"] --> M["模型读着查询看文档"] --> S["相关性分数<br/>每个候选一次前向,只做 top-20"]
end
BI -->|"top-50 → RRF → top-20"| CE
classDef bi fill:#eef6ff,stroke:#5b8fd6,color:#222
classDef ce fill:#eefaf0,stroke:#4d9a5c,color:#222
class Q1,E1,QV,D1,DV,DOT bi
class P,M,S ce
2. 性价比
流水线:两路召回各 50 → RRF → top-20 → rerank → top-5 进上下文。rerank 只对 20 个候选打分,延迟几十到几百毫秒(托管 API)或更少(本地小模型),换来的是 top-5 的精度明显提升——Anthropic 的实验里加 rerank 让失败率从 −49% 再降到 −67%;很多团队的经验是 rerank 带来的提升大于换 embedding 模型。它还减少进入上下文的块数:没有 rerank 时为了保证召回要放 top-10,有了 rerank 放 top-3 到 5 就够——直接省 L2 的预算与 L1 的钱。
3. 候选
Cohere Rerank、Voyage rerank、Qwen3-Reranker(开放,0.6B / 4B / 8B)、BGE-reranker、ColBERT 式的晚交互模型(介于双塔与 cross-encoder 之间,可预计算文档侧)。选法与 embedding 相同:自己的查询集上比 rerank 前后的 recall@5 与 nDCG@5,看延迟。ZeroEntropy 的分级重评里 rerank 模型之间差距也不小。
4. 什么时候不需要
候选本来就少(小语料、精确过滤后只剩几个);延迟预算极紧(每毫秒都算的自动补全);或者 agentic 检索里模型自己会多轮筛(第五篇)——此时 rerank 的收益小。
六、权限过滤
1. 在哪一步
在两路召回时:查询带用户的权限(用户 id、组、角色,或可见的 ACL(access control list)id 集合),向量索引与倒排索引都只在该用户可见的块里搜。不是 RRF 之后、不是 rerank 之后、更不是生成之后(第三篇第六章讲过为什么)。
2. 实现
- 元数据里每块有
acl(可见的主体集合或 ACL 组 id),查询时acl ∩ 用户主体 ≠ ∅; - 向量库要支持这种集合过滤且过滤下推到索引(否则先搜 top-50 再过滤可能剩不下几个);
- 权限变化要同步:源系统的 ACL 变了,块的元数据要更新——这通常是入库流水线里最容易断的一环;
- 测:第七篇的”不该看到”查询集。
3. 多租户
多租户 SaaS(software as a service)的租户隔离是权限过滤的极端形式:要么每租户独立索引(隔离强、成本高),要么共享索引 + 租户 id 过滤(要确保过滤不可绕过)。多数向量库对此有专门的分区 / 命名空间机制。
七、更新、删除与重建
1. 增量更新
文档变了:删旧块、加新块(块 id 按文档 id + 块序号或内容哈希)。HNSW 的删除通常是软删除(标记后在查询时跳过,定期重建清理),大量删除后召回与延迟会变差,要有重建窗口。倒排索引的增量更新便宜得多——这是第二篇里词法检索”过期税低”的另一面。
2. 删除的合规含义
用户要求删除数据、文档下线、权限收回——块必须真的不可检索,软删除的”标记跳过”要经得起审计;备份与副本里的向量也要处理。
3. 全量重建
三种情况要全量重建:换 embedding 模型(向量空间变了,新旧向量不可比)、改分块策略、改 contextual 前缀。百万块的语料重建是几小时到一天的 embedding 调用加索引构建;要有双写切换的流程(新索引建好、评测通过、流量切换、旧索引保留一段时间),与 《Prompt 与上下文工程(06):prompt 当代码管——版本、评测、A/B,以及上下文 vs 检索》的发布流程同构。这是”换 embedding 模型很贵”的具体含义。
八、实践建议
- 建检索评测集(50–200 条真实查询 + 标注的相关块),先测纯向量的 recall@5 作为基线。
- 加 BM25 混合 + RRF,再测;多数语料上这一步的提升大于换模型。
- 加 rerank(top-20 → top-5),再测;同时把进入上下文的块数从 10 降到 5,看成本与质量。
- embedding 选型放最后:在混合 + rerank 的配置下比两三个候选,判据加上上下文长度、Matryoshka、版本稳定性、出域。
- 向量库先用现有的:PostgreSQL + pgvector 到百万级;已有 Elasticsearch 就用它做混合。
- 权限过滤进召回:块带 ACL、查询带主体、过滤下推;写”不该看到”的测试。
- 规划重建:块 id 用内容哈希、软删除加重建窗口、换模型走双写切换。
九、本文小结
- embedding 选型与模型选型同构:MTEB 版本不可比、二元相关性抹平差异(ZeroEntropy 分级重评后排名变化)、聚合分掩盖任务方差、领域不在分布里——榜单缩范围,自己的查询集决定;判据是语言领域、上下文长度(2K 到 128K)、维度与 Matryoshka、多模态、开放 vs API、版本稳定性(换模型 = 全量重建)。
- 索引:百万级以下 HNSW + 标量量化;亿级 IVF / 磁盘方案;带过滤的搜索要测。向量库:先用现有的(pgvector、Elasticsearch),千万级或复杂过滤再上专用库。
- 混合:向量抓语义、BM25 抓精确,RRF 只用排名融合(\(k = 60\))不需要调权重;BGE-M3 一类可三路。
- rerank:cross-encoder 有查询—文档交互,只用于 top-20 后的精排;性价比最高(Anthropic:−49% → −67%),且让进入上下文的块从 10 降到 5。
- 权限在两路召回时过滤,元数据带 ACL、过滤下推、与源系统同步;多租户用分区。
- 更新:块 id 用哈希,HNSW 软删除要重建窗口,删除要经得起审计;换模型 / 改分块 / 改前缀要全量重建,走双写切换。
十、自测
-
一个团队在 MTEB 上选了榜首模型,上线后中文合同检索效果不如原来的 BGE-M3。可能原因有哪几个?
答案
榜单分布里没有中文法律文书(领域与语言);聚合分掩盖了检索子任务的表现;二元相关性下的排名与真实分级相关性下不同;榜首模型可能上下文更短导致分块被切得更碎。正确做法是在自己的 50–200 条合同查询上比 recall@5 与 MRR。详见第二章。
-
查询”X-200 的额定电压”在纯向量检索下返回了 X-2000、X-20 的文档。为什么?怎么修?
答案
型号这类精确标识符在向量空间里靠得很近,向量抓语义不抓字面。修:加 BM25 一路(精确匹配 “X-200”),用 RRF 融合两路——两路都命中的 X-200 文档分数最高;再加 rerank 精排。详见第四章。
-
用 RRF(\(k = 60\))计算:文档 A 在向量路排第 1、BM25 路排第 10;文档 B 在向量路排第 3、BM25 路排第 2。谁分数高?
答案
A:\(1/61 + 1/70 \approx 0.01639 + 0.01429 = 0.03068\)。B:\(1/63 + 1/62 \approx 0.01587 + 0.01613 = 0.03200\)。B 更高——两路都靠前胜过一路第一、一路靠后。详见第四章。
-
为什么 rerank 不能替代 embedding 检索直接对全库打分?它在流水线里的正确位置与收益是什么?
答案
cross-encoder 要对每个(查询,文档)对过一遍模型,不能预计算,百万文档每次查询要百万次前向——不可行。正确位置是召回 + RRF 之后的 top-20 精排,取 top-5 进上下文;收益是精度显著提升(Anthropic:失败率 −49% → −67%),并把进入上下文的块数从 10 降到 5,省预算与钱,延迟增加几十到几百毫秒。详见第五章。
-
团队决定把 embedding 模型从 text-embedding-3 换成 Qwen3-Embedding-8B。列出要做的事与顺序。
答案
(1)在检索评测集上验证新模型(在混合 + rerank 配置下)确实更好;(2)新旧向量空间不可比,全量重建:新建索引、对全部块重算 embedding(百万块几小时到一天);(3)双写期间新旧索引并存,新索引通过评测后切流量,旧索引保留一段时间可回滚;(4)块 id 用内容哈希保证对应;(5)若同时改 rerank 为 Qwen3-Reranker 一起评。这就是”换 embedding 模型很贵”的含义。详见第七章。
-
候选:Qwen3-Embedding-8B(开放,MMTEB 70.58,32K,配 Qwen3-Reranker)、Gemini Embedding 001(68.32,跨语言强,输入 2K)、Voyage-3-large(32K,Matryoshka,量化感知)、Cohere Embed v4(128K,多模态)、OpenAI text-embedding-3-large(256 维胜旧 ada-002 1,536 维)、BGE-M3 / e5 等生产基线。MTEB 不能直接用:版本不可比、二元相关性抹平差异(ZeroEntropy 用分级相关性重标 28 个数据集后排名明显变化)、聚合分掩盖检索子任务、领域与语言不在分布里——榜单缩范围,自己的 50–200 条查询集决定。判据:语言领域、上下文长度、维度与 Matryoshka、多模态、开放 vs API、版本稳定性(换模型 = 全量重建索引)、配套 rerank。多数情况模型间差距小于加混合与 rerank 的提升。详见第二章。 ↩
-
索引:百万级以下 HNSW + 标量量化(内存驻留、高召回),亿级 IVF / DiskANN 一类,带过滤的搜索要在自己的过滤选择性下测召回。向量库先用现有的——pgvector 到百万级、已有 Elasticsearch 用它做混合——千万级或复杂过滤再上 Qdrant / Milvus / Weaviate / turbopuffer。混合检索:向量抓语义、BM25 抓精确(型号、函数名、编号),两路各取几十候选,用 RRF \(\sum 1/(k + \text{rank})\)(\(k = 60\))只按排名融合,不需归一化与调权重。rerank:cross-encoder 让查询与文档交互,比双塔精确但不能预计算,只用于 RRF 后 top-20 的精排取 top-5;性价比最高——Anthropic 实验失败率从 −49% 再到 −67%,且把进入上下文的块从 10 降到 5 省预算与钱,延迟加几十到几百毫秒。详见第三章、第四章、第五章。 ↩
-
权限在两路召回时过滤:块的元数据带 ACL,查询带用户主体集合,向量索引与倒排索引只在可见块里搜,过滤下推到索引;不能在 RRF、rerank 或生成之后过滤——模型已看到无权内容且 top-k 位置被无权文档占用;ACL 变化要与源系统同步;多租户用分区 / 命名空间或独立索引;用”不该看到”查询集测。更新:块 id 用文档 id + 序号或内容哈希,文档变了删旧块加新块;HNSW 删除是软删除,大量删除后要重建窗口,删除要经得起合规审计(含副本与备份);倒排索引增量便宜。全量重建的三种情况:换 embedding 模型(向量空间不可比)、改分块、改 contextual 前缀——百万块数小时到一天,走双写切换:新索引建好、评测通过、切流量、旧索引保留可回滚。详见第六章、第七章。 ↩
上一篇:文档解析与分块——检索失败的上游
本文由 arganzheng 创作,采用 CC BY 4.0 许可协议。在保留原文作者、署名以及完整原文链接(https://arganzheng.life/indexing-hybrid-search-and-reranking.html)的前提下,欢迎各种形式的转载、翻译或商业引用。
COMMENTS
评论存放在 GitHub Discussions, 用 GitHub 账号登录即可发表,支持 Markdown。 想针对正文某句话说?选中那段文字,点浮出的「评论」即可划线评论;觉得哪里写错了,发表时勾上「同时提交 Issue」。 有人回复你时 GitHub 会按你的通知设置发邮件,不用守在这里。