<!-- title: 副作用税：回滚即双花塌方 -->

## 概述

2026年自主智能体最致命的缺口，不是"会不会用工具"，而是"懂不懂什么是不可逆"。当业界把 checkpoint/restore、time-travel、`/rewind` 当成安全网铺进主流框架时，一个反直觉的漏洞被集体忽略：**回滚一个已经执行过不可逆动作的检查点，等于把转账、下单、删库原样重放一遍**。IBM STRATUS（NeurIPS 2025）、ACRFence 语义回滚攻击研究、Cursor "9秒删生产库"事件，三者共同指向同一结论——自主智能体普遍缺失"可逆性模型"，把一次只读查询和一次删生产集群压进同一个"允许/拒绝"开关，副作用税随之塌方。本文拆解可逆性光谱、TNR 无回归原则、回滚即双花攻击、爆炸半径分级，以及 `Ctrl+Z` 的三种实现路径，给出从权限开关到影响惩罚的完整治理地图。

## 一、可逆性光谱：自主智能体缺失的"第七维"

主流框架的权限模型本质是二维的：工具名 × 允许范围。但自主智能体一次任务序列里的动作代价，横跨至少七个数量级——读一个文件的成本是 0，删一封已发送的邮件成本是无穷大。把这两件事交给同一个布尔开关，是"按工具名做权限"范式的根本错误。

可逆性不是连续值，而是一条分五段的光谱：

| 层级 | 动作类别 | 可逆性 | 可用回退手段 | 单次代价量级 | 治理等级 |
|------|----------|--------|--------------|--------------|----------|
| L0 | 纯读 / 查询 | 完全幂等 | 无需回退 | ~10⁻³ 元 | 全自动 |
| L1 | 本地可逆写 | 时间对称 | git / 内容寻址快照 | ~10⁻² 元 | 自动 + 事后审计 |
| L2 | 外部有状态改写 | 需补偿事务 | 逆操作（解绑、撤单） | ~10¹ 元 | 自动 + 预演 |
| L3 | 外部无逆操作 | 不可逆 | 仅限快照外重放 | ~10³ 元 | 强制人审 |
| L4 | 资金 / 物理世界 | 双花级 | 不可回滚 | ~10⁵+ 元 | 永不自动 |

L1 与 L4 之间差着七个数量级，却常被 Claude Code、Cursor、Devin 用同一套 "dangerously-skip-permissions" 旗子一杆子放行。代价不是出在复杂工具上，而是出在**模型对层级的无感知**：它把 `git reset --hard`（L1）和 `rm -rf /data && rm -rf /backup`（L4）当成同一种"shell 命令"。可逆性盲区的本质，是工具描述里缺少一个机器可读的 `reversibility` 字段，使得任何规划层都无法据此分级。

## 二、TNR 原则：把"无回归"写成门控

IBM 与 UIUC 在 NeurIPS 2025 发表的 STRATUS 给出了可逆性的数学化定义——**Transactional-No-Regression（事务无回归）**：一个变更只有在不破坏系统既有可达能力时才允许提交，破坏者必须能被 `undo` 回退到上一个检查点再换路径重试。研究员 Saurabh Jha 的原话是："我们观察到 AI agent 会毫不犹豫地执行灾难性动作，比如试图删除整个生产集群——人类工程师几乎不会在没做大量验证前做这种决定。" STRATUS 靠这条原则在 AIOpsLab、ITBench 上比 SOTA 高出至少 150%。

把 TNR 落成代码，是一个挂在工具执行前后的双门：

```python
class TNRGate:
    def __init__(self, snapshot):
        self.capabilities_before = snapshot.measure()  # 既有可达能力基线

    def before(self, action):
        if action.reversibility >= L3:
            raise HardStop("L3+ must yield to human or shadow-run first")

    def after(self, action, result):
        now = environment.measure()
        # 关键：只允许"不削弱既有能力"的变更进入
        if now.dominates(self.capabilities_before) is False and not action.reversible:
            self.undo_to_last_checkpoint()   # 回退，换路径重试
            return Retry(alternative=action.fallback)
        self.commit_checkpoint(now)
```

TNR 的颠覆性在于：它不要求 agent "判断对错"（LLM 最不擅长），只要求 agent "**变更后能力域是否单调不缩**"。后者是可以用环境探针机械测量的。代价是必须为每个环境定义 `measure()`，这正是大多数框架偷懒省掉、最终塌方的地方。

## 三、回滚即双花：checkpoint/restore 的致命反模式

业界把 `Ctrl+Z`、`/rewind`、time-travel 当成"安全网"满心欢喜地铺进框架时，ACRFence 揭示了一个反直觉的攻击面：**检查点之后的不可逆动作，在 restore 时会被当成新请求重放**。

```
T0  checkpoint C0            快照建立
T1  execute transfer($10k)   ✅ 已执行，钱已出账
T2  agent 觉得方向不对
T3  restore C0 → 重跑        ❌ 服务方视为全新请求
T4  transfer($10k) 再发一次  💸 双花
```

这不是 bug，是**状态机的根本错配**：检查点记录的是 agent 侧的对话/内存状态，而转账的副作用发生在**检查点无法触及的外部账本**上。restore 把内部时钟拨回，外部账本却向前走了。ACRFence 把这类漏洞命名为"语义回滚攻击"（semantic rollback attack）——包括重复支付、未授权复用、被撤销权限的复活（revived authority）。

更隐蔽的是：即便 agent 不主动 restore，框架的**自动重试 / 崩溃恢复**也会触发同样的重放。这就是为什么"给会发邮件、会转账的 agent 上 git 检查点"是个陷阱——git 只能保护文件树（L1），对 L3/L4 的副作用完全透明。真正的修法不是更聪明的 undo，而是**意图感知围栏**：restore 时扫描"自上个检查点起已执行的不可逆动作清单"，把它们的副作用标记为已发生、拒绝重放。

## 四、爆炸半径分级：单一自主开关是错的抽象

治理可逆性的第二根支柱，是把"一个 autonomy 开关"换成"按爆炸半径逐工具分级"。这个观点在 2026 年成为共识：读是免费的，merge 是事故级的，二者中间不该只有一道闸。

```yaml
# blast-radius.yaml —— 给每个工具标注半径，而非全局放行
tools:
  read_file:        { tier: L0, auto: true }
  edit_file:        { tier: L1, auto: true, snapshot: git }
  run_tests:        { tier: L1, auto: true }
  git_commit:       { tier: L1, auto: true }
  npm_publish:      { tier: L2, auto: false, dry_run: true }   # 预演
  send_email:       { tier: L3, human: true }
  db_migrate:       { tier: L3, human: true, backup_outside: true }
  cloud_provision:  { tier: L3, human: true }
  payment:          { tier: L4, never: true }                  # 永不自动
```

这条分级表的实战含义远超"多设几道确认门"。它要求**能力衰减（capability attenuation）按半径伸缩**：agent 在 L0/L1 区可全速跑，一旦触达 L3，可调用的工具集瞬间收缩到只读 + 预演。Cursor 事件的根因之一，正是 backup 删除工具和生产库删除工具处于同一半径内——备份本应处在 agent 的能力域**之外**。把"备份必须在工作目录之外、用独立凭证"写进 L3 治理，比任何"危险工具确认弹窗"都管用。

## 五、Ctrl+Z 架构：undo 栈的三种实现及其边界

承认"必须能回退"之后，工程问题变成：**对哪类动作，哪种 undo 有效？** 实践中有三条路径，各有硬边界。

```mermaid
flowchart LR
    A[动作] --> Q{可逆性层级?}
    Q -->|L0-L1 本地| G[内容寻址快照<br/>git/快照栈]
    Q -->|L2 有逆操作| C[补偿事务<br/>解绑/撤单/退款]
    Q -->|L3 无逆操作| S[影子执行<br/>dry-run 预演]
    Q -->|L4 资金物理| N[永不自动<br/>人审 + 人工对账]
    G --> R[可回滚]
    C --> R
    S --> P{副作用可模拟?}
    P -->|是| D[采纳]
    P -->|否| N
```

- **内容寻址快照（git-checkpoint）**：对文件树完美，代价极低。STRATUS 的"undo 到上一个检查点"主要走这条路。**边界**：只覆盖 L1，对外部副作用盲视。
- **补偿事务（compensating transaction）**：对 L2 有效——发了一封邀请就发一封撤销，绑了一张卡就解绑。**边界**：要求逆操作存在且幂等；一旦动作有"已被人看到"的副作用（邮件已读、推送已下发），补偿也只能止损不能消除。
- **影子执行（shadow / dry-run）**：对 L3 是唯一现实解——先用只读权限或沙箱模拟整条动作链，验证不破坏能力域再真跑。**边界**：当副作用依赖外部真实状态（真实余额、真实库存）时，影子执行给的是"假阴性安全"，仍需人审。

三条路径共同承认一件事：**L4（资金出账、物理世界）没有 undo**。给它配 Ctrl+Z 是工程上的伪命题，唯一治理是"永不进入 agent 的自动能力域"。

## 六、AUP 与影响惩罚：把副作用写进决策

前面四节是"硬围栏"，本节是"软约束"：让 agent 自己**不愿意**制造副作用。这来自 AI 安全的成熟方法——**Attainable Utility Preservation（AUP，可达效用保持）**。其逻辑是：定义一组 agent 本不需要的辅助目标，惩罚任何使这些目标"更难达成"的动作。一辆扫地机器人撞倒花瓶，错不在"撞倒"本身，而在于撞倒之后，"把花瓶摆回去"这个辅助目标的可达度掉了。

迁移到 LLM agent，落地形态是一份**影响账本（impact ledger）**：每步记录"我改变了环境的什么、谁的能力因此受损"，并设一个**副作用预算**：

```python
# 影响惩罚：动作不仅要达成任务，还要不削减辅助目标的可达度
def impact_penalty(action, env):
    reachable_before = env.attainable_aux_goals()
    env.apply(action)
    reachable_after  = env.attainable_aux_goals()
    # AUP 核心：可达度下降即副作用
    penalty = reachable_before - reachable_after
    if penalty > BUDGET:
        return Reject("side-effect budget exceeded")
    return Accept(action)
```

AUP 与 TNR 互补：TNR 是硬门控（L3+ 必停），AUP 是软偏好（L1/L2 区也要少动）。二者叠加，才构成"既敢跑、又不乱跑"的自主度。可逆性盲区的最终解，不在某一个框架的某一个开关里，而在于**把可逆性、爆炸半径、影响惩罚这三件事变成 agent 的一等公民字段**——而不是留给部署者事后用 yaml 祈祷。

## 推荐方案

- **个人开发者 / 单人 repo**：L0–L1 全自动 + git 自动快照即可，TNR 太重，不必上。
- **会触达外部 API 的脚本型 agent**：必上爆炸半径分级表（第四节 yaml），L2 强制 dry-run，L3 强制人审，备份/凭证移出工作目录。
- **长程运维 / 云工程 agent**：上 TNR（STRATUS 同款 undo-and-retry），并部署 ACRFence 式意图感知围栏，杜绝"回滚即双花"。
- **会动钱的 agent（电商、交易、采购）**：L4 永不自动，支付只走"人审 + 人工对账"双签，不配任何 undo 幻觉。
- **训练营/产品包装**：把"可逆性光谱五段 + 爆炸半径分级表 + AUP 影响账本"做成一套可交付的治理 starter kit，远比又一个"全自主 YOLO agent demo"有护城河——2026 年缺的不是能跑的 agent，是**知道什么不能跑**的 agent。

## 参考来源

1. [9 Seconds to Irreversible: The Cursor Incident — Rogue Security](https://www.rogue.security/blog/cursor-9-seconds-to-irreversible) — Cursor 编码 agent 在约 9 秒内删除生产数据库及其备份的事件复盘，论证备份必须在爆炸半径之外。
2. [An 'undo-and-retry' mechanism for agents — IBM Research](https://research.ibm.com/blog/undo-agent-for-cloud) — IBM 与 UIUC 提出 STRATUS，基于 Transactional-No-Regression 的 undo-and-retry，NeurIPS 2025，AIOpsLab/ITBench 上超 SOTA 150%。
3. [ACRFence: Preventing Semantic Rollback Attacks in Agent Checkpoint-Restore — eunomia](https://eunomia.dev/blog/2026/05/21/acrfence-preventing-semantic-rollback-attacks-in-agent-checkpoint-restore/) — 揭示 checkpoint/restore 会重放不可逆动作，造成重复支付与权限复活（语义回滚攻击），并给出意图感知围栏方案。论文见 arXiv:2603.20625。
4. [The Coding Agent Autonomy Curve: Reading Is Free, Merging Is Incident-Class — Tian Pan](https://tianpan.co/blog/2026-04-27-coding-agent-autonomy-curve-blast-radius-tiers) — 论证单一自主开关是错误抽象，应按爆炸半径逐工具分级，动作代价横跨七个数量级。
5. [How we contain Claude across products — Anthropic](https://www.anthropic.com/engineering/how-we-contain-claude) — Anthropic 工程团队关于如何为 Claude 各产品"封顶爆炸半径"的官方工程实践。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
