Skip to content

Agent 与 Workflow 如何协作?状态应该由谁保存 ​

内容摘要:不是所有事都该交给模型决定。本章讲确定性工作流与模型驱动决策的边界,介绍状态机、有向无环图(DAG)、事件驱动三种编排模型,以及 Agent 状态的持久化与恢复——这是长任务与故障恢复的基础。 难度:进阶 | 前置知识:08 Agent Loop

常见误区

对话历史就是 Agent 的完整状态;进程重启后把 messages 重新发给模型,就能可靠地从断点继续。

先给结论 ​

生产系统通常用确定性 Workflow 管理关键状态转换,只把无法穷举的局部决策交给模型。任务阶段、工具结果、审批和副作用必须进入显式状态与 Checkpoint,不能只存在自然语言历史中。

带着这三个问题阅读:

  1. 状态机、DAG 与事件驱动编排分别解决什么问题?
  2. 对话上下文、业务状态和执行 Checkpoint 有何区别?
  3. 恢复任务时如何避免重复执行已经成功的副作用?

一、确定性 vs 模型驱动:先划边界 ​

原则:能确定的就确定。把流程骨架写成确定性工作流,只在真正需要判断的节点交给模型。这样更可测、更可控、更便宜。很多"Agent 项目"其实是"工作流 + 几个模型节点"。

二、三种编排模型 ​

模型结构适合说明
状态机(State Machine)状态 + 转移有明确阶段、需审批暂停易表达"等待人工"等停顿
有向无环图(DAG)无环任务依赖批处理、并行、无循环天然并行,不能表达循环
事件驱动(Event-driven)事件 + 处理器异步、长任务、解耦扩展性好,调试更难

Agent 常把三者组合:外层状态机管阶段、某阶段内用 DAG 并行检索、跨阶段用事件解耦。

三、状态:Agent 的事实来源 ​

把状态设计成显式、可序列化的结构,节点之间只通过状态通信,不用隐式全局变量:

python
from dataclasses import dataclass, field, asdict
from typing import Literal
import json

@dataclass
class AgentState:
    task_id: str
    goal: str
    phase: Literal["planning", "gathering", "await_approval", "executing", "done", "failed"] = "planning"
    findings: list[str] = field(default_factory=list)
    pending_action: dict | None = None      # 待审批的高危动作
    approved: bool = False
    version: int = 1                         # Schema 版本,便于迁移

    def to_json(self) -> str:
        return json.dumps(asdict(self), ensure_ascii=False)

    @classmethod
    def from_json(cls, s: str) -> "AgentState":
        return cls(**json.loads(s))

状态分层(务必分开存,不要混成一坨):

  • 当前请求上下文(临时)
  • 任务状态(本表,需持久化)
  • 会话历史(可摘要,10)
  • 业务事实/用户偏好(长期记忆,10)

四、持久化与恢复(Checkpoint) ​

长任务、需要暂停/审批的任务,必须把状态持久化到可靠存储,进程重启后能恢复:

python
class CheckpointStore:
    """最小 Checkpoint 接口。生产用 Postgres/Redis 等,示例用内存。"""
    def __init__(self):
        self._data: dict[str, str] = {}
    def save(self, state: AgentState) -> None:
        self._data[state.task_id] = state.to_json()
    def load(self, task_id: str) -> AgentState | None:
        raw = self._data.get(task_id)
        return AgentState.from_json(raw) if raw else None

# 恢复即"读最近状态 + 从对应 phase 继续"
store = CheckpointStore()
store.save(AgentState(task_id="t1", goal="排查慢查询", phase="gathering"))
resumed = store.load("t1")
assert resumed and resumed.phase == "gathering"

幂等要点:恢复后可能重放某个节点,写操作节点必须用幂等键防重复(15)。

五、失败路径 ​

  • 状态藏在内存/全局变量:进程一挂就全丢,无法恢复。
  • 状态 Schema 变更不兼容:升级后旧 checkpoint 反序列化失败——用 version 字段做迁移或失效策略。
  • 恢复后重复写:无幂等键导致重复创建工单/重复扣款。

六、测试与验证 ​

  • 测"崩溃-恢复":保存到某 phase,重建对象从 checkpoint 恢复,断言不重复执行已完成节点。
  • 测状态迁移:旧版本 JSON 能否被新代码安全加载或明确拒绝。

七、安全与权限 ​

  • 持久化状态可能含敏感信息,需加密/脱敏与访问控制。
  • await_approval 阶段的高危动作在获批前不得执行(13)。

八、性能与成本 ​

  • Checkpoint 频率是权衡:太频繁增加 IO,太稀疏丢进度。按节点边界保存通常合适。

九、框架差异 ​

  • LangGraph(1.0)以"状态图 + 持久化 checkpoint + interrupt 人工审批"为核心卖点;langgraph.prebuilt 的能力在 1.0 后迁入 langchain.agents。LlamaIndex 用事件驱动 Workflows。选型见 20。

十、关联章节 ​

面试复述 ​

Workflow 决定可预测的主路径,Agent 处理局部动态决策;显式状态才是事实来源。恢复时应读取 Checkpoint 和幂等记录,而不是让模型从对话文本猜测进度。

复述时先给结论,再补机制、适用边界和一个可验证指标;不要只罗列框架名称或产品功能。

迁移练习 ​

把一个三步 Agent 任务改写为显式状态机,列出每个状态的进入条件、可执行动作、持久化字段和恢复位置。

检索关键词 ​

确定性工作流 vs Agent 状态机 DAG 事件驱动 Agent 状态持久化 Checkpoint 恢复 状态 Schema 版本 幂等恢复

官方来源 ​

  • LangGraph 持久化/中断文档;工作流引擎(如 Temporal)文档作为工程对照(verified_at: 2026-09-07)。

ICP 备案号待补充 · Gitee 主页