跳到主要内容

规划 agent:把大任务拆成多步

本章讲:复杂度被判为 HIGH 的任务交给 planner,它怎么拆任务、调度子 agent、传递上下文、出错重规划。

3.1 它要解决的小问题

“搜三家咖啡馆并把带地址的名单存成文件”这种请求,单个 agent 接不了:要先 web 搜、再 file 写。需要一个“项目经理”把它拆成有顺序、有依赖的子任务,再派给对的 agent。

3.2 思路/直觉:让 LLM 输出结构化计划

planner 本身也是个 agent,但它不直接干活,而是让 LLM 输出一份 json 计划,每步是一个对象:

{
"plan": [
{"agent": "Web", "id": "1", "need": [], "task": "Search for cafes in Rennes"},
{"agent": "File", "id": "2", "need": ["1"], "task": "Save three cafes with addresses to rennes_cafes.txt"}
]
}

三个字段:agent(派给谁)、id(步骤编号)、need(依赖哪些上游步骤的输出)。need 是联系上下文的关键:下游能拿到上游的结果。

这份格式是 prompt 里明确规定的(prompts/base/planner_agent.txt)。

3.3 图示:planner.process 的主循环

怎么读:先出计划,再一步一步跑,每步跑完都问一下“要不要重规划”。

goal 进来
v
make_plan(goal) 出一份 JSON 计划(解析失败最多重试 4 次)
v
i = 0,steps = 计划长度
+-> i < steps 且未 stop?
| v
| 拿 task[i],按 need 从 agents_work_result 取上游结果
| v
| start_agent_process(task, infos) 调 self.agents[agent].process(...)
| v
| 记下结果到 agents_work_result[id]
| v
| update_plan(...) 问 LLM:要不要改后续步骤?
| v
+---- i += 1,steps = 新计划长度

主函数 planner_agent.py:262-303PlannerAgent.process)。

3.4 真实实现:几个关键步骤

出计划 + 容错重试planner_agent.py:150-182make_plan):调 LLM、解析 JSON,解析失败则提示“请把计划写进 json 块”重试,最多 4 次。这是针对“小模型输出不出合法 JSON”的防御。

解析计划planner_agent.py:63-108parse_agent_tasks):用 json 工具的 load_exec_block 抽出 json 块,逐个校验 agent 名存不存在(planner_agent.py:87-90)。

调子 agentplanner_agent.py:232-255start_agent_process):

# 示意,非源码
agent_prompt = make_prompt(task['task'], required_infos) # 把上游结果拼进 prompt
answer, _ = await self.agents[task['agent'].lower()].process(agent_prompt, None)
self.blocks_result = sub_agent.blocks_result # 把子 agent 的执行块提上来
success = sub_agent.get_success
answer += "Agent succeeded" if success else "Agent failed"

依赖传递planner_agent.py:257-260get_work_result_agent):按 need 里的 id 从 agents_work_result 里挑出该传给下游的结果。

3.5 巧妙之处:动态重规划

每跑完一步,planner 都调 update_planplanner_agent.py:184-230)问 LLM:刚才这步是成是败?要不要改后面的步骤?

  • LLM 回 NO_UPDATE -> 不改,按原计划走。
  • 否则 -> 重出一份计划,但 prompt 明确要求“只改 task {id} 之后的步骤、不动过去的步骤、长度不变或只多一步”(planner_agent.py:217-222)。

这让 planner 能从子任务失败中恢复(加一个重试步骤),而不用从头重拆。

3.6 关键细节/坑

  • planner 自己持有一套子 agent 实例planner_agent.py:25-30),与顶层交互的 agent 列表是两套。子 agent 名是 coder/file/web/casual(小写)。
  • 成功与否靠子 agent 的 get_successagent.py:86-87),而 get_success 又由 execute_modules 里工具的失败检测决定——所以误报会连锁到重规划。
  • 任务名与 JSON 数量不匹配时的兼容planner_agent.py:105-108):若 ## 标题数与 JSON 步骤数不等,改用 task 描述当名字。

3.7 代码地图

主题文件符号
规划主循环sources/agents/planner_agent.pyPlannerAgent.process
出计划sources/agents/planner_agent.pymake_plan
解析 JSON 计划sources/agents/planner_agent.pyparse_agent_tasks
调子 agentsources/agents/planner_agent.pystart_agent_process
依赖传递sources/agents/planner_agent.pyget_work_result_agent
动态重规划sources/agents/planner_agent.pyupdate_plan
计划格式规范prompts/base/planner_agent.txt