让 AI 学会"自己干活、自己检查、自己改":Auto Agent 多角色执行链路设计
从"话痨聊天机器人"到"能自主闭环的智能体",差的不是模型,是一套执行架构。
一、从一个需求说起
你打开聊天窗口,输入:
"检索小傅哥的相关项目,列出一份学习计划。"
普通聊天机器人怎么做?——把这句话甩给大模型,模型凭"记忆"(或者干脆瞎编)给你列一份。
Auto Agent 怎么做?
AI 分析员:这需求要先联网搜资料 → 再整理成学习计划 → 现在才刚开始,完成度 5%
AI 执行员:好,我调用搜索工具,去查小傅哥的开源项目……
AI 质检员:搜到是搜到了,但没按难度归类,60 分,回去重做
AI 执行员:好,我重新整理,按"基础→进阶→实战"排好
AI 质检员:这次可以,90 分,通过 ✅
AI 总结员:下面是最终的学习计划……
看到了吗?它不是在"回答你",它是在把任务当成一个项目在干——自己拆解、自己动手、自己验收、自己交差。这就是 Agent(智能体)和 Chatbot(聊天机器人)最本质的区别。
二、为什么一个模型搞不定这件事?
你可能想问:让一个大模型"又分析又干活又检查又总结",不行吗?
不行。核心原因有三个:
1. 干活的和检查的,必须是两个人。 你让同一个模型干完活,再让它自己挑毛病——它永远觉得自己干得挺好。这是模型的通病(自我感觉良好)。只有换个角色、换个视角,才可能真发现问题。Auto Agent 能"自主改进",靠的就是这个。
2. 能"动手"的和只能"动嘴"的,要分开。 搜索、发文章、查数据库,这些是"真刀真枪"的操作,会花成本、会有副作用。分析员和质检员只是"动脑"的,不该给它们工具。工具权限要收敛到执行员一个人手里,否则模型容易乱调工具。
3. 每个角色只干一件事,提示词才能写得"狠"。 让一个模型干四件事,提示词写成一锅粥,它顾此失彼。拆开后,每个角色的人设和输出格式可以约束得非常具体——比如强制执行员必须按固定格式输出"执行目标/执行过程/执行结果/质量检查",输出质量明显更高,也更好解析。
一句话:单一职责不只对代码有用,对 AI 的"人设"同样适用。
三、拆成四个角色:分析 / 执行 / 质检 / 总结
这套链路可以抽象成一条"流水线 + 质检回炉":
┌──────────────────────────────┐
│ │
│ 质检不过,退回重做 │
│ ▼
用户输入 → ①分析员 → ②执行员 → ③质检员 ─→ 通过 → ④总结 → 最终答案
(动脑) (动手) (挑刺) (交差)
▲ │
└─────────── 循环,直到完成或达上限 ──────┘
① 分析员(动脑)
拿到用户需求后,先"盘一下":
- 这个任务现在干到哪了?
- 之前干过什么(执行历史)?
- 下一步该干嘛?
- 完成度打几分(0-100%)?任务状态是继续(CONTINUE)还是完成(COMPLETED)?
它输出的完成度,是整个循环的"方向盘"。
String analysisResult = chatClient.prompt(analysisPrompt)
.advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
.call().content();
// 分析员说完成了,就直接进入总结
if (analysisResult.contains("任务状态: COMPLETED") ||
analysisResult.contains("完成度评估: 100%")) {
dynamicContext.setCompleted(true);
}
② 执行员(动手)
这是唯一一个"挂工具"的角色。它拿着分析员的策略,去真正调用工具干活:搜索、查数据库、发文章……干完,把"执行目标/过程/结果/质量检查"存进上下文。
// 执行员这个客户端,装配时挂了 MCP 工具
ChatClient executor = getChatClientByClientId(PRECISION_EXECUTOR_CLIENT);
// 模型在这里自主决定:调 search 工具 → 拿结果 → 继续
String executionResult = executor.prompt(executionPrompt).call().content();
③ 质检员(挑刺)
把执行员的结果拿过来,用独立的视角挑毛病:
- 质量评估、问题识别、改进建议
- 打分(0-100)
- 给结论:PASS(通过) / FAIL(重做) / OPTIMIZE(优化后重做)
if (supervisionResult.contains("是否通过: FAIL")) {
// 打回重做
dynamicContext.setCurrentTask("根据质量监督的建议重新执行任务");
} else if (supervisionResult.contains("是否通过: OPTIMIZE")) {
// 优化后重做
dynamicContext.setCurrentTask("根据质量监督的建议优化执行结果");
} else {
// 通过!标记完成
dynamicContext.setCompleted(true);
}
这里是整个设计的灵魂:质检不过,流程会带着"改进建议"重新回到 ① 分析员,再走一轮。
④ 总结(交差)
循环终于跑完(质检通过,或撞了步数上限),把整个执行历史喂给总结员,让它产出一份完整的最终答案——哪怕任务没做完,也会基于已有过程尽力回答,并说明哪些没完成、为什么。
四、两个保命机制:循环回炉 + 步数上限
这套设计有两个必须成对出现的机制:
1. 回炉重造(循环):质检不过就重来,这是"自主改进"的来源。没有它,就退化成"干一票就交差"。
2. 步数上限(maxStep):防止 AI 死循环。一个任务最多跑 N 轮(1/2/3/5/10/20/50),撞上限就强制进总结,宁可给"未完成报告"也不能无限烧 token。
// 达到上限,进总结
if (dynamicContext.isCompleted() || dynamicContext.getStep() > dynamicContext.getMaxStep()) {
return getBean("step4LogExecutionSummaryNode");
}
有闭环,但闭环必须有刹车——这是生产级 Agent 的基本素养。
五、角色是"配置"出来的,不是写死的
这四个角色不是四个独立系统,而是一个 Agent 内部、由数据库配置驱动的四个"角色客户端":
- 一个智能体 = 一套执行策略(走哪条链路)+ N 个角色(每个角色一个 ChatClient)
- 每个角色独立配置:用哪个模型、哪个 API、什么角色人设、什么干活提示词(step_prompt)、挂不挂工具
- 它们共享同一个会话ID,所以"分析员说过的话,执行员都知道"——是同一个 agent 在接力干活
-- 智能体-客户端关联表:一个 agent 挂多个角色
INSERT INTO ai_agent_flow_config (agent_id, client_id, client_type, sequence, step_prompt)
VALUES ('3', '3101', 'TASK_ANALYZER_CLIENT', 1, '你是一个专业的任务分析师……%s……'),
('3', '3102', 'PRECISION_EXECUTOR_CLIENT', 2, '你是一个精准任务执行器……'),
('3', '3103', 'QUALITY_SUPERVISOR_CLIENT', 3, '你是一个质量监督员……');
好处很直接:想换模型?改一行配置。哪个角色不行就换哪个。想加角色?再加一行。完全不用动代码。
六、把"思考过程"实时播给用户看
用户最烦的是一句话发出去,干等几秒出结果,不知道 AI 在干嘛。这套按角色拆开的架构,天然能解决这个问题:
- 每个角色的输出都是独立的阶段消息,通过 SSE 实时推给前端
- 用户能看到:
分析阶段 → 执行阶段 → 监督阶段 → 总结阶段,像看 AI 的"直播思考过程" - 最终总结单独显示在结果区,思考过程单独显示在过程区,互不干扰
这也是"为什么拆角色"的隐藏福利:步骤拆得开,过程才播得出来。
七、别神话它:这套设计的边界
作为学习沉淀,也得说清楚它没解决什么:
- 工具调用靠模型自觉:模型调工具是"自主决定",规划里写的工具和实际调用的工具之间没有强校验
- 没有参数级校验:模型传错的参数不会在代码层被拦截
- 工具清单可能写死:有的版本里"可用工具白名单"是硬编码的,不是动态从 MCP 服务拉取的
- 成本不低:多角色 + 循环重做 = 多次模型推理,token 烧得比单轮对话快得多
所以它是**"流程编排 + 提示词工程"层面的正确性保障**,想要"几乎必然正确",还得补上:工具调用校验、失败重试、动态工具发现、参数 Schema 校验。
八、总结
把文章浓缩成三句话:
- 聊天的 AI 回答你,干活的 AI 完成任务——差的那部分,叫"执行链路设计"。
- 拆角色的三个理由:检查的和干活的分开(否则自己夸自己)、动手的和动嘴的分开(否则乱调工具)、单一职责(提示词才写得狠)。
- 好 Agent 的三个标配:能循环(质检不过就回炉)、有刹车(步数上限兜底)、可配置(角色和提示词都从配置来,不改代码)。
下次你再看到一个"AI 帮我把事办成了"的演示,不妨扒一扒它的执行链路——背后大概率就是这么几个角色在接力干活。