两个 AI agent 可以编辑同一个文件,两者都收到了“成功”确认,但最终只有一个人的修改得以保留。在一个包含五个并发 agent 的简单测试中,五次写入中有四次消失了,且没有任何错误或日志记录——这是一个典型的“丢失更新”(lost-update)异常,白白浪费了为那些消失的工作所支付的 token。
为什么这个问题很重要
当 AI agent 写回结果时,底层服务会按生成的 token 进行计费。如果写入被静默覆盖,服务商仍会针对产生被丢弃输出的计算过程进行计费。在多 agent 流水线中——无论是 agent 集群(agent swarms)、并行数据清洗工作流,还是任何多个机器人共享计划文件或草稿本的系统——这些隐性损失都可能演变成巨大的成本漏洞。此外,该异常还会威胁数据完整性:下游步骤可能会基于不完整或过时的信息进行操作,从而导致连锁错误。
异常是如何发生的
根本原因是竞态条件(race condition):
- 两个(或更多)agent 读取了资源的同一个版本,例如一个 JSON 计划文件。
- 每个 agent 根据该快照执行各自的推理或转换。
- 两个 agent 都向共享存储发起写入操作。
- 存储系统接受了第二次写入,在没有任何冲突检测的情况下覆盖了第一次写入。
- 两个 agent 都收到了确认写入成功的“ACK”,尽管第一次的贡献已经丢失了。
存储系统的确认仅证明了写入动作已发生,并不保证该写入相对于其他并发更新是安全的。通常被视为保障手段的“仅追加日志”(append-only log)也存在同样的问题:它记录了写入动作的发生,但无法阻止后来的写入覆盖先前的写入。
Compare-and-set (CAS) 闸门的作用
Compare-and-set (CAS) 闸门在写入被接受之前增加了一个版本检查:
- 读取 (Read):agent 获取文件的当前版本号(或哈希值)。
- 计算 (Compute):agent 执行其工作,生成文件的新版本。
- 写入 (Write):agent 将新内容连同其最初读取的版本号一起发送。
- 验证 (Validate):存储层将提供的版本号与当前版本进行比较。如果两者不同,写入将被拒绝;否则,写入将继续进行并递增版本号。
如果版本已更改,agent 就会知道其视图已过时,必须使用新版本重新尝试整个循环——读取、计算、写入。这把不可见的覆盖变成了可以记录、重试并进行核算的显式失败。
安全的代价
CAS 闸门并非免费。在同样的五个 agent 模拟实验中:
| 场景 | 尝试写入次数 | 成功的贡献 | Token 成本 |
|---|---|---|---|
| 无 CAS 闸门 | 5 | 1 | 5 个单位 |
| 有 CAS 闸门 | 5 | 5 (重试后) | 9 个单位 |
对于遇到版本冲突的 agent,闸门会增加额外的“读取-计算-写入”循环,从而提高 token 消耗。权衡很明显:没有闸门,你会静默地丢失数据;有了闸门,你只需支付少量的额外成本,就能获得对每一次冲突的可见性。
这种失败有多常见?
即使只有两个 agent,测试也显示有 75% 的概率会丢失其中一次写入。当使用五个 agent 时,丢失率接近 100%。这些数据表明,对于任何生产级的多 agent 工作流来说,“通常没问题”是一个危险的假设。
反方观点:何时可以跳过闸门
如果系统为每个资源只运行单个 agent,或者在更高层级强制执行严格的串行化,那么额外的 CAS 检查可能是不必要的。然而,风险计算必须包含重新运行失败工作所带来的隐性成本,以及数据缺失可能对下游产生的影响。
后续关注点
- 工具支持:寻找能够直接提供版本号或 ETag,并原生支持原子 CAS 操作的存储 API。
- 指标:为你的 agent 配置监控,记录因版本不匹配而被拒绝写入的频率。冲突率上升预示着你需要扩展资源或重新设计工作流。
- 重试策略:简单的指数退避(exponential back-off)效果良好,但要注意重复重试会增加 token 消耗。需在重试限制与可接受的数据丢失之间取得平衡。
- 混合方案:一些团队将用于审计的“仅追加日志”与用于一致性的 CAS 闸门相结合,既能记录发生过什么,又能防止覆盖。
总结
丢失更新异常会将 Token 驱动的 AI 流水线变成漏钱的黑洞。引入一种 Compare-and-set 版本门控机制会增加少量的 Token 开销,但它能将静默的数据丢失转化为可见且可重试的事件。对于任何存在多个智能体共享状态的系统——无论是数据库、计划文件还是临时存储区——在写入前嵌入版本检查,是防止隐藏成本和工作流损坏的最廉价保险。
