微信扫码
添加专属顾问
我要投稿
混合搜索正成为RAG系统的未来,它巧妙结合关键词与语义搜索,解决单一搜索范式的局限性。核心内容: 1. 关键词搜索与语义搜索各自的优缺点分析 2. 混合搜索如何实现1+1>2的效果 3. 混合搜索在RAG系统中的实际应用案例
在构建检索增强生成(RAG)系统时,我们常常陷入一个困境:如何确保检索到的上下文既“语义相关”又“关键词精确”?
想象一下这个场景:
这两种情况都指向了一个核心问题:单纯依赖一种搜索范式,无论是基于稠密向量的语义搜索,还是基于稀疏向量的关键词搜索,都有其局限性。
为了解决这个问题,混合搜索(Hybrid Search)应运而生。它并非简单的两者叠加,而是通过智能地融合两种搜索范式的结果,实现 1 + 1 > 2
的效果,正在成为构建下一代高质量 RAG 应用的关键。
要理解混合搜索,我们首先要了解它的两个核心引擎。
这类引擎的核心是找到与查询词完全匹配或高度相关的文档。
这是经典的、基于统计的关键词搜索算法。它们通过计算词频(Term Frequency)和逆文档频率(Inverse Document Frequency)来评估一个词在一个文档中的重要性。简单来说,一个词在一个文档中出现次数越多,但在所有文档中越稀有,它的权重就越高。
这是对传统关键词搜索的一次“智能升级”。像 SPLADE、BGE-M3-Sparse 这样的模型,通过深度学习来生成一个高维但大部分值为零的“稀疏向量”。
这类引擎的目标是理解查询背后的深层意图。
通过 Sentence Transformers 这类模型,我们可以将文本转换成一个几百维的“稠密向量”(Dense Vector)。这个向量可以被看作是文本在语义空间中的一个坐标。
核心原理 | |||
向量类型 | |||
优点 | |||
缺点 | |||
最适用场景 |
当我们从稀疏和稠密两种搜索中各得到一个按相关性排序的文档列表后,如何将它们合并成一个更优的列表?这就是结果融合的艺术。
最简单的方法是加权平均,但它依赖于两种搜索返回的、不可直接比较的分数,效果往往不佳。
目前,业界最推崇的方法之一是 倒数排名融合 (Reciprocal Rank Fusion, RRF)。
Score(doc) = Σ (1 / (k + rank_i))
其中,rank_i
是文档在第 i
个搜索结果列表中的排名,k
是一个小的平滑常数(通常设为 60),用于降低排名靠后结果的权重。下面,我们用 rank-bm25
和 sentence-transformers
库来模拟一个混合搜索过程。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
# 安装必要的库
# pip install rank-bm25 sentence-transformers scikit-learn
import numpy as np
from rank_bm25 import BM25Okapi
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# 1. 准备数据
documents = [
"Apple Inc. announced the new M3 chip, focusing on performance and efficiency.",
"The latest financial report from Apple Inc. shows strong growth in the services sector.",
"A detailed review of the MacBook Pro with M3 chip highlights its impressive speed.",
"Google's new Pixel phone features an advanced AI-powered camera.",
"How to bake the perfect apple pie from scratch.",
"Microsoft's Surface Laptop competes directly with Apple's MacBook Air."
]
# 2. 创建双索引
# 稀疏索引 (BM25)
tokenized_docs = [doc.lower().split() for doc in documents]
bm25 = BM25Okapi(tokenized_docs)
# 稠密索引 (Sentence Transformer)
model = SentenceTransformer('all-MiniLM-L6-v2')
doc_embeddings = model.encode(documents)
# 3. 执行搜索
query = "latest review of Apple's M3 chip"
tokenized_query = query.lower().split()
# BM25 搜索
bm25_scores = bm25.get_scores(tokenized_query)
# 向量搜索
query_embedding = model.encode(query)
cosine_scores = cosine_similarity([query_embedding], doc_embeddings)[0]
# 4. 实现 RRF 融合
def reciprocal_rank_fusion(search_results_list, k=60):
fused_scores = {}
for doc_scores in search_results_list:
# 对每个搜索结果列表按分数降序排序,获取排名
sorted_docs = sorted(doc_scores.items(), key=lambda item: item[1], reverse=True)
for rank, (doc_index, score) in enumerate(sorted_docs):
if doc_index not in fused_scores:
fused_scores[doc_index] = 0
fused_scores[doc_index] += 1 / (k + rank + 1) # rank 从 0 开始,所以 +1
# 按 RRF 分数重新排序
reranked_results = sorted(fused_scores.items(), key=lambda item: item[1], reverse=True)
return reranked_results
# 准备 RRF 输入
bm25_results = {i: score for i, score in enumerate(bm25_scores)}
vector_results = {i: score for i, score in enumerate(cosine_scores)}
fused_results = reciprocal_rank_fusion([bm25_results, vector_results])
# 5. 展示结果
print("--- Query ---")
print(query)
print("
--- BM25 (Keyword) Search Results ---")
for i, score in sorted(bm25_results.items(), key=lambda item: item[1], reverse=True):
print(f"Score: {score:.4f} Doc: {documents[i]}")
print("
--- Vector (Semantic) Search Results ---")
for i, score in sorted(vector_results.items(), key=lambda item: item[1], reverse=True):
print(f"Score: {score:.4f} Doc: {documents[i]}")
print("
--- Hybrid Search (RRF Fused) Results ---")
for doc_index, score in fused_results:
print(f"Score: {score:.4f} Doc: {documents[doc_index]}")
运行结果分析:
将混合搜索集成到 RAG 系统中,带来的不仅仅是检索精度的提升:
混合搜索并非一个复杂的概念,但它通过智能地融合稀疏和稠密两种搜索范式,精准地解决了各自的短板,让搜索结果的质量产生了质的飞跃。它不再是锦上添花,而是正在成为构建下一代强大、可靠 RAG 应用的核心组件。
展望未来,我们可能会看到更智能的、能够根据查询意图自适应调整融合权重的策略出现。但就目前而言,掌握并应用混合搜索,无疑是每一位 AI 应用开发者都应该具备的关键能力。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-08-02
RAG与Agentic RAG:智能AI系统的进化之路
2025-08-02
RAG应用如何进行有效的文本切分
2025-08-02
为什么你的RAG效果总差一点?从RankNet到Qwen,一文读懂Rerank模型的演进
2025-08-02
提升RAG表现的15个实战分块技巧
2025-08-01
96.3%准确率!Routine框架:让企业级Agent告别“不靠谱”
2025-08-01
中小企业AI破局:RAG 部署从 “能用” 到 “能用好” 的 10 条经验
2025-08-01
关于一个RAG功能需求分析案例——、怎么优化RAG的检索精确度
2025-08-01
踩了无数坑后,我终于搞定了RAG系统的"胡说八道"问题
2025-06-06
2025-05-30
2025-06-05
2025-05-19
2025-05-08
2025-05-10
2025-06-05
2025-05-20
2025-06-05
2025-05-09
2025-07-28
2025-07-09
2025-07-04
2025-07-01
2025-07-01
2025-07-01
2025-07-01
2025-06-30