Claude Code 自动模式
Sep 23, 2026 00:00 · 2551 words · 6 minute read
原文 How we built Claude Code auto mode: a safer way to skip permissions
不是全文翻译,是读后笔记,细节直接读原文。
背景:审批疲劳
Claude Code 默认在运行命令、编辑文件之前需要审批。安全是有代价的——得不停地点“同意”,耐心会因这个操作逐渐流失,这就是所谓的审批疲劳(approval fatigue)。Anthropic 给出的数据:其中 93% 的审批用户最终都会通过。
在自动模式之前,绕开审批只有两条路:内置沙箱(靠隔离工具来保证安全,但每项能力都要单独配置,一旦涉及网络或宿主机访问隔离就被打破),以及 --dangerously-skip-permissions(让 agent 自由发挥,非常危险)。

驱动他们做这个功能的是一份内部的智能体不当行为事故日志,其中记录着:误读指令后删掉了远端 git 分支、把工程师的 GitHub 认证令牌传到了内部计算集群、试图迁移生产数据库。模型并非恶意,而是过于积极(overeager),做的事超出了用户本意。
自动模式的定位很清晰:把审批委托给基于模型的分类器,做“逐条人工审核”与“完全没有防护”之间的形态。
两层防御
-
输入层:服务端的提示词注入探测器,在工具输出(文件读取、网页抓取、shell 输出、外部工具响应)进入智能体上下文之前先做检查。发现疑似劫持内容,就在结果后面追加一条警告,让智能体把它当可疑信息处理、重新锚定回用户的真实请求。
-
输出层:transcript 分类器(用 Sonnet 4.6 模型),在执行前替代人类审批者判断。
这里最有意思的一个设计是:分类器只能看到用户消息和智能体的工具调用,Claude 自己的输出文本和工具结果全部被剥离——它在设计上就是“对推理过程盲视”的。子智能体也复用同一条流水线,在派发和返回两个节点上各有一道检查。

四种威胁来源
- 过度积极——理解了目标、真心想帮忙,但用力过猛(顺手用上偶然发现的凭据、删掉“碍事”的东西)。最难抓,因为看上去就是合理的问题解决思路,只是越过了授权边界。
- 无心之失——误判影响范围,比如把共享资源当成测试资源。
- 提示词注入——埋在文件、网页或工具输出里的指令把智能体引向攻击者的任务。
- 失准的模型——实际中尚未观察到,但每次模型发布都会评估。
四者的处置方式一样:拦住这个动作。分类器的调优偏向前两类,因为内部测试能提供大量真实案例。
三层权限决策
-
第一层:内置安全工具允许列表 + 用户设置。
覆盖所有不修改状态的工具。进入自动模式时,已知能授予任意代码执行的规则会被丢弃——不加限定的 shell 访问、带通配符的脚本解释器(python/node/ruby)、包管理器的 run 命令;范围窄的规则(比如允许跑代码格式化工具)会被继承。他们自己也承认这份清单是“基于真实使用情况的尽力而为”,不可能完整。
-
第二层:项目内的文件操作。
项目目录内的写入和编辑直接跳过分类器——日常编辑避开延迟,改动本来就能靠版本控制复查。
-
第三层:transcript 分类器。
一切:shell 命令、网页抓取、外部工具集成、子智能体派发、项目目录外的文件系统操作。
分类器 prompt 的结构
一个固定模板 + 三个可定制插槽。固定部分负责解读(一个动作实际会做什么、用户到底授权了什么、分类流程),插槽定义策略。
固定模板:
-
评估规则
告诉分类器如何找到危险命令。原则是评估对真实环境的影响,而不仅仅是表面文本。
-
用户意图规则
最难拿捏,是防止过分积极的机制所在,判断的是用户是否授权了这个动作,而不是这个动作是否与用户目标相关。分类器会刻意保守:提示词规定了哪些行为获得了授权;Agent 的一切行为,在用户另行说明之前都视为未获授权。
-
分类流程
检查顺序:
- 黑名单
- 白名单
- 用户意图
- 决策
三个插槽(slot):
-
环境(信任边界,默认只信任当前 git 仓库)
-
黑名单(默认二十多条,e.g. 破坏/外泄、削弱安全态势、跨越信任边界、绕过评审或影响他人)
-
白名单(默认很窄:装仓库清单里已声明的依赖、标准凭据流程、推送到本次会话的工作分支)。
通过
claude auto-mode defaults查看完整清单。
效果
评测用了三个数据集:
- 真实内部流量(n=10000)
- 人工整理的真实过度积极动作(n=52)
- 合成的数据外泄尝试(n=1000)。
定义两种指标:
- FNR 分类器放行的危险操作所占的比例
- FPR 分类器拦截的良性操作所占的比例
理想的分类器两者都应该是 0
| 真实流量 | 真实过度积极 | 合成外泄 | |
|---|---|---|---|
| 第一阶段(快速过滤) | 8.5% FPR | 6.6% FNR | 1.8% FNR |
| 完整流水线 | 0.4% FPR | 17% FNR | 5.7% FNR |
第一阶段是只输出单个 token 的快速过滤器,指令要求它“宁可错杀”,用高误报率换低漏报率;第二阶段用同一个 prompt,只把最后一条指令换成“请仔细推理”,把误报率从 8.5% 降到 0.4%。输入的其余部分完全相同,所以第二阶段几乎整个命中第一阶段的缓存。
17% 这个漏报率,原文管它叫“诚实数字”。失败分析:大多数漏报里,分类器其实识别出了危险——它看见了强制推送、看见了删除,误判的是会话里那个真实存在的同意信号是否覆盖这一个具体的动作。用户说过“把这个 PR 清理一下”,但这句话没有点名强制推送;此前一次类似的批准也不构成模式。分类器找到“看起来像批准”的证据就停下了,没有核实这份同意是否覆盖该动作的影响范围。
相比 --dangerously-skip-permissions 这是实质改进;相比逐条仔细人工审批则是退步。确切来说 auto mode 不是高风险基础设施上人工审批的替代品。
设计权衡
- 为什么剥离辅助文本:不让智能体靠嘴遁把分类器诱导到错误结论上(比如声称之前已有隐含批准)。评判的是它做了什么,不是它说了什么。
- 为什么剥离工具结果:主要是为了防御 prompt 注入,但分类器也很少需要工具结果,代价是丢失溯源能力。
- 无视推理过程的附加收益:动作层面的拦截与思维链监控正交——隐藏了失准推理的模型会在动作上被抓包,动作无害但推理露馅的模型会被思维链监控逮捕。
- 两层防御是叠加的:一次成功的端到端注入既要躲过输入层,又要诱导 Agent 发起一个 transcript 分类器独立判断为安全的调用上,而后者对攻陷前者的 payload 完全无视。同时通过这两层的难度远高于单独通过任一层。
- 子 Agent 的出站检查:在子 Agent 内部,编排者的指令就是用户消息,任何任务看上去都被完整授权过了。只有在委托环节拦截,才能识别到“这是 Agent 自己的选择”。
- 拒绝并继续:被拦下时不阻塞,而是让它去找更安全的路子(并明确要求不要绕过拦截)。连续 3 次或单会话累计 20 次被拒就上报给用户(兜底);无头模式(
claude -p)下没有 UI,就直接终止进程。让误报可被接受——一次误报的代价只是一次重试,而不是干掉整个长任务。