在构建 RAG 流水线时,您会很快发现仅靠语义搜索并不总能返回最佳结果。有时您需要精确的术语匹配,而语义搜索可能会遗漏这些内容。解决方案是使用一种称为 BM25 的技术,将语义搜索与词法搜索结合起来。
仅使用语义搜索的问题
假设您在文档中搜索一个特定的事件 ID,例如"INC-2023-Q4-011"。尽管这个确切的术语在相关章节中多次出现,但语义搜索可能会返回一些语义上相似但实际上并不包含您要查找的特定术语的无关章节。

这是因为语义搜索关注的是含义而非精确匹配。当您需要精确的术语匹配时,就需要一种不同的方法。
混合搜索策略
解决方案是并行运行两种搜索并合并结果:

- 语义搜索 - 使用嵌入和向量数据库进行基于含义的匹配
- 词法搜索 - 使用经典文本搜索进行精确术语匹配
- 合并结果 - 结合两个结果集以获得更好的覆盖率
BM25 的工作原理
BM25(Best Match 25)是 RAG 流水线中用于词法搜索的一种流行算法。以下是它处理搜索查询的方式:

该算法遵循以下关键步骤:
- 对查询进行分词 - 将用户的问题拆分为单个术语
- 统计术语频率 - 查看每个术语在所有文档中出现的频率
- 按稀有度加权术语 - 使用频率较低的术语获得更高的重要性分数
- 找到最佳匹配 - 返回包含更多高权重术语实例的文本块
关键的洞察是,像"INC-2023-Q4-011"这样的稀有术语对搜索的重要性远高于像"a"或"the"这样的常见词。
实现 BM25 搜索
以下是设置 BM25 搜索系统的方法:
# 创建一个 BM25 存储
store = BM25Index()
# 向存储中添加文档
for chunk in chunks:
store.add_document({"content": chunk})
# 搜索存储
results = store.search("What happened with INC-2023-Q4-011?", 3)BM25 实现提供了与您的语义搜索系统相同的 API——两者都有 add_document() 和 search() 方法,使它们易于配合使用。
更好的搜索结果
当您对同一个在仅使用语义搜索时失败的查询运行 BM25 时,会获得更好的结果。BM25 不会返回不相关的章节,而是会优先返回实际包含您特定搜索术语的章节。
该算法正确地识别出"INC-2023-Q4-011"是一个稀有且重要的术语,并将包含该术语的文档排名远高于仅包含查询中常见词的文档。
后续步骤
既然您已经让语义搜索和词法搜索系统独立运行起来,下一步就是合并它们的结果。这种混合方法让您兼得两者的优势——语义搜索的上下文理解能力,结合词法搜索的精确术语匹配能力。

两个搜索系统使用相似的 API,这使得并行查询两者并将其结果合并为一个更全面的单一结果集变得简单直接。