Agent 写操作应区分成功、失败与未知
写操作已生效但回读验证失败时,将结果判为失败并重试可能产生重复副作用。文章主张区分已完成、未完成和未知三种状态,分别依据明确证据处理。
AI 深度解读
Agent 发完评论,脚本却因为找不到页面上的标记而返回 unknown。评论其实已经上线,再执行一次就会重复发布。作者从自己的运行日志出发,指出一个容易被忽略的问题:动作执行成功与否,不能只靠验证脚本返回的成功或失败来判断。
他的结论是,写操作至少需要三种判定:已完成、未完成、无法确认。对写浏览器自动化、Node 脚本和 AI Agent 工具的人来说,这个区分直接影响重试是否会制造重复副作用。
没查到结果,为什么不能直接重试
常见的动作封装把执行和验证揉在一起:先操作,再检查结果里有没有预期内容。有就是成功,没有就是失败。
问题在于,验证工具也可能失灵。作者通过 headless browser 发布评论后,页面没有按选择器预期的方式渲染,导致回读检查找不到标记。失败的是观察过程,评论发布已经完成。
因此,三个状态需要分别定义:
done:有明确证据证明预期效果已经存在。not done:有明确证据证明预期效果不存在。unknown:现有检查无法区分前两种情况。
没有查到成功证据,不等于拿到了失败证据。
把 unknown 当成未完成,可能重复评论、重复扣款;把 unknown 当成已完成,则可能让实际未发生的操作永远无人核查。后两类后果是作者指出的风险,原文实际描述的案例是评论发布成功、验证失败,并没有报告重复扣款实验。
作者还引用了 yuki-uix 检查单个配置字段的设计:两个 ETags 都存在且不同,可以确认基线不匹配;必需的 ETag 缺失,只能说明一致性无法验证。缺证据和证据证明无效,是两件事。
unknown 应该触发核查,而不是再次写入
第三个状态只有影响调用方的行为,才有价值。作者给出的规则有三条。
第一,非幂等写操作遇到 unknown,不能自动重试。非幂等就是重复执行可能多产生一次效果,例如再发一条评论。只有明确确认未完成,或者有幂等键让重复请求不会增加副作用,才考虑重试。
第二,unknown 必须附带证据:执行过哪些检查,哪个检查无法执行,原因是什么。只记一个状态,一小时后很难追查。
第三,通过读取当前状态来消除疑问。如果读取后仍然无法确认,就停止并升级处理,不能靠反复执行原动作碰运气。
下面的骨架展示了这种控制流:验证不确定时,追加一次读取来核对状态。
async function act(op) {
const before = await read(op.target); // state before
const r = await op.write(); // non-idempotent
const v = await verify(op, r, before); // done | not_done | unknown
if (v === "unknown") {
const after = await read(op.target); // reconcile by reading
return classify(before, after, r); // may still be unknown
}
return v;
}
要看的是 const after = await read(op.target) 这一行:进入 unknown 分支后,代码执行的是读操作;classify(before, after, r) 仍然可以返回 unknown,并不保证每次都能得出确定结论。
日志里的零,也可能没有回答你的问题
作者把同一个问题延伸到了内容数据:他发布的两篇内容分别有 20 和 12 次浏览,反应数都是 0。但这些数字不足以支持「没人读」这个判断。
浏览计数无法区分用户到达后就离开,还是阅读后没有互动。0 次反应是一个确定的观测值,读者是否认真阅读却仍然不确定。错误发生在把前者直接当成后者的答案。
作者因此认为,动作日志最该补充的字段是「判定依据」:有哪些证据、缺了什么证据,以及后续核查读到了什么。状态负责驱动流程,证据负责让流程可以被复查。
我的判断
我赞同把 unknown 作为正式状态。它让 Agent 承认观察能力的边界,也能阻止调用方用一个布尔值决定所有重试。
但原文提供的是日志案例和设计建议,没有对照数据证明这种改造能降低多少错误率。作者自述是自主 Agent,文章来自其自身运行日志;文中没有提供足够材料让读者独立复现实验。
代码也只是骨架:op.write() 抛异常怎么处理,read() 读到的是不是最新状态,多个执行者同时修改目标时如何归因,都没有展开。在并发或状态更新存在延迟的系统里,一次回读未发现结果,也未必足以判为 not_done。
三态判定值得采用,但判定标准和读取可靠性仍要单独设计。
与统一失败重试相比,它更谨慎;与幂等键相比,它解决的是证据不足时如何决策的问题。两者可以配合使用,三态本身不会让重复写入变得安全。
能拿来做什么
- 检查浏览器自动化和 AI 编程工具中的发布、评论、配置修改流程,把「选择器没找到」「读取超时」与「明确确认未写入」分开处理。
- 给 Node 动作封装增加
unknown返回值,并检查上层调用方,避免它把所有非成功结果都送进自动重试队列。 - 在动作日志里记录验证步骤、失败原因和回读结果;无法确认时保留现场,停止自动写入并交给人工核查。
- 阅读访问量和互动数据时,先明确指标实际测量了什么,不用 0 次互动推断 0 人阅读。