设计可靠的智能体工作流

让长任务经得起现实折腾:幂等性、检查点、可恢复性,以及显式的失败状态。

advanced · Claude / GPT-5 / DeepSeek
#工作流#可靠性#编排

假设进程随时会死

长时工作流一定会被打断:网络抖动、限流、容器重启、用户合上笔记本。从一开始就为中断而设计,因为给一段线性脚本后补可恢复能力等于重写。

每个步骤都要问的核心问题:如果此刻崩溃,重试时会发生什么?

幂等让重试变安全

一个操作跑两次等于跑一次,就是幂等。正是这一条性质让重试从危险变成安全。

不幂等改造成幂等
create_report(id)create_report(id, dedupe_key=task_id)
append_row(...)upsert_row(row_id, ...)
send_email(to, body)send_email(idempotency_key=hash(to+body+date))
increment_counter()set_counter(computed_value)

幂等键要从任务本身确定性推导,不能用随机数——随机就失去意义了。

检查点:把状态写到上下文之外

每完成一个有意义的步骤就把进展写入持久化存储,而不是留在模型记忆里:

run-2026-10-16-a1/
├── manifest.json     # 输入、任务 ID、开始时间
├── steps/
│   ├── 01-extract.json   # 状态、产物指针、耗时
│   ├── 02-transform.json
│   └── 03-review.json
└── artifacts/

恢复时读 manifest,找到第一个未完成的步骤,从那里继续。已完成的步骤应通过检查产物是否存在来跳过,而不是相信状态字段——进程在写一半时挂掉,状态字段会说谎。

失败状态必须显式

「失败」不是诊断结论。要区分,因为每种都有不同处置:

状态含义应对
retryable 可重试瞬时问题(超时、429)退避重试
validation_failed 校验失败输出格式错误带上错误信息重试
needs_input 需补充信息关键信息缺失询问人工,不要猜
blocked 被阻塞外部依赖不可用挂起任务并通知
fatal 致命不可恢复干净停止,保留产物供排查

把一切失败都当 retryable 的工作流会烧光预算并最终损坏状态;把一切当 fatal 的工作流则过早放弃。

绝不让模型静默吞掉失败。某一步没成功,工作流必须知道,而不是只留下一段模糊的印象。

预算跟踪

长任务往往是钱先花完,而不是想法先穷尽。按次运行跟踪:

在开始每个步骤前检查预算,而不是事后发现超支。触顶时以 interrupted 状态停止并留下可恢复的检查点,绝不停在一半已应用的状态上。

恢复检查清单

  1. 读 manifest → 还原任务身份与输入
  2. 通过产物是否存在发现已完成步骤
  3. 重新校验上一轮遗留的步骤产物(不要默认完好)
  4. 从第一个未完成步骤继续
  5. 之后每步开始前复查预算

第 3 条最常被跳过。崩溃前几毫秒写入的检查点可能是截断的;校验它只需一次读取,却能省下数小时的困惑。