外观
混合检索
混合检索
介绍
混合检索(BM25 + Dense)→ 企业级 RAG 的标配,准确率较大提升
| 场景 | 向量检索(Dense) | BM25(Sparse) | 混合效果 |
|---|---|---|---|
| 查询“如何请病假?” | ✅ 能匹配“医疗期规定”等语义相近内容 | ❌ 可能漏掉(无关键词) | ✔️ 互补 |
| 查询“订单号 A-9527 的状态?” | ❌ 向量模型觉得“A-9527”没语义,忽略 | ✅ 精准命中含该编号的文档 | ✔️ 必须用 BM25 |
| 查询“感冒怎么办?” | ✅ 可召回“上呼吸道感染” | ✅ 可召回“风寒、流感”(若分词覆盖) | ✔️ 更全面 |
Milvus混合检索
Milvus 支持在同一个 collection 中定义多个向量字段,并同时搜索它们。

两种典型混合场景
| 类型 | 描述 | 适用模型 |
|---|---|---|
| 稀疏+稠密混合检索 | 结合 BM25(关键词匹配) + Dense Embedding(语义理解) | BGE-M3(输出 dense)、传统 BM25 |
| 多模态混合检索 | 文本 + 图像 + 音频联合搜索 | CLIP(图文)、Whisper(语音)等 |
RRF排序
RRF(Reciprocal Rank Fusion,互反排名融合)是一种用于融合多个排序列表(ranked lists)的算法
- 无需归一化分数:不同检索系统(如关键词搜索 vs 向量搜索)的打分尺度不同,直接融合分数不可靠,而 RRF 只看排名,规避了这个问题。
- 简单有效:无需训练,参数少(通常固定 k=60),在很多基准测试中表现优异。
- 适合多路召回:例如同时使用稠密向量(Dense)、稀疏向量(Sparse)、全文检索(BM25)等,RRF 可有效融合它们的结果。

| 步骤 | 建议值 |
|---|---|
| 稠密向量搜索 limit | 5 ~ 10 |
| 稀疏向量搜索 limit | 5 ~ 10 |
| RRF 融合后输出 limit | 3 |
参数k设置
| 场景 | 推荐 $ k $ |
|---|---|
| 默认 / 通用 / limit ≤ 10 | 60 ✅ |
| 大召回(limit ≥ 20)且需平滑融合 | 可试 80~100 |
| 你的当前设置(limit=5) | 坚持用 60 |
参考资料
Milvus混合检索实战
配置
- 定义 Schema 和 BM25 函数
- 配置索引
- 创建 Collections,插入数据后
以上过程,参考文档《BM25检索》
创建多个 AnnSearchRequest 实例
混合搜索是通过在hybrid_search() 函数中创建多个AnnSearchRequest 来实现的,其中每个AnnSearchRequest 代表一个特定向量场的基本 ANN 搜索请求。
python
from pymilvus import (
AnnSearchRequest,
Function,
FunctionType,
MilvusClient,
SearchResult,
)
from langchain_ollama import OllamaEmbeddings
# 嵌入模型
embeddings = OllamaEmbeddings(model="bge-m3", base_url="http://127.0.0.1:11434")
query = "危险化学品"
query_dense_vector = embeddings.embed_query(query)
# print(type(query_dense_vector))
# print(query_dense_vector)
request_1 = AnnSearchRequest(
data=[query_dense_vector],
anns_field="vector",
param={"nprobe": 10}, # TODO 可调优
limit=6,
)
request_2 = AnnSearchRequest(
data=[query],
anns_field="sparse_vector",
param={},
limit=6,
)
reqs = [request_1, request_2]重排策略
对 ANN 搜索结果集进行合并和重新排序
- RRF排序策略
- 加权排序策略
python
# RRF排序策略
rrf_ranker = Function(
name="rrf",
input_field_names=[],
function_type=FunctionType.RERANK,
params={"reranker": "rrf", "k": 60}, # TODO 可调优
)混合搜索
python
client = MilvusClient(uri="http://127.0.0.1:19530")
client.use_database(db_name="default_db")
res = client.hybrid_search(
collection_name="default_collection", reqs=reqs, ranker=rrf_ranker, limit=3
)
print(type(res))
print(len(res[0]))
for i in res[0]:
print(i)输出结果示例
json
<class 'pymilvus.client.search_result.SearchResult'>
3
{'id': 464289779212620541, 'distance': 0.03154495730996132, 'entity': {}}
{'id': 464289779212620286, 'distance': 0.03151364624500275, 'entity': {}}
{'id': 464289779212620353, 'distance': 0.016393441706895828, 'entity': {}}LangChain Milvus混合检索实战
介绍
密集+稀疏混合检索

配置
- 定义 Schema 和 BM25 函数
- 配置索引
- 创建 Collections,插入数据后
以上过程,参考文档《BM25检索》
混合检索
python
from langchain_milvus import Milvus, BM25BuiltInFunction
from langchain_ollama import OllamaEmbeddings
embedding = OllamaEmbeddings(model="bge-m3", base_url="http://127.0.0.1:11434")
uri = "http://127.0.0.1:19530"
vectorstore = Milvus(
embedding,
builtin_function=BM25BuiltInFunction(),
vector_field=["vector", "sparse"],
connection_args={
"uri": uri,
"db_name": "default_db",
},
collection_name="default_collection",
auto_id=True,
consistency_level="Session",
)
# 执行混合检索
query = "热门专业top20中,前3名有哪些?"
docs_and_scores = vectorstore.similarity_search_with_score(
query=query, k=3, ranker_type="rrf", ranker_params={"k": 60}
)
# 打印结果
for doc, score in docs_and_scores:
print(doc.metadata)
print(score)
# print(doc.page_content[:50]) # 打印前50个字符输出结果示例
| 检索方式 | 分数特征 | 分数范围 | 含义 |
|---|---|---|---|
| 混合检索 (RRF) | 0.016 左右 | 通常 < 0.1 | RRF 融合后的倒数排名分数 |
| 纯向量检索 | 0.84/0.81 | 0 ~ 1 | 余弦相似度分数 |
- 分数非常小(例如 0.01639...),这通常是 RRF (Reciprocal Rank Fusion) 算法的特征。
- 分数< 0.015时,两种检索都排名靠后,结果可能不相关
bash
{'source': 'uploads\\1\\691bf8886d054d458f7845176dbc1914ba41d566ec36843c40baf1692c25ed6e.md', 'kb_id': '1', 'doc_id': '1', 'original_filename': '热门专业top20.md', 'id': 464429499724323791}
0.016393441706895828
{'source': 'uploads\\1\\691bf8886d054d458f7845176dbc1914ba41d566ec36843c40baf1692c25ed6e.md', 'kb_id': '1', 'doc_id': '1', 'original_filename': '热门专业top20.md', 'id': 464429499724323792}
0.016129031777381897