在 if Studio 里做智能体,先别急着画多智能体的编排图。判断标准很朴素:单智能体已经能稳定完成一类任务、输出格式固定、出错时你能从日志里看出是哪一步坏了,这时候才考虑拆。如果单智能体现在还能跑,只是偶尔答得不够好,拆成多个智能体通常不会让答案变好,只会让你多出几份日志要对照。多数情况下,拆分带来的收益是“职责清晰、可分别验证”,付出的代价是“链路变长、定位变难”,这两者需要一起权衡。
单智能体先跑通的意思是:一类任务、一套提示词、一种输出格式,能在 if Studio 里连续复现并通过你的验收。多智能体不是能力升级,而是把一个大任务拆成若干可单独验证的小任务,用字段约定和调用顺序把它们串起来。只有当单智能体已经出现任务冲突、提示词打架或格式不统一这三种可观察信号时,拆分才值得做;否则优先改提示词、约束输出。拆分后必须约定子智能体之间的输入输出字段,并在主流程里写清失败兜底,否则链路一旦中途出错,你很难定位是哪一步的问题。
列出单智能体已经做不好的具体表现
拆不拆,不看感觉,看现象。以下三种信号在 if Studio 里通常可以通过对话记录、系统提示词和输出格式直接观察到。出现其中一种,可以考虑拆;三种都没有,先把单智能体的提示词收紧。
- 任务类型互相冲突。同一个智能体里既有“把用户问题分类”又有“根据分类写一段解释”,分类要求简短、写作要求展开,模型会在两者间摇摆。表现是同一句输入,有时只给分类标签,有时直接开始写长文,你无法预测它这次会走哪条路。
- 提示词互相打架。系统提示词里同时写着“不确定时请提问用户”和“直接给出完整方案”,模型可能先反问再自顾自回答,或者两种行为交替出现。这类冲突靠调提示词缓解的空间有限,因为两条规则本身指向不同动作。
- 回答格式不统一。下游如果要用这段输出,就要求字段固定。单智能体在长提示词下容易今天返回纯文本、明天返回带标题的结构,下游解析经常失败。可以通过固定输出模板观察,如果多次运行仍然漂移,说明这个智能体承担了不该由它一个承担的输出约束。
把这三类现象记录到具体对话ID或日志条目上,而不是仅凭“感觉它不太行”。有记录,才有拆分的依据,也才有拆分前后对比的基线。
把任务按输入和输出切成独立单元
拆分的动作不是“多建几个智能体”,而是先把任务写成若干条独立的输入输出约定。规则很简单:每个子任务,给出输入字段、输出字段,以及取不到数据时返回什么。写不出来,说明这个子任务边界还不清楚,先别建智能体。
假设一个“用户问题分类并生成回复建议”的任务,可以先切成三类单元:
- 分类单元。输入:
user_query。输出:category,取值限定在预先约定的几个类别中。取不到数据时返回:category=unknown,不要硬猜。 - 检索/取数单元。输入:
category、user_query。输出:evidence列表。取不到数据时返回:空列表,并带上empty_reason。 - 生成单元。输入:
category、evidence。输出:reply_text。取不到证据时,按空列表分支走保守回复,不编造内容。
这三条单元可以分别用同一批测试问题单独跑,看输出是否符合约定。只有在单元级别能稳定验证之后,再考虑把它们连成流程。否则拆出来的子智能体只是把不可控从一个地方搬到了三个地方。
约定子智能体之间的数据格式
拆完最容易出的事是字段对不上:上游返回 category,下游读的是 type;上游异常返回空字符串,下游当成正常值继续走。建议在进入编排之前,先用一份通用 JSON 骨架把所有子智能体的输出统一起来。下面的骨架是通用示例,字段名可以按你的约定替换,重点是结构本身:任务名、入参、出参、异常标记四项不能少。
{
"task": "classify_query",
"input": {
"user_query": "..."
},
"output": {
"category": "billing"
},
"error": {
"flag": false,
"type": "",
"message": ""
}
}
几个使用要点:
task用固定字符串,方便日志里直接按任务名过滤,出问题时你能立刻看出是哪一步的返回。output里只放约定过的字段。不要顺手把模型的解释性文字也塞进去,否则下游又要重新解析。error.flag为 true 时,output允许为空,但type要能区分“超时”“空返回”“格式不符合约定”这几类,方便主流程决定怎么兜底。
这份骨架不依赖任何平台内置的接口名或调用方式,你可以在 if Studio 的智能体输出设置、后处理脚本或主流程代码里落地。落地后先手工造几条异常返回,验证下游能否正确识别 error.flag。
在主流程里定义调用顺序和兜底
子智能体之间的连接方式,通常分串行和并行两种,选择依据是子任务之间有没有数据依赖。
- 串行适用:后一步需要前一步的输出,比如先分类再检索。串行的好处是每一步的输入都能追溯,坏处是任何一步慢了或挂了,整条链路都会等或断。
- 并行适用:多个子任务互不依赖、可以同时取数,比如同时查两个不同来源。并行的好处是整体等待时间通常更短,坏处是其中一路失败时,需要主流程决定是“等它”还是“先跳过”。
不管串行还是并行,主流程里都要写明子任务失败时的动作。常见处理方式有三类,按任务对完整性的要求在流程里选一种:
- 超时。给每个子任务设超时上限,超时后不再等待,按
error.flag=true、type=timeout继续往下走。 - 空返回。子任务正常返回但内容为空,主流程按“无数据”分支处理,不要把它当正常结果传给下游。
- 整体降级。如果关键子任务失败且没有替代数据,主流程直接返回一段保守回复或提示用户补充信息,而不是硬走后续生成。
这些动作都要在流程配置里显式写出来,并在测试时人为触发一次超时和一次空返回,观察主流程是否按预期分支。
用同一批问题对比拆分前后的表现
拆完之后别只盯着“看起来更清晰”。用同一批问题分别跑拆分前和拆分后的流程,按下面几个维度做对比,才能知道拆分换来了什么、付出了什么。
- 回答正确性。同一批问题上,拆分后的回答是否仍然覆盖了拆分前能答对的部分。如果拆分后某些原本能答的问题反而答错,多半是子任务边界切错了。
- 整体耗时。记录从输入到最终输出的总耗时。串行拆分通常会变慢,并行拆分可能持平或略慢,如果明显变慢,确认是否引入了不必要的等待。
- 可读性。最终输出对读者是否仍然连贯。多智能体容易产出拼接痕迹,需要在生成单元里统一语气和结构。
- 出错时能否定位到具体哪一步。这是拆分最主要的价值。人为让某一子任务失败,看日志是否直接指向该任务名和错误类型。如果定位不到,拆分就没达到目的,需要检查是否有统一的
task字段和错误标记。
对比时用同一批问题、同样的输入条件,不要一边换问题一边比结果。哪个维度没变好、甚至变差,就回到对应的小节去调整边界或兜底动作,而不是继续加智能体。拆分本身不是目标,让每个环节可验证、出错可定位才是。