结合关键词、向量与重排序的工业级 RAG 检索方案

前言

在 RAG(检索增强生成)系统的落地过程中,开发者往往会发现单纯的向量检索(Dense Retrieval)并非万能。它在处理专有名词、缩写、特定型号(如 “iPhone 15 Pro”)或罕见词汇时,表现往往不如传统的关键词检索(Sparse Retrieval)。混合检索(Hybrid Search)通过融合两者的优势,已成为构建高性能 RAG 系统的标准配置。本文将深入探讨混合检索的原理、算法实现及优化策略。


检索技术的三驾马车

1. 关键词检索 (Sparse Retrieval / BM25)

  • 原理:基于词频(TF)和逆文档频率(IDF)进行匹配。
  • 优势:精确匹配能力强,对专有名词、编号极其敏感。
  • 劣势:无法理解语义,受限于“词项重叠”(Vocabulary Overlap)。

2. 向量检索 (Dense Retrieval / Embedding)

  • 原理:将文本映射到高维连续向量空间,计算余弦相似度。
  • 优势:具备语义理解能力,能处理同义词和跨语言检索。
  • 劣势:容易产生“语义漂移”,对长尾词和精确编号匹配较弱。

3. 稀疏向量检索 (Learned Sparse Retrieval / SPLADE)

  • 原理:利用模型学习词项的重要性,生成具备语义扩展能力的稀疏向量。
  • 优势:兼具关键词的精确性和向量的语义扩展性。

核心算法:结果融合 (Fusion)

混合检索的关键在于如何将来自不同检索器的结果列表合并。

1. RRF (Reciprocal Rank Fusion)

RRF 是一种无需归一化分数的排名融合算法,它只关注文档在各列表中的相对排名。

\[score(d) = \sum_{r \in R} \frac{1}{k + r(d)}\]
  • $r(d)$:文档 $d$ 在列表 $R$ 中的排名。
  • $k$:平滑常数,通常取 60。
  • 特点:极其鲁棒,不受不同检索器分数量级差异的影响。

2. 加权得分融合 (Weighted Score Fusion)

如果各检索器的分数已经过归一化(如都在 0-1 之间),可以使用加权求和。

\[FinalScore = \alpha \cdot Score_{dense} + (1 - \alpha) \cdot Score_{sparse}\]
  • $\alpha$:调节权重。在 Weaviate 等数据库中,$\alpha=1$ 为纯向量,$\alpha=0$ 为纯关键词。

工业级检索流水线:从召回到重排

一个成熟的检索系统通常分为两个阶段:

[用户查询] ──→ [查询改写/扩展]
                     │
       ┌─────────────┴─────────────┐
       ▼                           ▼
 [向量检索 (Top 100)]       [BM25 检索 (Top 100)]
       └─────────────┬─────────────┘
                     ▼
             [RRF 结果融合 (Top 50)]
                     │
                     ▼
           [重排序 (Re-ranking)]  <-- 使用 Cross-Encoder (如 BGE-Reranker)
                     │
                     ▼
             [最终 Top 5 结果] ──→ [送入 LLM 生成]

技术实现:LangChain 混合检索与重排

以下代码展示了如何构建一个包含 BM25 + Vector + Cross-Encoder Re-ranker 的完整链路。

from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain.retrievers.contextual_compression import ContextualCompressionRetriever
from langchain_community.document_compressors import BGERerank

# 1. 初始化基础检索器
doc_list = [
    "LLM 应用的多租户架构主要分为 Silo, Bridge 和 Pool 三种模式。",
    "混合检索结合了向量检索和关键词检索的优点。",
    "RRF 算法常用于融合不同来源的检索结果。"
]

# 向量检索器
vectorstore = FAISS.from_texts(doc_list, OpenAIEmbeddings())
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

# 关键词检索器
bm25_retriever = BM25Retriever.from_texts(doc_list)
bm25_retriever.k = 2

# 2. 融合检索器 (Ensemble)
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.5, 0.5]
)

# 3. 引入重排序 (Reranker)
# 使用 BGE-Reranker 提升精度
reranker = BGERerank(model="BAAI/bge-reranker-large", top_n=2)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker, 
    base_retriever=ensemble_retriever
)

# 执行检索
query = "多租户架构有哪些模式?"
results = compression_retriever.get_relevant_documents(query)

进阶:查询增强技术

检索的质量不仅取决于数据库,还取决于你如何“问”问题。

1. HyDE (Hypothetical Document Embeddings)

  • 原理:先让 LLM 根据问题生成一个“虚假的答案”,然后用这个虚假答案去向量数据库里检索。
  • 优势:虚假答案与真实文档在向量空间中往往比原始问题更接近,能显著提升语义检索的召回率。

2. Multi-Query Retrieval (多查询检索)

  • 原理:让 LLM 将用户的问题改写成 3-5 个意思相近但措辞不同的新问题,分别检索后取并集。
  • 优势:克服了用户提问不专业或措辞单一的问题。

3. Self-Querying (自查询)

  • 原理:让 LLM 从问题中提取出结构化的过滤条件。
  • 例子:用户问“2023 年关于 AI 安全的论文有哪些?”,LLM 提取出 year=2023topic='AI Safety',并将其转化为向量数据库的 Metadata Filter。

深度解析:为什么重排序 (Reranking) 如此重要?

Bi-Encoder (向量检索):将问题和文档分别编码,计算余弦相似度。速度极快,但无法捕捉问题与文档之间细微的交互。 Cross-Encoder (重排序):将问题和文档拼接在一起,同时输入模型。模型可以逐字逐句对比两者的相关性。精度极高,但计算量巨大。

最佳实践

  1. 使用向量检索从百万级数据中快速召回 Top 100。
  2. 使用重排序模型对这 Top 100 进行精细打分,选出最终的 Top 5。 这种“粗排+精排”的架构是目前工业界 RAG 系统的天花板。

总结

混合检索不是简单的“1+1”,而是一套精密的工程体系。

  • 基础层:BM25 + Vector。
  • 融合层:RRF 算法。
  • 精排层:Cross-Encoder 重排序。
  • 增强层:HyDE 与多查询扩展。

通过这套组合拳,你可以构建出一个既懂语义、又能精准匹配专有名词的“超级大脑”。 “混合检索结合了 BM25 的精确匹配和向量检索的语义理解。”, “RRF 算法通过排名倒数求和来融合不同来源的检索结果。” ]

向量检索器

vectorstore = FAISS.from_texts(doc_list, OpenAIEmbeddings()) vector_retriever = vectorstore.as_retriever(search_kwargs={“k”: 5})

BM25 检索器

bm25_retriever = BM25Retriever.from_texts(doc_list) bm25_retriever.k = 5

2. 使用 EnsembleRetriever 进行 RRF 融合

ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, vector_retriever], weights=[0.4, 0.6] # 权重分配 )

3. 引入重排序 (Re-ranking) 提升精度

使用 BGE-Reranker 模型 (Cross-Encoder)

注意:在生产环境中,建议将 Reranker 部署为独立服务

reranker = BGERerank(model=”BAAI/bge-reranker-large”, top_n=3)

compression_retriever = ContextualCompressionRetriever( base_compressor=reranker, base_retriever=ensemble_retriever )

4. 执行检索

query = “什么是混合检索的优势?” docs = compression_retriever.get_relevant_documents(query)

for doc in docs: print(f”Score: {doc.metadata.get(‘relevance_score’, ‘N/A’)}”) print(f”Content: {doc.page_content}\n”) ```


性能优化与调优建议

  1. 权重调优 (Alpha Tuning)
    • 对于技术文档/代码库:增加 BM25 权重(如 0.7),因为精确术语匹配至关重要。
    • 对于客服/闲聊:增加向量检索权重(如 0.8),侧重语义理解。
  2. 查询改写 (Query Rewriting)
    • 在检索前,利用 LLM 将用户模糊的提问改写为更适合检索的关键词组合。
  3. 多路召回的并发化
    • 向量检索和 BM25 检索应并行执行,以降低端到端延迟。
  4. 重排的成本控制
    • Cross-Encoder 计算开销巨大,仅对召回阶段的前 20-50 个文档进行重排,不要对全量文档重排。

总结

混合检索不再是“可选项”,而是生产级 RAG 系统的“标配”。通过 BM25 召回硬匹配 + 向量召回软语义 + Cross-Encoder 精准重排 的组合拳,可以显著提升 LLM 应用的回答准确率和用户信任度。

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 LLM应用开发——混合检索策略深度解析 》

本文链接:http://localhost:3015/ai/%E6%B7%B7%E5%90%88%E6%A3%80%E7%B4%A2%E7%AD%96%E7%95%A5.html

本文最后一次更新为 天前,文章中的某些内容可能已过时!