跳转到内容

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 先 PrepareDocumentsWritePRD
  • 不需要 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:530run() 方法入口
  • 源码验证: metagpt/roles/role.py:82RoleReactMode 枚举
  • 源码验证: metagpt/roles/role.py:454_react() 实现
  • 源码验证: metagpt/roles/role.py:472_plan_and_act() 实现
  • 源码验证: metagpt/roles/role.py:340_think() 三种模式分支
  • 源码验证: metagpt/roles/role.py:92RoleContext 定义