信息检索基础¶
背景知识
信息检索是 AI 系统的核心组件——无论是搜索引擎、RAG 系统,还是 Agent 记忆系统,都需要从海量数据中快速找到相关内容。本文档聚焦检索算法的技术原理和设计权衡。
相关文档:RAG 检索策略 | Agent 记忆系统
1. 检索范式演进¶
信息检索经历了从规则匹配到语义理解的演进:
timeline
title 信息检索范式演进
section 早期
1950s-1980s : 布尔检索<br>(AND/OR/NOT)
1970s-1990s : 向量空间模型<br>(TF-IDF)
section 经典
1990s-2000s : 概率检索<br>(BM25)
2000s-2010s : 学习排序<br>(Learning to Rank)
section 现代
2010s-2020s : 神经检索<br>(Dense Retrieval)
2020s-至今 : 混合检索<br>(Hybrid + RRF)
| 范式 | 核心思想 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| 布尔检索 | 精确匹配关键词 | 简单、快速、可解释 | 无法处理同义词、语义 | 专利检索、法律文档 |
| 向量空间模型 | TF-IDF 加权 | 考虑词频和文档频率 | 无法理解语义 | 传统搜索引擎 |
| 概率检索 (BM25) | 概率排序模型 | 饱和函数、长度归一化 | 仍依赖关键词匹配 | 现代搜索引擎默认算法 |
| 神经检索 | 向量嵌入语义匹配 | 理解同义词、语义相近 | 计算成本高、黑盒 | RAG、语义搜索 |
| 混合检索 | BM25 + 向量融合 | 兼顾精确匹配和语义理解 | 复杂度高、需要调参 | 高质量检索系统 |
2. BM25 概率检索¶
BM25 (Best Matching 25) 是一种概率信息检索函数,由 Robertson & Walker 在 1994 年正式提出1。它是现代搜索引擎(如 Elasticsearch、Lucene)的默认评分算法,在 RAG 和 Agent 记忆系统中被广泛采用。
2.1 核心思想¶
BM25 的核心直觉可以用"图书馆卡片目录"类比:
想象你在图书馆找关于"机器学习"的书。你会: 1. 先找标题或目录中包含"机器学习"词的书(词频高) 2. 如果"机器学习"在所有书中都出现,这个词就不太有区分度(逆文档频率) 3. 偏好薄书而非厚书,因为薄书中关键词密度更高(长度归一化)
BM25 将这个直觉形式化为数学公式。
2.2 BM25 公式¶
BM25 对查询 Q 和文档 D 的相关性评分:
参数含义:
- \(f(q_i,D)\):词 \(q_i\) 在文档 D 中的频率(TF)
- \(|D|\):文档 D 的长度(词数)
- \(\text{avgdl}\):语料库的平均文档长度
- \(k_1\):词频饱和参数(通常 1.2-2.0),控制 TF 饱和速度
- \(b\):长度归一化参数(通常 0.75),控制长度惩罚强度
- \(\text{IDF}(q_i)\):逆文档频率,衡量词的稀有程度
IDF 计算公式:
其中: - \(N\):语料库中文档总数 - \(\text{df}(q_i)\):包含词 \(q_i\) 的文档数
2.3 数值示例¶
假设有一个微型语料库:
| 文档 | 内容 | 长度 |
|---|---|---|
| D1 | "JWT auth middleware protects API" | 5 |
| D2 | "OAuth2 is an authentication protocol" | 5 |
| D3 | "JWT tokens are used for login" | 5 |
平均文档长度 \(\text{avgdl} = 5\),文档总数 \(N = 3\)。
查询:"JWT auth"
步骤 1:计算词频
| 文档 | \(f(\text{"JWT"})\) | \(f(\text{"auth"})\) |
|---|---|---|
| D1 | 1 | 1 |
| D2 | 0 | 0 |
| D3 | 1 | 0 |
步骤 2:计算 IDF
步骤 3:计算 BM25 分数(设 \(k_1=1.5\), \(b=0.75\))
对于 D1: $$ \frac{|D1|}{\text{avgdl}} = \frac{5}{5} = 1 $$ $$ \text{length_norm} = 1 - 0.75 + 0.75 \times 1 = 1 $$
对于 D3(只有 "JWT"): $$ \text{total_score}(D3) = -1.61 $$
D2(无匹配词):分数为 0
结果排序:D1 > D2 > D3
注意:实际 BM25 实现通常使用平滑的 IDF 公式避免负值,这里用原始公式展示计算过程。
2.4 BM25 vs TF-IDF¶
BM25 是对 TF-IDF 的改进,核心差异:
| 特性 | TF-IDF | BM25 |
|---|---|---|
| TF 处理 | 线性增长(词频越高分数越高) | 饱和函数(k1 参数控制) |
| 长度归一化 | 简单除以文档长度 | 参数化惩罚(b 参数控制) |
| IDF 平滑 | log(N/df) | log((N-df+0.5)/(df+0.5)) 避免负值 |
| 参数调优 | 无 | k1, b 可调优 |
TF 饱和的重要性:
TF-IDF 中,词频从 10 增加到 20,分数翻倍。但 BM25 中,由于饱和函数,词频 10 和 20 的分数差异很小——这更符合直觉:一个词出现 10 次已经足够表明其重要性,没必要过度奖励。
2.5 BM25 的优势与局限¶
优势: - ✅ 可解释性强:分数可分解为词频、IDF、长度惩罚 - ✅ 计算高效:无需神经网络,毫秒级响应 - ✅ 精确匹配:擅长匹配专有名词、错误信息、代码片段 - ✅ 参数简单:只有 k1, b 两个参数,易于调优
局限: - ❌ 词汇鸿沟:无法理解同义词("auth" ≠ "authentication") - ❌ 语义盲区:无法处理语义相近但词不同的查询 - ❌ 依赖分词:分词质量直接影响检索效果 - ❌ 长查询衰减:查询词越多,每个词的权重被稀释
3. 向量检索¶
向量检索(Dense Retrieval)通过将文本编码为高维向量,用向量相似度衡量语义相关性。
3.1 向量相似度度量¶
余弦相似度¶
衡量两个向量之间的角度差异:
特点: - 关注方向而非大小,适合文本嵌入 - 值域:[0, 2],越小越相似 - 不受向量长度影响
示例:向量 \(A = [1, 2, 3]\),向量 \(B = [2, 4, 6]\) - \(A \cdot B = 1 \times 2 + 2 \times 4 + 3 \times 6 = 28\) - \(\|A\| = \sqrt{1^2 + 2^2 + 3^2} = \sqrt{14} \approx 3.74\) - \(\|B\| = \sqrt{2^2 + 4^2 + 6^2} = \sqrt{56} \approx 7.48\) - 余弦相似度 = \(28 / (3.74 \times 7.48) = 1.0\)(完全同向)
欧氏距离¶
两点之间的直线距离:
特点: - 受向量长度影响 - 值域:[0, ∞),越小越相似 - 适合需要考虑向量大小的场景
3.2 近似最近邻搜索 (ANN)¶
暴力搜索需要与所有向量计算距离,时间复杂度 O(n)。ANN 通过以下方式优化:
| 算法 | 原理 | 特点 |
|---|---|---|
| IVF (Inverted File) | 聚类分区,只搜索最近的聚类中心 | 平衡精度和速度 |
| HNSW (Hierarchical NSW) | 分层图结构,从顶层粗定位到底层精搜索 | 高精度,高召回 |
| Annoy | 随机投影树 | 内存高效 |
| FAISS | Meta 开发,支持多种索引算法 | 高性能,GPU 加速 |
HNSW 工作原理:
HNSW 构建分层图,类似跳表:
第 2 层: ── 节点 ── 节点 ── 节点 ──
第 1 层: ── 节点 ── 节点 ── 节点 ── 节点 ──
第 0 层: ── 节点 ── 节点 ── 节点 ── 节点 ── 节点 ──
搜索时: 1. 从顶层入口点开始 2. 在每层找到最近的邻居 3. 逐层下降到底层进行精确搜索
时间复杂度:O(log n),比暴力搜索快几个数量级。
3.3 向量检索 vs BM25¶
| 特性 | BM25 | 向量检索 |
|---|---|---|
| 匹配方式 | 精确关键词匹配 | 语义相似度 |
| 查询示例 | "JWT auth middleware" | "如何添加登录功能" |
| 同义词处理 | ❌ 需要手动扩展同义词 | ✅ 自动理解语义相近 |
| 专有名词 | ✅ 精确匹配 | ❌ 可能匹配到语义相近但不同的词 |
| 计算成本 | 低(毫秒级) | 高(需要嵌入计算 + ANN 搜索) |
| 可解释性 | 强(分数可分解) | 弱(黑盒向量空间) |
| 适用场景 | 搜索特定术语、代码片段 | 搜索概念、意图 |
权衡:BM25 快速精确但语义盲区,向量检索语义丰富但成本高。实践中通常结合两者。
4. 混合检索¶
混合检索(Hybrid Search)结合 BM25 和向量检索的优势,通过加权融合提升检索质量。
4.1 RRF (Reciprocal Rank Fusion)¶
RRF 是最常用的融合算法,核心思想:对多个排序列表进行融合,每个列表的排名转换为分数后相加。
RRF 公式:
其中: - \(d\):文档 - \(\text{rank}_i(d)\):文档 \(d\) 在第 \(i\) 个列表中的排名(从 1 开始) - \(k\):常数(通常 60)
数值示例:
假设有 3 个文档,BM25 和向量检索的排名:
| 文档 | BM25 排名 | 向量检索排名 |
|---|---|---|
| D1 | 1 | 3 |
| D2 | 2 | 1 |
| D3 | 3 | 2 |
计算 RRF 分数(\(k=60\)):
融合后排名:D2 > D1 > D3
RRF 的优势: - ✅ 无需参数调优(k=60 是经验值) - ✅ 对不同检索算法的分数尺度不敏感 - ✅ 简单高效,易于实现
4.2 加权融合¶
另一种方式是直接加权融合原始分数:
其中 \(\alpha\) 是权重参数(通常 0.3-0.7)。
权衡:
- 加权融合需要归一化不同检索算法的分数尺度
- 需要调参 α,但可以更灵活地控制检索策略
4.3 混合检索在实践中的应用¶
混合检索已在多个系统中得到验证,常见应用模式:
- 三路融合:BM25 + 向量 + 知识图谱,通过 RRF 统一排序,适合需要多维度相关性的场景
- 可配置权重分配:允许根据场景调整 BM25 和向量的权重(如 BM40% + 向量60%),平衡精确匹配和语义理解
- 混合查询引擎:支持在同一查询中结合布尔查询、BM25 和向量检索,提供灵活的检索策略
5. 检索优化技巧¶
5.1 查询扩展¶
通过同义词、相关词扩展查询,提升召回率。例如,原始查询 "JWT auth" 可扩展为 "JWT auth authentication login token",覆盖更多语义相关的文档。
权衡: - 手动同义词词典:精确可控但维护成本高,适合领域专有名词 - 通用词库(如 WordNet):覆盖面广但可能包含领域无关的同义词 - LLM 自动扩展:灵活智能但增加延迟和成本,适合开放域查询
5.2 重排序 (Reranking)¶
先用快速检索(BM25/ANN)召回候选文档,再用精确模型(如 Cross-Encoder)重排序:
权衡:重排序增加延迟(通常增加 50-200ms),但显著提升精度(Top-10 准确率可提升 10-30%)。适合对精度要求高但对延迟不敏感的场景。
5.3 元数据过滤¶
结合文档元数据(时间、作者、类别)进行过滤。例如,只检索最近 6 个月的文档,或限定特定作者的内容。
权衡:元数据过滤可以显著提升结果的相关性,但需要: - 检索前过滤:可能错过相关但元数据不匹配的文档 - 检索后过滤:召回更多候选文档但增加计算开销
6. 检索评估指标¶
6.1 精确率与召回率¶
| 指标 | 公式 | 含义 |
|---|---|---|
| Precision@K | 相关文档数 / 返回文档数 | 前 K 个结果中有多少是相关的 |
| Recall@K | 相关文档数 / 总相关文档数 | 前 K 个结果覆盖了多少相关文档 |
| MRR | 1 / 第一个相关文档的排名 | 第一个相关文档排得越靠前,分数越高 |
指标权衡: - 精确率 vs 召回率:通常存在此消彼长的关系。提高召回率(返回更多结果)会降低精确率,反之亦然。需要根据场景选择:搜索引擎重视精确率(用户希望前几个结果就准确),知识库检索重视召回率(不遗漏相关信息) - Precision@K 的 K 值选择:K=1 关注第一个结果的质量(适合问答系统),K=10 关注前十个结果的整体质量(适合列表展示场景) - MRR 的局限性:只关注第一个相关文档的排名,对多个相关文档的排序质量不敏感,适合单答案场景但不适合多答案场景
参考资料¶
-
Robertson, S. E., & Walker, S. (1994). Some simple effective approximations to the 2-Poisson model for probabilistic weighted retrieval. SIGIR '94. https://doi.org/10.1145/188490.188561 ↩