什么是 RAG 中的 Hybrid search?

发布: (2026年4月30日 GMT+8 21:47)
4 分钟阅读
原文: Dev.to

Source: Dev.to

混合搜索的需求

我们有包含 Python 错误码及其相应定义和使用场景的文档。用户提出查询 “What is ERR_404_AUTH?” 来了解该错误码。

  • 经典 RAG: 从向量数据库(文档嵌入)中检索所有与身份验证和错误相关的上下文。
  • 词法搜索: 搜索词组 ["What", "is", "ERR_404_AUTH"]
  • 混合搜索: 搜索关键字 "ERR_404_AUTH" 并通过相似度搜索检索语义相似的文档。

使用 BM25

BM25 看作 TF‑IDF 的扩展版本,用于基于关键字的搜索。
LangChain 提供了内置的 BM25Retriever,实现非常简洁。

# pip install rank_bm25
from langchain_community.retrievers import BM25Retriever
from langchain_core.documents import Document

# 来自你的文本切分器的块
chunks = [
    Document(page_content="The AX-705 engine uses a 4-stroke cycle."),
    Document(page_content="Maintenance for AX-705 requires synthetic oil."),
    Document(page_content="Four-stroke engines are common in modern cars.")
]

# 构建 BM25 索引(倒排索引)
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 2  # 检索前 2 条

创建混合 “Ensemble”

为了将精确关键字匹配与语义意义相结合,需将 向量检索器BM25 检索器 合并。

from langchain.retrievers import EnsembleRetriever

# 假设 `chroma_retriever` 已经从你的向量库创建
hybrid_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, chroma_retriever],
    weights=[0.3, 0.7]  # 关键字占 30%,语义占 70%
)

BM25 的四个步骤(内部实现)

当你调用 hybrid_retriever.invoke("AX-705 engine") 时,BM25 组件会执行以下步骤:

  1. 分词 – 将查询 “AX-705 engine” 拆分为 ["ax-705", "engine"]
  2. 查找 – 检索器在其倒排索引(字典)中查找包含这些精确字符串的文档块。
  3. 打分 (f(q, d)) – 为每个匹配计算 BM25 分数,考虑以下因素:
    • 稀有度: 像 “AX-705” 这样的罕见词会获得更高权重,而像 “engine” 这样的常见词权重较低。
    • 饱和度: 同一词出现多次并不会线性提升分数,防止关键词堆砌。
    • 长度惩罚: 较短、聚焦的块会比包含这些词的超长块排名更高。
  4. 排序 – 返回按 BM25 分数排序的块列表。

下一步:倒数排名融合(RRF)

EnsembleRetriever 获得 BM25 与向量检索的独立列表后,需要将它们合并。由于两者的分数尺度不同,采用 RRF(Reciprocal Rank Fusion)进行融合。

  • 原理: RRF 关注文档在每个列表中的 排名(位置),而不是原始分数。
  • 直觉: 若某文档在 BM25 中排名第 1,但在向量搜索中排名第 50,它仍会获得较高的综合得分,体现出完美的关键字匹配。

这些技术共同实现了检索增强生成(RAG)流水线中的高效混合搜索。

0 浏览
Back to Blog

相关文章

阅读更多 »

模型越智能,节省越多。

神话:更智能的模型会让插件变得多余。自从 WOZCODE 推出以来,许多 Claude Code 高级用户低声说插件的优势将会消失。