Routing-Table RAG实测:700题准确率99.86%及成本分析
Follow-up: measured the routing-table RAG on 700 questions. It beat retrieval everywhere except the one place a human wrote a false sentence
提供了一手且详尽的RAG工程复盘,不仅给出了路由策略的量化性能数据,还深入剖析了成本计算逻辑与典型失败模式,对构建复杂检索系统极具参考价值。
Follow-up: measured the routing-table RAG on 700 questions. It beat retrieval everywhere except the one place a human wrote a false sentence
后续:在 700 个问题上的路由表 RAG 进行了测量。它在除一处人类编写了错误句子的地方之外的所有场景下都优于检索。
Follow-up to my routing-table RAG post, where I asked how to evaluate it. I measured it: 700 questions, one frozen corpus (1,126 docs, 5 areas), four arms (rag, rag+rerank, routing, routing+overlay), full count, not a sample. Walker is claude-sonnet-5, reranker gpt-5, embeddings text-embedding-3-large.
这是我关于路由表 RAG 帖子的后续,当时我询问如何评估它。我对其进行了测量:700 个问题,一个冻结语料库(1,126 个文档,5 个区域),四种模式(rag、rag+rerank、routing、routing+overlay),全量计数,而非抽样。Walker 是 claude-sonnet-5,重排器是 gpt-5,嵌入模型是 text-embedding-3-large。
What I tested, in order:
我按顺序测试了以下内容:
- Find where plain RAG breaks. Then look at what the routing table does on exactly those questions.
- Bolt a reranker onto RAG at those breaking points. Find where that breaks. Then look at what the routing table does there.
- Put each tool's cost next to its result — calls, tokens, dollars, latency, per question.
- 找出纯 RAG 失效的地方。然后查看路由表在这些确切问题上的表现。
- 在这些失效点将重排器附加到 RAG 上。找出这也会失效的地方。然后查看路由表在那里做什么。
- 将每个工具的成本与其结果并列——调用次数、令牌数、美元成本、延迟,每个问题。
Short version: routing hit 699/700, and the one miss wasn't a routing failure — it was one false sentence a human wrote in the map, and both routing arms obeyed it identically. That's the part worth reading. The chapter where routing just wins on accuracy comes first only because it's the shortest — reporting only the winning side is advertising, so the cost section is where the real numbers are.
简短版:路由达到了 699/700,唯一的那个失误并非路由失败——而是人类在地图中写了一句错误的句子,且两种路由模式都完全遵循了它。这是值得阅读的部分。路由仅在准确性上获胜的章节排在前面,仅仅是因为它最短——只报告获胜方属于广告宣传,因此成本部分才是真实数据的所在。
(Terms: the map is the human-written routing table. A walk is one agent run on one question — several tool calls. routing+overlay is routing plus an explicit working set of docs opened so far.)
(术语:地图是人类编写的路由表。一次行走(walk)是在一个问题上运行一个代理——涉及多次工具调用。routing+overlay 是路由加上显式的工作集,即已打开的文档集合。)
1. Where plain RAG breaks — and what routing does there
1. 纯 RAG 失效的地方以及路由在此处的表现
I split the 700 questions by how the answer has to be reached, and ran every arm on all of them.
我根据答案必须如何被获取的方式对 700 个问题进行了分类,并在所有问题上运行了每种模式。
| Family | What it asks | n | rag | rag+rerank | routing |
|---|---|---|---|---|---|
| direct | one doc, phrasing matches | 320 | 0.991 | 1.000 | 1.000 |
| indirect | one doc, indexed by code only | 320 | 0.028 | ≈0.07 | 1.000 |
| old version | a rule as it was two revisions ago, by date | 15 | 0.133 | ≈0.20 | 1.000 |
| boundary day | the exact day a rule changed | 10 | ≈0.60 | ≈0.60 | 1.000 |
| needs both | two docs must be combined | 10 | ≈0.80 | ≈0.80 | 1.000 |
| current rule | the latest version | 10 | 1.000 | 1.000 | 0.900 ← |
| 类别 | 它要求什么 | n | rag | rag+rerank | routing |
|---|---|---|---|---|---|
| direct | 单个文档,措辞匹配 | 320 | 0.991 | 1.000 | 1.000 |
| indirect | 单个文档,仅通过代码索引 | 320 | 0.028 | ≈0.07 | 1.000 |
| old version | 两条修订前的规则,按日期 | 15 | 0.133 | ≈0.20 | 1.000 |
| boundary day | 规则变更的确切日期 | 10 | ≈0.60 | ≈0.60 | 1.000 |
| needs both | 必须组合两个文档 | 10 | ≈0.80 | ≈0.80 | 1.000 |
| current rule | 最新版本 | 10 | 1.000 | 1.000 | 0.900 ← |
rag ● routing ◆ direct ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━●◆ n=320 indirect ●────────────────────────────────────────────────◆ n=320 rag 0.028 old version ──────●─────────────────────────────────────────◆ n=15 rag 0.133 boundary day ──────────────────────────────●─────────────────◆ n=10 needs both ────────────────────────────────────────●───────◆ n=10 current rule ───────────────────────────────────────────◆────● n=10 routing 0.900 0.0 0.5 1.0 rag ● routing ◆ direct ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━●◆ n=320 indirect ●────────────────────────────────────────────────◆ n=320 rag 0.028 old version ──────●─────────────────────────────────────────◆ n=15 rag 0.133 boundary day ──────────────────────────────●─────────────────◆ n=10 needs both ────────────────────────────────────────●───────◆ n=10 current rule ───────────────────────────────────────────◆────● n=10 routing 0.900 0.0 0.5 1.0(≈ values are read off my chart, not exact. routing+overlay is omitted — it matches routing to three decimals on every row and misses the same single question.)
(≈值是从我的图表中读取的,并非精确值。routing+overlay 被省略——它在每一行都与 routing 在小数点后三位完全匹配,并且同样错过了那同一个问题。)
Plain RAG breaks on two nameable classes: prose questions against code-indexed docs (0.028) and questions about a superseded version (0.133). On those it doesn't degrade — it just fails. There's no map to be wrong, but also no map to be right; nothing tells it the doc it wants is filed under a code it never saw.
纯 RAG 在两类可命名的场景中失效:针对代码索引文档的自然语言问题(0.028)和关于已被取代版本的问题(0.133)。在这些情况下,它不会性能下降——而是直接失败。没有地图会出错,但也没有地图能正确指引;没有任何东西告诉它它想要的文档被归档在它从未见过的代码下。
Routing on exactly those questions: 1.000 and 1.000. The map row for that area says in plain English when to go there, and the walk goes there.
针对这些问题的路由结果:1.000 和 1.000。该区域的地图行用通俗英语说明了何时前往,而 Walk(探索)确实去了那里。
Worth saying plainly: 320 of the 700 are questions plain RAG already gets on the first try (0.991). Nothing in this data says to walk those.
有必要直白地说:700 个问题中有 320 个是普通 RAG 第一次尝试就能答对的(准确率 0.991)。数据中没有任何迹象表明需要对这些问题进行 Walk。
2. Add a reranker — where does that break?
2. 添加重排序器(reranker)——它会在哪里失效?
Reranking fixes what it can see. It takes direct from 0.991 to 1.000, and that's about it: indirect moves 0.028 → ≈0.07, two versions back 0.133 → ≈0.20. The reason is mechanical: the reranker only fired on 390 of 700 questions (0.56×), because on the other 310 the fusion candidates didn't contain the answer, so there was nothing to reorder. A reranker can't promote a doc that retrieval never surfaced. RAG's breaking points and rerank's breaking points are the same points.
重排序只能修复它能看到的部分。它将准确率从 0.991 提升至 1.000,仅此而已:间接相关的部分从 0.028 升至约 0.07,两个版本前的内容从 0.133 升至约 0.20。原因是机械性的:重排序器仅在 700 个问题中的 390 个上触发(占比 0.56),因为在其余 310 个问题中,融合候选项不包含答案,因此没有可重新排序的内容。重排序器无法提升检索从未召回的文档。RAG 的失效点与重排序的失效点是相同的。
Routing on those: still 1.000. Which brings us to the one row where routing loses.
针对这些问题进行路由:结果仍为 1.000。这引出了唯一出现路由失败的那一行。
The one miss, and why it's the real finding
唯一的失误,以及为何它是真正的发现
The single routing failure is a current rule question — a family plain RAG gets 1.000 on. It wasn't a bad walk. Two docs in the corpus are relocation notices — stubs left behind when a topic moves to another area, telling the walker where it went. Both said:
唯一的路由失败涉及一个当前规则问题——普通 RAG 对此类问题的准确率为 1.000。这并非一次糟糕的 Walk。语料库中有两篇文档是搬迁通知——当主题迁移到其他区域时留下的存根,告知 Walk 目标已移至何处。两篇通知均写道:
These pages remain correct for dates before 2026-01-01, and incorrect after.
这些页面在 2026-01-01 之前的日期仍然正确,在此之后则不正确。
False. Those pages were already superseded on 2024-07-01, 18 months before the relocation the notice describes. The notice wasn't wrong about the move; it was silent about the revision before it, and silence reads as "nothing more to know." A walk read it, did exactly what it said, and answered a 2025 claim with the 2023 rule.
错误。这些页面已于 2024-07-01 被取代,比通知所述的搬迁早 18 个月。通知关于搬迁的说法没错;但它对之前的修订保持沉默,而沉默会被解读为“无需知晓更多信息”。Walk 读取了该通知,完全按照其指示操作,并用 2023 年的规则回答了关于 2025 年的主张。
Evidence it was the map and not the model: routing and routing+overlay — no shared context, one of them carrying a record of its own decisions — failed the same question through the same two docs onto the same wrong era. The working set couldn't help. Nothing had been forgotten; the notice was read, understood, and obeyed.
证明是地图而非模型出错:路由与路由+叠加层(routing+overlay)——前者无共享上下文,后者携带自身决策记录——都通过相同的两篇文档,将同一问题错误地归入同一个时代。工作集未能提供帮助。没有任何内容被遗忘;通知已被读取、理解并遵照执行。
I fixed the sentence (full version table, explicit "dates after 2024-07-01 are answered elsewhere") and reran the 10 current rule questions:
我修正了该句子(完整版本表格,明确注明“2024-07-01 之后的日期需参考其他解答”),并重新运行了 10 个当前规则问题:
| before | after |
|---|---|
| current rule, routing | 0.900 |
| failing walk's path | notice → 2023 rule |
| 修改前 | 修改后 |
|---|---|
| 当前规则,路由 | 0.900 |
| 失败 Walk 的路径 | 通知 → 2023 年规则 |
Same notice, different destination. The agent didn't get more careful. It was handed a true sentence.
同样的通知,不同的目的地。代理并未变得更加谨慎。它只是被提供了一句真实的话。
Two things this taught me about where the approach is exposed:
这让我对该方法的暴露点有了两点认识:
- Docs compete; map rows are obeyed. A bad doc is one of ten candidates weighed against nine others. A bad sentence in the map isn't weighed — it's an instruction.
- The failure hides. RAG's wrong answers look wrong (thin, off-topic, empty). Routing's wrong answers look right — specific numbers, cited source, a clean-looking walk log. A 50-question sample I ran first happened to miss the bad path and reported 1.000. That's why it took all 700.
- 文档相互竞争;地图行必须被遵守。一篇错误的文档是在十个候选项中与另外九个一起被权衡的结果。而地图中的一句错误句子不会被权衡——它是一个指令。
- 失败被隐藏了。RAG 的错误答案看起来是错的(内容单薄、偏离主题、空洞)。路由的错误答案看起来却是对的——包含具体的数字、引用的来源,以及一份看似整洁的行走日志。我最初运行的一个 50 题样本恰好避开了错误路径,报告结果为 1.000。这就是为什么它用完了全部 700 题的原因。
3. Cost next to result, per question
3. 每个问题的成本与结果之比
| rag | rag+rerank | routing |
|---|---|---|
| network round-trips | 1 | 1.56 |
| new text processed | ~30 tokens | ~2,500 tokens |
| latency | <1 s | a few s |
| measured cost | negligible | model-dependent |
| rag | rag+rerank | routing |
|---|---|---|
| 网络往返次数 | 1 | 1.56 |
| 新处理文本量 | ~30 tokens | ~2,500 tokens |
| 延迟 | <1 s | 几秒 |
| 测量成本 | 可忽略不计 | 取决于模型 |
Within routing, cost tracks how many docs the answer stands on (n=5, one walk per family):
在路由内部,成本取决于答案所基于的文档数量(n=5,每个家族一次行走):
direct ████████████████████ $0.122 · 23 s · 6 turns current rule █████████████████████ $0.128 · 24 s · 8 turns indirect ██████████████████████████ $0.161 · 43 s · 9 turns indirect ████████████████████████████ $0.170 · 47 s · 10 turns needs both ██████████████████████████████████████████████ $0.281 · 111 s · 14 turns $0 $0.10 $0.20 $0.30direct ████████████████████ $0.122 · 23 s · 6 turns current rule █████████████████████ $0.128 · 24 s · 8 turns indirect ██████████████████████████ $0.161 · 43 s · 9 turns indirect ████████████████████████████ $0.170 · 47 s · 10 turns needs both ██████████████████████████████████████████████ $0.281 · 111 s · 14 turns $0 $0.10 $0.20 $0.30A two-doc question costs ~2× and takes ~5× a one-row question. That's the work the question demanded, not overhead to engineer away.
涉及两篇文档的问题成本约为单行问题的 2 倍,耗时约为 5 倍。这是问题本身所需的工作量,而非可以通过工程手段消除的开销。
The number that will get misquoted: raw usage shows 200k–500k input tokens per walk. Real, but every tool call resends the conversation so far and nearly all of it is served from cache:
最容易被误引的数字:原始使用数据显示每次行走消耗 20 万至 50 万输入 tokens。数据确实如此,但每次工具调用都会重新发送迄今为止的对话内容,而其中几乎全部内容都来自缓存:
| Family | new input | cache write | cache read | output |
|---|---|---|---|---|
| direct | 12 | 16,842 | 198,549 | 1,330 |
| needs both | 28 | 25,633 | 498,935 | 7,694 |
| 家族 | 新输入 | 缓存写入 | 缓存读取 | 输出 |
|---|---|---|---|---|
| direct | 12 | 16,842 | 198,549 | 1,330 |
| needs both | 28 | 25,633 | 498,935 | 7,694 |
Quote 500k and you overstate cost 10×. Quote the ~20 new tokens and you understate it 1000×. $0.12–$0.28 is the measured number.
引用 50 万会高估成本 10 倍。引用约 20 个新 tokens 则会低估成本 1000 倍。测量得出的数值为 $0.12–$0.28。
And that price is the price when the map works. A full traversal of this corpus would be ~1,340 calls and ~2.7M tokens — it fits in no context. The runner caps at 40 turns (~82k tokens), which is about one session's capacity. So one walk can see at most ~3% of the tree; the median walk sees 0.52%.
而且这个价格是在地图正常工作时产生的价格。对该语料库进行完整遍历将需要约 1,340 次调用和约 270 万 tokens——这超出了任何上下文窗口的容量。运行器限制为 40 轮对话(约 82k tokens),这大约是一个会话的容量。因此,一次行走最多只能看到树结构的约 3%;中位数行走看到的比例为 0.52%。
whole corpus ████████████████████████████████████████████████████ 1,340 calls · ~2.7M tokens · unreachable runner cap ██ 40 calls · 3.0% median walk ▌ 7 calls · 0.52%whole corpus ████████████████████████████████████████████████████ 1,340 calls · ~2.7M tokens · unreachable runner cap ██ 40 calls · 3.0% median walk ▌ 7 calls · 0.52%The map's job isn't to save calls — it's to make the 0.5% a walk can afford the right 0.5%.
地图的任务不是节省调用次数——而是确保行走所能负担的那 0.5% 是正确的 0.5%。
更进一步:量化金融体系
看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力