跳到主要内容

混合检索

1. 定义与边界

混合检索(Hybrid Retrieval)把关键词检索、稀疏向量检索和稠密向量检索结合起来。典型做法是 BM25 + dense embedding,然后用 RRF 或加权融合合并结果。

它不是简单地跑两次搜索再拼接列表。关键在于分数归一、结果融合、去重、权限过滤和重排。

2. 为什么重要

向量检索擅长语义相似,关键词检索擅长精确匹配。RAG 场景常同时需要:

  • 产品型号、错误码、函数名、法规条款号。
  • 同义词、概念解释、跨语言表达。
  • 长文档中的标题、表格、命名实体。

混合检索能降低单一路径召回失败的风险。

3. 核心机制

常见融合方式:

  • RRF(Reciprocal Rank Fusion):按名次倒数融合,减少不同分数体系的归一难题。
  • 加权分数融合:需要校准各检索器分数。
  • 级联:先高召回,再用 reranker 精排。

4. 工程实现

def hybrid_search(query, filters, k=20):
bm25_hits = keyword_index.search(query, filters=filters, k=50)
dense_hits = vector_index.search(embed(query), filters=filters, k=50)
merged = reciprocal_rank_fusion([bm25_hits, dense_hits], k_const=60)
return cross_encoder_rerank(query, merged)[:k]

def reciprocal_rank_fusion(result_lists, k_const=60):
scores = {}
for results in result_lists:
for rank, hit in enumerate(results, start=1):
scores[hit.id] = scores.get(hit.id, 0) + 1 / (k_const + rank)
return sorted(scores, key=scores.get, reverse=True)

5. 生产实践

  • 对代码、日志、法律、医学等精确词重要的场景优先使用混合检索。
  • 用 metadata filter 统一作用在所有检索器上。
  • 对短查询提高关键词权重,对长自然语言问题提高向量权重。
  • 对结果做去重和 chunk 邻接合并。
  • 记录每条结果来自哪个检索器,方便 bad case 定位。

6. 常见反模式

  • 向量检索替代所有关键词搜索。
  • BM25 和向量结果简单拼接,重复文档占满 top-k。
  • 分数直接相加但没有校准。
  • 混合检索后不 rerank。
  • 只评估端到端回答,不看各检索器贡献。

7. 评测方法

  • 单路检索与混合检索的 recall@k 对比。
  • 分 query 类型评测:错误码、概念问答、长问题、缩写。
  • RRF 后 nDCG / MRR。
  • 重复率和多样性。
  • latency budget:并行检索与 rerank 的端到端延迟。

8. 安全与治理

  • 各检索器必须共享权限过滤,不允许某一路绕过 ACL。
  • 对精确匹配命中的敏感词做额外审计。
  • 混合检索增加召回面,也增加提示注入内容进入候选的概率,需要后续清洗和重排。

工程化补强:架构与实现细节

A. 与 Memory 的硬边界

混合检索处理的核心对象是结合 dense vector、sparse/keyword、metadata 和业务排序信号。它的目标是把外部知识转化为可验证证据,而不是保存用户偏好或 Agent 经验。 Memory 可以影响“怎么服务这个用户、这个项目、这个流程”;RAG 只能回答“证据中是否支持这个事实”。

维度RAGMemory
数据来源外部文档、网页、代码、数据库、知识库对话、任务轨迹、用户偏好、历史经验
写入方式ingestion pipeline、同步任务、管理员上传互动后抽取、用户确认、后台总结
核心约束证据可追溯、权限过滤、引用准确状态延续、偏好复用、隐私最小化
典型失败召回错证据、引用不支持、上下文污染错误记忆持久化、越权画像、投毒
评测指标per-query-type recall、fusion win rate、duplicate rate、tail query successmemory precision、task lift、staleness

B. 端到端 Pipeline

本主题在总链路中的重点可以概括为:query analyze -> dense search + BM25/sparse search -> fusion -> dedupe -> rerank

C. 索引数据结构

{
"chunk_id": "doc_2026_05_09#sec_04#chunk_003",
"document_id": "doc_2026_05_09",
"document_version": "v7",
"source_uri": "s3://kb/product/manual.pdf",
"source_type": "pdf|html|code|ticket|database",
"title": "支付失败排查手册",
"section_path": ["支付", "错误码", "超时"],
"text": "...可用于回答的原文片段...",
"span": {"page": 12, "start_char": 1840, "end_char": 2610},
"metadata": {
"tenant_id": "org_1",
"acl": ["support", "engineering"],
"created_at": "2026-05-01",
"updated_at": "2026-05-09",
"source_trust": "official_internal"
},
"retrieval": {
"dense_vector_id": "vec_abc",
"sparse_vector_id": "sparse_abc",
"graph_node_ids": ["entity:timeout", "claim:retry-policy"]
},
"fusion": "rrf",
"dense_weight": 0.55,
"lexical_weight": 0.45,
"lineage": {
"parser_version": "parser-2.1",
"chunker_version": "heading-aware-1.4",
"embedding_version": "emb-2026-05-09",
"checksum": "sha256:..."
}
}

没有 document_versionspanacllineage 的 RAG 索引,很难做引用、回滚、权限审计和 bad case 修复。

D. Indexing Pipeline 设计要点

阶段关键决策常见坑
连接器增量同步、删除同步、权限同步只追加不删除,导致旧知识继续被召回
解析PDF 表格、代码块、标题层级、脚注丢页码和结构,引用无法定位
切分chunk 大小、overlap、父子块、表格整体性切断条款、代码函数或表格行
元数据tenant、ACL、时间、版本、来源可信度检索后才做权限过滤,已经泄露给模型
向量化embedding 模型、维度、批量、缓存模型切换后混用旧向量
索引vector、BM25/sparse、graph、rerank cache不记录索引版本,无法回归评测
回收删除、过期、重建、压缩向量残留和缓存残留

本文件建议的索引原则是:同一 chunk 维护 dense id、sparse id、document id 和统一 metadata。

D.1 向量数据库混合检索核对

主流向量数据库和搜索服务对 hybrid search 的实现并不完全相同。Weaviate 官方文档强调向量搜索与 BM25/BM25F 结果融合,并允许配置融合方式和权重;Azure AI Search 使用 hybrid search 与 RRF 排名;Qdrant 常见方案是 dense、sparse 和 rerank 组合。工程上要把“混合检索”拆成可评测的融合策略,而不是只开一个开关。

平台能力架构启发
Weaviate hybrid关注 alpha/fusion、BM25 属性范围和向量目标
Azure AI Search hybrid关注 BM25、vector query 和 RRF 的排序解释
Qdrant sparse+dense关注多向量字段、稀疏向量和二阶段 rerank
Pinecone sparse/dense关注稀疏编码、dense index 与应用层融合方式

选型时要用自己的 query 分布评测:错误码、精确标题、自然语言概念问答、多语言查询的最优融合权重通常不同。

E. 查询期策略

错误码/人名/术语提高 lexical 权重,概念问答提高 dense 权重。查询期不要把“召回更多”当成唯一目标,而要控制证据质量、权限、时效和上下文预算。

def rag_query(user_query, user_ctx):
plan = plan_retrieval(user_query, user_ctx)
filters = enforce_acl(user_ctx, plan.filters)
rewritten = rewrite_query(user_query, plan, metadata_schema=INDEX_SCHEMA)
candidates = []
for source in plan.sources:
candidates.extend(source.search(rewritten, filters=filters, k=plan.candidate_k))
ranked = rerank(user_query, candidates, features=["text", "metadata", "trust", "freshness"])
evidence = pack_context(ranked, budget=plan.context_budget, diversity=True)
answer = generate_with_evidence(user_query, evidence)
return verify_citations(answer, evidence)

F. 引用与证据策略

融合后仍保留每个候选的来源路径和原始排名。引用不是格式问题,而是 evidence contract:模型只能用传入证据支持关键断言。

断言类型证据要求不满足时动作
简单事实至少一个直接 chunk 支持给出不确定或拒答
跨文档综合多个 chunk 覆盖关键维度明确证据范围和缺口
高风险建议官方/内部可信来源优先要求人审或给出保守答案
时间敏感信息来源版本和更新时间足够新触发刷新或说明可能过期
权限受限内容用户有权查看原文不引用、不泄露摘要

G. 失败模式与修复

失败模式早期信号修复动作
分数直接相加导致某一路径支配结果,或没有按 query 类型调权重答案流畅但找不到支持片段加 citation verifier 和无证据拒答
chunk 边界错误命中片段缺上文或表格列调整切分器、加入 parent expansion
召回偏科概念问答好,错误码/ID 查询差增加 hybrid search 和字段 boost
top-k 污染上下文里半数以上无关rerank、diversity filter、query rewrite
权限绕过无权限文档出现在 trace服务端 ACL 前置过滤,索引按租户隔离
索引陈旧用户指出文档已更新增量同步、版本水位、freshness 监控
引用漂移引用存在但不支持断言claim-level citation check 和回源校验

H. 评测指标

层级指标说明
检索recall@k、precision@k、nDCG、MRRgold span/doc 是否进入候选和前排
重排rerank lift、first relevant rank观察 reranker 是否真正改善上下文
上下文evidence coverage、token waste、duplication rate是否既覆盖证据又不浪费窗口
生成answer correctness、faithfulness、abstention accuracy答案是否正确且不编造
引用citation precision、claim support rate、broken link rate引用是否可打开且支持断言
安全prompt injection success、unauthorized recall、sensitive leakage外部内容和权限场景的红线
运维p95 latency、index freshness、cost/query、cache hit rate生产可用性和成本

I. 安全治理清单

  • 检索内容是数据,不是指令;提示词中明确外部证据不能覆盖系统和开发者约束。
  • 权限过滤必须在检索前或索引层完成,不能依赖模型“不要使用”。
  • 对网页、用户上传文件和第三方文档做 prompt injection 扫描和来源可信度标记。
  • 高风险领域使用白名单来源、版本锁定、引用校验和无法支持时拒答。
  • 记录 query、filters、命中文档、分数、rerank 理由、上下文包和最终引用,支持审计。
  • 建立 bad case 回流:每个失败样本标注失败层级,并绑定索引版本、prompt 版本和模型版本。

9. 权威资料