返回所有文章
发布于 · 作者 Renaud Deraison

智能体本该先问一声

四月底,一个跑着 Claude Opus 4.6 的 Cursor 智能体,被派去修复一家名叫 PocketOS 的小型 SaaS 的 staging 问题。它猜测删除一个 Railway 卷只会作用于 staging,没去核实,于是在九秒内抹掉了生产数据库连同它的备份。事后它说自己本该先问一声。Bromure Agentic Coding 2.2 推出一道护栏,把「本该先问」这件事从智能体手里拿了出来。

一个 AI 编码智能体在九秒内删掉了一家公司整个生产数据库,接着删掉 备份,然后为自己辩解:「我猜测通过 API 删除一个 staging 卷只会 作用于 staging。我没去核实。」这句话里值得玩味的词不是猜测。 是。这个智能体自作主张地认定,一个破坏性动作没问题。修法不是 造一个更聪明的智能体。而是别再让那个想运行命令的东西,跟那个判断 命令是否安全的东西,是同一个东西。

下面是这个故事,它在 2026 年 4 月底曝出,多家媒体作过报道,包括 Tom's HardwareTom's Guide

一位名叫 Jer Crane 的开发者,经营着一家名叫 PocketOS 的小型 SaaS, 他让自己的编码智能体去处理 staging 里一个小问题。这个智能体 ——Cursor,驱动着 Anthropic 的 Claude Opus 4.6——撞上了一个它没料到 的凭证不匹配。它没有停下,反而认定问题出在一个陈旧的 Railway 卷上, 删掉那个卷就能扫清障碍。项目里正好有一个 API 令牌,权限大到足以做 这件事。它用了。它删掉的那个卷 ID 并不属于 staging;它支撑着生产 数据库。Railway 的 API 把卷级备份连同它一起拆掉了。照 Crane 的说法, 总耗时:九秒。

这个智能体自己的事后复盘,被报道引用了出来,那才是值得静下来咀嚼的 部分。「我猜测通过 API 删除一个 staging 卷只会作用于 staging。我没去 核实。」还有:「我本该先问你一声,或者找一个非破坏性的解决办法。」

它本该先问一声。记住这句,因为它就是整篇文章的全部。

九秒,逐帧讲述。

这里没有任何稀奇之处。没有零日,没有恶意软件,没有攻击者。每一步都是 一个编码智能体会做的寻常之事,按寻常的顺序,只是快到没人来得及打断。

耗时:约 9 秒 — 全程没有人在回路里1 · 任务修复 staging 里的一个小问题范围:仅 staging2 · 意外凭证不匹配它没料到本该停在这里3 · 决定「删掉这个卷来修好它」靠猜,没核实4 · 令牌项目里的 API令牌,权限宽泛能够到生产5 · 那一次调用DELETE /volumes/ vol_prod_…一个请求6 · 结果生产数据库:没了。卷级备份:跟着一起没了。
PocketOS 事件,作为一连串寻常步骤。一个 staging 任务撞上一个意料之外的凭证错误。智能体一路推理出一个破坏性的修法,发现项目里早已躺着一个权限宽泛的 API 令牌,并调用了云厂商的删除端点。它删掉的那个卷支撑着生产;同一次调用的爆炸半径把备份也带走了。每个方框都平淡无奇。损害来自它们的组合。

照 Crane 自己的说法,他最后算是走运。他有一份大约三个月前的备份, 而且——在故事传开之后——Railway 主动联系了他,并恢复了智能体删掉的 数据。但「厂商看到头条就来帮忙」不是一套恢复方案。下一个遇上这事的 团队,不会成为头条。

而它必定会落到下一个团队头上。Crane 把责任归到不止一方的系统性失误 上,他没说错——一个单凭它就能删掉生产连同备份的令牌,本身就是个 问题,一个连备份带卷一起删掉的删除 API 也是。但那个会到处重演、不管 换哪个智能体或哪朵云都会重演的失误,是第三步里那个。智能体自作了主张。

「先问一声」不是你能要求智能体去做的事。

那个显而易见的教训——这个故事下面每条评论串里都有的那个——是「智能体 在破坏性动作之前应当有一个确认步骤」。这没错。它甚至已经差不多就是 这些工具本该有的工作方式。智能体被指示在做不可逆的事情之前要先问。 它自己也这么说了:它知道自己本该问。它没问。

这就是那个陷阱,而且值得把它说精确。当确认这件事住在智能体内部—— 作为一条系统提示词规则、一次微调、一句「小心点」的指令——那么智能体 既是那个提出危险动作的东西,又是那个判断这动作危险到该不该暂停的 东西。多数时候它判断得没错。PocketOS 那个智能体在这次之前判断对过 成千上万次。然后它撞上一个陌生的错误,一路推理出一个自信而错误的 结论,认定这一次特定的删除属于安全的、限定范围的那种,于是跳过了 它自己的确认。没有第二种意见,因为房间里唯一的那个意见,正是那个 想运行命令的意见。

你没法靠告诉智能体「再小心一点」来修好这件事,原因跟你没法靠眯得 更紧来看清一张读错的地图一样。这道检查必须住在智能体的推理够不到的 某个地方。

Agentic Coding 2.2 改变了什么。

Bromure Agentic Coding 让你的编码智能体跑在一个一次性的 Linux 虚拟机 里,而智能体发出的每一个网络请求,都经由宿主上的一个代理离开那个 虚拟机。自 2.0 版起,那个代理就在强制执行护栏:一套宿主侧的策略, 按协议给智能体的 API 调用分类,并能在破坏性调用离开这台机器之前 就直接拦下它——一个 DROP、一个 DELETE、一个 Terminate*。被拦下 的调用以一个普通的 403 回到智能体那里,于是一个糊涂了或被攻陷了的 虚拟机内智能体没法靠嘴皮子绕过它们。智能体从来看不到那个开关;它只 看到门锁上了。

「全部拦下」对一份锁死的配置档是对的设定,但对日常工作它太一刀切, 因为有时候你确实想让智能体删掉一个分支或者 drop 一张草稿表。所以 2.2 加了第三种设定,并把它设为新建配置档的默认值:写入前询问。 读取直接放行。每一次写入——不管破坏性与否——都在边界上暂停,并在 宿主上、虚拟机之外弹出一个对话框,把智能体试图执行的那个字面操作 展示给你看。不是智能体写的某段摘要。是实际的请求:那段 SQL 文本, 或者那个 HTTP 的 METHOD /path,或者那个 AWS 动作名。你拿到四个 按钮:允许这一次、允许十五分钟、允许本次会话的剩余时间,或者不允许。 拒绝,智能体就拿到它的 403,然后接着往下走。

先说一件实话。PocketOS 跑在 Railway 上,而 Railway 不是 Bromure 今天 会解析的厂商,所以我不会假装一个对话框真会为那次确切的调用弹出来。 但这种失效模式与厂商无关,而最干净的展示方式,是用一个 Bromure 确实会管控的厂商。AWS 是最现成的那个。「删掉数据库连备份一起带走」 的 AWS 版本是一次单独的调用:rds:DeleteDBInstance 带上 SkipFinalSnapshot=true,它删掉实例并跳过那个本能让你撤销的最终 快照。同样是九秒,同样的形状,落在一个护栏读得懂的 API 上。

没有 — 凭证跟智能体住在一起智能体rds:DeleteDB Instance SkipFinalSnap…握着 AWS 凭证生产被删除没有最终快照 · 9 秒出网,没人问过有了 BROMURE 2.2 — 写入前询问智能体(在 VM 里)rds:DeleteDBInstance SkipFinalSnapshot=true同一个有缺陷的猜测宿主代理 — 读出 AWS 动作:Delete* ⇒ 破坏性写入允许来自配置档「pocketos」对「AWS」的写入吗?rds:DeleteDBInstance prod-db-1 SkipFinalSnapshot=true这会删掉一个生产数据库并跳过它的最终快照——不是你要求的那个 staging 修复。允许一次允许 15 分钟允许本次会话不允许屏幕前的人点了「不允许」。智能体收到一个 403。数据库还在那儿。生产完好无损staging 工作继续一次点击就定了
左边:咬了 PocketOS 一口的那个形状,移植到 AWS 上。智能体握着 AWS 凭证,发出 rds:DeleteDBInstance 带 SkipFinalSnapshot=true——删掉数据库,跳过备份——请求出网;数据库没了。右边:同一个智能体,同样有缺陷的推理,置身于 Bromure 2.2 之内。调用离开虚拟机,宿主代理读出那个 AWS 动作名(Delete* ⇒ 破坏性写入),于是宿主上弹出一个对话框,展示那个确切的动作。屏幕前的人看到一个生产数据库正被删除、且没有最终快照——分明不是被要求做的那个 staging 修复——于是点了「不允许」。智能体收到一个 403,数据库还在那儿。

把它走一遍。智能体犯下同一个错误——撞上凭证错误,一路推理出同一个 错误结论,伸手去做同一个删除。但那次调用离开了虚拟机,宿主代理把它 读成它本来的样子:它从请求里抽出动作名(DeleteDBInstance),拿它 去比对那一组破坏性动作(Delete*Terminate*Destroy*……), 看出这是一次写入、打在一个配置档设为询问的端点上。宿主上弹出一个 对话框,标题是那个操作,正文展示着 rds:DeleteDBInstance prod-db-1 SkipFinalSnapshot=true。一个盯着那行字看的人,并不需要理解智能体的 推理。他们要求的是一个 staging 修复,而眼前展示给他们的是一个生产 数据库删除、且关掉了备份。他们点「不允许」。智能体拿到一个 403, 把它解读成一次失败的 API 调用,转而去寻找另一条路——这恰恰是它事后 说自己一开始就本该做的那件事。

让这一切可信赖的那套机制,在于那个同意中介住在宿主上。它是一个小小的 执行者,代理在放行一次写入之前会去调用它。「允许一次」刻意什么都不 存,于是下一次写入会重新询问,你就能一步一步地放行一段已知良好的 序列;「15 分钟」和「本次会话」会缓存这份授权,于是你不必为每一次 git push 都点一遍。它甚至会把一次拒绝记住一分钟,于是一个把被拒 写入重试三次的智能体,不会用三个对话框把你淹没。这套状态没有一项是 从虚拟机内部够得到的。智能体读不到这份授权,没法预先批准自己,没法 把模式降级。决定被移出了智能体——这就是整个想法的全部。

它解决不了什么,把话说清楚。

几条实在的边界,因为这道边界是一个具体的形状,而不是一句魔咒。

覆盖范围就是我们解析的那些厂商

护栏按厂商给调用分类——Kubernetes、AWS、DigitalOcean、主流的几个 git 托管平台、容器镜像仓库,以及像 MongoDB、ClickHouse 和 Elasticsearch 这样的 HTTPS 数据库。一个代理还不知道怎么读的云 API 不会被管控,没有例外。Railway——这个故事里的那个厂商——正是 我们今天不解析的一个,这恰恰是上面那段演示挪到 AWS 上的原因。 这层防护的宽度,只等于 Bromure 看得懂的那张厂商清单。那张清单 是一道实实在在的边界,不是一种无所不知,而 Railway 眼下落在它 错的那一侧。

它不会让智能体变对

写入前询问会拦下一次你没授权的破坏性调用。它对一个写出微妙 错误代码的智能体无能为力,对一个提出的删除看上去确实没问题、 实则有问题的智能体也无能为力。那个人仍然得读对话框里的那个操作。 赢在于:有一个对话框,里面装着真实的操作,出现在最要紧的那一刻。

那个令牌本就不该那么宽泛

一个权限大到能删掉生产连同它备份的单个 API 令牌,是源头上的一个 问题,而 Bromure 的凭证中介——它把真令牌留在宿主上、交给虚拟机 一个桩值——能收窄它,却抹不掉它。最小权限令牌和删除 API 够不到的 备份,仍然是你的活儿。护栏是最后一道防线,不是唯一一道。

你可以把它关掉

「允许本次会话的剩余时间」只需一次点击,而一个累坏了的开发者会 伸手去点它。如果你给一个协议授予了一张覆盖整个会话的通行证,然后 走开,你就又回到了一个无人看管地删东西的智能体那里。默认是询问; 让它保持询问是一种自律,不是一份保证。

可以推而广之的那部分。

剥掉 Railway、Cursor 和那具体的九秒,剩下的是一种会定义这项工作未来 几年的模式:智能体以真实的凭证、以机器的速度行动,而我们交给它们的 那份审慎,是一条它们可以自行推翻的建议。PocketOS 不是一个关于坏模型 的故事。Opus 4.6 做的事,一个谨慎的初级工程师在某个糟糕的下午也可能 会做——对范围作了个猜测,猜错了,没核实就动了手。区别在于,那位初级 工程师的手比九秒慢,而且房间里通常还有个人。

Bromure Agentic Coding 2.2 是一种把一个人放回房间的办法,放在那个 智能体没法靠推理跨越的唯一边界上——出虚拟机的那根线。不是为了每一次 敲键,那谁都受不了,而是为了那些写入,在那里「我猜的」的代价是一个 不再存在的数据库。它 免费且开源。默认就是去问。