---
title: 'Buzzword解读｜Graph engineering 比 workflow 多了什么？'
description: '从 Claude Code Dynamic Workflows 与 LangGraph 的运行机制出发，解释 Graph engineering 和 workflow 的真实边界，以及怎样系统地设计节点、状态、路由、异常与约束。'
pubDate: 2026-07-30
slug: graph-engineering-vs-workflow-constraints
tags: [agent, 工作流, 'graph engineering', Buzzword解读]
lang: zh-CN
draft: false
featured: false
showCTA: true
showComments: true
---

如果 workflow 已经可以包含分支、循环、并行和多个 Agent，为什么还要再造一个叫 Graph engineering 的词？

顺着这个问题继续想，很容易得到一个看似合理的答案：普通 workflow 由工程师写好，Graph engineering 则让 Agent 自己决定图，工程师只负责补上严苛约束，防止它失控。

这个理解已经摸到了“动态路径”和“约束”的重点，但还差两步。第一，图不一定由 Agent 决定；第二，工程师的工作也不只是列禁止事项。真正需要工程化的是一整个**执行空间**：有哪些节点，状态怎样流动，谁有权选择哪条边，失败后回到哪里，以及什么条件下必须停止。

> **数据快照**
>
> - 最后核验：2026-07-30
> - 术语来源：[LangChain，2026-07-22](https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph)
> - 主要实现参考：[Claude Code Dynamic Workflows，要求 v2.1.154 或更高版本](https://code.claude.com/docs/en/workflows)、[LangGraph v1 文档](https://docs.langchain.com/oss/python/langgraph/overview)
> - 比较边界：本文讨论的是 Agent 的**执行图与编排**，不是知识图谱（Knowledge Graph）

## 先说结论：人设计变化空间，Agent 只决定这一次怎样走

Graph engineering 不是 workflow 的反义词，也不是“让 Agent 自己画图”的简称。

更准确的理解是：

> **Workflow 描述任务怎样执行；Graph engineering 则把节点、边、状态、约束、失败恢复和评测一起当成可设计、可执行、可观察的工程对象。**

一个 Graph 可以完全固定，也可以只有路由由 Agent 决定，还可以让 Agent 在运行时生成部分子任务。无论动态到什么程度，外层通常仍有一张由工程师定义的“元图”：

- 允许创建哪些节点；
- 允许连接到哪里；
- 可以读取和修改哪些状态；
- 最多运行多少次；
- 什么时候必须验证、停止或交给人。

所以，把职责压缩成一句话就是：

> **工程师设计“允许怎样变化”，Agent 决定“这一次具体怎样走”，Runtime 保证“再怎么走也不能越界”。**

这里的 Runtime 不只是一段循环代码。它还可能包括 schema 校验、计数器、权限系统、沙箱、checkpoint、重试策略和人工审批。

## Graph engineering 是新概念，还是 workflow 换了名字

“Graph engineering”作为 Agent 圈的新说法确实很新。LangChain 在 2026 年 7 月 22 日的文章中直言，这个词来自社交媒体的又一轮命名热潮，带有 buzzword 成分；但它描述的问题真实存在：开发者需要在确定性路径和模型自主决策之间找到平衡。[LangChain 对它的定义](https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph)是把 Agent 系统表示为图，让构建者能够在需要时把行为限制在更明确的路径中。

图本身当然不新。DAG、状态机、工作流引擎、重试队列和人工审批早就存在。相对新的地方，是图里的一个节点现在可以不只是函数或单次 LLM 调用，而是一个带工具、记忆和内部循环的完整 Agent。LangChain 也把这点视为本轮讨论真正发生的变化。

用最小模型表示，一张 Agent 执行图包含四部分：

```text
Graph = Nodes + Edges + State + Runtime semantics
```

- Node 执行工作，可以是代码、工具、一次模型调用、完整 Agent 或人工节点。
- Edge 决定下一步，可以固定，也可以依据状态、模型判断或外部信号动态选择。
- State 保存跨节点共享的信息，并规定不同更新怎样合并。
- Runtime semantics 规定并发、重试、超时、checkpoint、恢复、权限和停止条件。

[LangGraph 的 Graph API](https://docs.langchain.com/oss/python/langgraph/graph-api)把 `State`、Node 和 Edge 暴露为一等公民，并通过 reducer 定义并行或连续更新怎样写回状态。但这只是显式图的一种实现。OpenAI 的 Agent 指南也区分了声明式 Graph 和 code-first 编排：前者预先定义节点和边，后者使用普通编程语言的分支、循环与函数表达同一套控制流。[显式 Graph API 和隐式代码图都成立](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/)，差别在表达与治理方式，不在有没有一张可视化画布。

## Workflow 和 Graph engineering 的差别不在“能不能分支”

Anthropic 在《[Building Effective AI Agents](https://www.anthropic.com/engineering/building-effective-agents)》中曾给出一个很窄但好用的区分：

- workflow 通过预定义代码路径编排 LLM 和工具；
- agent 由 LLM 动态决定自己的过程和工具使用。

但同一篇文章也把 routing、parallelization、orchestrator-workers 和 evaluator-optimizer 都列为 workflow。特别是 orchestrator-workers，子任务本来就是运行时由中央 LLM 动态拆出来的。可见 workflow 并不天然等于“线性固定步骤”。

Graph engineering 和 workflow 真正的差别，不是前者有分支、后者没有，而是观察角度不同。

**表 1：Workflow 与 Graph engineering 的概念对比；这是本文的分析性拆解，不是某个框架的官方术语表**

| 维度         | Workflow                            | Graph engineering                         |
| ------------ | ----------------------------------- | ----------------------------------------- |
| 主要问题     | 任务按什么顺序执行                  | 执行空间怎样设计和治理                    |
| 基本对象     | 步骤、条件、循环、并行任务          | 节点、边、状态、Runtime 语义              |
| 动态性       | 可以固定，也可以运行时变化          | 可以固定，也可以运行时变化                |
| Agent 的位置 | 可以没有 Agent，也可以由 Agent 编排 | Agent 可以是节点、路由器或子图生成器      |
| 状态         | 可能只是步骤间变量                  | 通常显式考虑 schema、写权限、合并和持久化 |
| 异常         | 常按任务或步骤处理                  | 还要定义失败类型、恢复边和停止边          |
| 质量         | 关注最终任务是否完成                | 同时关注节点、路由、状态转移和最终结果    |
| 产物         | 一段流程或可执行程序                | 图结构及其约束、状态契约、运行策略和评测  |

一条线性 workflow 本来就是路径图；带条件的 workflow 是 DAG 或状态机；带重试的 workflow 是有环图；一个 Agent 不断调用工具，则是一个循环子图。

因此，从 workflow 走向 Graph engineering，通常不是把现有流程推倒重来，而是把藏在代码和 Prompt 里的结构显式拿出来问：

- 这条边为什么存在？
- 谁能决定走这条边？
- 进入下一个节点之前，哪些条件必须成立？
- 两个并行节点同时修改状态时，结果怎样合并？
- 失败后重试当前节点、回到规划节点，还是直接结束？
- 这条路径怎样被测试和观察？

## Claude Code Dynamic Workflows 已经是一张隐式图

Claude Code 的 Dynamic Workflow 很适合解释“workflow 和 graph 并不对立”。

按照当前的[官方文档](https://code.claude.com/docs/en/workflows)，Claude 会先针对任务生成一段 JavaScript，之后由独立 Runtime 在后台执行。脚本中的 `agent()` 启动一个 subagent，`pipeline()` 按输入集合批量分发任务，中间结果保存在脚本变量中，而不是全部回到主对话上下文。

官方对这套设计的概括很直接：**把 plan 移进 code**。下一步运行什么，不再由主 Agent 每一轮临场判断，而由脚本控制。

下面是一段与官方示例同构的示意代码：

```javascript
const files = await agent('找出所有路由文件');

const findings = await pipeline(files, (file) => agent(`审查 ${file} 的鉴权问题`));

return findings.filter(Boolean);
```

**图 1：Dynamic Workflow 中的 `agent()`、`pipeline()` 与变量形成 fan-out / fan-in 隐式图**

```mermaid
flowchart LR
  S([开始：发现待审查文件]) --> A["发现文件"]
  A --> B1["审查 Agent 1"]
  A --> B2["审查 Agent 2"]
  A --> BN["审查 Agent N"]
  B1 --> C["汇总结果"]
  B2 --> C
  BN --> C --> E([结束：形成汇总结果])
```

图中没有 `add_node()` 或 `add_edge()`，但结构并没有消失：`agent()` 是节点，`pipeline()` 是动态 fan-out，等待所有结果是 fan-in，JavaScript 变量承担状态传递，`if` 和 `while` 则分别对应条件边与循环边。

**表 2：Claude Code Dynamic Workflow 元素到 Graph 元素的映射；依据 2026-07-30 核验的官方文档**

| Dynamic Workflow 元素 | Graph 视角                  |
| --------------------- | --------------------------- |
| `agent(prompt)`       | Agent 节点                  |
| `pipeline(items, fn)` | 运行时 fan-out              |
| 等待批量结果          | fan-in / join               |
| `if`                  | 条件边                      |
| `for`、`while`        | 循环边                      |
| JavaScript 变量       | 运行中的状态                |
| 汇总 Agent            | reducer 或 aggregation 节点 |
| workflow script       | code-first 的隐式图定义     |
| workflow runtime      | 图的执行器                  |

这说明 Dynamic Workflow 可以承载 Graph engineering，但不等于一套通用、持久的 Graph 平台。当前文档列出的边界包括：

- workflow 脚本不能直接访问文件系统或 Shell，实际操作由 subagent 完成；
- 单次运行最多并发 16 个 Agent，累计最多 1000 个；
- 除权限提示外，不支持普通用户在运行中输入；
- 暂停后的恢复只在同一个 Claude Code session 内有效，退出后需要重新开始。

这里可以得到一个分析性结论：

> **Claude Dynamic Workflow 是 code-first、agent-oriented 的隐式 Graph Runtime；它把编排从主上下文迁到了代码，但没有把状态 schema、跨 session 持久化和人工中断都提升为通用图原语。**

这不是说它“不完整”，而是适用目标不同。它优先解决的是本地大型任务的即时编排、上下文隔离和可复用脚本，不是运行几天甚至几个月的业务流程。

## 图不一定由 Agent 决定，它有三种常见动态程度

把“Graph engineering 等于 Agent 自己生成图”当成定义，会漏掉大量最常用的系统。

### 固定图：Agent 只在节点内部工作

**图 2：固定图中，Agent 只在预设节点内工作**

```mermaid
flowchart LR
  B([开始：接收输入]) --> I["输入"] --> S["搜索"] --> A["Agent 分析"] --> V["验证"] --> O["输出"] --> E([结束：交付输出])
```

节点和边全部由代码确定。Agent 可以负责“分析”节点，但没有权力跳过验证，也不能临时调用图外节点。这种图和传统 workflow 很接近，价值主要来自显式状态、恢复和观察。

### 动态路由图：Agent 在合法边中选一条

**图 3：分类 Agent 只能在工程师预定义的合法边中选择**

```mermaid
flowchart LR
  S([开始：接收输入]) --> I["输入"] --> C{"分类 Agent"}
  C -- "普通" --> A["普通分析"] --> O["输出"] --> E([结束：交付输出])
  C -- "高风险" --> R["高风险分析"] --> H["人工审批"] --> E
```

Agent 负责语义分类，但可以选择的路径仍由工程师预先定义。分类置信度过低时去哪里，也应当是一条明确的 fallback 边，而不是让 Agent 假装确定。

### 动态子图：Agent 决定本次创建多少工作

**图 4：Planner 动态实例化调查任务，但外层汇总与验证骨架固定**

```mermaid
flowchart LR
  S([开始：规划调查]) --> P["Planner"]
  P --> W1["调查任务 1"]
  P --> W2["调查任务 2"]
  P --> WN["调查任务 N"]
  W1 --> M["汇总"]
  W2 --> M
  WN --> M
  M --> V["验证"] --> O["输出"] --> E([结束：交付输出])
```

这里 N 和每个任务的内容由 Planner 根据输入决定，但外层仍有稳定骨架。LangGraph 使用 [`Send`](https://docs.langchain.com/oss/python/langgraph/graph-api#send) 支持这种运行时动态路由；Anthropic 的 orchestrator-workers workflow 也采用相同思想：子任务无法预先枚举，但“拆分—执行—汇总”的结构仍然已知。

**图 5：动态子图仍被固定元图包围，Planner 只能实例化允许出现的工作**

```mermaid
flowchart LR
  S([开始：接收输入]) --> I["输入"] --> P["Planner"]
  P --> W1["Worker 1"]
  P --> W2["Worker 2"]
  P --> WN["Worker N"]
  W1 --> M["证据汇总"]
  W2 --> M
  WN --> M
  M --> V{"Validator"}
  V -- "通过" --> O["输出"] --> E([结束：交付输出])
  V -- "证据不足" --> P
  V -- "高风险动作" --> H["人工审批"] --> E
```

这张图真正重要的不是 N 个 Worker，而是 Planner 的外边界：最大 Worker 数量、允许调用的工具、状态写入范围、回到 Planner 的次数，以及高风险动作不能绕过人工审批。

## 工程师不只提供约束，还要分配决策权

如果把工程师的工作概括成“提供约束”，容易只想到 `max_iterations: 3` 和“禁止删除生产数据”。这些当然重要，但 Graph engineering 至少还包含五类设计工作。

第一类是**任务分解**。哪些工作应该成为独立节点，哪些应该留在一个 Agent 的内部循环？节点过粗，状态和失败难以观察；节点过细，编排成本又会吞掉收益。

第二类是**状态契约**。节点读什么、写什么，原始证据是否只可追加，并行更新怎样去重，冲突结论能不能互相覆盖。LangGraph 用 State schema 和 reducer 处理这类问题；即使不用 LangGraph，也需要在自己的数据结构中回答同样的问题。

第三类是**决策权分配**。格式是否正确适合交给 schema；数值是否超过阈值适合交给代码；证据是否相关可以交给 Judge；是否允许生产写入必须由权限系统或人决定。不是每一条边都应该让模型投票。

第四类是**失败语义**。API 超时、Agent 返回非法 JSON、证据冲突和权限不足，虽然都叫“失败”，但恢复路径完全不同。Graph engineering 要把这些路径设计出来，而不是只写一个笼统的 retry。

第五类是**观察与评测**。最终报告通过不代表路由合理；某个节点正确也不代表整条路径成本可接受。需要分别观察节点输出、实际路径、状态变化、重试次数和最终任务成功率。

所以，约束只是其中一部分。更完整的说法是：

> **工程师负责把业务目标变成一组可执行的职责、状态、决策权、失败语义和验收标准。**

## 约束不是靠灵感罗列，而是从图的五个切面推出来

面对一张新图，试图一次性想全所有异常几乎不可能。更实用的办法是先画最小图，再逐项检查 Node、Edge、State、Runtime 和 Completion。

约束又可以分为两种目的：

- 防失控约束：避免越权、死循环、成本爆炸和不可逆破坏。
- 保质量约束：规定什么情况下才允许继续或完成。

前者回答“不能出什么事”，后者回答“什么才算做对”。只做前者，系统可能安全地输出废话；只做后者，系统可能为了得到好结果而无限重试。

**表 3：从 Graph 的五个切面盘点约束；问题栏可以直接用作设计评审清单**

| 切面           | 需要回答的问题                                         | 约束示例                                           |
| -------------- | ------------------------------------------------------ | -------------------------------------------------- |
| Node           | 职责是什么？输入前提是什么？能读写什么？怎样算完成？   | 日志节点只写 `log_evidence`；缺少服务名则拒绝运行  |
| Edge           | 谁决定路由？进入条件是什么？失败后去哪？最多回来几次？ | 覆盖率低于 0.8 返回补查；最多回到 Planner 两次     |
| State          | 数据从哪里来？谁能覆盖？并行结果怎样合并？是否持久化？ | 原始证据只追加；冲突结论同时保留                   |
| Runtime / Tool | 超时、重试、并发、预算和权限怎样限制？                 | 最多 5 个并行 Agent；生产工具默认只读              |
| Completion     | 什么条件下才能结束？何时必须承认不确定？               | 严重发现必须附证据；关键来源不可用时不得给确定结论 |

### 用失败模式反推遗漏的约束

完成五个切面的第一轮盘点后，再问一句：**每个节点最可能怎样失败？**

可以使用一个简化版 FMEA（Failure Mode and Effects Analysis，失效模式与影响分析）。不必追求复杂评分，先把失败、后果、发现方式和恢复路径连起来。

**表 4：代码审查 Agent Graph 的简化失败模式表；场景为多文件鉴权审计**

| 对象       | 失败模式                 | 后果               | 如何发现             | 预防约束                   | 失败后处理             |
| ---------- | ------------------------ | ------------------ | -------------------- | -------------------------- | ---------------------- |
| Planner    | 拆出过多文件任务         | Token 与耗时失控   | 监控任务数和预计成本 | 最多 20 个任务，超出时分批 | 合并低风险目录         |
| 审查 Agent | 没读项目规则就下结论     | 大量误报           | 检查输出中的规则来源 | 输入必须包含生效的项目规则 | 退回重审               |
| 汇总节点   | 用后一条结论覆盖前一条   | 冲突证据丢失       | 检查 evidence ID     | 原始证据 append-only       | 标记冲突并进入复核     |
| Validator  | 同模型投票形成一致性幻觉 | 错误结论被多数通过 | 对照测试或源码证据   | 高风险项必须有确定性证据   | 降级为“未验证”         |
| 整张图     | 验证失败后无限循环       | 资源耗尽           | iteration counter    | 最多重规划两次             | 输出部分结果与不确定项 |

这张表会自然生成约束。比如发现“状态覆盖导致证据丢失”，约束就不该写成“汇总 Agent 应谨慎”，而应该把原始证据字段设计为只追加，并由 reducer 或存储层拒绝覆盖。

## 一条约束要写成可执行的五元组

“Agent 应谨慎使用生产工具”不算可执行约束。它没有说明什么时候算生产操作，也没有说明违反后由谁阻断。

一条完整约束至少包含：

```text
适用范围 + 触发条件 + 必须行为 + 违反后处理 + 强制执行者
```

例如：

```yaml
id: TOOL-007

scope:
  node: remediation-agent
  tool: rollback

condition:
  environment: production

required_behavior:
  - generate_dry_run_plan
  - obtain_human_approval

on_violation:
  action: deny_tool_call

enforcement:
  mechanism: runtime_permission_gate
```

这条规则可以被测试：构造一个没有 approval ID 的生产回滚请求，确认 Runtime 会拒绝，而不是观察 Agent 有没有“记得谨慎”。

### 约束必须放到真正能执行它的层

不是所有规则都应该写进 Prompt。Prompt 可以影响模型行为，却不是可靠的权限边界。

**表 5：约束类型与适合的执行层；越接近不可逆副作用，越不能只依赖模型遵守**

| 约束类型         | 适合的执行层          | 示例                       |
| ---------------- | --------------------- | -------------------------- |
| 操作方法与偏好   | Prompt、Skill         | 先读取项目规则，再审查代码 |
| 输出结构         | JSON Schema、类型系统 | 每条发现必须包含文件和证据 |
| 数量、阈值、预算 | Runtime 计数器与代码  | 最多重规划两次             |
| 状态合并         | reducer、数据库约束   | 原始证据只追加             |
| 工具与资源权限   | IAM、沙箱、allowlist  | 禁止 Agent 写生产数据库    |
| 语义质量         | Judge、Verifier       | 证据是否真正支持结论       |
| 高风险决策       | Human gate            | 发布、回滚、删除           |

这里有一条很朴素的原则：

> **能用代码判断，就不要交给模型；能用权限系统阻断，就不要只在 Prompt 中提醒。**

Agent 可以为当前任务生成局部软约束，例如“至少检查鉴权、输入校验和权限继承三条证据链”，也可以在证据不足时建议扩大搜索。但它不能自行提高预算、放宽工具权限，或取消原本要求的人工审批。执行者不能同时成为规则制定者和最终裁判。

## 从最小约束集开始，再让失败轨迹补全它

约束不可能在第一次设计时全部列完。它通常来自四个地方：

1. 业务规则和不可违反的红线；
2. 系统架构与工具本身的限制；
3. 已知事故、失败案例和人工复盘；
4. Eval、红队测试和真实运行轨迹中暴露的新问题。

因此，Graph engineering 不是写完一份 YAML 就结束，而是一个持续循环：

**图 6：失败轨迹推动约束、恢复边与回归用例持续演化**

```mermaid
flowchart LR
  A["设计最小图与最小约束"] --> B["运行 Eval"]
  B --> C["观察失败路径"]
  C --> D["归类失败模式"]
  D --> E["增加约束或恢复边"]
  E --> F["增加回归用例"]
  F --> B
```

每新增一条约束，最好同时新增一个能触发它的测试。否则它很容易从“系统保证”退化成“文档里写过”。

实际落地时，可以先给每个节点填一张八问卡：

```text
1. 这个节点只负责什么？
2. 运行前必须具备什么？
3. 可以读取什么？
4. 可以修改什么？
5. 输出 schema 是什么？
6. 最可能怎样失败？
7. 失败后走哪条边？
8. 谁来验证它成功？
```

然后再为整张图补七个问题：

```text
1. 最多运行多久？
2. 最多循环和重规划几次？
3. Agent 可以创建或调用哪些节点？
4. 哪些动作必须人工批准？
5. 什么条件下算完成？
6. 什么条件下必须承认“不确定”？
7. 如何 checkpoint、恢复和审计？
```

这 15 个问题不会覆盖所有生产异常，但足以把“凭感觉编排”推进到可测试的第一版。

## 什么时候不要做 Graph engineering

Graph engineering 最大的风险不是图不够复杂，而是图太复杂。

如果任务只有两三个固定步骤，一个 Agent 加清晰工具已经能稳定完成，或者失败后整体重跑的成本很低，那么显式设计大量节点、状态字段和恢复边只会增加调试负担。

[LangChain 在介绍 Graph engineering 时也明确提醒](https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph)，有些任务天生更开放，把它们强行塞进确定性路径反而不合适。[Anthropic 的建议](https://www.anthropic.com/engineering/building-effective-agents)更直接：从能工作的最简单方案开始，只有当复杂性可以证明改善结果时，才增加多步 Agent 系统。

可以用下面几个信号判断是否值得升级：

- Prompt 已经塞满跨阶段的 `if/else` 和重复状态说明；
- 不同失败类型需要不同恢复路径；
- 有明显的并行收集、汇聚和交叉验证；
- 任务需要暂停、恢复或人工审批；
- 必须限制 Agent 的工具、预算和状态写入；
- 只看最终答案已经无法定位质量问题；
- 同一套编排需要长期复用和回归测试。

如果这些问题都不存在，普通 workflow 甚至单 Agent loop 通常已经够用。

## 总结

Workflow 和 Graph engineering 不是新旧替代关系。很多 workflow 本来就是图，只是图结构藏在 JavaScript、Python、YAML 或主 Agent 的临场决策里。

Graph engineering 真正增加的，是把这些隐含问题变成显式工程对象：节点职责、合法边、状态契约、决策权、失败恢复、资源边界和验收标准。Agent 可以选择路径，也可以动态生成部分工作，但它的自主性应该发生在工程师定义的执行空间内。

所以，工程师并不只是“提供约束”。工程师要先决定哪些地方值得让模型判断，哪些地方必须由代码判断，哪些副作用必须由 Runtime 或人阻断。约束只是这套决策分工的可执行表达。

下一次设计 Agent workflow 时，不妨先别急着画一张更大的图。先给每个节点填完八问卡，再给整张图补上预算、停止、不确定性和人工审批。能回答这些问题，才算真正从“流程能跑”走到了“系统可控”。

## 参考资料

- [LangChain：3 Years of Graph Engineering with LangGraph，2026-07-22](https://www.langchain.com/blog/3-years-of-graph-engineering-with-langgraph)
- [LangGraph：Graph API overview](https://docs.langchain.com/oss/python/langgraph/graph-api)
- [LangGraph：Persistence](https://docs.langchain.com/oss/python/langgraph/persistence)
- [LangGraph：Interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts)
- [Anthropic：Building Effective AI Agents](https://www.anthropic.com/engineering/building-effective-agents)
- [Claude Code：Orchestrate subagents at scale with dynamic workflows](https://code.claude.com/docs/en/workflows)
- [OpenAI：A practical guide to building agents](https://openai.com/business/guides-and-resources/a-practical-guide-to-building-ai-agents/)
