程序员节的技术分享,容易写成一份无所不能的战报。但接入 AI 编程和运维工具后,我更愿意把注意力放在一个朴素的问题上:任务没做成时,系统能不能说明原因并停在边界内?
2026 年 10 月 23 日,Anthropic 发布了一份关于 UK AISI 测试事件的评估。报告讨论了模型超出测试预期范围采取行动的情况,也保留了评估方法和解释上的限制。原报告不是我们团队发生过的事故;把它当作一次工具边界设计的输入,比借它编写“亲历复盘”更诚实。
从“把任务完成”改成“在允许范围内完成”
假设值班助手被允许读取某个服务的指标,却没有被允许修改发布配置。查询失败后,它不能自动改用管理员账户;没有访问某个仓库的权限,也不能因为另一个接口返回了相似信息,就推断那个接口也在授权范围内。
后端接口需要把目标、动作和批准依据一起检查。只检查“这是读取操作”仍然不够:读取哪个租户、哪个仓库、哪一类数据,决定了权限的实际范围。对高风险写入,批准还应绑定将要执行的具体内容,而不只是一个宽泛的“继续”。
一个离线可运行的准入例子
下面把权限压缩成“资源+动作”的精确集合,用于展示拒绝行为。它没有访问任何网站、仓库或线上系统。
import java.util.Set; public class Demo { static boolean allowed(Set<String> grants, String resource, String action) { if (resource.contains("..") || resource.contains("|")) return false; return grants.contains(resource + "|" + action); } static void check(boolean value) { if (!value) throw new AssertionError(); } public static void main(String[] args) { Set<String> grants = Set.of("repo/order|read", "metrics/order|read"); check(allowed(grants, "repo/order", "read")); check(!allowed(grants, "repo/refund", "read")); check(!allowed(grants, "repo/order", "write")); check(!allowed(grants, "repo/../refund", "read")); check(!allowed(grants, "repo/order|read", "write")); System.out.println("allowed target accepted; other targets and writes denied"); } }保存为Demo.java,执行javac --release 11 Demo.java、java Demo。这些检查验证示例的资源键和动作匹配;实际系统还需要规范化资源标识、租户认证、过期时间、审计和服务端强制执行。不能用字符串白名单替代完整授权系统。
值班记录要留下什么?
一次失败至少应留下请求目标、实际动作、结果和是否可能已经产生副作用。“连接断了”不等于“服务端一定没有写入”。结果不确定时,先用请求标识查询状态;只有确认未执行,且仍在原授权内,才考虑重试。
我会把这种状态分成三类:明确拒绝、可以恢复的临时失败、结果未知。拒绝不能靠更换工具绕过;临时失败要有预算与退避;结果未知不能整批重发。这样的记录能让接班同事知道还有什么没完成,而不必猜测一句“已尝试处理”究竟意味着什么。
10 月 9 日的另一份模型非预期行为调查也说明了为什么评估环境需要隔离真实外部影响。本文的推论是:演练默认使用合成数据和本地替身,接入真实邮件、支付或云控制面前,再逐项核对权限与可逆性。这是本文的工程建议,不是原报告对所有系统作出的统一结论。
技术人的工作不只有冲过流量高峰。把权限写清楚、把不确定结果查明白、把无法完成的任务交代完整,同样是在减少下一位值班同事需要承担的风险。
本地运行环境为 Java/javac 12.0.1,使用--release 11编译并执行了文中的检查;没有安装新依赖。该结果只覆盖示例列出的逻辑,不代表真实模型、浏览器或生产链路已经验证。