目录
[1. 医疗领域](#1. 医疗领域)
[2. 法律领域](#2. 法律领域)
[3. 技术文档](#3. 技术文档)
[1. 结果融合(Score Fusion)](#1. 结果融合(Score Fusion))
[2. 重排序(Reranking)](#2. 重排序(Reranking))
[3. 使用支持混合检索的向量数据库](#3. 使用支持混合检索的向量数据库)
[1. 根据场景选择权重](#1. 根据场景选择权重)
[2. 结合重排序提升效果](#2. 结合重排序提升效果)
[3. 使用专业工具和平台](#3. 使用专业工具和平台)
[4. 持续评估和优化](#4. 持续评估和优化)
引言
在构建RAG(检索增强生成)系统时,检索质量直接决定了生成内容的上限。如果检索阶段无法召回相关文档,即使大模型能力再强,也难以生成准确的答案。
然而,单一检索方法总有局限:稠密向量检索 擅长理解语义,却可能忽略精确的关键词匹配;**稀疏检索(如BM25)**能精准命中关键词,却难以理解同义词和上下文语义。那么,有没有办法让两者优势互补?
答案是肯定的------这就是本文要介绍的混合检索(Hybrid Search)。
什么是混合检索?
混合检索是一种结合多种检索技术(通常是稀疏检索和稠密检索)的查询方法,旨在融合不同检索方式的优势,提升整体检索效果。
在RAG系统中,混合检索通常发生在检索阶段,通过聚合多个信息流,为后续的生成提供更准确、更丰富的上下文。
混合检索的核心思想
传统的RAG方案中,检索到的多个文档往往只是简单拼接后输入给大模型。而混合检索则采用更专业的机制,跨多个检索结果组合相关信息:
-
在检索后增强:对多个检索结果应用重排序、过滤或合并
-
在生成中融合:让大模型独立处理每个检索结果,再融合生成
稀疏检索(BM25)与稠密检索的对比
要理解混合检索的价值,首先需要了解这两种检索方式的优缺点。
稀疏检索(BM25)
BM25(Best Matching 25)是基于关键词匹配的传统信息检索算法,它通过计算查询词与文档的词频(TF)和逆文档频率(IDF)来评估相关性。
优点:
-
精准匹配:能精确命中特定术语、编号、名称等
-
可解释性强:清楚知道为什么匹配(因为包含某些关键词)
-
无需训练:直接基于统计计算,无需模型训练
缺点:
-
语义盲区:无法理解同义词(如"汽车"和"车辆")
-
词汇鸿沟:如果文档用词与查询不同,即使语义相关也无法召回
-
无法处理复杂语义:对意图理解能力有限
稠密检索(向量检索)
稠密检索通过神经网络将文本映射到高维语义空间,用向量表示语义,通过计算向量相似度进行检索。
优点:
-
语义理解:能理解同义词、上下文和隐含意图
-
跨语言检索:支持不同语言的语义匹配
-
容错性强:对查询中的拼写错误有一定容忍度
缺点:
-
可能引入噪音:语义相近但不相关的内容可能被误召回
-
可解释性差:难以解释为什么匹配
-
依赖训练数据:对长尾或专业领域术语可能效果不佳
为什么需要混合检索?
单一检索方法在实际应用中往往力不从心,尤其是在以下场景:
1. 医疗领域
医生搜索"2型糖尿病 儿童患者 病例",纯向量检索可能召回一堆1型糖尿病的资料------语义相近,但与需求不符。
2. 法律领域
用户查询"XX场景下的连带责任",纯向量检索可能返回大量"XX场景补充责任"的文书------仅两字之差,法律含义却天差地别。
3. 技术文档
搜索"Oracle JDBC驱动配置",纯关键词搜索可能错过用"Java数据库连接"表述的文档,纯语义搜索可能召回过于泛化的内容。
混合检索的价值 正是在于:既能理解整体语义,又能匹配精确术语,弥补单一方法的不足。
混合检索的实现方式
1. 结果融合(Score Fusion)
最常用的混合检索方式是分别执行稀疏检索和稠密检索,然后将两个结果集按一定权重融合。
python
def hybrid_search(query, dense_retriever, sparse_retriever, alpha=0.5, top_k=10):
"""
混合检索:融合稠密检索和稀疏检索的结果
Args:
query: 查询文本
dense_retriever: 稠密检索器
sparse_retriever: 稀疏检索器(BM25)
alpha: 稠密检索权重 (0-1),稀疏检索权重为 1-alpha
top_k: 返回结果数量
Returns:
融合后的检索结果
"""
# 执行稠密检索
dense_results = dense_retriever.retrieve(query, top_k=top_k*2)
# 执行稀疏检索
sparse_results = sparse_retriever.retrieve(query, top_k=top_k*2)
# 融合分数
combined_scores = {}
# 归一化分数并加权融合
for doc_id, score in normalize_scores(dense_results):
combined_scores[doc_id] = alpha * score
for doc_id, score in normalize_scores(sparse_results):
if doc_id in combined_scores:
combined_scores[doc_id] += (1 - alpha) * score
else:
combined_scores[doc_id] = (1 - alpha) * score
# 按融合分数排序,返回top_k
sorted_results = sorted(combined_scores.items(),
key=lambda x: x[1], reverse=True)[:top_k]
return sorted_results
def normalize_scores(results):
"""分数归一化"""
if not results:
return []
scores = [score for _, score in results]
max_score = max(scores)
min_score = min(scores)
if max_score == min_score:
return [(doc_id, 1.0) for doc_id, _ in results]
return [(doc_id, (score - min_score) / (max_score - min_score))
for doc_id, score in results]
2. 重排序(Reranking)
更精细的方式是先分别检索出较多候选结果,然后用一个更强大的模型(如交叉编码器)进行重排序
python
def hybrid_search_with_rerank(query, dense_retriever, sparse_retriever,
reranker, initial_k=20, final_k=10):
"""
混合检索 + 重排序
"""
# 分别检索更多候选
dense_results = dense_retriever.retrieve(query, top_k=initial_k)
sparse_results = sparse_retriever.retrieve(query, top_k=initial_k)
# 合并候选文档(去重)
candidate_docs = merge_deduplicate(dense_results, sparse_results)
# 使用重排序模型重新打分
reranked = reranker.rerank(query, candidate_docs)
return reranked[:final_k]
3. 使用支持混合检索的向量数据库
现代向量数据库如**Milvus 2.5+**已原生支持混合检索,内置BM25算法,可以自动从文本字段生成稀疏向量。
python
from pymilvus import MilvusClient, DataType, Function, FunctionType
# 创建支持混合检索的集合
schema = MilvusClient.create_schema()
# 添加文本字段(启用分析器)
schema.add_field(
field_name="text",
datatype=DataType.VARCHAR,
max_length=65535,
enable_analyzer=True,
analyzer_params={"type": "chinese"} # 中文分析器
)
# 添加稠密向量字段
schema.add_field(
field_name="dense",
datatype=DataType.FLOAT_VECTOR,
dim=768
)
# 添加稀疏向量字段(将由BM25函数自动生成)
schema.add_field(
field_name="sparse_bm25",
datatype=DataType.SPARSE_FLOAT_VECTOR
)
# 定义BM25函数:自动从text字段生成稀疏向量
bm25_function = Function(
name="bm25",
function_type=FunctionType.BM25,
input_field_names=["text"],
output_field_names="sparse_bm25",
)
schema.add_function(bm25_function)
# 创建集合
client.create_collection(
collection_name="hybrid_collection",
schema=schema
)
# 混合检索:同时使用稠密向量和稀疏向量
hybrid_results = client.hybrid_search(
collection_name="hybrid_collection",
reqs=[
# 稠密检索请求
{
"vector": query_dense_embedding,
"anns_field": "dense",
"param": {"metric_type": "IP"},
"limit": 10
},
# 稀疏检索请求
{
"vector": query_text, # 自动转换为BM25稀疏向量
"anns_field": "sparse_bm25",
"param": {"metric_type": "BM25"},
"limit": 10
}
],
rerank={"strategy": "rrf"}, # 使用倒数秩融合
limit=10
)
权重优化:从静态到动态
混合检索的核心挑战之一是如何确定稠密检索和稀疏检索的权重 (即前述代码中的alpha值)。
静态权重的局限
传统的固定权重方案(如始终alpha=0.5)无法适应不同查询的特性------有些查询更需要语义理解,有些则更需要关键词精确匹配。
动态权重调整
最新研究提出了动态权重调整方案,让系统根据查询特性自适应地调整融合权重。
方法一:基于LLM的动态权重调优
**DAT(Dynamic Alpha Tuning)**框架利用大语言模型评估两种检索方法的效果,动态校准最优权重:
python
def dynamic_alpha_tuning(query, dense_retriever, sparse_retriever, llm):
"""
使用LLM动态调整混合检索权重
"""
# 分别获取两种检索的top-1结果
dense_top1 = dense_retriever.retrieve(query, top_k=1)[0]
sparse_top1 = sparse_retriever.retrieve(query, top_k=1)[0]
# 让LLM评估两个结果的有效性
prompt = f"""
查询:{query}
结果A(稠密检索):{dense_top1.text}
结果B(稀疏检索):{sparse_top1.text}
请评估这两个结果与查询的相关性,分别给出0-10的分数。
只返回两个数字,格式:A分数, B分数
"""
response = llm.generate(prompt)
dense_score, sparse_score = parse_scores(response)
# 归一化作为权重
total = dense_score + sparse_score
alpha = dense_score / total if total > 0 else 0.5
return alpha
实验表明,DAT方法在各种评估指标上显著优于固定权重混合检索。
方法二:基于信息熵的动态加权
另一种前沿方法是使用归一化香农熵作为检索置信度的代理,迭代优化稀疏和稠密分数的线性组合:
python
def entropy_based_weighting(query, dense_retriever, sparse_retriever,
max_iterations=5, epsilon=0.1):
"""
基于熵的动态权重调整
"""
# 初始化权重
w_dense, w_sparse = 0.5, 0.5
for iteration in range(max_iterations):
# 执行混合检索
results = hybrid_search(query, dense_retriever, sparse_retriever,
alpha=w_dense, top_k=20)
# 计算检索结果的熵(衡量不确定性)
scores = [score for _, score in results]
entropy = calculate_entropy(scores)
# 熵归一化
norm_entropy = entropy / max_entropy
# 更新权重:熵越高,越偏向稀疏检索(更精确)
w_dense = 1 - norm_entropy
w_sparse = norm_entropy
# 检查收敛
if abs(w_dense - prev_w_dense) < epsilon:
break
return hybrid_search(query, dense_retriever, sparse_retriever,
alpha=w_dense, top_k=10)
这种方法在HotPotQA和TriviaQA等数据集上显著优于固定权重基线。
混合检索的最佳实践
1. 根据场景选择权重
-
技术文档/法律条文:提高稀疏检索权重(alpha较小),确保术语精准匹配
-
开放域问答/对话:提高稠密检索权重(alpha较大),强调语义理解
-
混合场景:从0.5开始,根据实际效果微调
2. 结合重排序提升效果
混合检索后,可以使用交叉编码器等重排序模型对结果进行精排,进一步提升相关性。
3. 使用专业工具和平台
-
Milvus/Zilliz Cloud:原生支持混合检索,提供完整的工具链
-
Oracle Database 23ai:同时支持向量搜索和全文搜索,内置混合检索能力
-
RAGFlow框架:集成混合检索模块,简化开发流程
4. 持续评估和优化
建立评估指标,持续监控检索效果:
-
Precision@K:检索结果的相关性
-
Recall@K:相关文档的召回率
-
MRR:首个相关结果的排名
总结
混合检索通过结合稀疏检索和稠密检索的优势,显著提升了RAG系统的检索质量:
-
稀疏检索(BM25):确保关键词精准匹配,可解释性强
-
稠密检索(向量):捕捉语义相似性,理解深层意图
-
混合检索:两者优势互补,应对复杂查询场景
随着向量数据库技术的进步(如Milvus 2.5+的原生混合检索能力)和动态权重优化算法的成熟(如DAT、基于熵的调整),混合检索正变得越来越易用和高效。
在实际应用中,建议从简单的加权融合开始,根据具体场景调整权重,逐步引入重排序和动态优化策略,打造最适合自己业务需求的RAG系统。