跳转至

信息检索基础

背景知识
  • 词嵌入 (Embedding):将文本映射为高维向量,语义相近的文本在向量空间中距离近 → 详见
  • 余弦相似度:衡量两个向量之间的角度差异,不受向量长度影响,适合文本嵌入的相似度计算
  • RAG (检索增强生成):从外部知识库检索相关文档,注入 LLM 上下文以减少幻觉 → 详见

信息检索是 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 的相关性评分:

\[ \text{score}(D,Q) = \sum_{q_i \in Q} \text{IDF}(q_i) \times \frac{f(q_i,D) \times (k_1 + 1)}{f(q_i,D) + k_1 \times (1 - b + b \times \frac{|D|}{\text{avgdl}})} \]

参数含义

  • \(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 计算公式

\[ \text{IDF}(q_i) = \log \frac{N - \text{df}(q_i) + 0.5}{\text{df}(q_i) + 0.5} \]

其中: - \(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

\[ \text{df}(\text{"JWT"}) = 2 \text{ (D1, D3)} $$ $$ \text{IDF}(\text{"JWT"}) = \log \frac{3 - 2 + 0.5}{2 + 0.5} = \log \frac{0.5}{2.5} = \log 0.2 \approx -1.61 \]
\[ \text{df}(\text{"auth"}) = 1 \text{ (D1)} $$ $$ \text{IDF}(\text{"auth"}) = \log \frac{3 - 1 + 0.5}{1 + 0.5} = \log \frac{2.5}{1.5} = \log 1.67 \approx 0.51 \]

步骤 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 $$

\[ \text{score}(\text{"JWT"}) = \text{IDF}(\text{"JWT"}) \times \frac{1 \times (1.5 + 1)}{1 + 1.5 \times 1} = -1.61 \times \frac{2.5}{2.5} = -1.61 \]
\[ \text{score}(\text{"auth"}) = \text{IDF}(\text{"auth"}) \times \frac{1 \times (1.5 + 1)}{1 + 1.5 \times 1} = 0.51 \times \frac{2.5}{2.5} = 0.51 \]
\[ \text{total\_score}(D1) = -1.61 + 0.51 = -1.10 \]

对于 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 向量相似度度量

余弦相似度

衡量两个向量之间的角度差异:

\[ \text{余弦相似度} = \cos(\theta) = \frac{A \cdot B}{\|A\| \times \|B\|} $$ $$ \text{余弦距离} = 1 - \text{余弦相似度} \]

特点: - 关注方向而非大小,适合文本嵌入 - 值域:[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\)(完全同向)

欧氏距离

两点之间的直线距离:

\[ d(A, B) = \sqrt{\sum_{i} (A_i - B_i)^2} \]

特点: - 受向量长度影响 - 值域:[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 公式

\[ \text{RRF\_score}(d) = \sum_{i} \frac{k}{k + \text{rank}_i(d)} \]

其中: - \(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\)):

\[ \text{RRF}(D1) = \frac{60}{60+1} + \frac{60}{60+3} = 0.984 + 0.952 = 1.936 $$ $$ \text{RRF}(D2) = \frac{60}{60+2} + \frac{60}{60+1} = 0.967 + 0.984 = 1.951 $$ $$ \text{RRF}(D3) = \frac{60}{60+3} + \frac{60}{60+2} = 0.952 + 0.967 = 1.919 \]

融合后排名:D2 > D1 > D3

RRF 的优势: - ✅ 无需参数调优(k=60 是经验值) - ✅ 对不同检索算法的分数尺度不敏感 - ✅ 简单高效,易于实现

4.2 加权融合

另一种方式是直接加权融合原始分数:

\[ \text{hybrid\_score} = \alpha \times \text{BM25\_score} + (1-\alpha) \times \text{vector\_score} \]

其中 \(\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)重排序:

查询 → 快速检索(召回 100 个)→ 重排序(Top 10)→ 返回

权衡:重排序增加延迟(通常增加 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 的局限性:只关注第一个相关文档的排名,对多个相关文档的排序质量不敏感,适合单答案场景但不适合多答案场景


参考资料


  1. 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