从 Rag 到领域 Agent
第一天的 Agent 会查日程、订机票、调用接口。同事接着问的往往是另一类问题:「上海住一晚上限多少」「未休年假怎么折算」「这张票超标了要不要审批」。这些话的依据在制度、公告和标准表里,不在模型参数里。
做法是 RAG:先从资料里找出相关段落,再让模型只根据这些段落回答。它接在第一天的公式上。检索是一个 Tool,召回的段落是送进下一轮的 Context。模型仍然只做一次决策;哪几段文字有资格进入上下文,由外层程序决定。
下面按笔记的两条流水线往下讲:资料怎么进库,一次提问怎么变成答案,向量模型怎么选,关键词、向量和混合检索各用在什么问法上,以及检索策略可以由规则选定,也可以交给 Agent。第 6 节处理问法、空库和多跳带来的偏差。第 7 节把 RAG 分成五级。第 8 节是再往后的 Deep Research。例子沿用同一次出差。
1. 资料先变成可检索的块
回答质量的上限,在用户提问之前就已经定了。数据准备是四步。
提取。 从 PDF、HTML、Word、数据库里取出正文。差旅场景里通常同时有三份材料:制度 PDF、协议酒店网页、数据库里的城市住宿标准表。表格若被抽成一串错位的数字,后面无论用什么检索,都找不到「上海 550 元」这一个事实。扫描件要先做文字识别,页眉页脚和目录页不要送进正文。
切分。 长文切成 chunk,检索和阅读都以块为单位。笔记里的例子是大约 500 字一块。块是召回的最小单位,也是后来放进提示词的一段上下文。
固定长度好实现,适合体裁统一的纯文本。它会把一条制度切坏:前一块是「适用对象」,后一块是「例外」,只命中其中一块时,模型会按半条规则回答。更稳妥的切法是先按标题、条款、段落和表格行切开,单块仍然过长时,再在块内用固定窗口,并留 10%–20% 的重叠,减轻句子正好被切断的情况。
还有一种矛盾要在切分时处理。小块容易被精确命中,大块才带得上「这条的例外是什么」。可以两级都留着:用句子或小段去做匹配,送进提示词的是它所在的整条条款。小块负责被找到,父块负责被阅读。
切分有三条理由。Embedding 有最大输入长度,超长文本进不去。小块比整章更容易命中真正相关的那一句,检索更准。小块的向量索引更快、编码更省,后面重排和拼进提示词时 Token 也更少。
切的时候守四条。语义要完整:「Flink 支持流批一体」不能切成「Flink 支持」和「流批一体」。长度要落在模型上限之内,也要让后面的重排读得完。上下文要连得上,长文里「前文提到的某项技术」要能回到它指的那一处。场景要跟着体裁:代码按函数或类,新闻按事件,表格按行或列,对话按一问一答。
六种切法可以按文档长相来选:
| 切法 | 怎么切 | 适合 | 注意 |
|---|---|---|---|
| 固定长度 | 按固定 token 或字符数 | 没有明显结构、先求速度的大库 | 容易把一句话切断 |
| 文档结构 | 按章节、标题、段落、列表,优先用换行和标题 | PDF、Word、Markdown | 要先解析结构 |
| 按内容类型 | 代码按函数和类,表格按行列,对话按问答对 | 代码库、数据表、聊天记录 | 每种体裁单独写规则 |
| 语义分块 | 相邻句子相似度变低的地方切开 | 专业文献、要保住逻辑连贯 | 计算更重 |
| 递归分块 | 先按空行,再按换行,再按空格,直到块足够小 | 书籍、万字报告 | 分隔符按优先级排好 |
| 上下文增强 | 块与块重叠,或给每块补一段上下文摘要 | 复杂问答、长文档 | 存储和处理更重 |
差旅制度用文档结构切开,过长的条款再按固定窗口并留重叠,匹配用小块、阅读用父块。这是上表里固定长度、文档结构和上下文增强合在一起。条款边界本身不可靠时,再考虑语义分块或递归分块。
向量化。 用 Embedding 模型把每个块变成一串数字。这串数字保留的是语义,相近的说法在空间里距离更近。「住宿报销上限」和「住一晚最多能报多少」可以靠这个距离碰到一起。
入库。 原文、向量和元数据一起写入检索引擎。元数据至少包括来源、标题、章节、更新时间、权限和父块标识。没有原文就无法引用,没有时间和权限就无法回答「以哪一版为准、这个人能不能看」。向量只负责找得快,不负责这些过滤。
2. 一次提问怎么变成答案
检索生成也是四步,并且必须和第 1 节使用同一个 Embedding 模型。两个模型的向量不在一个空间里,相似度没有意义。换模型就要整库重新向量化。
- 问题向量化。 「上海住一晚上限多少」变成一个向量。
- 数据检索。 用这个向量和库里每个块的向量算相似度,取出最接近的 Top-K 块。
- 注入 Prompt。 把这 K 段文字当作上下文,和原问题一起写成结构化提示:先给依据,再给问题,并要求答案里的数字、条款能在依据中找到。
- 生成答案。 模型阅读这段上下文后作答。笔记里的目标是「忠于事实」:上海的上限应来自召回的那一版标准表,而不是模型记得的某个旧数字。
朴素 RAG 只有「检索 → 增强 → 生成」这条直线,提问之前和召回之后都不加工。用一个跨文档问题看它会翻在哪里:比较英伟达和苹果近三年的财务表现,判断哪家更值得投资。年报按章切块、直接做向量检索之后,会出现三类失败:召回了同一章在不同年份的正文,时间范围错了;苹果那一侧的内容没进来;召回总量不够。生成结果往往只剩英伟达相对标普 500、纳斯达克的股价,并说明手头没有更细的财务数据,没法判断。读起来像一份分析,依据并没有覆盖问题。
高级 RAG 在这条直线两端加工序。检索之前做查询改写、按标题和年份建层次索引、解析 PDF 版面,把「财务表现」展开成关键财务指标、股价和其他因素。检索之后做重排,把相关性高的段落留下。改进之后的答案仍然可能只比了收入、把波动理解偏。工序加上之后,流程还是线性的;要反复改查询、换策略的问题,留到第 5 节的 Agent 循环。
这四步是一条误差链。提取丢了表格、切分拆开了例外、召回混进了相近城市的标准,模型都会给出一段读起来完整的话。所以出了错要能回到具体的块:当时注入的是哪几段、那几段里有没有这句话。
制度为什么不直接微调进模型,对照如下。RAG 更新的是库:换一版差旅 PDF 就能生效,不用重新训练;答案能指回某一段。微调把知识写进参数,更新要重新标注、再训一轮,答案也指不出出处。微调的响应更快,因为不用先检索。私有制度、要追溯出处、会经常改版,走 RAG。口径长期稳定、每次都要亚秒返回、又能接受重新训练的说法,才考虑微调。
| RAG | 微调 | |
|---|---|---|
| 知识怎么更新 | 改知识库,实时生效 | 重新准备数据,再训一次 |
| 要什么数据 | 文档和表格即可 | 高质量标注 |
| 时效 | 能接最新材料 | 停在训练数据的截止时间 |
| 响应 | 多一次检索,更慢 | 知识已在参数里,更快 |
| 隐私 | 留在本地库 | 送到第三方平台微调时,数据要出域 |
| 能否追溯 | 能回到具体片段 | 固化在参数里,难以对上原文 |
| 幻觉 | 可以按库校验 | 可能编出训练里没有的说法 |
3. 向量化模型按约束选
笔记把模型分成三类。选型先看数据能不能出域、主要是什么语言、术语有多专,再看榜单。
| 类型 | 代表 | 特点 | 适合 |
|---|---|---|---|
| 闭源 | OpenAI text-embedding-3-small、Google Gemini Embedding | 语义强,长文本支持好(如最大 8191 token),不用自己维护推理 | 快速落地,数据可以出域,对调用成本不敏感 |
| 开源 | Sentence-BERT(all-MiniLM-L6-v2)、BERT-base、通义千问 Embedding | 能本地部署,数据留在内网,轻量模型延迟低 | 企业私有制度,高并发、要压成本 |
| 领域专用 | CodeBERT(代码)、BioBERT(生物医疗) | 对专业术语和行业说法更稳 | 技术文档、医疗知识库等垂直材料 |
差旅制度、报销标准属于企业私有数据,优先用可本地部署的中英双语 Embedding,全库只用一个。all-MiniLM-L6-v2 适合作为英文或试验环境的轻量基线;中文制度要用在中文材料上表现稳定的模型,并用一批真实问法做对照,例如「住一晚多少钱」能否召回「住宿费标准」那一节。
模型能接受很长的输入,不表示块就该切到那么长。一块里塞进整章制度,一个向量会同时代表报销、审批和例外,相似度变钝。500 字量级的条款,通常比整章一个向量更好找。
领域模型解决的是通用模型不熟悉的说法。内部系统名、条款编号、药品名、函数名,字面本身就很关键。这类材料要么换领域模型,要么把下一节的关键词检索一并接上。
4. 三种检索,对应三种问法
关键词:BM25
TF-IDF / BM25 走的是词,不走向量。BM25(Best Matching 25)是一种概率检索模型,给「一块文档和这句查询有多相关」打分。笔记里的策略可以收成三句话:词出现得越多越相关,过长的文档要受惩罚,满篇都是的常用词权重更低。
三个维度就是这三句话的计算:
- TF,词频。 「协议酒店」在一个块里出现得越多,这个块越相关。次数会饱和:从 1 次到 3 次加分明显,从 30 次到 40 次几乎不再加分,避免把同一词重复堆上去。
- IDF,逆文档频率。 这个词在整个制度库里越少见,越重要。「的」「是」几乎每块都有,区分度低;「协议酒店」「550」很少见,区分度高。
- 文档长度归一化。 长块有更多机会碰巧含有查询词。用当前块长度除以平均块长度做惩罚,避免长文档只靠篇幅占优。
标准打分是:对查询里的每个词,用 IDF 乘上一个由词频和长度组成的比例,再把各词加起来。
Score(D, Q) = Σ IDF(qi) · [ f(qi, D) · (k1 + 1) ] / [ f(qi, D) + k1 · (1 - b + b · |D| / avgdl) ]
f(qi, D) 是词频,|D| / avgdl 是相对平均长度。k1 常用 1.2 到 2.0,控制词频多快饱和;b 常用约 0.75,控制长度惩罚有多重。分享和实现时记住三个维度即可,公式用来对齐实现,不必在现场展开推导。
在 RAG 里的顺序是:原文切成约 500 字的块,对每块分词,建立倒排索引 word → chunk_id。查询「协议酒店」时,只取出含有这个词的块。它很快,而且得分能指到具体的词。
用退款库看一次打分。四块分别是:C1「在订单页点击申请退款并填写原因」,C2「退款 3–5 个工作日到账」,C3「账户安全请联系客服」,C4「如何修改密码」。问「怎么申请退款」,分词得到「怎么 / 申请 / 退款」,去倒排里找含这些词的块,再算分。C1 约 9.8,C2 约 3.2,C3、C4 接近 0。送进模型的是分数最高的那几块,密码和账户安全不会因为「在同一本帮助中心」就被带进去。
它适合精确说法:城市名、金额、制度编号、错误码、接口名。字面一致就是相关。它不处理换一种说法。「住哪比较合适」和正文里的「住宿费标准」可能没有共同的关键词,BM25 会错过。
向量:按语义找近邻
向量检索把问题和块放在同一个语义空间里,用相似度取最近的 K 个块。它能把「住一晚最多报多少」和「住宿费标准」拉到一起,也能跨过一部分同义词。
代价也具体。短问题对上一个很长的块时,块里无关的句子会把向量带偏。条款编号、内部酒店编码在训练语料里少见,语义近邻未必是字面正确的那一条。相似度是一个小数,业务同学很难从小数看出「为什么是这一条」。索引之前还要先有 Embedding 模型。
对照放正之后是:
| 维度 | BM25 | 向量检索 |
|---|---|---|
| 匹配方式 | 关键词、字面 | 语义近邻 |
| 同义词和改写 | 基本不处理 | 能把不同说法拉近 |
| 意图 | 只看词是否出现 | 能贴近问法背后的主题 |
| 速度 | 倒排索引,极快 | 要做向量近邻,相对慢 |
| 可解释性 | 能指到命中的词 | 主要是一个相似度 |
| 冷启动 | 分词和倒排即可 | 需要 Embedding 模型 |
笔记摘录里「极快 / 可解释性强 / 冷启动好」这三项属于 BM25;「相对慢 / 可解释性弱 / 需要模型」属于向量检索。
混合检索,再重排
一次真实提问常常两种特征都有。「上海协议酒店超标了怎么批」里,「上海」「协议酒店」适合 BM25,「超标了怎么批」适合向量。混合检索就是两路一起召回,再合并候选。
两路分数的刻度不同,不宜直接相加。可以对每路分数做归一化后加权,也可以用倒数排名融合:只比较各自的名次,不比较分数的绝对值。名次融合对「两套分数不可比」更稳。
这一步的目标是把网撒宽。每一路先取 Top-20 到 Top-50。BM25 那路可能字面相关、语义跑偏;向量那路可能语义相近、关键词对不上。合并后还有重复和噪声。模型的上下文很贵,塞进几十条相近条款,注意力被稀释,也更容易编出依据里没有的话。重排要把这几十条压到 Top-3 至 Top-10,再送进生成。
重排的输入是用户查询和单个候选块,输出是 0 到 1 的相关性分,按分从高到低取 Top-K。它读的是两边的原文,判断这句话是否真在回答这个问题。召回阶段用的是 Bi-Encoder:问题和文档各自算一个向量,靠距离比较,所以能扫全库。重排换成 Cross-Encoder:问题和文档拼在一起过一次模型,直接出相关性。Cohere Rerank、bge-reranker-v2-m3、bge-reranker-large、英文上的 ms-marco-MiniLM-L-6-v2 都是这条路线。重排只能打少量候选,不拿来扫描全库。
两路合成一个顺序,有四种做法:
| 做法 | 怎么合成 | 适合 | 注意 |
|---|---|---|---|
| 加权融合 | 两路分数各自归一化后加权 | 想在关键词和语义之间调比重 | 刻度不同,权重要试 |
| 倒数排名融合 RRF | 只看名次:Σ 1 / (k + rank) | 两套分数不可比 | 两路候选要有一定重合 |
| 级联 | 先粗召回,再轻量重排,再重量重排 | 库很大 | 第一阶段没召回的,后面补不回来 |
| 投票 | 多路各自投票 | 要看得懂、要多样性 | 不看具体名次和分数 |
没有单独重排模型时,用 RRF 或线性加权:final = α · normalize(BM25) + (1 - α) · normalize(向量)。也可以让模型自己看「这块和问题有没有关系」,适合候选已经很少的时候。库到了百万级,用级联:BM25 和向量各取 Top-100,去重后大约 150 条;bge-reranker-m3 先压到 Top-20;bge-reranker-large 或模型再压到 Top-5,然后生成。
场景可以先按这张表选:
| 场景 | 推荐 |
|---|---|
| 中文问答、内部知识库 | BM25 + 向量 + bge-reranker-v2-m3 |
| 英文、不想自己部署重排 | BM25 + 向量 + Cohere Rerank |
| 快速验证、先不加模型 | BM25 + 向量 + RRF |
| 要更高置信 | 重排之后,再让模型看留下的几条是否真相关 |
| 超大库 | 召回约 200 条 → 轻量重排 → 重量重排 |
出差例子里,粗召回可能同时命中「协议酒店名单」「一线城市住宿上限」「超标审批流程」。问的是上限时,重排应把标准表那一条排到最前,审批流程靠后。进入提示词的是重排之后的 3 到 8 条,不是粗召回的全部。条数再多,模型的注意力会被相近条款稀释。
5. 检索策略可以按问题切换
同一套混合检索,事实问题和开放问题不该用同一组参数。静态策略是无论问什么,都用同一个模型、同一组权重、同一个截断数。动态策略先看懂问题,再决定用什么排、排不排、留几条。决策点可以收成这张表:
| 决策点 | 怎么变 |
|---|---|
| 用哪一路 | 事实类加重 BM25;语义类用 Cross-Encoder 重排 |
| 权重 | 政策、条文提高 BM25;闲聊和总结提高向量 |
| 要不要重排 | 简单 FAQ 可以跳过;复杂推理必须重排 |
| Top-K | 精确答案留 Top-3;综述可以放到 Top-15 |
| 排序目标 | 按相关性、按时效,或按来源的权威性 |
笔记给了两种做法。意图分类是第一种。模型在循环里自己选,是第二种。第三种用策略网络预测最优重排参数,训练数据难造,线上不稳定,延迟也难控,分享时知道有这条路即可,落地先用前两种。适合上动态策略的,是企业知识库里 FAQ、技术文档和政策混在一起,以及法律、医疗、金融这类要精确条文的场景。
用意图选择参数
先判断这句问的是事实还是语义,再返回一套固定参数。把笔记里的片段补成可运行的形式:
def route_rerank_strategy(query: str) -> dict:
intent = classify_intent(query)
if intent == "fact":
return {
"use_bm25": True,
"bm25_weight": 0.7,
"rerank_model": "bge-reranker-m3",
"top_k": 3,
}
if intent == "semantic":
return {
"use_bm25": False,
"vector_weight": 1.0,
"rerank_model": "bge-reranker-large",
"top_k": 8,
}
return {
"use_bm25": True,
"bm25_weight": 0.5,
"vector_weight": 0.5,
"rerank_model": "bge-reranker-m3",
"top_k": 5,
}
「上海住宿上限是多少」是事实。提高 BM25 权重,让城市名和金额这些词起主要作用;重排后只留 3 条。留得太多,北京的标准和上海的标准会一起出现,模型容易把数字抄错城市。bge-reranker-m3 覆盖多语言,成本更低,适合这种短事实。
「这次出差怎样安排才不违反制度」是语义。问法分散在住宿、交通和审批好几节里,向量更有用,候选放到 8 条,让更重的 bge-reranker-large 有余地挑选。语义问题里往往仍有专名,例如「上海」「协议酒店」。分享时的建议是语义类也保留一小路 BM25,只把权重降下来。上面 use_bm25: False 是笔记里的原策略;专名多的制度库,完全关掉关键词会错过最硬的锚点。
意图判断不了时,走函数末尾的固定混合比例,取 5 条。不要在分类失败时临时发明第三套权重。
让 Agent 自己决定怎么查
第二种做法把选择放进第一天的循环。模型先写出判断,再显式调用检索工具。笔记里的思考是:
这个问题涉及公司内部政策,需要精确条文。因此我应该:优先使用 BM25,再用重排筛选 Top-5,然后生成答案。
对应的行动是:
use_tool("hybrid_search", query, rerank=True, top_k=5)
用出差问句走一遍。「协议酒店超标,要先找哪一条审批」会被判断成要精确条文,于是走 BM25,重排留 5 条,再根据那 5 条写答案。「帮我看这次行程整体还缺什么手续」则可能改成语义检索,多留几条,覆盖交通、住宿和报销。
这就是 ReAct:思考,行动,观察。多跳问题靠这一步才完整。例如先查「适用哪一版差旅制度」,看见「2024 年修订版」,再拿这个版本去查违约和超标。一次 Top-K 拿不齐中间事实,循环里的第二次检索可以。
自主选择要有第一天已经立住的工具边界。模型只能在登记过的模式里选:bm25、vector、hybrid,top_k 限制在一个范围内。它不能临时指定一个不存在的重排模型,也不能一次取回几十条把上下文撑满。参数不合法时,把错误说明送回模型,让它改一次调用。检索结果进入工作记忆时只保留重排后的短列表:块标识、标题、正文摘要。审计日志另存全文。答案里引用的块标识必须来自这次工具结果。
工具调用本身还会错,常见的是:选错工具、编出不存在的参数、JSON 不合法、把一次完整调用嵌进另一个工具的参数里、多步调用的顺序乱了,以及长对话里把关键条件弄丢。推理更强的模型、少量成功调用的示例、信息不够时先追问,能先抬高选对工具的比例。选工具可以用更强的模型,把检索结果总结成答案可以换更省的模型。执行阶段的失败是另一类:网络波动、接口暂时不可用、权限不足、触发限流。把错误码和说明作为观察送回模型,让它换参数或换工具,而不是让整条任务在这一步断掉。
6. 如何减少偏差
混合检索加重排,解决的是候选里谁更相关。问法对不上正文、库里没有依据、一个问题要连查几次,仍会把答案带偏。下面三件事分别压这三种偏差。
问法和正文差很远。 同事说「老板不批住宿怎么办」,制度写的是「超标审批」。检索前让模型先把问句改写成接近制度用语的两三个查询,多路召回再合并。改写只用于检索。最终答案仍必须能在召回段落里找到原句。
这种偏差分成六类,改写时对症下药:
| 问题 | 原问法长什么样 | 改写成 |
|---|---|---|
| 口语、不规范 | 「苹果股价咋样了」 | 「Apple Inc.(AAPL)最新股价及相关分析」 |
| 指代不清 | 前文说过苏轼,接着问「他的词风」 | 「苏轼的词风特点是什么」 |
| 缩写、错字、术语不准 | 「AI 在衣料领域的应用」 | 「人工智能在医疗中的应用有哪些具体案例」 |
| 无关背景太多 | 先讲孩子成绩,绕一圈才问方法 | 「有哪些方法可以帮助学生提高数学成绩」 |
| 问得太宽 | 「新能源材料的研究」 | 「当前提升电池能量密度的新型材料研究进展」 |
| 语义太薄 | 「flink」 | 「介绍一下 Flink 的核心架构与优势」 |
一个问句里有多件独立的事,先拆成子查询再分别召回。比较 Flink 和 Spark 的优缺点及适用场景,拆成四问:Flink 的优缺点、Spark 的优缺点、Flink 适合什么项目、Spark 适合什么项目。四路结果合并之后再写对比。
问得过细、又依赖背景时,先退一步生成更宽的上位查询。例如「Flink 任务反压时,Checkpoint 超时怎么排查」,先查「反压和 Checkpoint 的关系」以及「Checkpoint 超时的主要原因」,再和原问题的检索结果合在一起回答。
HyDE 换一个方向:先让模型写一段假设中的答案,用这段假设文档的向量去库里找真实段落。它用来对付关键词对不上、意图又含糊的问法。假设文档只参与检索,不能当作已经查到的依据。
库里没有依据。 重排分整体很低,或召回文字里根本没有这个问题的对象,就返回「制度里没有这一条」,并留下查过的查询。继续生成一段流畅的建议,会把 RAG 退回成普通聊天。
一个问题要连查几次。 「这个客户适用哪版合同,那一版的违约金怎么算」放到 Agent 循环里,多次调用 hybrid_search。每一轮只把「查到了什么、还缺什么」留在工作记忆里。单轮就能答完的上限、定义、条款,不必为了架构去绕多智能体。
7. 不同阶段 RAG
第 6 节做了三件事:口语改成制度里的说法再查,库里没有就直说没有,一个问题拆成两次查。这三次查的都是切好的文字块,用的也是同一套关键词加向量。第二次查「2024 年修订版的超标审批」,换的是查询词,查法没有换。这种做法放在五级里的第二级,也就是高级 RAG:先把问题收拾好,再去文段里找,找到之后重排。
后面三级换的是查法。第三级把改写、检索、重排拆成可替换的模块,方便按场景重新拼。第四级不再只找相似段落。问「这笔超标先过谁、再过谁」,答案在人和审批步骤的关系上,要沿着关系走。第五级由模型看完上一步结果,再决定下一步查制度、查订单,还是停止。差旅里的住宿上限,第二级就够。
| 阶段 | 核心理念 | 检索对象 | 解决什么 |
|---|---|---|---|
| 朴素 RAG | 开卷考试 | 文本块的向量 | 模型知识静止、会凭空作答 |
| 高级 RAG | 在线性流程前后加工 | 仍然是文本块 | 查询太口语、召回不相关、上下文太长 |
| 模块化 RAG | 积木 | 模块可以替换 | 不同场景要不同的信息流 |
| 图谱 RAG | 在知识网络里找路 | 实体和关系 | 多跳、要沿着关系推理 |
| 智能体 RAG | 自主决定下一步 | 可以调用上面每一级 | 规划、反思、多轮取证 |
朴素 RAG
流程是检索、把段落塞进提示词、生成。它让模型开始依据外部材料作答,而不是只靠参数里的旧知识。第 2 节的年报问题落在这一级:同一章的不同年份被一起召回,苹果那一侧没进来,生成结果却写成一份完整分析。检索质量和直线流程是这一级的两个瓶颈。
高级 RAG
检索之前做查询改写、按标题和年份建层次索引、解析 PDF 版面。检索之后做重排,把更相关的段落留下。这一级的改进里还有上下文压缩、查询扩展、查询路由。扩展和路由就是第 6 节的改写、第 5 节的意图选择。流程仍然是线性的。要反复改查询、换策略的任务,一条直线覆盖不了,所以才有后面三级。
模块化 RAG
把流水线拆成七块,每块都能换成别的实现:Indexing、Pre-Retrieval、Retrieval、Post-Retrieval、Memory、Generation、Orchestration。信息流可以是直线,也可以是条件、分支和循环。记忆模块可以插拔,用来累计长期上下文。编排模块负责路由、调度和策略,第 5 节「先看意图再选权重」就落在这一块。第 6 节的查询改写落在 Pre-Retrieval,重排落在 Post-Retrieval。
模块再分成三层。顶层是这七个阶段。中间层是阶段内部的子模块,例如 Pre-Retrieval 里的查询改写、子查询、HyDE。底层是具体操作,例如切块、向量化、过滤、选择留下哪几段。换一个场景,换的是积木,不必重写整条流水线。
图谱 RAG
文本块答不了「影响了 J.K. 罗琳的那位导师,他的作者是谁」。这类问题要先找到导师,再沿关系找到导师的作者。图谱 RAG 先从文档里抽出实体和关系,例如「苹果公司 —创立者→ 乔布斯」,检索从找相似段落变成沿边行走,再把走过的路径补进上下文。
知识库和知识图谱各管一块:
| 知识库 | 知识图谱 | |
|---|---|---|
| 材料 | 文档切成的文本块 | 实体和关系 |
| 适合 | 企业内部文档问答、长文辅助写作、初级客服 | 金融风控与反欺诈、供应链、精准推荐、复杂多跳问答 |
差旅制度的「上海住宿上限」用知识库。审批链要回答「这笔超标先过谁、再过谁」时,关系本身就是答案,再考虑图谱。还有一种做法是 HyperbolicRAG:用双曲空间表示有层次的知识,专门加强多跳问答。它是图谱这一级上的一种做法,制度问答不必先上。
智能体 RAG
这一级把规划、反思和协作放进循环。它自己决定下一步检索什么、用哪一级的工具,图谱检索也只是其中一种工具。第 5 节里模型先判断「这是政策条文,走 BM25,重排留 5 条」,就是这一级的最小形态。要写成一份可核对的长报告时,做法放到第 8 节。
8. Deep Research
第 7 节的智能体 RAG 已经能自己决定下一步查什么。第 2 节那个年报问题说明,只把这一步加上仍然不够:比较英伟达和苹果近三年谁更值得投资,高级 RAG 改写了查询、也做了重排,答案还是只比了收入,把波动理解偏,一边公司的材料没进上下文。
缺的是一条能跑完的研究闭环。问题先拆开,缺什么再去对应的材料里取,取到的数字写进可核对的记忆,冲突在写报告之前处理掉,最后每一句都能指回记忆里的那一条。承担这条闭环的模型就是研究代理。闭环固定是四步:规划、多源取证、记忆、成文。产出可以停在短答案,也可以拉长到报告,再拉长到假设和实验。
用这道年报题走一遍,四步就具体了。
- 规划。 先列出要填的格子:两家公司、三个年份、收入、利润、现金流、主要风险。格子之间有依赖:没确定「近三年」是哪三年,就不能并行去抽表。
- 取证。 收入和利润去财务报表,风险去 MD&A 正文,股价去另一份材料或网页。某一格是空的,再触发一次检索,而不是每写一句都重查全库。
- 记忆。 核对过的数字按「公司—年份—指标」记下来,并带上来源页。正文里的口头数字和表上的审计数字不一致时,留下表,丢掉口头数字。
- 成文。 按大纲写对比,每句数字指向记忆里的那一条。缺了 2021 年苹果的现金流,报告里写「这一格没有取到」,不拿模型记得的旧数补上。
同一条闭环,三档产出
三档用的是同一套四步,变的是交付物有多长、验收看什么。
| 档位 | 交付物 | 年报题里它长什么样 | 验收 |
|---|---|---|---|
| 代理搜索 | 带引用的短答案 | 「2023 年英伟达收入是多少,出自哪一页」 | 找得到,引用的页码和数字对得上 |
| 集成研究 | 结构报告、政策简报 | 两年报、三年份的对比,分节写增长、利润、风险,并说明依据不足的格子 | 每个事实落在某一句上,节与节接得上 |
| 全栈 AI 科研 | 假设、实验、论文 | 先提出「高增长是否伴随现金流同步改善」,再写代码算三年比值,最后把过程和结果写成可复现的短文 | 假设是否新,实验别人能否重跑 |
第一档比第 6 节的「连查几次」多了两样:工具不只有 hybrid_search,还有读表、读网页;查完要反思这一跳有没有填上格子,并记在记忆里。第二档是在第一档的格子填完之后写长文,并回头核对句子和格子是否一致。第三档才开始提出材料里没有直接写明的判断,并用代码去验。差旅制度问答用不到第三档。
四个组件怎样交接
四步不是四段独立说明。上一步的产出就是下一步的输入。
查询规划的输入是原问题,输出是一组带依赖的子任务。 拆法有三种。互不依赖的格子并行,例如两家公司的 2023 年收入可以同时抽。有先后的格子串行,例如先定年份范围,再抽表。分支很多、做完一条才知道要不要做下一条时,用树:先看收入差是否大,大再展开利润和现金流,不大就改去比风险披露。分解一旦稳定,可以用强化学习调「怎样拆更不容易漏格」。一开始用固定大纲就够,不必先训练一个拆题模型。
信息获取的输入是当前还空着的格子,输出是带来源的材料。 两件事先定好。第一件是何时查:记忆里这格已有核对过的数,就不再查;这格为空,或上一条材料和表冲突,再查。第二件是查哪种模态:正文、表、网页可以进同一次取证。年报的收入在表里,风险在段落里,只做段落向量会再次掉进第 2 节那种「只有股价、没有财务数据」。
记忆的输入是取证结果,输出是一份可更新的事实表。 管理收成四拍:固化、索引、更新、遗忘。固化是把「英伟达 2023 年收入 = 某数,出自 10-K 第 N 页」写成一条,而不是把整页正文留在对话里。索引是后面能按公司、年份、指标找回这一条。更新是新取到的审计表覆盖旧的口头数字。遗忘是把已经合并进事实表的长原文从工作记忆里拿掉,也把明确过期的年份拿掉。存的形式可以混用:指标用表,审批或股权关系用图,时间顺序用时间线。真正发给模型写报告的是这张事实表,不是几十页年报原文。
答案生成的输入是事实表,输出是读者能核对的文本。 先处理表内冲突:两个来源都在,按可信度加权,审计后的表高于新闻稿,新闻稿高于模型转述。仍裁决不了时,可以让多个角色辩论,或用「这句话能否在事实表中找到」作为奖励去训练。然后才写。先有大纲,再按节填;需要比较的数字用表,不写成一段形容词。写完做一次核对:报告中的每个数字必须能指回事实表的一条,指不回的句子删掉或改成「材料未给出」。
闭环里哪一段要训练
四步都能先用提示词和工作流跑起来。三条训练路线,差在改闭环的哪一段。
| 路线 | 代表 | 改的是哪一段 | 好处 | 代价 |
|---|---|---|---|---|
| 工作流提示 | Anthropic 的多智能体研究 | 四步都写在流程里,模型只负责每步的判断 | 可以并行,预算可控,不用训练 | 拆题、取证、核对的质量停在基座模型 |
| 监督微调 | WebSailor、MaskSearch | 用强模型跑出的「问题 → 拆解 → 工具调用」去训弱模型 | 弱模型能学会这一套动作 | 示范数据变差,弱模型会跟着变差 |
| 端到端强化学习 | Search-R1、R1-Searcher | 按最终答案对不对,反向调整整条长链 | 能优化到最后一格有没有填对 | 中间很少有可打分的信号,训练不稳,成本高 |
年报对比这种题目,先用工作流把四步跑通,并用事实表做核对。拆题经常漏格、工具经常选错,再考虑用强模型的轨迹做监督微调。端到端强化学习留到短答案已经有标准、又能大量自动打分的时候。
按交付物验收
验收跟着三档走,不拿一个总分代替。
| 交付物 | 看什么 | 常用基准 |
|---|---|---|
| 短答案,要跨几跳才能找到 | 该找的证据找到没有,网页或工具操作是否成功 | HotpotQA、GAIA、BrowseComp |
| 长报告 | 引用是否对得上原句,结构是否连得上,事实是否写错 | AutoSurvey、DeepResearch Bench、ReportBench |
| 假设和实验 | 想法是否新,实验能否重跑,写作是否把过程写清 | AI Idea Bench、Scientist-Bench、PaperBench |
| 改代码才能完成的研究 | 测试是否通过,Issue 是否真的解决 | SWE-Bench |
前两行对应代理搜索和集成研究。后两行对应全栈科研,以及研究过程里要改代码、跑实验的那一段。制度库没有这些基准也能验收:抽一批真实问题,看事实表的格子是否填对、报告里的数字是否都能点回条款。
差旅助手回答「上海住一晚上限多少」,四步用不上,高级 RAG 取前几条即可。要写「这次行程每一处超标对应哪一条现行条款」,才用到第一档:先列出行程里的费用格子,再逐格查制度,写成带条款编号的说明。比较两家公司多年财报并给出可核对的长文,才把四步走全。提出新的投资假设并用代码去验,才进入第三档。