很多人第一次做带检索的问答,写着写着就乱了:数据在 RAG 里、工具在 MCP 上、流程由 Agent 串,可真出问题时不知道是哪一层的问题,也不知道该先改哪里。这篇不复述名词定义,而是给你一条能落地的分层思路、一张职责对照表和一套排查顺序,让你能判断自己的需求到底该用哪几层,以及哪一层暂时可以先不上。
很多人第一次做带检索的问答系统,做着做着就乱了:数据这一摊在 RAG 里,工具那一摊挂在 MCP 上,流程又交给 Agent 去串,功能是都跑通了,可一旦线上答得不对、答得慢或者干脆报错,根本不知道是哪一层的问题,也不知道该先动哪一块。多数时候不是模型不行,而是分层没对齐。
这篇不复述名词定义,也不打算把几个词排个高低。它想给的是一条能落地的分层思路、一张出问题时按层认领的对照表、一套从后往前查的排查顺序,让你能判断自己的需求到底该用哪几层,以及哪一层现在压根可以先不上。
四个词先各归各位:谁管能力、谁管数据、谁管流程
先把几个词放到各自的位置上,后面讨论才不会打架。一句话概括:AIGC 是生成内容这件事本身,属于大范畴;RAG 是给它补数据;MCP 是给它补工具通道;Agent 是给它补决策和编排;Agent Skill 是把反复出现的任务封装成可复用单元。它们解决的是不同层面的问题,不是一个比一个高级的递进关系。
- AIGC
- 生成内容这件事本身,回答的输入输出都在模型里完成,不涉及外部数据与工具
- RAG
- 解决模型不知道你私有内容的问题,输入是查询,输出是相关片段,错了多半是召回问题
- MCP
- 解决模型连不上外部系统的问题,本质是调用通道的约定,不负责数据质量也不负责决策
- Agent
- 解决下一步该做什么的问题,负责在多个动作之间做选择和编排
- Agent Skill
- 解决重复流程每次都要重写的问题,把固定步骤序列封成一个可复用单元
给每层定位,用三个问题去问就够了:输入是什么、输出是什么、错了谁负责。RAG 的输入是查询、输出是片段,召回不对就是它的责任;MCP 的输入是调用请求、输出是工具结果,通道断了或参数没对上就是它的责任;Agent 的输入是当前状态、输出是下一个动作,选错了动作就是它的责任。把这三问对齐,团队讨论时才不会互相甩锅。
- 只要检索私有数据,单上 RAG 就够了,不需要 Agent
- 只要连通外部系统读写数据,单上 MCP 就够了,不需要检索
- 任务路径固定、步骤有限,用一条写死的流程比 Agent 更稳
- 文档量小到能直接塞进上下文,检索这层可以先不加
- 每一层的能力如果换不来返工减少或出错率下降,就先别接
这里有个常见误区要提前点掉:有人把 RAG 说成 Agent,因为它会「思考要不要检索」;也有人把 MCP 说成 Agent,因为它「能调工具」。两者都不是。是否要检索、要不要多轮取数,那是 Agent 在决策;检索本身好不好、工具通道通不通,是另外两层的事。混着说,后面排错就无从下手。
什么时候不该叠这么多层:先算清值不值得
多一层不是多一个能力,是多一个故障点。叠加带来的代价是实打实的:整体时延变长、日志字段变长、排错路径变长、成本口径也变复杂。所以上线前先问一句,这层的引入到底换来了什么。如果换不来人工返工的减少,也换不来出错率的下降,那它现在就不该在这条链路上。
| 场景特征 | 建议层数 | 理由 |
|---|---|---|
| 文档少且稳定,能直接进上下文 | 只留 AIGC | 检索层带来的收益低于它引入的时延与维护成本 |
| 任务步骤固定、分支极少 | AIGC 加工具调用 | 写死流程比让模型决策更可控,出错归因也简单 |
| 只需读一个接口拿数据 | AIGC 加 MCP | 工具通道够用,检索与编排都是多余的 |
| 需要多轮取数再回答 | 上 Agent | 中间结果会改变下一步,静态流程覆盖不了 |
| 流程反复出现且输入输出固定 | 加 Skill | 封装一次复用多次,省的是维护成本不是调用成本 |
判断线其实很简单:这层能力能不能减少人工返工,或者能不能降低出错率。两个都不能,就先不接。要提醒的是,这条线不适用于所有团队——如果你的业务对响应时间极其敏感,那么即便某层能降低出错率,也可能因为时延代价不值得,这时候得回到具体场景里权衡,而不是照搬上面的表。
一张职责对照表:出问题时按层认领
真正让团队效率上去的,不是把架构画得漂亮,而是出事时能秒分派。下面这张表按五类常见问题来分派责任层,每类给一条最小验证动作,照着做就能快速缩小范围。
| 问题类型 | 大概率责任层 | 最小验证动作 |
|---|---|---|
| 数据进料 | RAG 的数据侧 | 拿已知文档里的一句话去检索,看能不能召回 |
| 检索质量 | RAG 的召回侧 | 换一个措辞再检索,看结果是否漂移严重 |
| 工具连通 | MCP 通道 | 单独调一次该工具,看返回体结构是否完整 |
| 决策编排 | Agent | 把中间结果打出来,看下一步选择是否合理 |
| 输出格式 | AIGC 输出侧 | 固定输入跑几次,看格式是否稳定可解析 |
层与层之间的接口也要说清楚。Agent 调检索,通常不是直接碰检索库,而是走工具通道发一个调用请求。这就导致一个现象:检索报错和工具报错长得非常像,日志里都表现为一次调用失败。所以日志里必须带够字段才能区分,至少要能看出这次调用是打在检索上还是打在其他工具上。
- MCP 只负责通道约定,不保证检索出来的东西是对的
- MCP 也不负责决策,下一步该不该调它是 Agent 的事
- 检索召回差,别怪工具通道,两者解决的是不同问题
- 通道返回成功不等于业务成功,空结果也是一种成功返回
- 把通道健康和业务正确拆开看,是最省时间的习惯
把常见误判点出来:工具状态是成功、但返回内容是空的,这种假象最容易被当成「检索没做好」,其实是调用参数没拼对,或者对方的查询条件没命中。排查时先看返回体里有没有内容,再看内容对不对,这个顺序能省掉很多来回。
Agent Skill 怎么封:把重复流程收成可复用单元
Skill 的价值在复用,判断标准也就一条:这件事是不是步骤稳定、输入输出固定、并且被反复触发。三条都满足,才值得封。反过来,每次判断都不一样的一次性任务别封,封了之后为了适配各种分支,代码会比不封还乱。
- 先跑通一遍裸流程不封装,手工走一遍完整步骤,确认每一步的输入输出都能看懂,中间结果能打印出来
- 固定入参与出参把每次都要传的字段单独拎出来,多传的、可推断的字段去掉,避免参数膨胀
- 加上入参校验在入口处判断必填项是否齐全、格式是否对,校验不过直接返回可读原因,别让它走到一半才炸
- 让失败可读失败时返回的是「哪一步、什么原因」,而不是一个笼统的失败状态;这一步决定后面能不能排错
- 回放验证拿几条历史输入重跑,看输出是否稳定,确认封装没有改变原有行为
Skill 和工具调用的分工要分清:工具是原子动作,一次干一件事;Skill 是动作序列,把多个原子动作按固定顺序串起来。常见的错误是把一长串编排硬塞进单个工具里,结果这个工具既难测又难改。正确的做法是让工具保持小,把顺序交给 Skill。
最小可行链路:从只有 RAG 到加上 Agent 的分步升级
很多人一上来就把四层全接上,结果任何一环出问题都定位不到。更稳的做法是分步加层,每一步都留一个可回退的状态,能退回上一步而不重写代码。下面这条升级路线,适合绝大多数从零开始的团队。
- 先把检索单独跑通只做检索,不做生成编排,准备一组小而稳的评测样本,看召回的稳定性;这一步的产出是一个能独立验证的检索组件
- 接入一个工具通过工具通道挂一个外部接口,确认通道稳定、返回结构可解析;先只挂一个,别一次挂一堆
- 再让 Agent 决定检索让 Agent 判断这次要不要检索、检索几次,中间结果打印出来;能看明白它的选择才算接好
- 每次加层都留回退开关新层用开关控制,出问题能一键退回上一步,不用改代码重发
什么时候必须引入 Agent?两种情况:一是需要根据中间结果决定下一步,静态流程覆盖不了;二是需要多轮取数再回答,检索次数不定。这两种之外的场景,能用固定流程就用固定流程,可控性远高于让模型自由决策。
可观测性:让一次回答的慢、贵、错都能复盘
可观测性的目标不是记更多日志,而是让一次请求的慢、贵、错都能复盘。所以字段要按层埋,而不是只记一条总耗时。下面这份清单是够用的最低配置,缺一项后面就会卡在某个问题上查不下去。
- 请求标识:一次请求贯穿所有层的唯一 ID,串起全部日志
- 进了哪一层:能看出这次走没走检索、走没走工具
- 检索命中情况:命中几条、命中的是哪些片段
- 工具调用次数与时延:每一次调用的耗时分布
- 最终是否命中兜底:区分是正常回答还是降级回答
埋完字段还要设预算。按层设上限,比如检索轮数上限、工具调用步数上限、整体时延上限,到限就走降级而不是无限重试。不设上限的系统,最典型的症状就是偶尔出现一次特别慢的请求,日志翻半天也找不到停在哪。
最后一个提醒:答得不对和答得慢是两类问题,复盘入口不一样。答得不对去看检索命中和中间结果,答得慢去看各层耗时分布。把这两类混在一起看,往往两边都看不明白。要对照同类系统的表现,可以到站内的速度测试页面核对当时的数字,别凭印象判断。
评测闭环:换一层之前先有基线
改任何一层之前,先有基线。没有基线的优化,改了以后只能凭感觉说「好像好点了」。基线不需要大,一组小而稳的回归用例就够,关键是每次改动都跑一遍,能对比。
| 用例类型 | 覆盖什么 | 怎么判断过没过 |
|---|---|---|
| 有答案类 | 正常检索能命中的问题 | 回答是否基于召回内容,而不是编造 |
| 无答案类 | 库里确实没有的问题 | 是否正确表示不知道,而不是硬答 |
| 多次取数类 | 需要多轮才能答的问题 | 中间步骤是否合理,轮数是否在预算内 |
| 格式类 | 对输出结构有要求的问题 | 结构是否稳定可解析 |
看指标时要分开:检索指标和最终回答质量是两回事。别用最终答案的好坏去反推检索好坏,中间隔着一层生成,会把问题掩盖掉。检索单独有一套判断标准,生成也有自己的标准,分开看才能定位。
还有一条纪律:每次只改一层。同时改两层以上,改完变好了也不知道是哪层的功劳,变差了也不知道该回退谁。这条规矩看着笨,但它是能不能积累经验的分水岭。
排错顺序:从最后一层往前查还是从前往后查
线上出问题时,推荐的排查顺序是从后往前:先确认最终输出格式是否正常,再看工具是不是都返回成功,再看检索有没有召回,最后才怀疑模型的判断。这个顺序的好处是,前面几层都是可验证的事实,能快速排除大面积可能性。
- 看输出格式最外层最容易确认:格式崩了就先去查生成那一段,不用往里翻
- 看工具返回确认每一次工具调用是否成功,注意状态成功但内容为空这种假象
- 看检索召回拿已知的句子去检索,确认召回是否存在、是否漂移严重
- 最后怀疑决策前面都正常再去看中间结果,判断是不是 Agent 选错了下一步
每步都要有最小验证动作,别指望靠读代码找到问题。工具那一步尤其要注意返回体内容,空返回和报错是两件事,处理方式完全不同。什么时候该停下来换方案?如果同一层反复改了多次都不见好,或者需要动的参数越来越多,那多半是分层本身有问题,这时候该回到架构层面看,而不是继续调参。
下一步把这几个词放进同一条链路后,你大概会想确认自己选的工具和中转通道靠不靠得住;站内有按工具分类的目录和可信度检测记录,值得先看一眼再决定接哪一层。→常见问题
RAG 和 Agent 能不能只选一个?
能,而且很多场景只选一个更好用。任务路径固定、问题类型单一,用检索就够;反过来,不需要私有资料、只是要串联几个外部动作,用 Agent 加工具就行。判断标准是看你的瓶颈在「不知道」还是在「做不到」:前者偏检索,后者偏编排。
MCP 和 Agent Skill 是不是重复的?
不重复。MCP 解决的是「怎么把一个外部能力接进来」这个通道问题,Skill 解决的是「一组固定动作怎么复用」这个封装问题。同一套外部能力可以既走 MCP 接入,又在上面包一层 Skill。通道和编排拆开看,改起来会轻松很多。
叠了四层以后变慢变贵,先砍哪一层?
先看哪一层在日志里占比最高,别凭感觉砍。经验上先收编排:限制检索轮数和工具步数上限,往往能立刻见效;其次是收工具调用次数,把可合并的调用合并。数据层通常最后动,因为它直接影响答案对不对。
一次回答错了,怎么判断是检索的问题还是模型的问题?
把该次请求实际召回的片段单独拿出来,人工看里面有没有答案。片段里有答案但回答错,问题在生成或提示组织;片段里就没有答案,问题在进料和检索。这一步做完,后面该改哪里基本就定了。
小团队要不要一上来就搭 Agentic RAG?
多数小团队不必。先做朴素检索加一次工具调用,跑一段时间攒出真实问题再决定是否加重编排。只有当你反复遇到「需要根据第一次结果决定搜什么」这类任务时,多轮编排带来的复杂度才划算。