工作流引擎

工作流是「把多个 Agent 调用、工具调用和人工确认串成一张图」:定义以节点 + 边的 JSON 落库,运行前先做图校验,运行时逐个节点执行并留下节点级记录。一个关键事实:它是顺序执行的,不是并行的——共享同一个作用域 DbContext,靠这个换来实现简单与事务一致性。

定义 Nodes / Edges(JSON) Version 每次更新自增 图校验 须有 Start / End 边端点存在 · Agent 需 AgentId 运行 写 GraphSnapshot 总迭代 100 · 单节点 20 节点执行记录 WorkflowRunNode:Pending / Running Succeeded / Failed / Skipped 出口 SSE:9 类事件 人审:/approve 回传 approved / rejected 节点执行器(10 种) start · agent · condition · loop · parallel / merge tool · human · subworkflow · end
定义 → 校验 → 运行 → 节点记录,四处都有落库;运行以快照固化当时的图,避免中途改定义影响已开始的运行。

定义模型

字段说明
Name · Description · SortOrder · IsEnabled元数据与列表排序
Nodes · Edges以 JSON 字符串存储;节点类型常量:start / agent / condition / loop / parallel / merge / tool / human / subworkflow / end
InputSchema · Variables输入契约与变量声明
Version新建为 1,每次更新自增
节点 Config各节点类型的 JSON 配置,见下方执行器表

端点

端点用途
GET /api/workflows · GET /api/workflows/{id}列表 / 详情
POST /api/workflows · PUT /api/workflows/{id} · DELETE /api/workflows/{id}增删改(保存时把节点与边序列化为 JSON,更新自增版本)
POST /api/workflows/{id}/duplicate复制定义,名称追加「副本」后缀
GET /api/workflows/{id}/validate只做图校验,不运行
POST /api/workflows/{id}/run一次性运行,返回运行结果
POST /api/workflows/{id}/run/streamSSE 流式运行
POST /api/workflows/{id}/run/topic/{topicId}/streamSSE 运行并把过程写入指定话题
GET /api/workflows/{id}/runs · GET /api/workflows/runs/{runId}运行历史 / 单次运行详情(含节点记录)
POST /api/workflows/runs/{runId}/approve人审节点回传:{ nodeId?, approve }

图校验规则

  • 至少一个 start 节点、至少一个 end 节点。
  • 每条边的两端节点必须存在。
  • 除 start 外不得存在孤立节点(必须可达)。
  • agent 节点必须有 AgentId(指向项目智能体预设)。

运行前会再次校验,所以「保存成功但运行报校验失败」通常意味着定义被外部改动或边被删。

节点执行器

节点配置与行为
start把原始输入存为 start.input;若输入是 JSON 对象,还会把每个字段拆成独立变量
agent配置 instruction / modelId / toolNames / mcpServerIds / toolApprovals / maxIterations / maxToolCallsPerTurn;上游输出注入为输入,无上游则回退运行输入;SessionId = workflow-{runId}-{nodeId};经 Agent 循环执行,额外写回 thinking 与 toolCalls;用量来源 workflow
condition{ branches: [{ handle, expression }], defaultHandle };首个匹配分支的 handle 决定后续走向
loop{ maxIterations, exitCondition };首次进入走 body,满足退出条件或达到上限走 exit
tool{ toolName, argumentsTemplate };直接调用内置或 MCP 工具,不经过 LLM
human{ prompt, timeoutSeconds };通过返回 approved、拒绝返回 rejected 作为分支句柄
subworkflow{ subWorkflowId, inputTemplate };递归深度上限 5
parallel / merge普通节点出现多条出边时自动 fan-out,分支结果汇总后在下游公共节点合并
end有 outputTemplate 则渲染模板,否则取首个非空上游输出,再无则回退运行输入
「并行」在这里是结构上并行、执行上顺序:分支会被逐个执行再合并,以共享同一个作用域 DbContext。理解这点能解释两件事:分支里的 Agent 调用是串行的;任何一个分支失败会终止整次运行。

运行与上限

项值 / 行为
运行记录WorkflowRun:Status(Pending / Running / Succeeded / Failed / Cancelled)· Input · Output · GraphSnapshot · ChatTopicId · Error · TotalIterations
节点记录WorkflowRunNode:NodeId · NodeType · Status · Input · Output · Error · Iterations
总迭代上限MaxTotalIterations = 100,超出抛错并终止
单节点访问上限MaxNodeVisits = 20,超出抛错并终止(防循环失控)
取消OperationCanceledException → 运行置 Cancelled
其它异常运行置 Failed,Error 写入异常消息

人审与工具审批

  • 人审节点会把「等待审批」通过 SSE 事件推到前端,前端显示待审批;回传走 /approve。
  • toolApprovals(节点级)优先;未显式配置时用运行级的全局模式补足。
  • 工具审批与权限模式的关系见 权限与审批;Agent 节点内部的循环与工具上限见 Agent 循环。

SSE 事件

事件含义
run_started · run_completed · run_failed运行生命周期
node_started · node_completed · node_failed节点级进度与错误
human_approval_required人审节点等待回传
agent_tool_callAgent 节点的工具调用过程(前端可按问答 / 计划 / 审批三类回传)
run_result最终结果载荷

更完整的事件协议(三种帧形态、未知事件的处理)见 SSE 事件协议。Agent 节点内部仍会写出 [ERROR] 兜底帧。

与任务看板的关系

  • 看板任务的运行记录支持 Kind = Agent | Workflow,触发来源 Trigger = Todo | Comment | Manual。
  • 也就是说:卡片可以挂工作流,进入待办后由执行器运行,过程与结果落在运行记录与评论里(见 任务看板与自动化)。
  • 工作流内部的 Agent 节点不复用看板的运行记录,而是写自己的节点记录。

实作要点

  • 循环一定配 maxIterations:单节点 20 次访问上限是最后一道闸,但它会直接让运行失败。
  • Agent 节点的 session id 里带运行与节点 id,所以每次运行都是干净会话;想跨节点共享上下文,靠变量传递而不是靠会话历史。
  • tool 节点不经 LLM:适合固定动作(跑命令、取数据),比让模型决定更省更稳。
  • 运行前把 /validate 接进编辑流程,能挡掉「缺 End 节点」「Agent 没选智能体」这类最常见保存即失败。
  • 定义改动不影响已开始的运行:排查看结果不一致时先看该次运行的 GraphSnapshot。