Day 06 / 共 20 天 · 第 2 周 Agent 执行

Agent 执行循环

拆开智能体的"大脑"。SuperAGI 有两级 step(宏观工作流步 + 微观迭代步),经典的 think→选工具→执行→观察 就发生在迭代步里。读 jobs/agent_executor.py + agent/

📍 你在整门课的位置 · 第 2 周「Agent 执行」开篇
D1-5 核心概念 D6 执行循环 D7 工作流 D8 提示词 D9 输出解析 D10 LLM抽象
L01

两级 step(一定要分清)

🤔 智能体不就是"一个 while 循环里反复调 LLM"吗?为什么 SuperAGI 要搞出两级 step 这么复杂? 如果真写成一个大 while,流程就"焊死"在代码里——想加个"先分解任务再循环""这步要人工审批"就得改代码。而且进程一崩,循环状态就没了。
💡 一句话本质:SuperAGI 把"循环"拆成了"数据" 外层 AgentWorkflowStep 是存在数据库里的有向图(宏观编排,可分支/循环/等待);内层 IterationWorkflowStep 才是经典的 think→act→observe(微观自治)。"循环"不在某个 while 里,而在"next_step 指回自己 + Celery 反复重排"里(Day 02 的啊哈点)。于是流程可配置、可中断续跑、可人工介入。

外层 AgentWorkflowStep(宏观流程节点)

  • 类型:TOOL / ITERATION_WORKFLOW / WAIT_STEP
  • 是"整个流程的一个大步骤"
  • 节点之间用 next_steps 连成有向图

内层 IterationWorkflowStep(微观迭代步)

  • 当外层是 ITERATION_WORKFLOW 时,内部还有迭代小步
  • 经典 think→选工具→执行→观察 在这里
  • 常指回自己形成循环
外层:AgentWorkflowStep(数据库里的有向图) TRIGGER Step A初始化任务 ITERATION_WORKFLOW 步(内层自治) COMPLETE-1 finish think 🧠 act 🔧 observe 👀 next_step_id 指回自己 → Celery 重排 → 再来一轮
外层是数据库里的工作流图(宏观编排);ITERATION 步内部才是 think→act→observe 的自治循环,靠"next_step 指回自己"反复轮转。
为什么要两级? 外层是"宏观编排"——整个任务分几个大阶段(比如:初始化任务 → 循环处理任务 → 汇总)。内层是"微观自治"——在"循环处理"这个大阶段里,智能体一轮轮 think-act-observe。两级解耦:外层用工作流图精确控制大流程(可分支、可循环、可等待),内层让 LLM 在某个阶段内自主发挥。这比"纯放飞的一个大循环"更结构化、更可控——呼应整个 Agent 行业"可控编排 + 局部自主"的觉悟。

🏢 生活类比(贯穿今天):把智能体想成一个带实习生的项目组外层工作流 = 项目经理手里的排期表/SOP:先立项 → 再开发 → 最后验收,顺序和卡点都定死;内层迭代步 = 实习生在"开发"这个阶段里自由发挥(想一步、写一段、跑一下、再想)。排期表保证不跑偏,实习生保证灵活——两级各司其职。

👶 小白:外层 workflow step、内层 iteration step,我老是绕晕——到底哪一级在"循环"?

👨‍🏫 老师:记一句话——外层是"排期表",内层才是"反复干"。外层工作流图可能只是一站一站往前走(初始化 → 处理 → 汇总),不一定循环;真正 think→act→observe 一轮轮重复的是内层迭代步——它的 next_step_id 指回自己、被 Celery 反复重排,直到 LLM 调 finish。所以"循环"主要发生在内层迭代步里。

L02

单步执行器

AgentExecutor.execute_next_stepjobs/agent_executor.py:39)——注意名字是"下一步",只跑一步:

# 39-56: 取 AgentExecution,防呆检查(旧执行跳过、状态不对退出)
# 59-61: _check_for_max_iterations 检查迭代上限(Day 02 熔断)
# 83-87: 按 current_agent_step_id 取当前 workflow step,调 __execute_workflow_step 跑这一步
读法:每次调用只推进"一个 workflow step",跑完就返回(然后自我重排续跑,Day 05 L05)。OpenAI 模型还会初始化向量长期记忆(Day 13)。这个"单步执行器"是被 Celery 反复调用的——回忆"循环在队列里"(Day 02)。
🍜 生活类比:很像餐厅叫号取餐——你(执行)拿个号排队,后厨(Celery worker)叫到号才做你这一道菜,做完你再排队等下一道。没人守着你从头做到尾,而是"叫一次、做一步"。
L03

按类型分派 handler(策略模式)

# agent_executor.py:105
if step.action_type == "TOOL":
    AgentToolStepHandler(...).execute_step()              # 编排者钦定工具
elif step.action_type == "ITERATION_WORKFLOW":
    AgentIterationStepHandler(...).execute_step()         # LLM 自选工具(经典循环)
elif step.action_type == "WAIT_STEP":
    AgentWaitStepHandler(...).execute_step()              # 等待
读法:按外层 step 的类型选不同 handler——这是策略/工厂模式。两种"选工具"模式很关键:TOOL 步(编排者预先指定用哪个工具,确定性)vs ITERATION_WORKFLOW 步(LLM 每轮自己选工具,像 ReAct)。Day 07 讲外层工作流,今天聚焦迭代步(L04)。
L04

迭代步的自治循环(经典 think→act→observe)

AgentIterationStepHandler.execute_stepagent/agent_iteration_step_handler.py:46)最贴近经典循环:

build_tools 组装可用工具列表(:62)
build_agent_prompt 填提示词模板(:63,Day 08)
build_agent_messages 拼提示+历史 Feed(:69,Day 08)
llm.chat_completion 调 LLM → think + 选工具(:74)
output_handler.handle 执行工具 + 观察结果(:96,Day 09)
决定去向 完成/等待/前进到下一迭代步(:101)
📝 一次迭代步的输入 → 输出(最小例子) 输入(build_agent_messages 拼好的上下文):
system: "你是旅行助手,目标:订一张最便宜的北京→上海机票。可用工具:SearchFlight, BookFlight, finish"
历史 Feed: "(第 1 轮)我调了 SearchFlight,得到 3 个航班:MU5101 ¥560 最便宜"
→ LLM 本轮输出(结构化 JSON,Day 09 解析):
{"thoughts":{"reasoning":"已找到最便宜航班,下一步预订"}, "tool":{"name":"BookFlight","args":{"flight":"MU5101"}}}
→ 执行 + 观察:跑 BookFlight → 结果 "预订成功,订单号 X" 写进 Feed → 下一轮 LLM 读到它,可能就调 finish 收尾。
读法:一次迭代步 = 拼提示(含历史记忆)→ 调 LLM(think + 选工具,一次调用同时完成)→ 执行工具、观察结果 → 决定下一步。think 和"选哪个工具"都在同一次 LLM 调用里完成(LLM 输出结构化 JSON,含 thoughts + tool,Day 09 解析)。

🔍 单步走查表:跟踪任务"查一下北京天气并汇报",看它怎么一轮轮走到结束(关注 Feed 和 next_step 怎么变):

轮次 这一迭代步发生什么 关键状态(Feed / next_step)
第 1 轮LLM think:"要汇报天气,得先查" → 选工具 GetWeather(city=北京)Feed += "调用 GetWeather";next_step = 自己
第 2 轮读回 Feed 看到 "晴 25℃" → think:"信息够了,可以汇报" → 选 finishFeed += "晴 25℃";LLM 调 finish
结束ToolExecutor 见工具名是 finish → 返回 COMPLETE执行状态 = COMPLETED,不再重排
🎢 第一人称:假如"你"就是那次执行 现在你扮演一次 AgentExecution:你先被 API 创建、丢进 Redis 队列排队 → Celery 把你领出来,让你跑一个迭代步 → 你想一步、调个工具、把结果写进 Feed、把 next_step 指回自己 → 然后你又被丢回队列排队 → 下次被领出来,读回自己上次写的 Feed,接着想……如此往复,直到某一轮你调了 finish,才算走完。
🧠 记忆口诀:拼提示 → 调模型 → 干活 → 记笔记 → 排回队(想·调·干·记·排)。
L05

执行工具与观察(闭环)

ToolOutputHandler.handleagent/output_handler.py:33)执行工具并形成观察闭环:

# 45: handle_tool_response 真正执行工具(ToolExecutor.execute)
# 48-61: 把 assistant 回复 + 工具结果都写进 AgentExecutionFeed(role=assistant/system)
# 65: add_text_to_memory 额外写入向量库(长期记忆,Day 13)
"观察"怎么喂回下一轮? 工具执行的结果被写进 Feed(Day 02 的短期记忆)。下一轮迭代步 build_agent_messages 会把这些 Feed 读回来、拼进 LLM 的对话上下文——于是 LLM 看到"我上一步调了什么工具、得到什么结果",据此想下一步。这就是 observe → 下一次 think 的闭环——通过 Feed 落库再读回实现,而非内存变量。ToolExecutor.executetool_executor.py:18)里:工具名是 finish → 返回 COMPLETE(智能体自己宣布结束);未知工具 → 返回错误让 LLM 改正(自我纠错)。
📓 生活类比:Feed 就像实习生的工作笔记本——每做完一件事记一笔("查了天气,晴 25℃"),下次接着干前先翻笔记才知道上次干到哪。结果不是记在脑子(内存)里、而是写进笔记本(数据库),所以换个人(重启 / 换 worker)接手也不会断。
L06

循环从哪来

迭代步执行完,决定"下一步去哪"(agent_iteration_step_handler.py:101)。关键:内层迭代步的 next_step_id 常常指回自己(如 workflow_seed.py:188add_next_workflow_step(step1.id, step1.id))。

"重复"就是这么来的 迭代步跑完,把 next_step_id 设成自己 → Celery 重排后又进同一个迭代步 → 再 think-act-observe 一轮 → 又指回自己……形成 think→act→observe 的反复循环,直到 LLM 调用 finish 工具或超迭代上限。所以"循环"= 迭代步的 next_step 指向自身 + Celery 反复重排。这就是"循环在数据(next_step_id)和队列里"的具体体现(Day 02 的啊哈点)。
⚠️ 常见误解:小白常以为 SuperAGI 里有个 while True: 在某个函数里一圈圈转。其实没有——每次只跑一个迭代步就返回,"下一轮"靠 next_step_id 指回自己 + Celery 重新排队触发。循环是"跨进程、可中断、可续跑"的,而不是一个卡在内存里的死循环——所以服务重启后任务还能接着跑。
L07

结束条件

  • LLM 调 finish 工具:智能体判断目标达成,调用内置 finish → 返回 COMPLETE。
  • 任务队列空:任务分解型工作流,所有任务处理完。
  • 走到 COMPLETE 边:工作流走到 step_id=-1
  • max_iterations 熔断:超上限强制停(Day 02)。
  • 等待人工:遇到 WAITING_FOR_PERMISSION 挂起(Day 07/受限模式)。
多个出口保证智能体"能停下来"——正常靠 LLM 自己 finish,异常靠熔断兜底,敏感操作靠人工审批挂起。"能自主循环、也能可靠停下"是生产级智能体的必备。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 两级 step(外层工作流步 vs 内层迭代步)的区别?
  • TOOL 步和 ITERATION_WORKFLOW 步的"选工具"方式区别?
  • 迭代步的 think→act→observe 具体几步?
  • "观察"怎么通过 Feed 喂回下一轮?
  • 循环怎么来的?(next_step 指回自己 + Celery 重排)结束条件?

✋ 动手

P=superagi
sed -n '39,127p' $P/jobs/agent_executor.py | head -50   # 单步执行器 + 分派
sed -n '46,121p' $P/agent/agent_iteration_step_handler.py | head -50  # 迭代步循环
sed -n '33,66p' $P/agent/output_handler.py              # 执行工具+观察闭环
sed -n '18,65p' $P/agent/tool_executor.py               # finish/未知工具
明天预告 · Day 07工作流 workflow 与 step——外层工作流是数据驱动的有向图,支持分支/循环/条件路由。看 fetch_next_step 怎么用"结果字符串"路由、TOOL 步怎么让 LLM 当路由器。
← Day 05 旅程 Day 07 · 工作流 →