冲突、同步与失败恢复
本节目标
理解并发协作的主要故障:重复、乱序、冲突写、局部失败和失联;用资源所有权、版本、检查点与有限重试得到可解释结果。
先消除不必要的共享写
最可靠的冲突处理是避免冲突:
- 为每个文件、记录或任务指定唯一写入所有者。
- 并行专家只产出不可变建议,汇总者统一写最终产物。
- 临时结果按 task_id 分区,不共用“latest.json”。
- 输入做快照或记录版本,避免同一轮读取不同事实。
如果多个 Agent 必须写同一对象,可选:
- 乐观并发控制:读取版本 v,提交时要求当前仍为 v;冲突则重新读取和合并。
- 锁/租约:在有限时间内独占资源。租约必须过期,持有者还需心跳,避免进程崩溃后永久锁死。
- 串行化队列:所有变更经过一个写入者,牺牲吞吐换取简单一致性。
- 领域合并规则:例如标签集合可取并集,但金额、权限和发布状态不能自动合并。
不要默认“最后写入获胜”。它会静默丢失更早但可能更正确的结果。
幂等重复与结果冲突要分开
幂等键并不是“忽略所有同 key 消息”的许可证。接收器应在 durable record 中保存 key、带算法/版本的 intent/result digest、验收状态和外部 receipt 引用:同 key、同 digest 才复用结果;同 key、不同 digest 是证据冲突,必须冻结任务、停止尚未开始的下游有副作用调度并转 needs_review。人工决定应绑定当前 state_version、两个 digest、receipt 指纹和一次性 decision ID;不是让某个 Agent 选“看起来更合理”的版本。
已经启动或已经提交的下游不能被一次状态迁移“撤回”。冲突发生后还要隔离其发布/继续写入,标记已发生的 receipt 与影响范围,并由有权限的人决定查询、补偿、撤销或向外披露;补偿本身也是新的、受审计和可能需要审批的动作。
这与 工作流的幂等记录 和 环境型 Agent 的 receipt 冲突 是同一类问题:名称不同,核心都是“外部事实不再唯一,自动化不得继续写”。
失败分类决定恢复方式
| 失败类别 | 例子 | 是否重试 |
|---|---|---|
| 输入错误 | 缺少字段、格式不符 | 否,退回上游 |
| 策略拒绝 | Agent 无写权限 | 否,不得换角色绕过 |
| 临时故障 | 连接中断、服务繁忙 | 有限退避重试 |
| 永久故障 | 资源不存在、能力不支持 | 否,改计划或人工处理 |
| 质量失败 | 输出结构正确但证据不足 | 带反馈返工,次数受限 |
| 预算耗尽 | 步数/时间/费用达到上限 | 否,保存进度并停止 |
“所有异常重试三次”会重复不可逆副作用。只有确认操作幂等,或能用幂等键识别已提交结果时,才能安全重放。
检查点与恢复
检查点保存的是可恢复状态,不是整段内部思维:
- 任务与依赖状态;
- 已接受的产物引用和哈希;
- 当前预算、尝试次数;
- 已执行副作用的幂等键;
- 等待中的审批;
- 最近可验证事件位置。
恢复流程:加载 → 校验 schema/version → 验证外部副作用是否已发生 → 将过期 running 任务转为可判定状态 → 只调度未完成任务。检查点应原子写入,例如先写临时文件、同步后替换目标文件。
补偿而非“撤销一切”
分布式副作用往往不能真正回滚。发送邮件后删除本地记录不会收回邮件。应为动作设计补偿:取消预订、发送更正、恢复上一版本,并明确补偿也可能失败。高风险动作更适合执行前审批。
死锁、活锁与重复劳动
- 死锁:A 等 B,B 等 A;通过 DAG 环检测、锁顺序和超时预防。
- 活锁:Agent 不断互相退让/返工,状态变化但无进展;设置最大返工次数和进度度量。
- 重复劳动:两个 Agent 不知彼此正在做同一任务;用任务租约和唯一所有者。
- 脑裂:两个经理都认为自己是领导者;生产系统需使用可靠的领导选举或单一调度服务。
实践
为“两个审查者同时提交建议”设计:不可变审查报告、唯一合并者、草稿版本号、冲突后的处理。再模拟消费者收到同一 task_result 两次,验证最终状态只更新一次。
自测
- 何时租约优于永久锁?
- 为何 policy_denied 不能通过换 Agent 重试?
- 检查点显示 running,但进程已不存在,应直接标记 succeeded 吗?
- 哪些副作用必须在重试前查询外部提交状态?
下一步
继续 预算、停止与人工介入。
参考资料
- OpenAI Agents SDK:Running agents(访问于 2026-07-22)
- OpenAI Agents SDK:Human-in-the-loop(访问于 2026-07-22)