[English](../en/workflows.md) | 简体中文 # 工作流 这篇讲在画布上搭工作流:节点怎么连、数据怎么传、人工节点和 agent 的规则、怎么发布,以及运行和断点续跑。给搭建者看。 ## 画布 在画布上拖拽节点、连线。运行时: - 节点实时高亮,边上的光点表示数据流向,卡片里直接显示流式 token。 - 底部的航迹把各节点的起止和并行度排在一条时间轴上,实时和回放共用。 - 右栏是运行步骤,和画布读同一份事件流。 - 多 agent 节点在卡片里展开协作矩阵:谁在跑、几个人并行、省下多少时间。 - 分支节点跑完会点亮命中的出口、压暗其余。实际走过的边留在画布上,就是这一次的执行路径。 ### 动效表示什么 画布上每个会动的东西都对应一件真实发生的事: | 动效 | 表示 | |---|---| | 边框上转一圈光弧 | 节点正在跑 | | 扫描线扫过 | 正在产出 | | 绿色扫一遍 | 刚跑完 | | 抖动 | 刚失败 | | 琥珀色呼吸 | 在等人 | | 边上的光点 | 数据正从这边流向那边 | 协作矩阵的花名册固定不重排;被派出去的人亮起来并显示当前任务;条形长度按「这一轮里最慢的那个人」归一化,所以墙钟时间等于最长那条;页脚给出并行一共省下多少。 系统关掉动效时(`prefers-reduced-motion`),光效整体不绘制。这时「谁在跑」由实心圆点和「进行中」三个字表示。 ### 自动排版 - 按拓扑分层:并行的支路落在同一列,层内按中位数启发式排序,减少交叉。 - 分支节点的出口按 yes/no 的声明顺序自上而下排。 - 循环的回边不参与分层,否则循环体会被压到循环节点左边。 - 每条线有自己的竖直车道:扇出、汇聚的线不叠在同一段上,跨层的长边从没有节点的空档绕过去(做法见[架构](architecture.md#连线走线))。 ### 内置模板 内置 9 个模板,从「最小问答」到「可追溯周报」。它们可以直接运行,也是各类节点用法的可执行文档。 ## 节点类型 | 分类 | 节点 | 说明 | |---|---|---| | 起止 | `input` `output` | 声明输入字段 / 收集结构化成果 | | 模型 | `llm` `agent` `supervisor` `report` | 单次调用 / 带工具循环 / 多 agent 协作 / 报告撰写(只写引用标记,数字由系统填) | | 执行 | `tool` `code` `merge` | 直接调用工具 / 沙箱内执行代码 / 合并几次查询的结果(跨库按键对齐) | | 控制 | `branch` `loop` `subgraph` | 条件或语义分支 / 遍历与条件循环 / 嵌套工作流 | | 上下文 | `memory` `retrieve` `transform` | 长期记忆读写 / 知识检索 / 数据整形 | | 把关 | `human` `validate` `metrics` | 人工介入 / Schema 校验与自动返工 / 口径卡 | `output` 节点按 JSON Schema 校验结构化成果,不合格时把错误交回模型自动返工。`metrics`(口径卡)和 `report`(报告撰写)见[证据与出具](evidence.md);`merge`(合并查询)见[数据源](data-sources.md#跨库合并)。 ## 节点之间怎么传数据 用模板语法引用别的节点的产出: ``` {{ input.question }} 入口输入 {{ vars.answer }} 某节点 assign_to 写入的变量 {{ nodes.n1.text }} 指定节点的输出 {{ vars.items | json }} 过滤器:json / compact / upper / length / first … ``` ### 条件和表达式不是模板 分支条件、while 循环条件、整形表达式、口径卡指标、跳过条件这几处直接求值,变量直接写:`vars.gate != 'ok'`、`len(vars.items) > 0`。 - 多套了 `{{ }}` 时意思没有歧义,照 `vars.gate` 理解,只给一条提示。 - 下面这些写法在校验阶段就拦下,不会等跑到那一步才报错:`| length` 这类过滤器(改写成 `len(x)`)、`{'a', 'b'}` 集合(改用列表)、不认识的函数、把 `==` 写成 `=`、引号里的 `{{ }}`(它不会被渲染,条件永远不成立)。 - 校验、助手自查和运行时用同一个解析器,不会出现「校验说能跑、跑起来报错」。 - 求值器只认 AST 白名单里的写法,不用 `eval`。 ### 代码节点的结果要 print 出来 `assign_to` 拿到的是 stdout。脚本最后一行写个裸表达式不会输出(自动显示是 notebook 的行为),变量会是空的。 - 要交给下游一个对象,写 `print(json.dumps(结果))`。stdout 是 JSON 时自动解析成对象。 - 设了 `assign_to`、却找不到任何输出的 Python 代码,校验直接拦下。 - 代码在沙箱里执行。每个代码节点可以单独选隔离档位:strict 是 microVM,fast 是系统沙箱(见[身份、权限与安全](identity-and-security.md#代码沙箱))。 - bubblewrap 沙箱不继承后端的环境变量,代码里读不到模型的 API Key、数据库地址这类变量。代码要用的值请显式传进去。 - `evidence_role` 区分 `source`(取数)和 `compute`(计算,默认)。沙箱算出来的数不能被报告直接引用,要进口径卡(见[证据与出具](evidence.md#取数链路))。 ## 并行与汇合 - 一个节点连出多条边就是扇出,几条支路并行执行。 - 多条边汇入同一个节点时自动等待汇聚:汇合节点等图里其余待执行的任务都跑完,再执行一次。支路一长一短也不会触发两遍。 - 分支之后的二选一汇合,不会去等没走的那条。 - 代价:汇合节点也会等图里和它无关、恰好还在跑的支路。 ## 人工节点 `human` 节点让执行暂停并落盘,人做出决定后沿对应出口继续。 ![人工审批流程](../images/graph-human.png) - 人可以批准、驳回或改稿,之后从断点继续。进程重启不丢状态。 - 可以派给岗位、发起人或按表达式算出的人。岗位是图里写的名字,在应用里绑定到人或组(见[应用](apps.md#流程与待办))。 - 会签:任一人同意、全体同意(一票否决),或至少 m 人同意。 - 可以设时限,超时提醒、升级或按驳回处理。 - 表单可以由上游 Agent 拟定。 - 永远不会自动批准。只认明确的批准(`true` / 同意 / approve),看不懂的回复一律按拒绝处理。 除了审批,人工步骤还有:补充输入、编辑稿件、动作确认、代码和工具审批、双盲裁决。 ### 驳回 驳回是人的决定,不是故障: - 运行记为「已取消 · 被驳回」,不算失败、不重试,也不能继续运行。通知走「实例结束」,定时任务推「未出具(被驳回)」。 - 配了失败重试或「出错时继续」的关卡,驳回后不重问,也不接着往下走。 - 被驳回的那一步,`node.failed` 事件带 `reason: "rejected"`(和 `run.cancelled` 同一个字段)。画布、航迹、时间线、问数据过程都画成「被驳回」。读事件的外部系统按 `reason` 区分。 审批、补充输入、编辑稿件、动作确认、代码和工具审批、双盲裁决都可以多接一个「驳回」出口: - 驳回(包括超时驳回)后,这一步正常结束,沿驳回出口往下走。运行照路径结束,`run.finished` 带 `rejected_via`。 - 动作确认走驳回出口时,什么都不发出去。 - 实例页和通知写「被驳回,转到 X」。待办、通知、Webhook 里照实写驳回的去向(「被驳回,转到 X」「这一路到此为止」),子工作流里的写「子工作流 › x」。 - 不接驳回出口时,照旧记「已取消 · 被驳回」。 - 发布检查拦下走不到结束的驳回路径。 ## Agent 节点 `agent` 节点是一个带工具的模型循环,能用哪些工具由节点上的白名单决定(见[工具](tools.md))。配了 `output_schema` 的 agent 可以打开 `cite_fields`,让每个字段标出取自哪次查询的哪一格(见[证据与出具](evidence.md#取数链路))。 ### 护栏 护栏代替固定步数,防四件事: - **循环不收敛**:同一个工具、同样的参数第二次不再执行,把上次的结果交还给它;连续 3 步拿不到新信息就收尾。 - **花费越滚越大**:每个节点记令牌预算(默认 200 万)和金额预算(默认不限),都可以在「设置」里改成不限。 - **上下文会满**:用到窗口的 60% 先压缩早期的工具结果,到 85% 就收尾。 - **真正失控**:步数只留兜底,默认 100,在设置里改,`AGENTLAB_MAX_AGENT_STEPS` 封顶。 临近任何一个上限,先提醒模型一次。上限在运行发起时快照,恢复和接着跑沿用同一份:审批恢复时节点整个重放,上限一变,循环停的位置就和断点对不上。 下游结构化校验失败时,报错写明是上游哪个 agent 提前收了尾。agent 提前收尾时,时间线里也有一条提示写明原因。 agent 内部的工具审批不重复计费:审批恢复时节点重放,之前的模型调用和工具执行直接读断点里的结果(见[架构](architecture.md#选用-langgraph))。 ### 多 Agent 协作 `supervisor` 节点里,调度者按进展把任务分派给多个专家。它属于探索层能力,受管级发布禁用。 ![多 Agent 协作](../images/graph-supervisor.png) 协作团队的成员停不下来等人:需要确认的调用不执行,并告诉成员换一种做法。 ## 子工作流 `subgraph` 节点嵌套另一个工作流。 - 子工作流固定的版本须已发布且未退役。 - 子工作流里的每一步进同一个运行的事件流:时间线、记录页会出现「子工作流 › 那一步」;封存也包含子工作流查过的数。 - 子工作流出口的字段带着出处回到父图,父图的口径卡和报告能一路追到子工作流里的那一格,最多 3 层。子工作流里有追不到原始数据的,父图照样降档。 - 子工作流里的报告按带前缀的节点 id 记,父图只认自己的报告。 - 放在循环里多次执行时,每次的步骤接着编号。写外部系统的幂等键用父运行里的全局 id,所以循环每一轮的写入都照常发送。 ## 知识库、记忆与 Skill - **知识库**:向量 + BM25 混合检索、倒排索引、可选模型重排;能解析 PDF / Word / PowerPoint / HTML / Markdown。两种得分各自归一化后加权,权重在界面上可调,命中结果分别显示语义分和关键词分。为什么要混合、实测效果见[架构](architecture.md#为什么检索是混合的)。 - **向量模型**:默认是本地特征哈希,不联网、不下载模型、零配置,但语义泛化弱。可以接任意 OpenAI 兼容端点(LM Studio、Ollama、vLLM、TEI)。维度靠实际探测,不按模型名推断。 - **长期记忆**:跨运行读写,自动去重;助手建图时主动记录应当记住的事实。 - **Skill**:把方法论做成可复用的单元,挂到节点上,注入 system prompt。 Excel / CSV 作为数据源上传,会变成可以用 SQL 查的表;放进知识库只能被切块检索(见[数据源](data-sources.md#上传表格))。 ## 发布与版本 ### 发布级别 工作流有两个发布级别:已发布和受管。 - 发布出去的是不可变版本,按图哈希固定。发布后再改画布,不影响已发布版本。 - 以已发布级发布:搭建者以上。以受管级发布、把受管工作流降为已发布、让版本退役:只有管理员。 - 子工作流、口径卡固定的版本,须已发布且未退役。 - 受管级发布要通过治理检查:禁用 `supervisor`(全动态的协作属于探索层);方法卡必须钉版本;agent 不得关闭全部审批;`output` 必须配置出具契约;另有证据门禁 G1–G5。 ### 证据门禁 受管级别在治理检查之外加了证据门禁。门禁只看图和配置,让「每个数都点得开」在结构上成立: - **G1** 带契约的出口,成果字段的文字只能来自报告撰写节点。 - **G2** 模型写的文字不绕过报告撰写节点直接流进出口。 - **G3** 报告撰写节点写明 `numbers: strict`、`on_violation: fail`、`claims: require_citation`(或 `judge`,并写预算)。 - **G4** 口径卡的输入不来自计算角色的沙箱代码。 - **G5** 给口径卡供数的 agent 配 `output_schema` 并开 `cite_fields`。 受管级别下这些是错误,挡住发布;已发布级别只给警告。已经发布的版本照常运行,下次发布时按新规则检查。 ### 发布前检查与修复 - 打开发布弹窗就先跑一遍发布前检查(`POST /api/workflows/{id}/publish-check`,和真正发布同一套标准)。问题面板里平时也看得到。 - 修复(`/autofix`)分三类:答案唯一的,一键修复;要人拿主意的,给选项,不替人选;结构性的,交给助手。 - 一律先预览,不自动保存,也不自动发布。 - 降低要求的改动一律拒绝:删节点、删契约、放宽审批、关掉 strict、改级别。助手的方案也要过这一关。应用修复后重跑检查,错误必须变少,不能冒出新的。 - 老工作流一键升级为可追溯结构(`POST /api/copilot/upgrade-evidence`),过的也是这道检查(见[证据与出具](evidence.md#旧运行与一键升级))。 - 发布检查还会拦下:走不到结束的驳回路径;工具清单里有写入能力的 Agent 和多 Agent 协作。停在 Agent 半路审批的实例升级后无法继续,所以发布时 `process.wait_mid_agent` 会提醒。 ### 从探索到模板 - 画布试跑自动标记为探索运行,结果不进正式归档。 - 「提取模板」把跑通的路径沉淀为草稿:只保留实际执行的节点,剪掉没走的分支。人工审核后再发布。 - 探索问题聚类提示哪些追问应当固化为模板里的一节。 - 工具白名单衰减报表(`/api/governance/tool-usage`)列出「已授权但从未使用」的工具,作为收缩权限的依据。 ## 运行 ### 正式运行与探索运行 - 正式运行只从已发布、未退役的版本发起,进正式归档;画布试跑是探索运行。 - 每次运行记下来源(问数据、画布、定时任务、应用入口、外部系统……),写在 `run.origin` 事件里,在封存范围内。用访问密钥发起的,记下是哪把密钥。 - 写外部系统时,正式运行走生产环境,探索运行走测试环境(见[应用](apps.md#写外部系统))。 ### 断点续跑 - 失败的运行可以从失败节点继续,已完成的节点不重复执行。 - 探索运行允许修改节点配置后继续,但拓扑必须一致;正式运行固定在发布的版本上,不能改配置后继续。 - 继续运行不改发起人。 - 服务重启后(包括开发时改后端代码触发的热重载),正在跑的运行显示中断、断点完好:在运行详情页点「接着跑」,跑完的节点不会重跑,后面的人工审批照常停下来等人。 ### 时限与步数 - 单次执行(两次人工介入之间的那一段)默认最多 600 秒(`AGENTLAB_MAX_RUN_SECONDS`)。 - 单次模型调用默认 300 秒没有输出即超时(`AGENTLAB_MODEL_TIMEOUT_SECONDS`)。 - 图的步数上限是 `AGENTLAB_MAX_GRAPH_STEPS`(默认 200)。循环按自己 `max_iterations` 声明的轮数另算步数预算,不受这个上限约束。 - 当前值在「设置 → 运行环境」里看得到。 ### 运行记录与成本 - 全部事件落库,可以回放。 - 逐节点记耗时、token 用量和按目录价折算的成本。被取消、超时的模型调用也记一次调用,标「未完成」。 - 评测、口径对账、口径召回是系统代为发起的运行:证据照常可查,但不进使用统计(探索问题聚类、工具白名单、目录使用次数)。记录页默认不列它们,并写明有几次没列出。 - 运行详情页可以一键核对封存(见[证据与出具](evidence.md#封存与核对))。