数据截至 (上游 commit 9c5a94d151f9)
R2R 是什么 · 全景与阅读地图
30 秒导读: R2R(SciPhi-AI 出品)是一套围绕 RESTful API 的 agentic 检索系统。 你把文档喂进去,它帮你做搜索(search)、检索增强问答(RAG),以及能自己反复检索、边查边想的 研究型 agent。它的价值不在"又一个向量库",而在于:把语义 / 全文 / 图谱三路搜索、 两级排名融合、带出处的方括号引用,和**"检索本身就是 agent 的一个工具"**这几件事, 拼成一条从 HTTP 请求到带引用答案的完整流水线。
本章是顶层导览(Layer 0 + Layer 1):讲清"这是什么、大盘怎么转、一次 agent 请求怎么走完", 再给你一张往下钻的阅读地图。任何具体机制的实现都留给分章,本章不进代码细节。
1. 这是什么(零基础也能懂)
一句话定义: R2R = Retrieval to Riches(检索到富信息),一个把"搜索 + RAG + 研究 agent" 封装成 RESTful API 的检索系统。
解决谁的什么问题。 假设你有一大堆内部文档(PDF、网页、音频转写……),想让 AI 基于它们回答问题, 而不是瞎编。你不想自己从零拼"切块 → 向量化 → 混合检索 → 重排 → 塞进 prompt → 让模型带出处回答" 这一整套。R2R 把这套做成了一个服务:文档管理、混合搜索、知识图谱、用户与权限、agent,一次给全。
它能做什么(核心能力):
| 能力 | 白话 |
|---|---|
| 多模态摄取 | 把 .txt / .pdf / .json / .png / .mp3 等切块、向量化、入库 |
| 混合搜索 | 语义搜索 + 关键词搜索,用 reciprocal rank fusion(倒数排名融合)合并 |
| 知识图谱 | 自动抽实体与关系,支持基于图的检索 |
| Agentic RAG | 一个会反复调用检索工具、边查边推理的 agent |
| Deep Research | 多步推理:能查你的知识库,也能查互联网,综合出答案 |
用起来什么样。 三行代码就是这个库对外的全部"表面积"——三个检索入口,从浅到深:
# 1) 纯搜索:只要命中的文档片段
results = client.retrieval.search(query="What is DeepSeek R1?")
# 2) RAG:检索 + 让模型生成带引用的答案
response = client.retrieval.rag(query="What is DeepSeek R1?")
# 3) Agent:把检索当工具,自己反复查、反复想(Deep Research)
response = client.retrieval.agent(
message={"role": "user", "content": "What does DeepSeek R1 imply? Think about market and societal implications."},
rag_generation_config={"model": "anthropic/claude-3-7-sonnet-20250219", "extended_thinking": True},
)
(取自 py/README.md:33-52。)
一句话直觉。 把 search 当"一次性查字典",rag 当"查完让助理替你写段带脚注的答复",
agent 当"派一个研究员:他能反复查字典、查网,直到把问题想透"——而三者用的是同一套底层检索。
本节到此不碰任何实现。下面上大盘。
2. 顶层全景(它大概怎么转)
2.1 一张全景图
R2R 的检索侧是分层的:HTTP 路由层很薄,真正的编排在 RetrievalService,它再往下调策略层 →
三路底层搜索 → 聚合 → 生成/agent。
怎么读这张图: 从上往下是"请求越走越深";search / rag / agent 三个入口共用下方的检索栈,
区别只在栈顶是否叠加"生成"或"agent 循环"。
客户端 SDK
client.retrieval.{search|rag|agent}
│ HTTP POST /v3/retrieval/*
▼
┌───────────────────────────────┐
│ retrieval_router.py (薄路由) │ 校验入参、合并搜索模式
└───────────────┬───────────────┘
▼
┌───────────────────────────────┐
│ RetrievalService │ 编排中枢
│ search() / rag() / agent() │
└───────┬───────────────┬────────┘
│ │
①检索策略层 ④生成 / Agent 循环
basic/HyDE/RAG-Fusion RAG 生成 · AgentFactory
│ │ (agent 把 ①当成一个可反复调用的工具)
▼ ▼
┌──────────────────────┐ 引用系统:short-id 方括号 [abc1234]
│ ② 三路底层搜索 │ 回填到 core/utils 的引用抽取
│ 语义 / 全文 / 混合 │
│ (pgvector, chunks) │
│ ③ 图谱检索 + 多源聚合 │
│ → AggregateSearchResult
└──────────────────────┘
2.2 部件一句话职责
| 部件 | 干什么 | 在哪 |
|---|---|---|
路由层 RetrievalRouter | 定义 /retrieval/{search,rag,agent,completion,embedding} 端点、校验、合并搜索模式 | py/core/main/api/v3/retrieval_router.py:49 |
| 搜索模式准备 | 把 basic/advanced/custom 模式默认值与用户覆盖项合并、套上权限过滤 | retrieval_router.py:59 _prepare_search_settings |
编排中枢 RetrievalService | 所有检索/RAG/agent 逻辑的落点;search() 按策略分流 | py/core/main/services/retrieval_service.py:248 |
| 三路底层搜索 | 语义 / 全文 / 混合三种 chunk 搜索(走 pgvector) | py/core/providers/database/chunks.py:327,484,538 |
| 多源聚合 | chunk + graph 结果打包成一个 AggregateSearchResult | retrieval_service.py:321 _basic_search |
| Agent 工厂 | 按 mode(rag/research)× 流式 × 模型,造出对应 agent 实例 | retrieval_service.py:60 AgentFactory.create_agent |
| Agent 实现 | RAG agent 与 Research agent 的具体行为 | py/core/agent/rag.py、py/core/agent/research.py |
| 引用系统 | 从模型输出里抽 short-id 方括号引用、映射回源结果 | py/core/utils/__init__.py:29 extract_citations |
2.3 主线走一遍(高层,不进代码)
拿最复杂的 client.retrieval.agent(...) 走一条端到端主线——把整条流水线一次点亮:
① 客户端 POST /v3/retrieval/agent,带 message + rag_generation_config
│
② 路由 agent_app 校验 message/messages、按 mode 选默认模型、
(router:546) _prepare_search_settings() 合并搜索模式并套上用户过滤
│ 调 services.retrieval.agent(...)
③ Service.agent 组装系统指令、按 mode 配好工具,交给 AgentFactory
(service:1268) create_agent() 造出 R2R(Streaming)RAGAgent / ResearchAgent
│ 关键:knowledge_search_method = self.search ← 检索"变成一个工具"
④ Agent 循环 模型自己决定何时调"搜索工具" → 每次调用就跑一遍
│ 策略层(basic/HyDE/RAG-Fusion)→ 三路搜索 → 图谱 → 聚合
⑤ 聚合结果回流 AggregateSearchResult 塞回上下文,模型继续想/继续查(可迭代)
│
⑥ 生成带引用答案 模型输出里带 [short-id] 方括号引用;引用系统把它映射回原文块
│
⑦ 返回 非流式:整包 WrappedAgentResponse;流式:SSE 事件
(thinking / tool_call / tool_result / citation / message / final_answer)
这条主线的题眼: 第 ③ 步那行 knowledge_search_method=self.search
(retrieval_service.py:1497 附近)——同一个 RetrievalService.search 方法,既是 /search 端点
的实现,又被当作 agent 手里的一个可反复调用的检索工具。 这就是"agentic RAG"名副其实的地方:
检索不是一次性前置步骤,而是 agent 循环里可以被多次触发的动作。详见
05-Agentic-RAG与Deep-Research.md。
3. 巧妙之处速览(带走三个"精华")
这里只点出妙在哪,具体实现各自有分章深讲。
-
两级 RRF(倒数排名融合)。 第一级在单次混合搜索内部——把"语义排名"和"全文排名"用 RRF 合成一个列表(
chunks.py:538hybrid_search)。第二级在 RAG-Fusion 策略里——把 原查询 + 若干改写子查询各自的结果再用 RRF 融合一次(retrieval_service.py:450_reciprocal_rank_fusion_chunks)。同一个融合思想,在两个尺度上各用一次。见 02-检索策略与两级RRF.md。 -
short-id 方括号引用。 每个检索结果对象都有一个 id;模型被要求在答案里用
[前几位短id]的形式引用。回填时用"前缀匹配"把短 id 认回完整结果(retrieval_service.py:1248_find_item_by_shortid,str(result_obj.id).startswith(sid))。短 id 省 token,又能精确回溯原文。 见 04-RAG生成与short-id引用.md。 -
检索 = 可迭代的 agent 工具。 不是"先检索再回答"的一锤子买卖,而是把
self.search作为工具 句柄交给 agent(AgentFactory.create_agent的knowledge_search_method形参,retrieval_service.py:67-82),让模型自己决定查几 次、查什么。见 05-Agentic-RAG与Deep-Research.md。
4. 阅读地图(建议按 01→05 顺序)
由浅入深:先看"底层怎么查一次",再看"多路怎么融合",再叠"图谱与聚合",最后到"生成与 agent"。
| 顺序 | 章节 | 讲什么 | 什么时候读 |
|---|---|---|---|
| 01 | 底层三路检索 | 语义 / 全文 / 混合三路搜索,pgvector 落地 | 想知道"一次搜索最底层怎么执行" |
| 02 | 检索策略与两级RRF | basic / RAG-Fusion / HyDE 三种策略与两级 RRF | 想知道"多路结果怎么被融合排名" |
| 03 | 知识图谱检索与多源聚合 | 图谱检索 + AggregateSearchResult 的多源打包 | 想知道"chunk 与 graph 结果怎么合流" |
| 04 | RAG生成与short-id引用 | RAG 生成与 short-id 方括号引用系统 | 想知道"答案里的 [abc1234] 怎么来的" |
| 05 | Agentic RAG 与 Deep Research | 把检索变成可迭代工具的 agent | 想知道"agent 怎么反复查、边查边想" |
推荐路线: 完全新手 → 01 → 02 → 03 → 04 → 05 顺序读;只关心 agent → 先扫本章 §2.3 主线, 再直奔 05,遇到"它到底怎么检索的"回头补 01/02。
5. 顶层代码地图(agent 的跳转表)
三列:主题 | 文件路径 | 真实符号名。行号 as-of sourceCommit;行号漂移时用符号名 grep。
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 检索路由(三入口) | py/core/main/api/v3/retrieval_router.py | RetrievalRouter |
| search 端点 | py/core/main/api/v3/retrieval_router.py:141 | search_app |
| rag 端点 | py/core/main/api/v3/retrieval_router.py:297 | rag_app |
| agent 端点 | py/core/main/api/v3/retrieval_router.py:546 | agent_app |
| 搜索模式合并 | py/core/main/api/v3/retrieval_router.py:59 / :33 | _prepare_search_settings / merge_search_settings |
| 编排中枢 | py/core/main/services/retrieval_service.py:248 | RetrievalService |
| 策略分流 | py/core/main/services/retrieval_service.py:259 | RetrievalService.search |
| basic 策略 | py/core/main/services/retrieval_service.py:281 | _basic_search |
| RAG-Fusion 策略 | py/core/main/services/retrieval_service.py:326 | _rag_fusion_search |
| HyDE 策略 | py/core/main/services/retrieval_service.py:554 | _hyde_search |
| 两级 RRF | py/core/main/services/retrieval_service.py:450 / :509 | _reciprocal_rank_fusion_chunks / _reciprocal_rank_fusion_graphs |
| 向量/图谱搜索逻辑 | py/core/main/services/retrieval_service.py:651 / :731 | _vector_search_logic / _graph_search_logic |
| RAG 生成 | py/core/main/services/retrieval_service.py:985 | RetrievalService.rag |
| Agent 编排 | py/core/main/services/retrieval_service.py:1268 | RetrievalService.agent |
| Agent 工厂 | py/core/main/services/retrieval_service.py:60 | AgentFactory.create_agent |
| short-id 回填 | py/core/main/services/retrieval_service.py:1248 | _find_item_by_shortid |
| 三路底层搜索 | py/core/providers/database/chunks.py:327,484,538 | semantic_search / full_text_search / hybrid_search |
| Agent 实现 | py/core/agent/rag.py、py/core/agent/research.py | R2RRAGAgent / R2RResearchAgent 等 |
| 引用抽取 | py/core/utils/__init__.py:29,55 | extract_citations / extract_citation_spans |