Retrieval-Router-RAG

用最贵的一路检索打全部查询:简单事实浪费 ColBERT/Graph,关系问题又走 Naive。根因是查询类型与检索器能力不匹配。本方法先路由再选检索器。路由错了会系统性漏检,要单独报路由准确率。

本文属于 RAG 工程框架中的「2 索引与召回」环节,聚焦「Retrieval Router(检索路由)」方法。

定位

维度 内容
角色 检索器分诊
输入 → 输出 $q$ → 检索器名 → 该路 hits(失败 fallback)
默认组合 LlamaIndex RouterRetriever
何时不用 只有一路检索器;路由准确率低于「永远走 Hybrid」

核心机制

$$
r^\star=\arg\max_r P(r\mid q)
$$

再 $\mathrm{Retrieve}_{r^\star}(q)$。错路 = 该类证据召回为零。

实现路径与心智:廉价分类(规则或小模型)把 $q$ 分到 boolean / dense / graph 等检索器,失败再 fallback。底层心智:检索器是专科医生,路由是分诊;分错不是「排名差一点」,而是整类证据从未进入候选。要单独报路由准确率,不要只看端到端分数。

优缺点

  • 优点:降平均成本,专项能力用在刀刃上。
  • 缺点:路由错误是系统性漏检。

契约与走通样例

输入

1
{"query": "Which genes does GAPDH regulate?"}

中间量

$P(\mathrm{graph}\mid q)=0.86$,$P(\mathrm{dense})=0.10$。走路 Graph;若误路由 dense,多跳边 Recall=0。

输出

1
{"route": "graph", "hits": [{"doc_id": "P-GAPDH-01-C7"}]}

分流案例

同一套约 100 篇糖酵解/GAPDH 文献库,线上混着四类问句。若一律 Graph,货号和凝胶问 Recall 塌且建图成本摊不掉;若一律 dense,硬约束和多跳边进不了候选。路由是把问句类型对齐到检索器能力,不是「再加一个分类模型好看」。

图 1 分诊:硬约束走 Boolean,改写方法走 dense/ColBERT,调控关系走 Graph,凝胶 lane 走多模

线上原话 失败若走错路 路由 为什么必须分
「只要小鼠、2023 年后、非综述的 GAPDH knockdown 时程」 走 dense:HEK293T 人源方法段排第一,物种约束被相似度吞掉 Booleanspecies=mouse AND year>=2023 AND NOT review,再在子集上 Hybrid 语义分没有逻辑完备性
「敲低 GAPDH 之后多久抽 RNA」 走 Boolean:字段里没有「时程」这个 filter dense / ColBERT(可先 Query Rewrite 把口语对到 Methods 措辞) 约束在段落里,不在元数据
「GAPDH 调控哪些糖酵解酶」 走 dense:两段各自含 GAPDH 与 PKM 共现,拼不出边;Recall@5 对「酶列表」=$0$ Graph 2-hop:GAPDH —regulates→ enzyme 段落相似度没有边
「Western 哪条 lane 是 knockdown」 走纯文本:正文不写 lane,Recall@5=$0$ Multimodal(图块进同一排名表) 事实在像素里

冻结评测(同一 300 条混合集):全走 Hybrid 时关系问 Recall@5=$0.31$、图问 $0.08$;按上表路由后分别为 $0.79$、$0.71$,平均时延从「全 ColBERT」约 $350,\mathrm{ms}$ 降到约 $90,\mathrm{ms}$(多数问走 Boolean/Hybrid)。误把货号问分到 Graph,该条 Recall 仍低且白烧子图——所以要单独报路由准确率,不要只看端到端平均分。

规则起点(可再叠轻量分类器):含物种/年份/期刊 → Boolean;含 regulate/上游/下游/通路 → Graph;含 blot/lane/figure → Multimodal;其余 → Hybrid,失败 fallback Hybrid。

社区实现

LlamaIndex RouterRetriever;LangChain 路由链。风险:规则过粗把货号问分到 graph,白烧 IE。

工程落地

最小可运行示例

复制为 .py 后直接运行(仅标准库)。生产对应 LlamaIndex RouterRetriever;规则过粗会把货号问分到 Graph。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"""按问句特征选检索器;空结果强制 fallback 到 hybrid。"""
from __future__ import annotations


class RuleRouter:
"""规则路由。生产可再叠轻量分类器,不要默认 LLM 路由。"""

def route(self, query: str) -> str:
q = query.lower()
if any(w in q for w in ("mouse", "2023", "journal")):
return "boolean"
if any(w in q for w in ("regulate", "上游", "通路")):
return "graph"
if any(w in q for w in ("blot", "lane", "figure")):
return "multimodal"
return "hybrid"


class NamedRetriever:
"""一路检索器。生产对应 Boolean / Hybrid / Graph / Multimodal 索引。"""

def __init__(self, name: str, hits: dict[str, list[str]]) -> None:
self.name, self.hits = name, hits

def search(self, query: str) -> list[str]:
return list(self.hits.get(query, []))


def routed_retrieve(
query: str,
router: RuleRouter,
retrievers: dict[str, NamedRetriever],
fallback: str = "hybrid",
) -> tuple[str, list[str]]:
"""输出实际走过的通道名与 hits。"""
name = router.route(query)
hits = retrievers[name].search(query)
if not hits:
name, hits = fallback, retrievers[fallback].search(query)
return name, hits


if __name__ == "__main__":
retrievers = {
"boolean": NamedRetriever("boolean", {"只要小鼠 2023 年 GAPDH": ["P-mm"]}),
"hybrid": NamedRetriever("hybrid", {"只要小鼠 2023 年 GAPDH": ["P-mm"]}),
"graph": NamedRetriever("graph", {}),
"multimodal": NamedRetriever("multimodal", {}),
}
print(routed_retrieve("只要小鼠 2023 年 GAPDH", RuleRouter(), retrievers))

参数

参数 起点 影响
路由特征 规则(含 gene/regulate→graph)+ 轻量分类器 纯 LLM 路由又贵又不稳
fallback hybrid 防止空结果

失效—信号—螺丝

  • 路由准确率低:专项 Recall 塌。螺丝:加混淆矩阵,补规则。
  • 无 fallback:分错即空。螺丝:强制 fallback。
  • 一切都走最贵路:平均成本不降。螺丝:提高简单事实走 boolean/dense 的阈值。

规模(100 篇生物学 PDF)

路由模型轻量,约 1–8 ms/问。建库成本等于所维护的多路索引之和。

-------------本文结束感谢您的阅读-------------