Advanced RAG:混合检索、重排与查询改写设计
发布于
在这世界上有一道被称为 你 的光芒,在这小小的地球上不断扩大照亮了黑暗。
文档性质:Phase 2 新增模块的学习说明与系统架构
代码核对日期:2026-08-25
当前实现:Dense / BM25 / Hybrid / Hybrid-Rerank / Advanced 五组可比较 Profile
当前评测:自建 60 题五组完整消融;MultiHop-RAG 2,255 题四组完整检索评测
Base RAG 已经建立了最小闭环:文档经过切块和 Embedding 进入 FAISS,问题通过 Dense Retrieval 找到 Top-K Chunk,最后由大语言模型基于证据回答。
Phase 2 不改变这条链路的目标,而是针对三个常见问题逐层增强:
- 只靠语义检索可能漏掉精确术语:增加 BM25 稀疏检索;
- 召回结果不等于最佳排序:先用 RRF 融合两路召回,再用 Reranker 精排;
- 用户问题不一定适合直接检索:在检索前增加一次结构化 Query Rewrite;
- 模块执行成功不代表模块有效:增加证据级指标与五组 Profile 消融实验。
Phase 2 的核心变化可以概括为:
本文先分别说明每个新增模块解决什么问题、依据什么原理工作,再给出完整的 Advanced RAG 架构。
1. Phase 2 新增模块
1.1 models.py:让一个命中记录完整保留多阶段排名
Base RAG 中的 SearchHit 只需要表达一个 Chunk 的最终相似度和排名。Phase 2 引入 Dense、BM25、RRF 和 Rerank 后,同一个 Chunk 会连续经过多个排序阶段。如果只保存最终 score,就无法解释它为什么上升或下降。
当前 SearchHit 因此增加了四组过程字段:
SearchHit(
chunk=chunk,
score=0.91,
rank=1,
dense_score=0.72,
dense_rank=8,
bm25_score=6.34,
bm25_rank=2,
rrf_score=0.0318,
rrf_rank=3,
rerank_score=0.91,
rerank_rank=1,
)
其中,score 和 rank 表示当前阶段的有效结果;dense_*、bm25_*、rrf_*、rerank_* 保存每一阶段留下的轨迹。
Dense 第 8 名 → BM25 第 2 名 → RRF 第 3 名 → Rerank 第 1 名
这组字段把“检索结果”升级成了“可解释的检索过程”。当最终答案错误时,可以继续判断:正确 Chunk 是从未召回,还是进入候选后被错误排序。
1.2 bm25.py:增加擅长精确词匹配的稀疏检索
Dense Retrieval 会把问题和 Chunk 分别编码成稠密向量,再按向量相似度检索。它擅长同义表达和概念匹配,但面对版本号、命令、代码标识符和罕见缩写时,不一定稳定。
BM25 从另一个角度判断相关性:
- 问题中的词是否出现在 Chunk 中、出现多少次
- 这个词在整个语料中是否稀有
- 当前 Chunk 是否过长。
BM25 被称为稀疏检索,是因为文本可以表示为一个词表向量:语料词表很大,而一个 Chunk 只包含少数词,大部分维度都是零。
当前实现先将文本分词:
- 中文部分使用
jieba; - 英文、数字和技术标识符保留为整体;
- 所有英文统一转成小写;
- 标题、章节和正文共同参与统计。
例如:
qwen3-rerank 可以对 RRF 候选做二阶段精排
会保留 qwen3-rerank、rrf 等技术词,同时对中文部分分词。
对查询中的每个词,BM25 分数可理解为:
公式中的三个核心因素是:
| 因素 | 含义 | 作用 |
|---|---|---|
TF(t,d) | 词在当前 Chunk 中出现的次数 | 出现越多通常越相关,但收益逐渐饱和 |
IDF(t) | 词在整个语料中的稀有程度 | 越少见的词越有区分力 |
| 长度归一化 | 当前 Chunk 长度与平均长度之比 | 避免长文本仅因包含更多词而占优势 |
当前参数为 k1=1.5、b=0.75。建库时,词频、文档频率、Chunk 长度和分词器版本会保存到 bm25.json。
BM25 与 Dense 不是替代关系,而是互补关系:
| 问题类型 | Dense | BM25 |
|---|---|---|
| “精排模型有什么作用?” | 能理解“精排”与“Reranker”的语义接近 | 文档未出现相同词时可能漏掉 |
“IndexFlatIP 是什么?” | 罕见标识符的语义表示可能不稳定 | 精确命中标识符时优势明显 |
| 口语化、同义改写 | 通常更强 | 依赖实际分词重合 |
| 命令、版本号、报错文本 | 可能召回相似概念 | 通常更适合精确匹配 |
1.3 retrieval.py:使用 RRF 融合 Dense 与 BM25 排名
Dense 分数与 BM25 分数来自不同计算空间:Dense 是归一化向量的内积,BM25 是词频、稀有度和长度共同形成的统计分。两者的数值范围与含义不同,不能直接相加。
RRF(Reciprocal Rank Fusion,倒数排名融合)绕开原始分数,只使用每个 Chunk 在各检索器中的名次:
当前 k=60。某个 Chunk 没有出现在一路结果中,就不获得该路加分;同时出现在 Dense 与 BM25 前列的 Chunk 会获得两路加分。
例如:
Chunk A:Dense 第 1,BM25 未命中
RRF(A) = 1 / (60 + 1)
Chunk B:Dense 第 3,BM25 第 2
RRF(B) = 1 / (60 + 3) + 1 / (60 + 2)
即使 Chunk B 在任何一路都不是第一名,它也可能因为获得两路共同支持而排到融合结果前面。
代码先用 chunk_id 合并重复命中,再保留 dense_* 和 bm25_* 字段,最后写入新的 rrf_score 与 rrf_rank。同分时按 chunk_id 排序,使重复运行保持确定性。
RRF 的职责是提高候选池的稳健性。它不会判断一个 Chunk 是否真正回答了问题,这一步交给后续 Reranker。
1.4 rerank.py:使用二阶段精排提升正确证据的位置
Dense、BM25 和 RRF 的目标是高召回:尽量把可能相关的 Chunk 放进候选池。候选池中的文本可能只是出现了相同术语,或主题相近,却没有直接回答问题。
Rerank 的目标是高精度:把用户问题与每个候选 Chunk 放在一起进行更细粒度的相关性判断,然后只返回最相关的少量证据。
典型的 Reranker 使用 Cross-Encoder 思路:
[Question] + [Candidate Chunk]
↓
同一个 Transformer
↓
relevance_score
它与 Dense Retrieval 常用的 Bi-Encoder 有明显区别:
| 结构 | 编码方式 | 优点 | 代价 |
|---|---|---|---|
| Bi-Encoder | 问题与 Chunk 分开编码,再计算向量相似度 | Chunk 向量可提前保存,适合全库检索 | 问题与文本缺少逐 Token 交互 |
| Cross-Encoder | 问题与 Chunk 一起输入模型 | 能细致判断文本是否真正回答问题 | 每次提问都要重新计算每个候选,速度较慢 |
因此,Reranker 只处理 RRF 已经筛出的有限候选,而不扫描整个知识库。
当前代码将原始用户问题、候选 Chunk 正文、top_n 和任务说明发送给 qwen3-rerank 服务。服务返回候选索引和 relevance_score,程序校验越界、重复和无效分数后,写入新的 rerank_score 与 rerank_rank。
Rerank 的能力边界也很明确:
如果正确证据没有进入候选池,Reranker 无法凭空找回它;它只能重新排列已有候选。
1.5 rewrite.py:把自然语言问题整理成可检索查询
用户问题不一定是适合检索的表达。例如“那个比赛要人会干啥”包含指代和口语,Dense 可能理解得不稳定,BM25 也缺少可以精确匹配的实体与术语。
Query Rewrite 在检索前调用一次大语言模型,将问题整理成结构化结果:
{
"intent": "了解 KDD Cup 2026 Data Agents 的核心能力要求",
"rewritten_query": "KDD Cup 2026 Data Agents 比赛强调哪些核心能力?",
"keywords": ["KDD Cup 2026", "Data Agents", "核心能力"]
}
当前 Prompt 要求模型:
你是 RAG 查询理解器。分析用户问题并只输出一个 JSON 对象,不要 Markdown、解释或代码块。
JSON 必须严格含有 intent(字符串)、rewritten_query(字符串)和 keywords(字符串数组)。
rewritten_query 应补全指代与上下文,保持原意;keywords 只保留实体、术语、缩写、版本号和限定词。
三个字段的用途不同:
intent:保存模型对用户意图的概括,当前仅用于运行记录;rewritten_query:作为 Dense 的查询文本;rewritten_query + keywords:共同作为 BM25 查询,补充精确术语。
改写使用 temperature=0,并严格检查 JSON 结构。
1.6 pipeline.py:用 Profile 编排不同能力组合
pipeline.py 将新增模块组合成五个可比较的 Profile:
| Profile | Dense | BM25 | RRF | Rerank | Rewrite |
|---|---|---|---|---|---|
dense | ✓ | ||||
bm25 | ✓ | ||||
hybrid | ✓ | ✓ | ✓ | ||
hybrid-rerank | ✓ | ✓ | ✓ | ✓ | |
advanced | ✓ | ✓ | ✓ | ✓ | ✓ |
- 离线
ingest()在原有 FAISS 索引之外,同步建立 BM25 索引。 - 在线
ask()按 Profile 依次执行 Rewrite、索引加载、Dense/BM25 召回、RRF、Rerank、Context 装配与生成。
默认候选规模为:
Dense Top-20 ─┐
├→ RRF Top-30 → Rerank Top-6 → LLM Context
BM25 Top-20 ──┘
最终运行记录会保存 Rewrite 结果、两路查询、每层候选及排名、Prompt、答案、引用、模型身份、阶段耗时和调用次数。
1.7 evaluation.py:用证据级指标判断模块是否有效
Phase 2 将 Base RAG 的来源命中评估扩展为“召回、排序、答案质量和成本”四类观察。
主要自动检索指标包括:
| 指标 | 评测问题 |
|---|---|
| Source Recall@6 | 最终 Top-6 是否至少来自正确文章 |
| Chunk Recall@6 | 最终 Top-6 是否包含标注的正确证据片段 |
| Chunk Recall@20 | 正确证据是否进入较大的初始候选池 |
| MRR@6 | 第一个正确 Chunk 排得有多靠前 |
| nDCG@6 | Top-6 中相关 Chunk 的整体排序质量 |
| unanswerable_retrieved | 无答案题是否仍返回了检索结果 |
| mean latency / stage calls | 指标变化付出了多少延迟和模型调用 |
其中,Chunk Recall@20 与 Chunk Recall@6 的组合可以区分两类问题:
Recall@20 = 0
→ 正确证据没有进入候选池,属于召回问题
Recall@20 = 1,Recall@6 = 0
→ 正确证据已被召回但排序靠后,属于排序问题
实验固定比较:
Hybrid - Dense → BM25 + RRF 的增量价值
Hybrid - BM25 → Dense + RRF 的增量价值
Hybrid-Rerank - Hybrid → Reranker 的增量价值
Advanced - Hybrid-Rerank → Query Rewrite 的增量价值
评测还可以使用 LLM Judge 对 correctness、completeness、groundedness 和 citation_correctness 给出 0~2 分,并生成匿名的 Dense/Advanced 人工复核表。不过当前主报告仍以检索指标和延迟为主,Judge 与人工复核是辅助证据,不应与确定性的检索指标混为一个总分。
2. Advanced RAG 架构
2.1 完整架构图
3. Advanced RAG 评测:模块能运行,不等于模块有效
前面的章节回答了 Advanced RAG 如何工作,但系统增加了 BM25、RRF、Reranker 和 Query Rewrite,并不意味着检索质量一定会提高。一个模块可能成功完成调用,却没有找回更多正确证据;也可能改善候选召回,却破坏最终排序;还可能只带来很小的质量收益,却显著增加响应延迟。
因此,本章不把评测理解为给整个系统计算一个总分,而是逐层回答四个问题:
- 正确证据是否进入了候选池?
- 正确证据是否被排到了足够靠前的位置?
- 多证据问题所需的事实是否被完整找回?
- 指标改善付出了多少延迟和模型调用成本?
3.1 从“找到文档”到“正确回答”的四层评测
RAG 的最终目标是根据证据正确回答问题,但错误可能发生在链路的不同位置。只看最终答案,无法判断问题究竟来自检索还是生成;只看 Source Recall,也无法证明模型获得了真正支持答案的 Chunk。
四层评测之间是递进关系:
| 层级 | 核心问题 | 主要指标 | 当前实验是否覆盖 |
|---|---|---|---|
| 候选召回 | 正确证据是否进入较大的候选池 | Chunk Recall@20、Coverage@10 | 是 |
| 最终排序 | 正确证据是否进入最终 Top-K,并且排得足够靠前 | Chunk Recall@6、MRR、nDCG、MAP | 是 |
| 证据完整性 | 多证据问题需要的事实是否被共同找回 | Evidence Coverage、Complete Evidence | 是 |
| 最终回答 | 回答是否正确、完整、忠实且引用准确 | Correctness、Groundedness、Citation Support | 否 |
当前两套完整实验都是仅检索评测,没有调用 LLM 生成最终答案。因此,本章可以判断检索链路是否找到了正确证据,但不能把这些指标写成答案正确率。
3.2 两套数据集分别验证什么
只使用自建题集,容易让评测结论依赖熟悉的语料和标注方式;只使用公开数据集,又很难精确定位某个模块为什么成功或失败。因此,当前评测采用“内部诊断集 + 外部压力测试”的双数据集结构。
| 数据集 | 规模与构成 | 主要用途 | 不能单独证明什么 |
|---|---|---|---|
| 自建数据集 | 60 题:12 道词法、16 道语义、12 道多证据、10 道歧义、10 道无答案 | 逐类诊断 Dense、BM25、RRF、Rerank 和 Rewrite 的增量价值 | 不能代表陌生领域上的泛化能力 |
| MultiHop-RAG | 2,556 道原始问题;跳过 301 道null_query,实际评测 2,255 道 | 检查系统在陌生英文新闻语料、跨文档和多事实问题上的表现 | 当前仅评检索,不能证明答案与推理正确 |
两套数据集的关系可以概括为:
自建题集回答“模块为什么变好或变差”,公开数据集回答“换一个领域以后,这个结论是否仍然成立”。
MultiHop-RAG 中实际参与评分的问题包含 inference_query、comparison_query 和 temporal_query。它们通常需要组合来自不同文档的事实,因此除了观察第一条相关证据的位置,还必须检查所需 Gold 事实是否被完整覆盖。
3.3 如何保证消融比较公平
五个 Profile 并不是五套互不相关的系统,而是在相同底座上逐步增加能力:
实验固定语料、Chunk、索引、问题集和主要候选规模,每次只观察一个新增模块带来的变化:
Hybrid - Dense → BM25 + RRF 是否带来互补召回
Hybrid-Rerank - Hybrid → Reranker 是否改善最终证据排序
Advanced - Hybrid-Rerank → Query Rewrite 的收益是否覆盖成本
质量指标还必须与运行成本一起报告。否则,一个 Profile 即使只提高很小的 MRR,也可能因为额外模型调用而被误判为更好的默认方案。
两套数据集的 Top-K 设置并不相同:自建题集观察最终 Top-6,MultiHop-RAG 观察 Top-4 和 Top-10。因此,二者适合比较“模块作用是否一致”,不应直接横向比较 MRR@6 与 MRR@10 的绝对数值。
3.4 自建 60 题:Reranker 收益最明确,Rewrite 成本过高
自建题集在相同 60 道题上完整运行了五个 Profile,所有 Profile 均完成 60/60,失败数为 0。该实验不生成答案,评分分母是 50 道可回答题;10 道无答案题的检索行为单独记录。
| Profile | Chunk Recall@6 | Chunk Recall@20 | Evidence Coverage@6 | MRR@6 | nDCG@6 | 平均延迟 |
|---|---|---|---|---|---|---|
| Dense | 0.7867 | 0.8667 | 0.7933 | 0.6117 | 0.6707 | 0.195s |
| BM25 | 0.6367 | 0.8467 | 0.6433 | 0.4898 | 0.5426 | 0.028s |
| Hybrid | 0.7767 | 0.9067 | 0.7867 | 0.5549 | 0.6259 | 0.170s |
| Hybrid-Rerank | 0.8567 | 0.9067 | 0.8567 | 0.6497 | 0.7214 | 0.447s |
| Advanced | 0.8567 | 0.9367 | 0.8567 | 0.6614 | 0.7299 | 17.071s |
3.4.1 Hybrid 找回更多候选,但不保证最终排序更好
Hybrid 的 Chunk Recall@20 从 Dense 的 0.8667 提升到 0.9067,说明 Dense 与 BM25 的互补候选确实找回了更多正确证据。
但是,Hybrid 的最终 MRR@6 从 0.6117 降至 0.5549,Evidence Coverage@6 也从 0.7933 小幅降至 0.7867。这说明 RRF 扩大了候选池,却没有充分判断哪个 Chunk 真正回答了问题:
更多正确证据进入 Top-20
≠
正确证据已经排进最终 Top-6
这一结果与 RRF 的算法职责一致。RRF 根据两路名次寻找共同支持,不直接建模“问题与候选文本是否构成答案关系”。
3.4.2 Reranker 是最明确的质量增益来源
从 Hybrid 到 Hybrid-Rerank:
| 指标 | Hybrid | Hybrid-Rerank | 变化 |
|---|---|---|---|
| Evidence Coverage@6 | 0.7867 | 0.8567 | +0.0700 |
| MRR@6 | 0.5549 | 0.6497 | +0.0948 |
| nDCG@6 | 0.6259 | 0.7214 | +0.0955 |
| 平均延迟 | 0.170s | 0.447s | +0.277s |
Chunk Recall@20 没有变化,但 Top-6 的覆盖与排序同时提高,说明正确证据原本已经进入候选池,Reranker 的主要作用是把它们从候选后部移动到最终上下文。
这正是“第一阶段追求高召回,第二阶段追求高精度”的两阶段检索价值。
3.4.3 Query Rewrite 改善了候选召回,但不足以支持全量启用
从 Hybrid-Rerank 到 Advanced:
Chunk Recall@20从0.9067提升到0.9367;MRR@6只从0.6497提升到0.6614;Evidence Coverage@6保持0.8567;- 平均延迟从
0.447s增加到17.071s,约为原来的 38 倍。
因此,不能简单地说 Query Rewrite 完全无效:它确实帮助部分正确证据进入了 Top-20 候选池。但这些新增候选没有转化成更高的最终 Top-6 证据覆盖,而每道题都增加了一次高延迟模型调用。
当前更合理的定位是:
Query Rewrite 适合作为检测到歧义、指代或首次检索不足时的按需能力,而不是所有问题都执行的默认步骤。
3.5 MultiHop-RAG:模块收益会随领域与 Top-K 改变
MultiHop-RAG 评测使用同一英文新闻语料、索引、问题集和 top_k=10。Dense、BM25、Hybrid、Hybrid-Rerank 四个 Profile 均完成 2,255/2,255,失败数为 0。
| Profile | Coverage@4 | Coverage@10 | Complete@10 | Hits@4 | Hits@10 | MAP@10 | MRR@10 | 平均延迟 |
|---|---|---|---|---|---|---|---|---|
| Dense | 0.2878 | 0.4440 | 0.1645 | 0.5960 | 0.7809 | 0.2057 | 0.4384 | 0.148s |
| BM25 | 0.3168 | 0.4749 | 0.1987 | 0.6284 | 0.7907 | 0.2329 | 0.4806 | 0.150s |
| Hybrid | 0.3375 | 0.5105 | 0.2337 | 0.6501 | 0.8279 | 0.2450 | 0.5029 | 0.349s |
| Hybrid-Rerank | 0.3252 | 0.5492 | 0.2745 | 0.6080 | 0.8470 | 0.2079 | 0.3963 | 0.598s |
3.5.1 BM25 在英文新闻语料上强于 Dense
BM25 在主要指标上均高于 Dense,平均延迟几乎相同。自建中文技术题中,Dense 的整体表现更强;换到英文新闻后,人名、机构、时间、标题和来源等精确词项为 BM25 提供了更强的区分信号。
这组差异说明:
检索器的强弱不是固定属性,而是查询表达、语言和语料分布共同作用的结果。
因此,不能只根据自建题集宣布 Dense 或 BM25 是永远更好的检索器。
3.5.2 Hybrid 是公开集上最稳定的综合基线
相对 BM25,Hybrid 将 Coverage@10 从 0.4749 提升到 0.5105,将 MRR@10 从 0.4806 提升到 0.5029。它同时取得最高的 Coverage@4、Hits@4、MAP@10 和 MRR@10。
这说明 Dense 与 BM25 的互补候选在陌生领域中仍然有效。即使 Hybrid 在自建题集的最终 Top-6 上没有直接超过 Dense,它仍然是后续 Rerank 或 Agentic 检索更稳健的无生成候选基线。
3.5.3 Reranker 提高完整覆盖,却降低前排质量
Hybrid-Rerank 相对 Hybrid:
| 观察目标 | Hybrid | Hybrid-Rerank | 变化 |
|---|---|---|---|
| Coverage@10 | 0.5105 | 0.5492 | +0.0387 |
| Complete Evidence@10 | 0.2337 | 0.2745 | +0.0408 |
| Hits@10 | 0.8279 | 0.8470 | +0.0191 |
| MRR@10 | 0.5029 | 0.3963 | -0.1066 |
| MAP@10 | 0.2450 | 0.2079 | -0.0371 |
它找全多条 Gold 事实的能力更强,却把第一条相关证据排得更靠后。这与自建题集上 Reranker 同时改善覆盖和排序的结果不同,但二者并不矛盾:
- 自建题集观察最终 Top-6,问题主要来自中文技术文档;
- MultiHop-RAG 观察 Top-10,问题需要组合英文新闻中的多个事实;
- 当前 Reranker 的任务说明强调“共同提供全部所需证据”,可能更偏向集合完整性,而不是首条证据排名。
另一个重要原因可能来自 MultiHop-RAG 的问题结构与当前重排方式并不完全匹配。多跳问题不是直接从问题定位答案,而是需要沿着一条证据链逐步找到中间实体。最直观的结构是:
问题提到 A
↓ 第 1 跳
证据 1:A → B
↓ 第 2 跳
证据 2:B → C
↓
最终答案在 C 中
例如,题目询问“创办 A 公司的人后来领导了哪家机构?”。第一篇文档只说明 A 公司 → 创办者 B,第二篇文档再说明 人物 B → 机构 C。最终答案是 C,但包含 C 的第二篇文档可能完全不出现 A;它只有通过中间实体 B,才能与原问题建立关系。
当前 Reranker 则把每个候选 Chunk 与完整的原始问题组成一对,逐条独立计算相关性:
完整多跳问题 + Chunk A → score_A
完整多跳问题 + Chunk B → score_B
完整多跳问题 + Chunk C → score_C
这种直接重排存在两个潜在问题:
A → B的 Chunk 与原问题直接相关,通常容易获得较高分数;- 真正包含最终答案的
B → CChunk 可能不包含 A,与原问题的直接语义相似度较低,反而会在 Rerank 时被降到后面; - 多个反复介绍 A 的相似 Chunk 还可能重复占据前排,进一步挤压包含 B 和 C 的关键证据。
因此,多跳检索真正需要优化的不是“每条 Chunk 单独有多相关”,而是“选出的整组 Chunk 是否共同覆盖了所有证据子目标”:
单条相关性目标:哪些 Chunk 与关于 A 的原问题最相似?
多跳证据目标:先找到 A → B,再使用 B 找到 B → C
这可以解释为什么直接使用 Reranker 不一定适合多跳查询:Reranker 可以判断一段文本是否直接回答当前问题,却不会自动执行 A → B → C 的链式检索。它可能保留大量与 A 直接相关的文本,同时把包含最终答案 C 的第二跳证据降权。
当前结果中,Hybrid-Rerank 的 Top-10 完整覆盖提高,但 MRR 和 MAP 没有同步改善,说明它确实改变了候选集合,却没有稳定地把多跳证据链按有效顺序放到前排。
后续更适合 MultiHop-RAG 的做法,是把检索改成迭代过程:先围绕 A 检索并识别中间实体 B,再使用 B 构造第二跳查询寻找 C。每一跳可以分别 Rerank,最后再进行去重和证据链组合,而不是一开始就使用关于 A 的原问题对所有候选统一重排。
因此,配置选择取决于下游如何使用上下文:
上下文很短,强调前几条证据
→ 优先 Hybrid 的前排质量
允许保留 Top-10,强调多事实完整覆盖
→ Hybrid-Rerank 更有价值
3.6 跨数据集结论:不存在脱离任务目标的“最佳 Profile”
| 模块 | 自建数据集 | MultiHop-RAG | 当前判断 |
|---|---|---|---|
| BM25 | 单路整体弱于 Dense,但词法题有优势 | 整体强于 Dense | 对实体和精确词项密集的领域很有价值 |
| Hybrid / RRF | 扩大 Top-20 候选召回,但 Top-6 排序未直接改善 | 综合检索表现最稳定 | 适合作为后续检索增强的候选基线 |
| Reranker | 明显改善 Top-6 覆盖与排序 | 提高 Top-10 完整覆盖,但降低前排质量 | 是否启用取决于上下文长度和证据完整性目标 |
| Query Rewrite | 小幅改善候选召回,最终覆盖不变,延迟显著增加 | 完整结果缺失 | 暂不适合全量默认启用,应改为按需触发 |
Advanced RAG 的价值并不来自模块数量,而来自每个模块能否针对特定失败模式产生可验证收益。
4. 下一阶段设想:从固定链路走向 Agentic Multi-Hop RAG
当前 Advanced RAG 已经具备混合检索、融合、重排和查询改写,但它仍然是一条固定的单轮链路:系统围绕原问题检索一次,再将得到的结果直接交给生成模型。这种方式适合答案能够被直接检索的问题,却不擅长需要逐步发现中间信息的多跳问题。
MultiHop-RAG 的评测结果已经暴露出这一边界。对于 A → B → C 类型的问题,原问题通常只提到 A,最终答案却位于描述 B 与 C 关系的另一篇文档中。即使第二跳证据已经进入候选池,它也可能因为没有直接出现 A,而在使用原问题统一 Rerank 时被降到后面。
下一阶段希望将这条固定链路升级为一种受控的 Agentic Multi-Hop RAG:系统先判断问题是否需要多跳。简单问题继续使用当前成熟的 Hybrid 或 Hybrid-Rerank,只有确实需要组合多条证据的问题才进入迭代检索。
多跳检索不再要求一次找到最终答案,而是允许系统沿证据链逐步前进:先围绕 A 找到中间实体 B,再使用 B 构造新的查询寻找 C。每一跳都围绕当前子问题检索和重排,最后将不同来源的证据组合成一条可解释的推理链。
这一变化也会重新定位现有模块:
- Hybrid Retrieval 继续作为稳定的基础召回能力;
- Reranker 不再用原问题统一处理所有候选,而是服务于当前一跳的具体子问题;
- Query Rewrite 不再对每个问题默认执行,而是在某一跳检索不足时按需触发;
- Evidence Evaluation 从判断单条 Chunk 是否相关,进一步扩展到判断整条证据链是否完整。
这里的“Agentic”并不意味着让模型自由调用任意工具或无限尝试。系统仍然运行在明确边界内,只在“继续下一跳、修复当前查询、生成答案或证据不足时结束”之间做有限选择。这样既保留动态决策能力,也能控制循环次数、模型调用和响应延迟。
理想情况下,下一阶段的系统将形成下面的能力分工:
简单问题
→ 单轮 Hybrid / Hybrid-Rerank
多跳问题
→ 发现中间实体
→ 生成下一跳查询
→ 补齐后续证据
→ 组合证据链
→ 生成并验证答案
这次升级希望解决的并不是“让流程看起来更像 Agent”,而是当前系统中几个已经被实验观察到的具体痛点:单轮检索无法主动追踪中间实体、直接 Rerank 可能压低后续跳证据、Rewrite 固定执行的成本过高,以及检索到多条材料后仍缺少证据链完整性判断。
因此,项目的下一阶段可以概括为:
保留当前 Advanced RAG 已验证的检索底座,在其上增加问题路由、逐跳检索、证据链组合和有限纠错,使系统能够根据问题难度决定“是否继续寻找下一条证据”,而不是对所有问题执行同一条固定流水线。