计划-执行控制流:可重规划的 Agent 本节摘要:扛不住失败的计划只是脚本,能重规划的脚本才是 Agent——先把重规划器建起来。思维链 Agent 发 token 让循环猜工具调用在哪结束;计划-执行 Agent 先发结构化计划,再确定性地执行每步。本节建两块:一个产出计划的规划器,一个跑计划的执行器。有趣的是执行器撞失败时怎么办——中止、跳过、还是重规划。重规划是把脚本变 Agent 的那一个。你会学到带类型 step 的有序计划、失败时带先前错误回交规划器、每次修订发计划 diff、两个硬预算(步数上限与重规划上限)。 对应原课程:Phase 19 · Lesson 24 · (原英文 )。本节属「Agent Harness 深度构建赛道」第五节。
本节摘要:扛不住失败的计划只是脚本,能重规划的脚本才是 Agent——先把重规划器建起来。思维链 Agent 发 token 让循环猜工具调用在哪结束;计划-执行 Agent 先发结构化计划,再确定性地执行每步。本节建两块:一个产出计划的规划器,一个跑计划的执行器。有趣的是执行器撞失败时怎么办——中止、跳过、还是重规划。重规划是把脚本变 Agent 的那一个。你会学到带类型 step 的有序计划、失败时带先前错误回交规划器、每次修订发计划 diff、两个硬预算(步数上限与重规划上限)。
对应原课程:Phase 19 · Lesson 24 ·
plan-execute-control-flow(原英文phases/19-capstone-projects/24-plan-execute-control-flow/docs/en.md)。本节属「Agent Harness 深度构建赛道」第五节。
阅读完本节,你应当能够:
计划-执行,而非思维链。计划是外壳可内省的数据,执行是外壳把那份数据跑过分发器。撞失败时三个选项:中止(返回失败,呈错)、跳过(标记步失败,继续其余)、重规划(把错误交规划器,从游标拿新计划)。重规划是把脚本变 Agent 的那一个。
Step 的形状:id(计划修订内单调)、tool_name、args、expected_outcome(规划器陈述的成功条件)、result、error。expected_outcome 是规划器随步发的一句短话,执行器不强制它——它用于两件事:重规划器修订计划时读它;事件流发它让追踪器展示「这步本该做 X」。
规划器是纯函数:
def planner(goal: str, history: list[Step], last_error: str | None) -> list[Step]: ...
goal 是用户目标,history 是已执行步(带结果与错误),last_error 首次调用为 None、后续每次是最近失败消息,返回从游标开始的下一份计划。规划器不知道执行器、不知道重试、不知道超时——它只产计划。
执行器是小状态机。每步经分发器,结果三选一:成功、可重规划失败、致命失败。可重规划失败交回规划器;致命失败(预算超、重规划上限触)返回 FAILED。
计划 diff(修订可见,非静默重写):
removed : 旧计划有新计划无的 step id added : 新计划有旧计划无的 step id revised : tool_name 或 args 变了的 step id
追踪器或 UI 可把 removed 渲染成删除线、added 高亮。重点不在 diff 格式,在「修订是可见事件」。
max_steps 给整会话的总步执行设上限(含重规划),默认 12。一个线性五步计划重规划两次各加三步,就达 16 次执行、超预算,执行器拒重规划返回 FAILED。max_replans 给首次计划后的规划器调用次数设上限,默认 5——这是更重要的限:一个连续五次返回同一坏计划的规划器,否则会循环到步预算抓住它。限重规划让失败更快、原因更清。
本节确定性规划器(不调模型):
last_error is None -> 四步计划 last_error 匹配 X -> 三步计划,绕开 X last_error 匹配 Y -> 两步计划,优雅放弃 otherwise -> [] (信号: 无可重规划)
这够测执行器在每条转移路径上的行为:成功、重规划一次、重规划两次、重规划耗尽、步预算耗尽。
code/main.py 定义 PlanExecuteAgent、Step、PlanDiff、SessionResult 与确定性规划器。执行器是单个 run(goal) 方法返回 SessionResult,计划 diff 通过比 step id 与 (tool_name, args) 元组算。code/tests/test_agent.py 覆盖线性成功、计划中失败重规划一次、重规划耗尽返回 failed:replan_budget、步预算耗尽、计划 diff 事件格式。
SessionResult 形状:status("completed"/"failed")、reason("goal_met"/"step_budget"/"replan_budget"/"no_plan")、history、revisions、events。第 20 节的循环可直接读它,第 23 节的分发器执行每步,第 21 节的注册表校验每步参数,第 22 节的传输会把整条流经 JSON-RPC 浮现给模型客户端。
ReAct(思维链 + 行动)与计划-执行是两条路。ReAct 灵活但每步都让循环猜工具调用边界;计划-执行把规划与执行解耦,计划可内省、可 diff、可预算。ReWOO 与本节的「先规划再执行」同源。本节的差异化在「重规划带先前错误」与「计划 diff 可见」——这让失败不是静默重写,而是可追踪的修订事件。接真模型后会想加两样:部分计划缓存(前六步成了三步、后三步失败时,不重跑前三步,规划器读 history 即可);并行分支(规划器发 gather_step 而非 next_step,两工具调用经分发器并发)。
max_replans 抓住它返回 failed:replan_budget。max_steps 在第 12 次执行时拒重规划。removed/added/revised 三字段正确。gather_step,确认两工具调用经分发器并发。下一节,我们建「验证门与观察预算」——决定工具调用是否允许触发、模型能看到多少输出的确定性门链。