跳转到主要内容

Agent 撤销按钮是 Saga,而非栈

阅读需 1 分钟Tian PanTian Pan

用户点击了智能体操作的“撤销”按钮,而该操作之前已经分发(fan out)到了十二个工具调用中。智能体发送了两封电子邮件,创建了一个日历邀请,更新了一条 CRM 记录,扣除了信用卡费用,并在 Slack 频道中发布了消息。其中三个操作通过 API 是不可逆的。两个操作只能通过触发自身下游通知的反向操作来撤销。剩下的七个操作各自都有自己的幂等性(idempotency)定义,而规划器从未协调过这些定义。你发布的撤销按钮看起来令人安心,它大约 60 % 的时间静默成功,其余时间则静默失败。

这不是一个 UX(用户体验)漏洞。这是一个 Saga 模式问题,分布式系统工程师已经研究了三十年,而忽略这段历史是发现它最昂贵的方式。

当产品团队要求在智能体操作中添加撤销按钮时,本能反应是将其建模为类似文本编辑器的撤销堆栈:一个操作列表,每个操作都有一个逆操作,并按相反顺序弹出。这种心理模型可以清晰地映射到单进程的状态变更——输入一个字符、移动一个形状、删除本地文档中的一行。但它很难映射到一个每个动作都是对不同供应商的网络调用、拥有各自的一致性保证的系统;在这样的系统中,有些操作会导致对方的人类采取自己不可逆的操作,且某一步骤的逆操作取决于尚未得到补偿的步骤的结果。

当工具跨越进程边界时,“可逆”究竟意味着什么

一个有用的第一步是停止将可逆性视为二进制属性,并开始将其视为每个注册工具的契约。划分为三个粗略的类别足以让你对自己诚实:

  • 完全可逆(Cleanly reversible) —— 工具暴露了一个逆向 API 调用,执行该调用可以完全消除原始操作的影响。例如创建一个草稿文档并删除该草稿,或者更新一条记录并写回之前的值。这些是容易处理的情况,但它们比你的工具目录所暗示的要少得多。
  • 带残留的补偿(Compensable with residue) —— 原始动作无法被抹去,但一个向前的补偿性动作可以恢复到一个已知的良好业务状态。付款无法撤销,但可以发起退款;会议无法静默地取消,但可以发送一封取消通知给每个受邀者。补偿是一个具有真实副作用的真实操作,而不是数据库回滚。
  • 不可逆(Non-reversible) —— 一旦执行,该操作的效果无法通过任何 API 调用序列中和。例如被人类阅读过的电子邮件、触发了回调的短信,或者超过了撤回窗口的电汇。唯一诚实的“撤销”是由人类撰写的后续消息,承认这一错误。

注册到智能体的每个工具都应该声明它属于哪一类,而注册信息应该是单一事实来源。如果工具作者无法回答这个问题,安全的默认选择是不可逆——将不可逆工具视为可补偿工具的失败模式,就是静默地发布一个“用户可以撤回”的谎言。

在执行时预计算逆操作,而非在撤销时

团队最先尝试的另一种模式是错误的形式:将执行步骤存储在日志中,在撤销时遍历日志并为每个步骤合成逆操作。这失败的原因与当状态已经逃离数据库时数据库回滚失败的原因相同:构建逆操作所需的信息已无法恢复。

如果智能体更新了一条 CRM 记录,逆操作是“将字段 X 设回其之前的值 Y”。值 Y 必须在写入的那一刻被捕获,因为到撤销时,该记录可能已被人类、另一个智能体或来自下游系统的 Webhook 修改,现在字段的值是 Z。从智能体操作日志中重建 Y 是行不通的——日志中从未记录过 Y,只记录了新值。

必须落地的纪律是,每个执行步骤都会写入一条 Saga 日志条目,其中包含正向操作和预计算的逆操作,这些操作是针对执行时观察到的世界状态捕获的。逆操作是数据,而不是稍后合成的代码。在撤销时,引擎遍历日志并按相反顺序分发每个步骤的预计算逆操作,每个补偿操作都是幂等且可重试的。

这正是像 Temporal 这样的编排器所规范化的纪律,如果开发者不使用现有的框架,就必须在自研架构中发明同样的纪律。跳过这一步意味着你的撤销按钮在演示流程中运行良好,因为演示流程没有并发写入者;但在第一个 CRM 同时也由其电子邮件集成更新的用户那里,它就会崩溃。

UX 必须如实告知部分撤销的情况

即使有了预计算的逆操作,真实的撤销也会处于三种状态,而将其合并为一个“已撤销”气泡提示的 UX 是在欺骗用户。

会员专享

余下内容仅对会员开放。

会员可读完整内容 —— 每一个公开发布的观点背后,那些框架、决策与推理的全貌。

  • 完整文章,包含未公开存档的部分
  • 可落地的工作框架,附带权衡与决策依据
  • 新文章抢先看,先于公开发布

随时取消 · 一次订阅,畅读全部

参考资料

保持联系,关注我获取更多内容

阅读需 9 分钟

那个因等待另一个 Agent 而死锁的 Agent

两个能力出色的 Agent 可能会在你的账单飞涨时永远互相等待。为什么是协作——而非模型能力——导致了 Agent 群体的崩溃,以及分布式系统准则如何修复这一问题。

insider
ai-agents
阅读需 10 分钟

你的智能体需要的是监督者,而不是重试循环

当长时间运行的智能体失败时,重试循环回答了错误的问题。Erlang 的 OTP 监督树在三十年前就定义了真正的决策路径:是彻底重启、从检查点重启,还是升级给人工处理 —— 以及如何将这些策略映射到智能体流水线中。

insider
ai-agents
阅读需 10 分钟

那些被你的智能体“触发并遗忘”的异步工具调用

函数调用将同步和异步工具视为相同的形式。智能体触发了一个任务,收到了一个 ID,随后标记该步骤已完成 —— 而实际工作却从未落地。

insider
ai-agents
阅读需 12 分钟

你的定时 Agent 有四个时钟,而你信任的是错误的那一个

通过 cron 触发的 AI Agent 继承了四个时钟 —— 调度器、工作节点、模型和工具 —— 而大多数生产系统都在默默地信任错误的那一个。本文将带你了解这些失败模式以及防止这些问题的‘时间交接合约’。

insider
ai-agents
阅读需 9 分钟

工具延迟尾部:为什么 p99 重塑了智能体架构而 p50 掩盖了问题

基于单个工具中位数构建的智能体延迟预算在生产环境中会悄无声息地失效:经过 7 个步骤后,尾部延迟开始占据主导地位,导致尽管单个工具的仪表盘显示为绿色,用户却仍在等待。本文将深入探讨为什么 p99 会重塑智能体架构,相关的工程规范是什么样的,以及哪些具有 40 年历史的分布式系统技术可以直接应用。

insider
ai-agents