Role 核心循环与三种反应模式
学习目标
理解 Role 类的核心循环 _observe → _think → _act,以及三种反应模式的差异与适用场景。
项目实践
核心循环
Role.run() 是 Agent 执行的入口,遵循标准的 observe-think-act 循环:
async def run(self, with_message=None) -> Message | None: # 1. 观察:从消息缓冲区接收新消息 if not await self._observe(): return # 无新消息,挂起等待
# 2. 反应:思考 + 行动 rsp = await self.react()
# 3. 发布:将响应发布到环境 self.publish_message(rsp) return rsp三级方法链
每个阶段都有默认实现和可覆盖方法:
| 阶段 | 公共方法 | 内部方法 | 职责 |
|---|---|---|---|
| 观察 | — | _observe() | 从 msg_buffer 弹出消息,按 cause_by 过滤,写入 memory |
| 思考 | think() | _think() | 决定下一步做什么(选择哪个 Action) |
| 行动 | act() | _act() | 执行选定的 Action,产生 Message 输出 |
三种反应模式
RoleReactMode 枚举定义了三种策略:
class RoleReactMode(str, Enum): REACT = "react" # LLM 动态选择 action BY_ORDER = "by_order" # 按 actions 列表顺序执行 PLAN_AND_ACT = "plan_and_act" # 先创建计划,再顺序执行1. react 模式(_react(),line 454)
async def _react(self) -> Message: actions_taken = 0 while actions_taken < self.rc.max_react_loop: has_todo = await self._think() # LLM 决定下一步 if not has_todo: break rsp = await self._act() actions_taken += 1 return rsp- 标准 ReAct 循环:交替思考和行动
_think()中 LLM 根据历史消息和可用 action 列表选择下一个max_react_loop默认 1,防止无限循环
2. by_order 模式(_think() line 353-357)
if self.rc.react_mode == RoleReactMode.BY_ORDER: self.rc.max_react_loop = len(self.actions) self._set_state(self.rc.state + 1) # 简单地切换到下一个 action return self.rc.state >= 0 and self.rc.state < len(self.actions)- 按
actions列表顺序执行:Action1 → Action2 → … - 适合固定 SOP 场景,如 ProductManager 先
PrepareDocuments再WritePRD - 不需要 LLM 参与决策,节省 token
3. plan_and_act 模式(_plan_and_act(),line 472)
async def _plan_and_act(self) -> Message: # 1. 创建初始计划 await self.planner.update_plan(goal=goal)
# 2. 顺序执行每个任务 while self.planner.current_task: task = self.planner.current_task task_result = await self._act_on_task(task) await self.planner.process_task_result(task_result)
# 3. 返回完成的计划 rsp = self.planner.get_useful_memories()[0] return rsp- DataInterpreter 使用此模式
- 先由 LLM 生成任务计划(Plan),再逐个执行
- 支持任务结果审核(ask_review)和计划动态更新
RoleContext
RoleContext 封装了 Role 的运行时状态:
class RoleContext(BaseModel): env: BaseEnvironment # 环境引用 msg_buffer: MessageQueue # 异步消息缓冲区 memory: Memory # 持久消息存储(长期记忆) working_memory: Memory # 工作记忆(任务级,可丢弃) state: int = -1 # 当前状态(action 索引) todo: Action # 下一步要执行的动作 watch: set[str] # 关注的 action 集合(用于过滤消息) react_mode: RoleReactMode # 反应模式 max_react_loop: int = 1 # 最大循环次数关键属性:
important_memory:通过memory.get_by_actions(watch)获取关注的消息news:本次 observe 到的新消息
问题与规避
max_react_loop 设置过小
- 默认值为 1,意味着 think-act 循环只执行一次就退出
- 对于需要多步推理的任务,需要增大此值
- RoleZero 默认设为 50
BY_ORDER 模式下 action 顺序错误
set_actions()会重置 state 为 0- 如果运行时动态调整 actions 列表,可能导致 state 越界
- 对策:在
_set_state()中检查边界,越界时设为 -1 终止
设计取舍
BY_ORDER vs LLM 决策
- BY_ORDER 模式不需要 LLM 参与决策,节省 token 和时间
- 代价是缺乏灵活性:无法根据中间结果调整后续 action
- 适用场景:SOP 明确、流程固定的任务(如 PRD → Design 的固定流水线)
单循环 vs 嵌套循环
- 当前设计是扁平的 think-act 循环,不支持嵌套(如 think → plan → act → act → act)
- Plan-and-act 模式通过外部 Planner 间接实现了”计划内循环”
- 更复杂的嵌套需要自定义 Role 子类
参考来源
- 源码验证:
metagpt/roles/role.py:530—run()方法入口 - 源码验证:
metagpt/roles/role.py:82—RoleReactMode枚举 - 源码验证:
metagpt/roles/role.py:454—_react()实现 - 源码验证:
metagpt/roles/role.py:472—_plan_and_act()实现 - 源码验证:
metagpt/roles/role.py:340—_think()三种模式分支 - 源码验证:
metagpt/roles/role.py:92—RoleContext定义