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

这是因为语义搜索关注的是含义而非精确的文本匹配。当您需要精确的关键词匹配时,就需要一种不同的方法。
混合搜索策略
解决方案是并行运行语义搜索和词法搜索,然后合并结果。这样可以兼得两者的优势:

- 语义搜索 - 使用嵌入(embeddings)查找概念上相关的内容
- 词法搜索 - 使用经典文本搜索查找精确的关键词匹配
- 合并结果 - 结合两种方法以获得更好的整体相关性
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 运行同一个在仅使用语义搜索时失败的查询时,会得到更好的结果。该算法能够正确地优先处理包含确切事件 ID 的部分,将其排名高于那些可能语义相关但不包含您所查找的特定术语的部分。
现在,搜索结果能够正确地呈现实际讨论该事件的软件工程部分和网络安全部分,而不是返回像财务分析这样的无关内容。
后续步骤
既然您已经拥有了独立运行的语义搜索和词法搜索系统,下一步就是合并它们的结果。这种混合方法将把嵌入的语义理解与关键词匹配的精确性结合起来,为您的 RAG 流水线创造更强大的搜索体验。