Agent AtlasAI Agent 知识库
03.06架构模式 · Architecture

工作流、状态机与图编排

用确定性骨架包住不确定的模型:节点、边、检查点、重试、人工审批与持久化执行。

把 Agent 的不确定性关进确定性的笼子里:外层流程可预测,内层判断交给模型。这就是生产系统最常见的样子。

为什么需要编排

一个 while 循环能跑通 Demo,但很难处理:

  • 任务需要运行几十分钟,进程重启怎么办?
  • 某一步失败,只重跑这一步,还是整个流程?
  • 需要人工审批,审批可能隔天才回来;
  • 多个分支、并行、汇合;
  • 出问题时要看到完整路径。

这些是工作流引擎要解决的问题。图编排把流程显式建模为状态、节点和边,让系统可以在任意一步暂停、恢复、重试和观测。

图的基本元素

图 1 · 一个带审批的图
classify分类
→
retrieve检索
→
draftAgent 草拟
→
validate校验
→
approve人工
→
send发送
validate 失败回到 draft;approve 拒绝回到 draft 或结束。每个节点都有超时、重试和 trace。
  • State:整个流程共享的数据结构;
  • Node:一个执行单元,可以是模型调用、工具、纯函数、人工等待;
  • Edge:固定的下一步;
  • Conditional Edge:根据状态选择分支;
  • Checkpoint:每一步后的状态快照;
  • Interrupt:暂停等待外部输入(人工审批、异步回调)。

State 设计:只放必要的、可序列化的数据

python
from typing import TypedDict, Literal, Annotated
import operator

class State(TypedDict):
    task_id: str
    goal: str
    category: Literal["billing", "technical", "refund", "other"]
    messages: Annotated[list, operator.add]   # 只追加
    evidence: list[dict]                       # 带来源的事实
    draft: str | None
    approved: bool | None
    attempts: int
    errors: Annotated[list[dict], operator.add]
    trace_id: str

原则:

  • 可序列化:能存 JSON,才能做检查点;
  • 显式:不要依赖闭包或全局变量;
  • 增量更新:用 reducer 定义「追加」还是「覆盖」,避免并发写冲突;
  • 有版本:State Schema 变更时,旧检查点要能迁移或标记不可恢复。

检查点与持久化执行

每一步执行后保存状态:

text
checkpoint = {
  "task_id": "...",
  "node": "draft",
  "state": {...},
  "created_at": "...",
  "attempt": 2
}

恢复时:

  1. 读取最新 checkpoint;
  2. 确认该节点的副作用是否已发生(幂等键);
  3. 从下一个节点继续,而不是从头重跑。

这让长任务可以跨进程、跨重启、跨天运行。也是人工审批能挂起的前提。

检查点不等于事务

如果节点内调用了外部 API 并成功,但在写 checkpoint 前崩溃,恢复时可能重复调用。写操作必须用幂等键,或先记录「意图」再执行。

人工介入:Interrupt 的正确姿势

错误做法:在 Agent 循环里 input() 等待,进程一直挂着。

正确做法:把人工审批建模为一个节点:

python
def approval_node(state):
    if state.get("approved") is not None:
        return state  # 已恢复
    raise Interrupt({
        "type": "approval",
        "summary": state["draft"][:500],
        "action": "send_email",
        "risk": "对外发送,不可撤回",
        "options": ["approve", "reject", "edit"],
    })

流程挂起,状态落库。审批者在前端看到摘要、动作、影响范围,选择后通过 API 恢复执行。

审批界面要展示:

  • 将要发生什么(动作、参数、目标);
  • 为什么(触发规则、模型理由);
  • 影响范围(金额、收件人、不可逆性);
  • 可选项(批准、拒绝、修改后批准)。

只给一个「同意」按钮,等于让人盲目签字。

重试、超时与幂等

每个节点独立配置:

配置说明
timeout单节点最长执行时间
max_retries重试次数,指数退避
retry_on只对暂时性错误重试(超时、429、5xx)
idempotency_key写操作去重
fallback重试耗尽后的降级路径

不要对整个流程统一重试。一个 10 步的流程从头重跑,可能重复发送 3 封邮件。应该只重跑失败节点,并保证副作用幂等。

一个最小图实现

不依赖框架也可以写得很清楚:

python
NODES = {
    "classify": classify,
    "retrieve": retrieve,
    "draft": draft,
    "validate": validate,
    "approve": approve,
    "send": send,
}

def run_graph(state, start="classify", max_steps=20):
    node = start
    for _ in range(max_steps):
        save_checkpoint(state, node)
        handler = NODES[node]
        try:
            state = handler(state)
        except Interrupt as it:
            state["interrupt"] = it.payload
            save_checkpoint(state, node)
            return state  # 等待外部恢复
        except RetryableError as e:
            state = retry_or_fallback(state, node, e)

        node = route(node, state)
        if node == "END":
            break

    return state


def route(node, state):
    if node == "classify":
        return "retrieve" if state["category"] != "other" else "draft"
    if node == "validate":
        return "draft" if not state["valid"] and state["attempts"] < 2 else "approve"
    if node == "approve":
        return "send" if state["approved"] else "draft"
    if node == "send":
        return "END"
    return NEXT[node]

真实框架(LangGraph、Temporal、Cloudflare Workflows 等)会替你处理持久化、并发、可视化和恢复。但理解这些原语,才能判断框架是否适合。

图编排 vs 直接写代码

场景直接写代码图编排
3–5 步、无持久化✓ 更简单过度设计
需要人工审批难✓
长任务、可恢复难✓
多分支、并行一般✓
需要可视化无✓
团队非工程师维护难✓(低代码平台)
极致性能✓有调度开销

一个实用判断:如果你需要「暂停后继续」,就需要编排。 否则普通函数 + 队列可能更简单。

测试图

图的最大好处是可测试。至少覆盖:

  1. 节点单测:给定 state,输出是否符合预期;
  2. 路径测试:分类为 refund 时是否走审批;validate 失败是否回到 draft;
  3. 恢复测试:在 approve 前杀掉进程,能否从检查点恢复;
  4. 幂等测试:重复执行 send,是否只发一封;
  5. 超时测试:某节点卡住,是否按策略降级。

这些测试不需要真实模型——用固定输出的 fake model 即可。模型质量用评估集测,流程正确性用单元测试测,两者分开。

反模式

把整个 Agent 塞进一个节点

「agent_node」里跑 20 步循环,外层图形同虚设。应该把关键步骤拆成节点,让流程可见、可恢复。

状态里放原始大对象

把 50MB 的 PDF 放进 state,检查点写入爆炸。存引用(URL/ID),用时再取。

所有节点共享一个超时

检索需要 5 秒,人工审批需要 2 天。超时必须按节点配置。

审批信息不足

只显示「是否批准退款」,不显示金额、订单、政策依据。审批者无法做判断,只能盲签。

忽略版本迁移

State Schema 改了,旧检查点恢复失败。上线前考虑兼容或清理策略。

检查清单

  • 流程有显式状态,且可序列化
  • 每个节点有超时、重试策略、错误分类
  • 写操作幂等,检查点与副作用一致
  • 人工审批是节点,不是阻塞等待
  • 审批界面展示动作、参数、影响、不可逆性
  • 能从任意检查点恢复
  • 关键路径有单元测试与恢复测试
  • 全链路 trace 与节点级指标

小结

  • 图编排把流程显式化,换来可恢复、可审批、可观测。
  • State 要可序列化、显式、带 reducer 和版本。
  • 检查点让长任务跨进程、跨天运行,但副作用仍需幂等。
  • 人工审批应建模为可挂起的节点,并展示足够上下文。
  • 短流程直接写代码,需要暂停/恢复时再上图。

下一篇进入记忆:Agent 如何跨步骤、跨会话记住该记的,忘掉该忘的。

读完了?进度会保存在本地浏览器。
内容会持续修订。发现错误或想补充,欢迎反馈。 遇到问题?查排查手册 →