Agent 长任务如何实现断点续跑?从 Temporal 持久化到人工审批卡点
·

为什么 Agent 长任务需要「可恢复」设计?
开发过自动化工作流的工程师都遇到过这类问题:一个需要调用 5 个 API、执行 20 分钟的任务在第 4 步失败后,是重头开始还是从断点继续?当业务方中途提出需求变更时,如何迁移已有状态?这些场景暴露了传统线性脚本的致命缺陷——缺乏持久化与恢复机制。
以某电商价格同步 Agent 为例:当同步 1000 个 SKU 时若在第 723 个中断,重跑全量将浪费 72% 的计算资源。更糟的是,若部分 SKU 已在第一次运行时修改过外部系统状态(如触发库存预警),重复执行可能导致业务异常。
核心问题拆解
Q1: 状态机应该先画给运行时还是开发者看?
- 正解:先为运行时设计可序列化的状态表示,再反向生成可视化图表。常见反例是先用绘图工具画漂亮的状态图,却无法映射到代码中的持久化字段。
- Temporal 实践:其
WorkflowState自动持久化所有变量变更,开发者只需关注业务逻辑。例如 QClaw 的工单处理 Agent 将每个审批节点状态存储为{stage: 'manager_approval', artifacts: {doc_url: 's3://...'}}的 JSON 结构。 - 落地步骤:
- 定义任务阶段枚举(如
['data_fetch', 'preprocess', 'approval', 'push']) - 为每个阶段设计输入输出 artifact 的存储路径规范(如
s3://bucket/${workflow_id}/artifacts/${stage}.json) - 使用 Temporal 的
continueAsNewAPI 实现阶段间状态迁移
Q2: 人工审批如何插入异步工作流?
- 方案:在 Temporal 中通过
await暂停执行,直到外部信号触发:// 在 Workflow 定义中插入审批卡点 await context.sleep(24h); // 最长等待时间 const approved = yield context.waitForSignal('approval_result'); if (!approved) throw new Error('Approval rejected'); - 观测要点:
- 记录审批等待耗时(Prometheus 指标
approval_wait_seconds)和拒绝率 - 为审批超时配置分级告警(如 1h 提醒负责人,4h 触发备审人)
- 审批界面需展示当前阶段的所有输入 artifact(如自动生成的报告链接)
- 反模式:
- 将审批状态存储在独立数据库,导致与工作流状态不同步
- 未设置超时自动拒绝策略,造成僵尸任务
Q3: 如何验证故障恢复能力?
- 混沌测试清单:
- 随机终止 Worker 进程(模拟节点崩溃)
- 注入第三方 API 500 错误(持续 2 分钟后恢复)
- 修改持久化状态中的关键字段(测试版本兼容性)
- 关键指标:
- 恢复后应继续产生相同最终结果(幂等性)
- 不会重复执行已成功步骤(需验证日志中
skip_already_done_stage标记) - 人工干预后状态变更能正确传播(如审批通过信号到达延迟 <5s)
持久化技术的选型边界
| 方案 | 适合场景 | 风险点 | 恢复验证方法 |
|---|---|---|---|
| Temporal Checkpoint | 需要强一致性的金融场景 | 学习曲线陡峭 | 检查 History 事件是否连续 |
| LangGraph 状态快照 | 实验性 ML 流水线 | 缺乏人工干预接口 | 对比两次执行的中间结果哈希 |
| 自定义 Redis 存储 | 简单工作流快速迭代 | 需自行处理版本迁移 | 强制触发 AOF 日志回放 |
典型问题排查指南
症状:任务恢复后重复发送邮件 - 检查: 1. 邮件服务是否实现幂等(如 Message-Id 去重) 2. 工作流是否在发送后更新了阶段状态 3. 重试时是否携带了原始请求 ID
症状:审批超时未触发备审人 - 检查: 1. Temporal Worker 是否订阅了超时事件队列 2. 备审人配置是否已持久化(非内存缓存) 3. 时钟漂移是否导致时间判断错误
TL;DR
- 长任务状态机应以机器可序列化为第一优先级,可视化展示为衍生需求
- 人工卡点需要显式超时控制和审批结果路由(如 Slack 交互式消息)
- 通过注入网络分区、进程崩溃等故障验证恢复逻辑的完备性
- 所有外部调用必须实现幂等,并通过 artifact 路径规范避免状态污染
更多推荐




所有评论(0)