什么是 RAG 中的 Hybrid search?
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 组件会执行以下步骤:
- 分词 – 将查询 “AX-705 engine” 拆分为
["ax-705", "engine"]。 - 查找 – 检索器在其倒排索引(字典)中查找包含这些精确字符串的文档块。
- 打分 (f(q, d)) – 为每个匹配计算 BM25 分数,考虑以下因素:
- 稀有度: 像 “AX-705” 这样的罕见词会获得更高权重,而像 “engine” 这样的常见词权重较低。
- 饱和度: 同一词出现多次并不会线性提升分数,防止关键词堆砌。
- 长度惩罚: 较短、聚焦的块会比包含这些词的超长块排名更高。
- 排序 – 返回按 BM25 分数排序的块列表。
下一步:倒数排名融合(RRF)
当 EnsembleRetriever 获得 BM25 与向量检索的独立列表后,需要将它们合并。由于两者的分数尺度不同,采用 RRF(Reciprocal Rank Fusion)进行融合。
- 原理: RRF 关注文档在每个列表中的 排名(位置),而不是原始分数。
- 直觉: 若某文档在 BM25 中排名第 1,但在向量搜索中排名第 50,它仍会获得较高的综合得分,体现出完美的关键字匹配。
这些技术共同实现了检索增强生成(RAG)流水线中的高效混合搜索。