撤销与可逆性

11 分钟读完

H10
实战手册 · 智能体体验与人机交互

撤销:每一个确认弹窗,都是你没做撤销而寄来的账单。

团队给智能体动作设卡时问的是"这件事危险吗",而这是个错问题——它造出的产品会不停打断人,却依然放行了那个唯一谁也收不回来的动作。真正能把动作分对类的问题是:"撤销它要付出什么代价,而这个价格还能买多久?"逐个工具回答一遍,两件事会同时发生:你大部分确认弹窗被证明根本不必要,而剩下的那少数几个,则变成了本就不该让人一路点过去的那些。

STEP 1

按撤销代价排序,而不是按吓人程度。

把一个已上线智能体的工具清单拿出来,逐条标注:一道审批关卡到底买到了什么。从一张每小时快照一次的表里删掉一行,动静很大而代价很小。发一封邮件,悄无声息,而一旦落进别人的收件箱就是永久的。大多数团队给前者设卡、不给后者设卡,因为"危险"是按动词听起来有多具破坏性来判断的,而不是按效果能否被收回。

  • 可逆性是效果的属性,不是动词的属性。delete_draftdelete_customer 共享一个单词,除此之外毫无共同点。不同系统里同名的两个工具,属于不同的层级。
  • 系统边界就是那道悬崖。凡是留在你自己掌控的基础设施内部的,通常可恢复;凡是越过边界出去的——一封邮件、一条 Slack 消息、一次 webhook、一笔付款、一次公开 API 写入、一份发给第三方的通知——都在你够不着的地方留下了副本。真正把层级分开的是这条边界,而不是操作本身的破坏力。
  • 自主性是按撤销代价定价的。自主性阶梯 通常被讲成一个信任问题。把它当成工程问题更划算:智能体可以在无人监督下行动,其边界恰好是它的动作能以可接受代价被收回的地方。为一个工具买下可逆性,你就买下了一级台阶,而无需请任何人更信任模型。
  • 不可逆的那一组比看上去小,而且从来没人审计过它。多数团队能说出智能体里三个不可逆的动作。多数智能体实际有十几个——通常藏在一个通用 HTTP 工具、一个没人读过工具清单的 MCP 服务器,或者一个什么都能干的 shell 后面。把它逐工具、书面地、彻底列一次。

在下一次提高自主性之前,把这件事当作一道练习跑一遍:列出每一个工具,在旁边写下撤销它的确切步骤序列,以及谁能执行这个序列。凡是答案是一段话而不是一次调用的那一行,你的确认弹窗就是承重的。凡是答案是"从我们反正都会做的快照里恢复"的那一行,那个弹窗就是纯粹的摩擦。

STEP 2

撤销的三个等级,以及那个根本不算撤销的第四级。

"撤销"这一个词,罩着几种保证强度差异极大的机制。把它们分开命名,能防止你承诺了最强的那种、却交付了最弱的那种。

  • 回滚——先前状态被原样恢复。只有在存储归你所有、并且你拿到了快照或版本化写入时才成立。这是唯一一个"已撤销"字面为真的等级。
  • 补偿——用第二个动作抵消第一个。对应扣款的那笔退款、回退的那次提交、跟发的那条更正。状态重新变得可接受;但历史上两个事件都在,而在这中间的任何观察者都看到了那个中间状态。现实世界里的撤销大多是这一种,也是你该照着设计的那一级。
  • 缓解——你抵消不了,只能减少伤害。撤回一条人们已经读过的消息、为一封发错的邮件道歉、通知客户此前发出的对账单有误。缓解是一份挂着工程标签的公关方案。
  • ——动作是终局的。汇往外部账户的钱、过了保留期的删除、一次不可撤回的 API 调用、任何具有法律效力的事情。这一层必须被显式列举出来,而不是被撞见。

设计上的推论很直接:把人工审批留给第三、四级。第一、二级不需要关卡,它们需要的是一个看得见、按得动的撤销入口——那是便宜得多的东西,也是好用得多的东西。

正确性正是从"补偿"这一级悄悄漏出去的。一笔退款不等于一次被取消的扣款——客户的账单上两笔都在,他的银行可能还要压几天资金,而某个下游系统可能早已对第一个事件做出了反应。请把补偿动作写成一个有自己测试的一等操作,而不是一个你假定存在的逆运算。持久化执行 的文献把这叫做 saga,即便你永远不采用那套框架,这份纪律也值得借来。

STEP 3

可逆性有半衰期,杀死它的是观察者。

就算认真做过分层,仍会活下来的那个错误,是把可逆性当成一个固定属性。它是会衰减的。一条发出三秒后被删掉的 Slack 消息,是回滚;同样这次删除放到四分钟后、已有两人读过、一人回复过,就成了缓解。API 没有任何变化,变的是受众。

  • 计时从"生效"开始,不是从"调用"开始。一封已入队待投递的邮件,在投递之前都是可逆的;一条写入的记录,在别的东西读到它之前都是可逆的。请把"暴露的那一刻"埋点出来,因为那正是你的层级发生变化的时刻。
  • 有意识地买时间。给对外动作加上三十秒的延迟,是整份手册里杠杆率最高的单一改动。它把一整类第三级动作变成第一级,用户几乎察觉不到任何代价,而人和你自己的护栏都因此获得了一个可介入的窗口。每一个邮件客户端几十年前就发过这个功能了;智能体产品却一再忘记它。
  • 把延迟合并,别把它们叠起来。十个被扣住的动作配十个独立计时器,产出的是十条通知和一个被惹毛的用户。把一次运行的对外效果一起扣住,作为一组可复核的集合呈现——这正是 渐进式披露 的精神。
  • 留意你忘掉的第二个观察者。Webhook、同步任务、搜索索引器、分析管道和其他智能体,都会读你的写入。一个动作可以在社交意义上可逆、而在技术意义上不可逆,只因为某个下游消费者已经被触发——这正是 幂等与重试 里描述的那个失败模式,只不过是从另一个方向撞过来的。
STEP 4

把机制建起来,并让每个工具自己声明它。

可逆性不是你能在外壳层加上去的属性,因为外壳并不知道一个工具做了什么。它必须由工具声明、由这次运行携带。

  • 每一个会改动状态的工具都返回一个撤销句柄。不是一个布尔值 reversible: true,而是撤销它真正需要的那个东西:先前版本 id、消息时间戳、事务引用、快照键。一个改了状态却只返回"ok"的工具,恰恰在保留成本最低的那一刻让你的撤销变成了不可能。这属于契约的一部分,与 工具 schema 与契约 里那些规则并列。
  • 优先用暂存效果,而非直接效果。写草稿而不是直接发送,开分支而不是直接推送,提出变更而不是应用变更。暂存把审批从一次打断变成了一份人可以按自己节奏读的产物——这也是编码智能体在别处会令人不安的自主级别上却让人觉得安全的最大原因。
  • 写之前就快照,并且和写在同一个步骤里。由夜间任务产生的快照是备份,不是撤销。撤销需要的是在变更发生那一刻捕获、并能按运行 id 寻址的先前状态。
  • 把撤销路径做成智能体能调用的工具。如果撤销只以运维手册的形式存在,那在它本可以救场的那九十秒里,它不会被用上。把同一个可调用的撤销交给智能体、交给急停开关、也交给人。停的那一半见 急停开关;撤销是停下之后跑的那部分。
  • 撤销路径要和正向路径按同样的频率被测试。没被测过的撤销就是智能体设计里的灾备预案:人人都有一份,而它第一次执行是在事故当中。一个每周跑一次、做一个动作再把它撤销掉的任务,成本很低,却能在用户之前发现那些坏掉的句柄。
STEP 5

界面:撤销必须能被那个被吓到的人够到。

一条谁也找不到的、能用的撤销路径,不是可逆性,是一张工单。这里的 UX 要求既窄又具体。

  • 撤销住在效果旁边,不在设置页里。在宣布这个动作的那条消息上、在这个动作产出的那份产物里、在用户真正收到的那条通知上。一次点击,不用跳转,不用找管理员。
  • 用对应等级的诚实措辞说清会发生什么。回滚就叫"撤销"。补偿就叫"发一条更正"。缓解就是"此操作无法撤销——请联系某某"。一个写着"撤销"却悄悄执行补偿的按钮,正是用户学会不再相信你界面的方式。
  • 把窗口显示出来,并允许暂停。如果动作三十秒后发出,就把这三十秒倒着显示给人看。一个看得见的计时器比一个确认弹窗更让人安心,而且不要求一个本来没什么可反对的人做出任何决定。
  • 别再为可以退休的确认付费。每一道因为动作变得可逆而被移除的关卡,都是还给用户的注意力;而注意力正是让剩下那几道关卡仍然有效的稀缺资源。一个每天点过九个无害弹窗的用户,也会点过第十个——这就是 审批与确认体验 里记录的那种疲劳背后的机制,而可逆性是唯一不依赖"人得小心"的解药。
  • 在共享空间里,撤销需要与动作同等的归属标注。谁撤销了什么,要让所有看过原动作的人都看得见——否则房间只记得那个动作,不记得那次更正。见 共享与多人智能体
STEP 6

该度量什么,以及这些数字会告诉你什么。

在各种 UX 属性里,可逆性有一点很特别:它会产出干净的量化信号,而这些信号正是你提高自主性时不必再靠嘴仗的证据。

  • 覆盖率:带可用撤销句柄的改动型工具调用占比。该挂到墙上的唯一一个数。它应该往上走,而每个新工具生来就该带一个。
  • 各工具的撤销率。一个被用户撤销掉 15% 的工具,告诉你的是提示词或 schema 有缺陷,而不是撤销做得如何。高撤销率是一个指向别处的质量信号。
  • 撤销时延的分布。如果多数撤销发生在一分钟内,你的延迟窗口尺寸就对了;如果它们堆在几小时那一档,说明你的用户是从下游效果里发现错误的,而你的通知来得太晚。
  • 每季度退休掉的关卡数。把它当作一个产品指标来跟踪。因为动作变得可逆而退休的确认弹窗,是一次真实的改进;因为它烦人而退休的,是一次穿着同款衣服的倒退。
  • 失败的撤销。很罕见,而每一次都是一起事故:用户被承诺了一件系统交付不了的事。请用 智能体事故响应 对待无声失败的方式对待它,因为它就是无声失败。

这周只做一件事的话:给每一个对外动作加一个延迟窗口,给每一个改动型工具的返回值加一个撤销句柄。两者合起来花不了几天,却能把智能体最吓人的那片表面从"先问人"变成"先做、展示、并提供撤销"——对用户更快,在高负载下更安全,而且这是你在评审会上唯一站得住的"提高自主性"版本。确认要求一个人去预测一个坏结果;撤销只要求他认出一个坏结果,而人在后者上强得多。

延伸:渐进式自主 讲怎么花掉可逆性给你买来的台阶,为失败而设计 讲撤销本身失败时该显示什么,持久状态与可恢复性 讲底下的状态机制,以及 决策回执 讲那份让几周后仍能重建一次撤销的记录。