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

工作流 workflow 与 step

SuperAGI 智能体不是纯放飞循环——外层是数据驱动的工作流有向图,支持分支、循环、条件路由、等待。今天读工作流模型。

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

工作流是有向图

🤔 昨天说"循环在 next_step 里",那这个 next_step 到底谁在管?为什么不把流程直接写进 Python? 硬编码的流程改一次就得动代码、发版;也没法让产品/运营去调"先干什么、根据结果走哪条边",更没法把一套好流程分享给别人复用。
💡 一句话本质:流程即数据(Flow as Data) 把"先做什么、根据结果走哪条边"建模成数据库里的节点 + 带条件的边(有向图),而不是硬编码的 if-else。代码只当"图的解释器"(Day 06 的外层 step 循环就在读这张图)。于是流程可配置、可分享、可视化、可循环分支——同一套执行引擎能跑无数种工作流。

AgentWorkflow(一个工作流)由多个 AgentWorkflowStep(节点)组成,节点之间用 next_steps 连成有向图。智能体绑定一个工作流(Agent.agent_workflow_id,Day 02)。

TRIGGER起点 Step A初始化任务 Step B迭代循环 COMPLETE-1
"数据驱动的流程图"是什么意思? 智能体"按什么流程干活"不是写死在代码里,而是存在数据库里的一张图(节点 = 步骤,边 = next_steps)。改流程 = 改数据库里的图,不用改代码。于是能有多种预置工作流(目标驱动、任务分解、SuperCoder…),还能在市场分享工作流。这和 CrewAI Flow、AutoGPT Graph 思路一致——把流程建模成数据/图,而非硬编码。

🚇 生活类比(贯穿今天):工作流图就像地铁线路图——每个 step 是一next_steps 是连接站点的轨道,条件边就是"到这站按情况换乘不同线路"。想改线路?改图纸(数据库里的图)就行,不用重造整条地铁(改代码)。这也是为什么工作流能在市场"分享"——发一张别人直接能坐的线路图给他。
L02

step 节点结构

# models/workflows/agent_workflow_step.py:13
class AgentWorkflowStep(DBBaseModel):
    agent_workflow_id = Column(Integer)
    step_type = Column(String)        # TRIGGER / NORMAL
    action_type = Column(String)      # TOOL / ITERATION_WORKFLOW / WAIT_STEP
    action_reference_id = Column(Integer)  # 指向具体 tool / 迭代工作流 / wait
    next_steps = Column(JSONB)        # ★ 带条件的出边:[{"step_response":"YES","step_id":"..."}]
读法:一个节点存"我是什么类型(action_type)、我引用哪个具体动作(action_reference_id)、我的出边(next_steps)"。next_steps 是 JSONB,形如"结果是 YES 就去 step5、NO 就去 step3"——这就是带条件的边,让流程能分支。
L03

条件路由 fetch_next_step

路由核心 fetch_next_stepagent_workflow_step.py:252):拿"当前步的执行结果字符串"去 next_steps 里匹配对应 step_id

# 拿执行结果(如 "YES")匹配 next_steps 里的 step_response
# 匹配到 → 去对应 step_id
# 匹配不到 → 走 "default" 边
# step_id == "-1" → COMPLETE(工作流结束)
📝 一次条件路由(输入 → 输出) 输入:当前 step6 执行结果字符串 = "NO";step6 的 next_steps = [{"step_response":"YES","step_id":"7"}, {"step_response":"NO","step_id":"5"}]
→ fetch_next_step 匹配:"NO" 命中第二条 → 返回 step_id "5"
→ 输出:下一步回到 step5(形成"没通过就重来"的循环)。若结果是 "YES" 就去 step7 前进;若结果没匹配上任何边就走 default;若 step_id 是 "-1" 就 COMPLETE 收尾。
🛠️ 如果让你自己实现"条件路由",你大概会这么写……(简化版 → 真实版对照) 朴素做法(写死在代码里):
if result == "YES":   go_to(step7)
elif result == "NO":  go_to(step5)
else:                 go_to(default)
问题:流程焊死在 Python 里——改流程要改代码、发版;产品经理不能自己调;没法可视化、没法分享。
真实版:SuperAGI 把这张"结果 → step_id"映射表存进 next_steps(JSONB 字段),fetch_next_step 运行时查表路由。多出来的这层"查表",换来的正是流程变成可编辑、可分享、可视化的数据——设计上多花一点,产品上灵活一大截。
读法:每个步骤跑完产出一个"结果字符串",用它决定走哪条边——这就是条件路由。比如一个"检查是否完成"的步骤返回 YES/NO,YES 走完成分支、NO 回到处理步(循环)。step_id="-1" 是约定的"结束"标记。
"结果字符串决定走向"很像状态机 这就是一个状态机:当前状态(step)+ 输入(结果字符串)→ 下一状态(next step)。用数据(next_steps 表里的映射)而非代码 if-else 来定义状态转移——所以能可视化编辑、能分享、能有多套工作流。Day 06 的"外层 step 循环"就是靠这个路由推进的。
L04

TOOL 步:LLM 当路由器

AgentToolStepHandler.execute_stepagent/agent_tool_step_handler.py:39)——TOOL 步是"编排者钦定工具"的确定性步骤(对比迭代步 LLM 自选):

# 1. 取绑定的 tool(tool_name, input_instruction, output_instruction)
# 2. _process_input_instruction:让 LLM 只为这个"指定工具"生成 args
# 3. 执行工具
# 4. 若配了 output_instruction:_process_output_instruction 再调 LLM,
#    把工具输出"归类成一个枚举结果"(从 output_options 里选一个)
#    → 这个字符串就是 step_response,喂给 fetch_next_step 决定走哪条边
"LLM 当路由器"是精妙设计 TOOL 步先用指定工具干活,然后(可选)再调一次 LLM 把结果"归类成一个枚举值"(比如把搜索结果判断成"找到了/没找到")。这个枚举值就是 step_response,决定工作流走哪条边。于是 LLM 不只用来"选工具/填参",还用来"判断结果、做流程路由决策"——LLM 当路由器。这让工作流能根据 AI 对结果的理解智能地分支,而不只是固定路径。TASK_QUEUE→QueueStepHandler、WAIT_FOR_PERMISSION→人工审批是特殊工具名的分流。
🏥 生活类比:这一步的 LLM 很像医院分诊台护士——先看你的症状(工具输出),判断该去哪个科室(哪条边)。它不治病,只做"看情况、分流去向"的判断。

👶 小白:fetch_next_step 拿"结果字符串"去匹配边,可 LLM 不是只会自由发挥吗?这字符串哪来的、凭什么正好匹配得上?

👨‍🏫 老师:关键就在 TOOL 步的第 4 步——它再调一次 LLM,让 LLM 从预先给定的 output_options 里"选一个枚举值"(比如只能答"找到了 / 没找到"),而不是随便写。这个受限的枚举字符串才是 step_response,拿去和 next_steps 里的 step_response 对号入座,自然匹配得上。是"让 LLM 判断,但把答案限定在几个选项内"——既智能又可控。

L05

内置工作流示例

内置工作流由 workflow_seed.py 播种(Day 04 的 seeding):

  • Goal Based Workflow:183):单个 ITERATION_WORKFLOW 步,边指回自己 + 一条 COMPLETE 边——最纯粹的"目标驱动自治循环"(就是经典 AutoGPT 式的放飞循环)。
  • Dynamic/Fixed Task Workflow:191):先 Initialize Tasks 生成任务队列,再 Task Queue 步循环消费——任务分解型
  • 还有 Sales、Recruitment、SuperCoder 等领域工作流。
"目标驱动"vs"任务分解" Goal Based:给个目标,智能体自由循环直到达成(灵活但可能跑偏)。Task 型:先把大目标拆成一个任务列表,再逐个完成(更有条理)。SuperAGI 提供多种预置工作流让你按任务性质选——开放探索用目标驱动、有明确子任务用任务分解。这体现了"工作流即模板"的价值:常见模式沉淀成可选工作流。
🧳 生活类比:就像出去玩——目标驱动 = 自由行(只定目的地,路线现场随机应变,灵活但可能绕路);任务分解 = 跟团游(行程表逐项列好,按表打卡,省心但不灵活)。按任务性质选团。
L06

分支与循环

add_next_workflow_stepagent_workflow_step.py:209)建边。真实例子(workflow_seed.py:99):

AgentWorkflowStep.add_next_workflow_step(session, step6.id, step7.id, "YES")
AgentWorkflowStep.add_next_workflow_step(session, step6.id, step5.id, "NO")  # NO 时回到 step5 → 循环
step5处理任务 step6检查是否完成? step7汇总 / 前进 COMPLETEstep_id = -1 YES NO → 回 step5(循环) 最终 next_steps 里的"结果字符串 → step_id"映射 = 带条件的边
step6 依据结果字符串分两条边:YES 前进到 step7、NO 回到 step5 形成循环——这就是"数据驱动的分支+循环"。
读法:step6 后面:结果 YES → 去 step7(前进);NO → 回 step5(形成循环)。这让工作流能表达"检查未通过就重来"的循环、"根据情况走不同路径"的分支——比线性流程强大得多。
起点与推进AgentExecution.assign_next_step_idmodels/agent_execution.py:153)设置 current_agent_step_id;若下一步是 ITERATION_WORKFLOW,还会把内层迭代步设成该迭代工作流的 TRIGGER 步。两级 step 的衔接就在这里。
L07

数据驱动流程的意义

  • 可配置:改流程改数据库图,不改代码。
  • 可分享:工作流能在市场分享(像分享一个"最佳实践流程")。
  • 可控 + 可自主:外层图精确控制大流程(分支/循环/等待/人工审批),内层迭代步让 LLM 自主发挥——两全。
  • 可视化:图结构天然能画出来,GUI 可视化编辑。
💥 如果没有"数据驱动流程"会出什么事故? 设想流程全硬编码在 if-else 里:产品想给销售智能体加一步"发邮件前先人工审批",得提需求 → 排期 → 程序员改代码 → 测试 → 发版,一周过去了;想同时上线"目标驱动版"和"任务分解版"两套流程,代码里就得塞两坨 if-else 互相打架。而数据驱动下,这些都只是"在数据库那张图上加/改几个节点和边"——运营自己在 GUI 上拖一下即可。把流程从代码里解放出来,正是为了躲开这类"改流程=改代码"的事故。
和其它框架对比:SuperAGI 的"工作流图 + 迭代步"≈ CrewAI 的"Flow + Crew"、AutoGPT 的"Graph + Block 执行"——都是"外层确定性编排 + 内层 AI 自主"的组合。五个框架殊途同归地走向"可控编排 + 局部自主"——这是自主智能体工程化的共同答案。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 工作流为什么是"数据驱动的有向图"?
  • step 节点的 next_steps 怎么表达带条件的边?
  • fetch_next_step 怎么用结果字符串路由?
  • TOOL 步怎么"让 LLM 当路由器"?
  • Goal Based vs Task 型工作流的区别?分支/循环怎么建?

✋ 动手

P=superagi
sed -n '13,47p' $P/models/workflows/agent_workflow_step.py    # step 结构
grep -n 'def fetch_next_step\|def add_next_workflow_step' $P/models/workflows/agent_workflow_step.py
sed -n '39,72p' $P/agent/agent_tool_step_handler.py           # TOOL 步 LLM 路由
sed -n '183,215p' $P/agent/workflow_seed.py                   # 内置工作流
明天预告 · Day 08提示词构建——role/goal/instructions/工具/记忆怎么拼成 LLM 提示。模板文件 + 变量替换、工具渲染成 JSON schema、历史记忆的滚动摘要压缩。
← Day 06 执行循环 Day 08 · 提示词构建 →