微信扫码
添加专属顾问
我要投稿
深入探索BM25算法在RAG系统中的关键作用与实现细节。 核心内容: 1. BM25算法在RAG检索阶段的应用 2. BM25判断相关性的方法与公式 3. BM25与TF-IDF的比较及优势分析
BM25 是一个文本相关性排序算法。
在 RAG 系统的检索阶段,它能快速地从海量文档中找到与查询最匹配的候选段落,为后续的生成模型提供更加聚焦的上下文。
BM25 可以独立使用,也可以和 dense 检索联合构建更强的 hybrid 检索器
-- 领取学习资料大礼包,见文末
当用户提出问题时,RAG(检索增强生成,Retrieval-Augmented Generation)首先会从海量数据中“检索”出相关的文档片段,然后将这些检索结果提供给LLM模型,以生成更准确、更可靠的答案。
信息检索是 RAG 的基石,而实现高效准确的检索,需要依赖各种排序和匹配算法。
在信息检索领域,既有基于向量相似度的现代方法,也有基于关键词的传统方法。
TF-IDF(词频-逆文档频率,Term Frequency-Inverse Document Frequency)是经典的关键词匹配算法之一,而 BM25(Best Matching 25)则是在 TF-IDF 基础上发展起来的一种更先进的算法。
BM25在信息检索领域久经验证且广泛应用,在 RAG 的检索阶段扮演着重要角色。
相关阅读:TF-IDF:理解“关键词”的价值
Okapi BM25(BM 是最佳匹配的缩写)是一种用来估计文档与给定搜索查询相关性的排序函数。
排序函数的名称是 BM25。完整的名称是Okapi BM25。
Okapi 是第一个使用它的系统的名称,即 1980 年代和 1990 年代在伦敦城市大学实施的 Okapi 信息检索系统。
简单来说,BM25是一个用来计算“用户查询”和“文档”之间相关性分数的算法。分数越高,说明文档与用户查询越相关。
在RAG的检索阶段,当用户输入一个查询时,BM25会计算这个查询与知识库中每一个文档的相关性分数,然后把得分最高的几个文档挑出来,交给生成模型。
BM25的核心思想和你平时找信息时的感觉很像:
如果一个词在文档中出现的次数越多,那么这个文档可能就越和这个词相关。
比如,你搜索“苹果手机”,如果一个文档里“苹果”和“手机”这两个词出现了很多次,那它很可能就是讲苹果手机的。
但是, BM25不会无限制地强调高词频,它有一个“饱和”的概念。 想象一下你吃苹果,吃第一个很开心,吃第二个也不错,但吃到第十个可能就没那么开心了。
BM25认为词频的贡献会逐渐趋于平缓,达到一定次数后,再增加词频对相关性的提升效果有限。
一个词在整个文档集合中出现的文档数量越少,它就越能区分文档的主题,因此它的重要性越高。
比如,“的”、“是”、“在”这些词几乎在所有文档里都会出现,它们对判断文档主题没什么帮助,IDF值就很低。
但像“BM25”、“RAG”、“Transformer”这些词,只会在特定领域的文档中出现,它们的IDF值就很高,更能说明文档是关于这些主题的。
BM25会考虑文档的长度。一篇只有 100 个字的新闻报道里提到了两次“人工智能”,和一本 10 万字的百科全书里提到了两次“人工智能”。很明显,前者的主题更可能集中在“人工智能”上。
BM25会倾向于认为,一个词在短文档中出现,比在长文档中出现更能体现相关性。它会通过一个机制来“惩罚”过长的文档,避免它们仅仅因为词多而获得高分。
BM25就是结合了这三个主要因素,通过一个公式来计算最终的相关性分数。公式里还有一些参数(比如和),可以调整词频饱和度和文档长度的影响程度。
现在我们来看看BM25是如何通过公式来实现这些想法的。
BM25计算查询 和文档 之间相关性分数 的基本思想是,将查询 中的每个词 的相关性贡献加起来。
公式可以左右滑动
对于查询中的 每一个词 ,它对文档 的贡献分数由以下几部分决定:
词 在文档 中的词频 (Term Frequency):
词 的逆文档频率 (Inverse Document Frequency ):
这是衡量词 在整个文档集合中的稀有程度。计算公式通常是:
是文档集合中的总文档数,
是包含词 的文档数量。
这里的 函数和 是为了平滑处理,避免某些词出现文档数为0或时出现问题。
IDF值越高,说明词越稀有,越重要。
词频饱和部分:
这一部分用来处理词频的饱和问题,公式是:
词频: 是词 在文档 中的词频;
饱和参数: 是一个正参数,控制词频(TF)对文档得分的影响,通常取值在 到 之间通常能获得较好的结果。
文档长度归一化(惩罚长文档): :
这一部分用来处理文档长度的影响。
公式中的 表示文档 的长度 与整个文档集合的平均文档长度 的比值。
它使用一个参数 来控制文档长度归一化的程度。参数 通常取值在 到 之间。当 时,不进行文档长度归一化; 当 时,进行完全的文档长度归一化;
拆完会发现,BM25 的结构就是三块:
整个公式就是在模仿我们人类“找关键词”、“判断重点”、“嫌弃水词多”的一系列直觉,只不过变成了数学语言。
为了更好地说明 BM25 相较于 TF-IDF 在处理文档长度和词频饱和度方面的优势,我们使用一个包含 3 篇文档的文档集合进行演示。
为了简化,我们假设这些文本已经经过了分词处理。
文档 A: 机器学习 模型 训练 算法 性能 (长度 5)
文档 B: 深度学习 模型 神经网络 训练 大数据 算力 优化 性能 (长度 8)
文档 C: 算法 效率 优化 性能 (长度 4)
总文档数
文档 A 长度
文档 B 长度
文档 C 长度
平均文档长度
查询中的词是 “模型”, “算法”, “性能”。
词“模型”出现在文档 A 和文档 B 中,
词“算法”出现在文档 A 和文档 C 中,
词“性能”出现在文档 A, 文档 B 和文档 C 中,
我们使用标准的 TF-IDF 公式:
词频 (TF):
TF-IDF 分数计算:
文档 A:
文档 B:
文档 C:
TF-IDF 排名结果:
根据 TF-IDF 分数,文档排名为:
文档 A (0.998) > 文档 B (0.528) = 文档 C (0.528)
在这个简单的 TF-IDF 计算中,文档 B 和文档 C 的得分相同,因为它们都包含查询中的两个词,且这些词的 IDF 值相同。TF-IDF 在这种形式下没有考虑文档长度对相关性的影响。
假设 ,,
首先计算每个文档的长度归一化项:
文档 A (长度 5):
文档 B (长度 8):
文档 C (长度 4):
然后使用 BM25 公式计算每个词在文档中的贡献并求和:
文档 A (D_A, 软长度归一化项 ≈ 0.91):
词“模型” (TF=1, IDF≈0.47):
词“算法” (TF=1, IDF≈0.47):
词“性能” (TF=1, IDF≈0.058):
文档 B (D_B, 软长度归一化项 ≈ 1.31):
词“模型” (TF=1, IDF≈0.47):
词“算法” (TF=0): 0
词“性能” (TF=1, IDF≈0.058):
文档 C (D_C, 软长度归一化项 ≈ 0.78):
词“模型” (TF=0): 0
词“算法” (TF=1, IDF≈0.47):
词“性能” (TF=1, IDF≈0.058):
BM25 排名结果:
根据 BM25 分数,文档排名为:
文档 A (1.055) > 文档 C (0.609) > 文档 B (0.445)
通过这个新的例子,我们可以更清楚地看到 BM25 和 TF-IDF 在排名上的区别:
TF-IDF 排名: 文档 A (0.998) > 文档 B (0.528) = 文档 C (0.528)
BM25 排名: 文档 A (1.055) > 文档 C (0.609) > 文档 B (0.445)
尽管文档 B 和文档 C 都包含查询中的两个词,且这些词的 IDF 值相同,但 BM25 给予了文档 C 更高的分数,并将其排在了文档 B 的前面。这是因为:
文档长度归一化: 文档 C (长度 4) 比平均文档长度 (≈ 5.67) 短,BM25 的软长度归一化项 (≈ 0.78) 小于 1,这会提升文档 C 中词的贡献。文档 B (长度 8) 比平均文档长度长,软长度归一化项 (≈ 1.31) 大于 1,这会降低文档 B 中词的贡献。
这个例子有效地展示了 BM25 如何通过文档长度归一化来调整相关性分数,使其排名结果更符合“短文档如果包含查询词,可能更聚焦于该主题”的直觉,从而在信息检索中产生更精确的排名,这对于 RAG 系统召回高质量的相关文档至关重要。
TF-IDF和BM25都是基于词频(TF)和逆文档频率(IDF)思想的文本检索算法,但在RAG场景中,BM25更加常用,因为它解决了TF-IDF在实际信息检索中的一些主要局限性,提供了更优越的排名效果。
BM25可以看作是TF-IDF的一个优化版本,它在TF的饱和度、文档长度归一化以及IDF的平滑处理上做得更好。
除了传统的基于关键词的检索方式( TF-IDF 和 BM25),现在很多 RAG 系统会使用基于向量的 dense 检索,但其实在一些实际场景中,BM25 依然非常有竞争力,特别是在以下几类任务中表现尤为出色:
所以 BM25 在某些任务中非常实用,它也可以作为构建复杂多阶段检索系统的第一步。
LangChain 提供了一个内置的 BM25 实现。以下是使用 LangChain 实现 BM25 检索的基本步骤:
# 安装必要的库
# pip install jieba rank_bm25
from langchain.schema import Document
from langchain_community.retrievers import BM25Retriever
import jieba
def chinese_tokenizer(text):
return list(jieba.cut(text))
# 示例文档内容
doc_contents = [
"人工智能 技术 发展 迅速 机器学习 人工智能 重要 分支",
"自然语言处理 人工智能 另一个 重要 分支 文本分析 自然语言处理 常见 应用",
"技术 发展 带来 了 很多 新的 应用 领域",
"这是一个关于自然语言处理的额外文档,包含更多文本分析的内容。"
]
# 将文档内容转换为 LangChain 的 Document 对象列表
documents = [Document(page_content=content) for content in doc_contents]
# 创建 BM25 检索器
# 默认情况下,k=4,即返回最相关的4个文档
# BM25Retriever默认分词器是针对英文的,需要传入中文分词器,避免分词错误导致检索排序不准
retriever = BM25Retriever.from_documents(documents, k=2, preprocess_func=chinese_tokenizer)
# 定义查询
query = "人工智能 技术 应用"
# 执行检索
relevant_docs = retriever.invoke(query)
# 打印检索结果
print(f"对于查询 '{query}', 检索到的相关文档:")
for i, doc in enumerate(relevant_docs):
print(f"\n--- 文档 {i + 1} ---")
print(doc.page_content)
总的来说,BM25 是一个兼具简单性、可解释性和高效性的文本相关性排序算法。
在 RAG 系统的检索阶段,它能在不依赖训练的前提下,快速地从海量文档中找到与查询最匹配的候选段落,为后续的生成模型提供更加聚焦的上下文。
BM25 可以独立使用,也可以和 dense 检索联合构建更强的 hybrid 检索器。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-10-27
2024-09-04
2024-05-05
2024-07-18
2024-06-20
2024-06-13
2024-07-09
2024-07-09
2024-05-19
2024-07-07
2025-05-16
2025-05-15
2025-05-14
2025-05-14
2025-05-13
2025-05-11
2025-05-08
2025-05-05