SmileCli04 Multi_Agent实现

📅 2026/7/6 1:59:22 👁️ 阅读次数 📝 编程学习
SmileCli04 Multi_Agent实现

总的来时,是在/plan+DAG的基础上,其中的task由原本的单一的agent,转换成有3个身份的agent(规划->执行->审查)来保证任务的执行。规划的agent由原本/plan的中的实现 这部分对应的代码直接复用了之前相关部分。

如下是测试结果:


SmileCli Multi-Agent 阶段总结

1. 阶段定位

React_ToolCall.md记录的是 SmileCli 从普通聊天推进到 ReAct + Tool Call 的过程。

Plan_DAG.md记录的是在 ReAct 基础上增加 Planner、ExecutionPlan、Task 和 DAG 执行顺序的过程。

Memory.md记录的是短期记忆压缩、长期记忆保存和长期记忆注入的过程。

这一阶段的主题是 Multi-Agent,也就是在已有/plan能力上增加一个/team协作模式。

当前/team不是重新发明一套规划系统,而是把/plan当作基础能力复用:

用户复杂目标 -> Planner 生成 ExecutionPlan -> ExecutionPlan / Task 表达任务和依赖 -> TeamOrchestrator 按 DAG 顺序调度每个 task -> Worker SubAgent 执行当前 task -> Reviewer SubAgent 审查 Worker 结果 -> 审查通过则完成 task -> 审查不通过则带着反馈重试一次 -> Main 通过 /team 接入 CLI -> 执行结果回填到普通 ReAct Agent 上下文

也就是说,/team当前可以理解为:

/plan 的增强版本 = Planner + DAG + Worker + Reviewer + Review Retry

2. 为什么需要 Multi-Agent

/plan阶段,PlanExecuteAgent已经可以把复杂任务拆成多个 task,然后逐个执行。

/plan的每个 task 主要是:

执行 task -> 如果 LLM 不再调用工具 -> 直接把 LLM 最终 content 视为 task result

这个流程可以跑通复杂任务,但缺少一个独立的检查环节。

对于带副作用的任务,例如:

创建文件 修改代码 执行命令 生成项目结构

只靠执行者自己说“我完成了”,有时不够稳。Multi-Agent 阶段引入 Reviewer 的目的就是让执行和审查分离:

Worker 负责做事 Reviewer 负责检查 TeamOrchestrator 负责调度

这样可以把原来的单执行链路升级成一个更接近协作流程的结构:

task -> worker execute -> reviewer review -> approve / reject -> retry or complete

3. 当前核心模块

AgentRole

AgentRole位于:

src/main/java/edu/sdu/smilecli/agent/AgentRole.java

它定义 Multi-Agent 中的角色。

当前启用的角色是:

WORKER REVIEWER

PLANNER当前没有作为独立角色启用,因为规划能力已经由原来的Planner负责。

这个设计是符合当前阶段目标的:/team/plan的增强版本,所以 Planner 不需要变成 SubAgent。

AgentMessage

AgentMessage位于:

src/main/java/edu/sdu/smilecli/agent/AgentMessage.java

它是 Multi-Agent 协作中的基本消息单元。

当前字段包括:

fromAgent fromRole content type

当前消息类型包括:

TASK RESULT APPROVAL REJECTION ERROR

当前语义划分是:

TASK -> Orchestrator 分配给 SubAgent 的任务 RESULT -> Worker 执行完成后返回的结果 ERROR -> Worker 执行过程中的系统级错误 APPROVAL -> Reviewer 审查通过 REJECTION -> Reviewer 审查不通过,需要重试或失败

这里有一个重要边界:

execute() 返回 RESULT / ERROR review() 返回 APPROVAL / REJECTION

也就是说,review()不是普通执行流程,它返回的是审查裁决。

当前暂时不考虑FEEDBACK。如果后续要把“需要修改但不是彻底拒绝”单独表达出来,可以再把FEEDBACK加回消息类型。

SubAgent

SubAgent位于:

src/main/java/edu/sdu/smilecli/agent/SubAgent.java

它表示一个具体子 Agent。

当前核心字段是:

name role llmClient toolRegistry conversationHistory

每个 SubAgent 有自己的conversationHistory,但 TeamOrchestrator 每次调用完对应逻辑后会调用:

clearHistory()

这样当前设计相当于:

每次 task 执行/审查都有独立上下文 SubAgent 内部仍然可以复用 conversationHistory 这套消息构造逻辑 每次调用结束后清空,避免不同 task 互相污染

SubAgent目前有两个核心能力:

execute() review()

execute()用于 Worker。它和普通 ReAct 循环类似:

1. 检查 taskMessage 是否为空 2. 如果历史为空,加入当前角色的 system prompt 3. 加入 user 任务消息 4. 调用 LLM,并给 Worker 提供 tools 5. 如果返回 tool calls,执行工具并加入 tool 消息 6. 如果没有 tool calls,返回 AgentMessage.result() 7. 超过最大轮数则返回 AgentMessage.error()

Worker 可以使用工具,因为:

privatebooleanshouldUseTools(){returnrole==AgentRole.WORKER;}

review()用于 Reviewer。它不调用工具,只把任务描述和 Worker 执行结果交给 LLM 审查:

当前任务: ... Worker 执行结果: ... 请检查 Worker 的执行结果是否正确、完整、符合当前任务要求。

Reviewer 的 system prompt 要求返回 JSON:

{"approved":true,"summary":"检查摘要","issues":["问题1","问题2"],"suggestions":["建议1","建议2"]}

parseReviewMessage()会清理 LLM 可能返回的 Markdown 代码块,然后解析 JSON。

当前判断规则比较简单:

approved == true -> AgentMessage.approval() approved == false -> AgentMessage.rejection()

issuessuggestions当前会被整理进审查消息文本,但不会改变通过/拒绝的二元判断。

TeamOrchestrator

TeamOrchestrator位于:

src/main/java/edu/sdu/smilecli/agent/TeamOrchestrator.java

它是/team模式的主控调度器。

当前核心字段是:

llmClient toolRegistry planner output worker reviewer MAX_REVIEW_RETRIES

其中:

planner -> 复用 /plan 阶段的 Planner worker -> AgentRole.WORKER,可以调用工具 reviewer -> AgentRole.REVIEWER,不传 toolRegistry,不调用工具 output -> 由 Main 注入,用于 CLI 输出

run()的流程是:

1. planner.createPlan(userInput) 2. output.accept(executionPlan.visualize()) 3. multiAgentExecutePlan(executionPlan) 4. 返回最终执行结果

multiAgentExecutePlan()的流程是:

1. plan.markStarted() 2. 获取 executionOrder 3. 按顺序执行每个 task 4. 每个 task 调用 multiAgentExecuteTask() 5. 如果某个 task 失败,plan.markFailed() 6. 全部成功后,plan.markCompleted() 7. 输出最终 plan 可视化 8. 返回最终结果

multiAgentExecuteTask()是当前/team的核心:

1. task.markStarted() 2. 构造 task context 3. executeWorker(context) 4. 如果 Worker 返回 ERROR,task.markFailed() 5. reviewTask(task, workerResult) 6. 如果 Reviewer APPROVAL,task.markCompleted() 7. 如果 Reviewer REJECTION,带着审查反馈重试一次 8. 重试后通过则完成 task 9. 重试后仍不通过则 task.markFailed()

当前最大重试次数是:

privatestaticfinalintMAX_REVIEW_RETRIES=1;

这说明当前策略比较保守:审查失败后只给 Worker 一次修正机会。

4. /team 的完整执行流程

用户在 CLI 输入:

/team 在 demo 下创建 test 文件夹,并在里面创建 1.txt,写入 Smile

主链路大致是:

Main -> 识别 /team -> goal = input.substring("/team".length()).trim() -> teamOrchestrator.run(goal)

TeamOrchestrator.run()先复用 Planner:

Planner -> createPlan(goal) -> ExecutionPlan

然后按 DAG 执行:

ExecutionPlan -> task_1 -> task_2 -> ...

每个 task 进入 Multi-Agent 流程:

TeamOrchestrator -> buildTaskContext() -> Worker.execute() -> Reviewer.review() -> APPROVAL / REJECTION

如果 Reviewer 返回:

APPROVAL

则:

task.markCompleted(workerResult.content())

如果 Reviewer 返回:

REJECTION

则 TeamOrchestrator 构造重试上下文:

上一次执行结果未通过审查 审查反馈: ... 请根据反馈修正执行结果。

然后再次调用 Worker。

全部任务完成后:

executionPlan.markCompleted() return "多 Agent 执行完成\n" + buildFinalResult(executionPlan)

最后Main会调用:

agent.rememberMultiAgentResult(goal,result);

/team的结果写回普通 ReAct Agent 的上下文历史中。

这样用户后续可以继续问:

刚才 /team 创建的文件在哪里?

普通Agent也能从上下文中知道刚才执行过的 Multi-Agent 任务。

5. 和 /plan 的关系

当前/team的设计不是替代/plan,而是在/plan之上增加审查层。

两者关系可以这样理解:

/plan -> Planner -> ExecutionPlan / Task -> PlanExecuteAgent -> 每个 task 自己执行,完成后进入下一个 task /team -> Planner -> ExecutionPlan / Task -> TeamOrchestrator -> Worker 执行 task -> Reviewer 审查 task -> 审查通过后进入下一个 task

也就是说,/team复用了:

Planner ExecutionPlan Task DAG 执行顺序 buildTaskContext 的基本思路 output 回调模式 执行结果回填 Agent 上下文的思路

新增的是:

AgentRole AgentMessage SubAgent TeamOrchestrator Worker / Reviewer 分工 Reviewer JSON 审查协议 审查失败后的 task 级重试

这个方向是合理的,因为它避免了两个系统重复造轮子。

6. 当前 Git 变更脉络

根据最近的 Git 记录,Multi-Agent 阶段主要经历了两步。

multi-agent 初步完成

相关提交:

0937907 multi-agent初步完成

这一阶段主要新增和修改了:

AgentMessage.java AgentRole.java SubAgent.java TeamOrchestrator.java Constants.java Main.java Agent.java PlanExecuteAgent.java

这个提交是/team主体结构成型的一步。

主要完成内容包括:

  1. 新增AgentRole,定义WORKERREVIEWER
  2. 新增AgentMessage,作为多 Agent 通信消息。
  3. 新增SubAgent,封装 Worker 和 Reviewer 的角色逻辑。
  4. 新增TeamOrchestrator,负责复用 Planner 并调度 Worker / Reviewer。
  5. 新增Constants.MAX_ITERATIONS,让 SubAgent 执行循环复用统一最大轮数。
  6. Main增加/team命令入口。
  7. Agent增加rememberMultiAgentResult(),把/team结果写回普通上下文。

这一阶段的核心是把 Multi-Agent 从概念变成主链路:

/team -> planner.createPlan() -> worker.execute() -> reviewer.review() -> markCompleted / markFailed

multi-agent 完成

相关提交:

3843f75 multi-agent完成

这一阶段主要调整了:

SubAgent.java TeamOrchestrator.java

主要完成内容包括:

  1. TeamOrchestrator在所有 task 成功后恢复executionPlan.markCompleted()
  2. 每个 task 完成后输出最新ExecutionPlan.visualize()
  3. 整个 plan 完成后再次输出最终 plan 状态。
  4. Reviewer 审查通过时输出通过提示。
  5. 调整 Reviewer JSON 清理后的调试输出。

这一步让/team的执行状态更完整:

plan RUNNING -> task RUNNING -> task COMPLETED -> plan visualize -> plan COMPLETED -> final visualize

7. 当前完成度

从功能角度看,Multi-Agent 当前已经完成了第一版闭环:

/team CLI 入口 复用 Planner 生成计划 复用 ExecutionPlan / Task / DAG 顺序 Worker SubAgent 执行任务 Worker 支持 tool call Reviewer SubAgent 审查任务结果 Reviewer 不调用工具 Reviewer 使用 JSON 协议返回审查结论 APPROVAL 时完成 task REJECTION 时重试一次 重试仍失败时标记 task 和 plan 失败 全部完成时标记 plan completed 最终结果写回普通 Agent 上下文

当前可以认为 SmileCli 已经从:

ReAct Tool Call -> Agent 能行动 Plan & DAG -> Agent 能规划复杂任务 Memory -> Agent 能保存和复用上下文

继续推进到了:

Multi-Agent -> Agent 能把执行和审查拆成不同角色

8. 当前仍需注意的问题

Reviewer 目前不能真实验证文件系统

当前 Reviewer 不传toolRegistry,也不会调用工具。

这意味着 Reviewer 的审查依据是:

任务描述 Worker 的文字执行结果

它不能自己读取文件、执行命令或验证真实状态。

这个设计适合当前阶段,因为 Reviewer 更纯粹,不会产生额外副作用。

但它也有一个限制:如果 Worker 的文字结果不准确,Reviewer 可能被误导。

后续如果要提高可靠性,可以考虑增加一个只读型 Reviewer:

Reviewer 只能使用 file_read / file_list / execute_command 中的安全检查命令

不过这会让审查流程更复杂,也需要工具权限控制。

当前暂时没有 FEEDBACK

当前AgentMessage.Type没有启用FEEDBACK

所以审查是二元逻辑:

approved == true -> APPROVAL approved == false -> REJECTION

issuessuggestions会进入审查消息内容,但不改变消息类型。

这作为 MVP 是可以的。

后续如果要区分:

完全通过 需要修改 无法接受

可以再扩展成三态:

APPROVAL FEEDBACK REJECTION

对应语义可以是:

APPROVAL -> 完全通过 FEEDBACK -> 可以修改后重试 REJECTION -> 审查认为结果不合格,或者无法继续

Reviewer JSON 解析仍依赖模型遵守格式

review()当前要求 Reviewer 只返回 JSON。

实际 LLM 有时可能返回:

这是我的检查结果: { ... }

或者返回不合法 JSON。

当前代码会清理 Markdown 代码块,但还没有做更强的 JSON 提取。

后续可以增强为:

先找第一个 { 再找最后一个 } 截取中间内容解析

或者在LlmClient层支持结构化输出。

Reviewer 审查失败和系统异常目前都落到 REJECTION

当前用户已经明确了一个边界:

execute() 的异常属于 ERROR review() 返回审查裁决

所以review()中 LLM 返回空、JSON 不合法、调用失败等情况目前也会转成REJECTION

这保持了“review 只返回审查类型消息”的简洁性。

但后续如果想区分:

审查认为不通过 审查系统自己失败

可以给AgentMessage增加更细的 review error 类型,或者允许review()返回ERROR

当前阶段先保持二元审查更容易理解。

Worker 和 Reviewer 的历史每次都会清空

当前TeamOrchestrator每次调用:

worker.clearHistory();reviewer.clearHistory();

这能避免 task 之间互相污染。

但也意味着 Worker / Reviewer 不会记住上一个 task 的原始对话,只能通过buildTaskContext()看到依赖任务结果。

这和/plan阶段的设计是一致的:每个 task 应该收到干净、聚焦的上下文。

如果后续要做真正的团队记忆,可以考虑:

Team memory -> 保存任务摘要和审查结论 -> 不直接保存所有 tool call 细节

tool 执行结果仍然是字符串

这个问题在/plan阶段已经存在,/team也继承了它。

当前ToolRegistry.executeTool()返回String

所以 Worker 是否真的成功,主要还是靠 LLM 解释工具结果。

后续更稳的设计是:

publicrecordToolResult(booleansuccess,Stringcontent,Stringerror){}

这样 Worker 或 TeamOrchestrator 可以更可靠地判断工具失败,而不是完全依赖自然语言。

/team 命令匹配可以更严谨

当前Main中使用:

input.toLowerCase().startsWith("/team")

这会让类似下面的输入也进入/team分支:

/teamwork xxx

后续可以改成:

StringlowerInput=input.toLowerCase();if(lowerInput.equals("/team")||lowerInput.startsWith("/team ")){...}

/plan/save也有类似问题。

目前没有 Multi-Agent 单元测试

当前 Multi-Agent 功能主要靠实际 CLI 手动测试。

后续可以用 fake LLM 测试这些场景:

Worker 一次执行成功,Reviewer approved=true Worker 第一次执行,Reviewer approved=false,重试后 approved=true Worker 第一次执行,Reviewer approved=false,重试后仍 approved=false Worker 返回 ERROR Reviewer 返回非法 JSON

这些测试不需要真实调用 LLM,只要用假的LlmClient按顺序返回预设响应即可。

9. 建议下一步路线

建议接下来按这个顺序推进:

  1. 保持当前/team二元审查逻辑稳定,不急着引入更多角色。
  2. 去掉或改造SubAgent.parseReviewMessage()中的调试System.out.println()
  3. /team增加 fake LLM 单元测试,先覆盖通过、拒绝、重试三种核心路径。
  4. 将 Reviewer 的 JSON 清理逻辑提取成独立方法,并增强非法格式处理。
  5. 再考虑是否恢复FEEDBACK,把“有建议但需要修改”和“彻底拒绝”分开。
  6. 继续保持 Reviewer 默认不使用工具,等主链路稳定后再考虑只读验证工具。
  7. ToolRegistry.executeTool()返回值升级为结构化ToolResult
  8. /plan/team的最终结果统一成结构化结果对象,方便写回上下文。
  9. 再考虑多 Worker,例如worker-1worker-2或按 task type 分配不同 Worker。

10. 当前阶段评价

Multi-Agent 阶段最大的价值不是多了一个/team命令,而是项目开始出现“角色分工”的架构雏形。

当前 SmileCli 的主线已经变成:

Main -> CLI 输入输出和命令分发 Agent -> 普通 ReAct 对话、工具调用、memory 注入 Planner -> 把复杂目标拆成 ExecutionPlan ExecutionPlan / Task -> 表达 DAG、状态、依赖和结果 PlanExecuteAgent -> 单 Agent 的计划执行模式 TeamOrchestrator -> Multi-Agent 的计划执行模式 SubAgent -> Worker / Reviewer 角色执行 AgentMessage -> 子 Agent 之间的通信语义 ToolRegistry -> 本地工具注册与执行 LlmClient -> LLM 交互抽象

从能力演进看,SmileCli 现在已经具备:

能聊天 能调用工具 能规划复杂任务 能按 DAG 执行 能管理短期和长期记忆 能用 Worker / Reviewer 协作完成 task 能把 /plan 和 /team 的结果回填到普通 Agent 上下文

当前/team是一个清晰的 MVP:

Planner 负责拆任务 Worker 负责执行 Reviewer 负责审查 TeamOrchestrator 负责调度和重试

下一阶段的重点不是立刻堆很多 Agent,而是把这条协作链路测试稳、错误语义理顺、工具结果结构化。这样后面再扩展FEEDBACK、多 Worker、只读 Reviewer 或更复杂的团队模式时,底座会更稳。

​​​