博客
架构

发布于 更新于

Arag 和 Shouryamaan

如何为长期运行的 AI Agent 构建持久状态

以 Markdown 阅读

持久 agent 状态是一份结构化记录,让新的 worker 无需重复已经完成的工作,也无需从聊天记录中猜测,就能恢复任务。它应标识当前步骤、已完成操作、待处理信号、重试状态和下一个合法状态转换。

状态不同于记忆、业务数据、产物和审计历史。将五类信息都当作向量存储中的一份文档,会导致恢复结果不明确,也增加访问控制难度。

区分五类存储信息

类型 回答的问题 常见存储位置
工作流状态 当前运行到哪里,下一步可以发生什么? 关系型数据行或工作流引擎
业务状态 订单、客户或部署的实际情况是什么? 权威应用数据库或提供商
记忆 哪些以往上下文可能帮助未来决策? 关系型记录、搜索索引或向量存储
产物 生成的文件、报告或代码 bundle 在哪里? 带元数据的对象存储
审计记录 谁在何时决定并执行了什么? Append-only 事件表或审计表

发票状态属于业务状态。工作流正在等待财务审批属于工作流状态。客户偏好摘要可以属于记忆。PDF 属于对象存储。审批决定则属于审计记录。

更全面的 agent 架构指南展示了这些存储如何与工具和持久执行连接。

存储状态机,而不是文字摘要

使用明确的状态和允许的转换:

stateDiagram-v2
    [*] --> Created
    Created --> Running
    Running --> WaitingForApproval
    WaitingForApproval --> Running: approved
    WaitingForApproval --> Cancelled: rejected or expired
    Running --> RetryScheduled: retryable failure
    RetryScheduled --> Running
    Running --> Completed
    Running --> Failed

任务行可以保存 state、state_version、current_step、attempt、wake_at、approval_id 和时间戳。已经完成的外部影响应通过操作记录引用,而不是以内嵌的模型自由文本保存。

在代码中定义合法状态转换,并拒绝过期更新。模型可以建议转换,但状态层应该决定在没有审批记录时,waiting_for_approval 能否变为 completed。

让并发 worker 安全地发生冲突

队列可能重复投递,lease 可能过期,较慢的 worker 也可能在另一个 worker 恢复相同任务后才完成。可以通过版本字段实现乐观并发控制,也可以使用包含所有者和过期时间的 lease。更新状态时应带上读取到的版本;如果另一个 worker 已经推进任务,则更新失败。

Lease 应与工作流状态分开。Worker 崩溃后应失去 lease,而不应将任务改为失败。下一个 worker 可以取得 lease、读取持久化状态并继续执行。

围绕外部影响建立检查点

写入前持久化意图,验证完成后持久化结果。如果超时导致结果未知,应转入 reconciling 等状态,而不是假定步骤已经失败。

持久执行指南详细介绍了幂等性和结果核对。状态存储的职责是保存操作引用,并在结果未确认时阻止不安全的状态转换。

将人工等待持久化为一等记录

审批记录应包含确切操作、资源、请求的权限范围、请求人、审批人、过期时间、决定和策略版本。工作流在数小时后恢复时,应再次确认审批适用于当前参数,而且其代表的用户仍有访问权限。

不要让服务器进程在等待期间保持休眠。应持久化等待条件,再由信号或计划任务将下一次状态转换加入队列。Temporal 的持久执行模型使用事件历史和信号处理这类等待,但同样的设计也可以通过数据库和队列实现。

让状态升级不阻断旧任务

长期运行的任务可能跨越多次部署。应保存工作流定义版本,并为活跃状态设计迁移。新的 worker 需要知道它能否读取旧 payload、迁移旧 payload,或继续使用旧处理程序。

避免将完整模型上下文放入一个没有版本信息的 JSON blob。JSON 适合各步骤特有的 payload,但用于调度、授权、数据保留和操作的稳定字段应该显式定义并建立索引。

为每条记录制定保留规则

工作流完成后可以压缩其状态。审计记录可能需要保留更长时间。记忆应支持纠正和删除。产物需要过期时间和所有权元数据。业务数据则遵循产品自身策略。

删除必须覆盖所有引用。只删除用户记忆,却在提示词、链路追踪和产物中留下相同个人数据,并不算完整删除。应保存引用和分类,让清理路径能够找到每份副本。

使用空白进程测试恢复

分别在等待审批、提供商调用完成后,以及重试退避期间停止 worker。使用没有本地缓存或对话对象的进程恢复,确保它能从持久化状态和权威后端记录中推导出下一步操作。

下方的提示词会先执行盘点,再提出改动建议。任何只存在于日志行或提示词中的必要事实,都是明确的持久化缺口。