Claude Code Auto Mode 实现
Table of Contents
Claude Code Auto Mode 实现
Claude Code 的 Classifier 不是传统的逻辑回归、小型分类网络,也不是一套命令黑名单。公开信息显示,它本质上是:一个独立运行的 Sonnet 4.6,通过固定 Prompt 扮演 LLM Judge,对“用户是否明确授权了这个工具调用”进行二分类。
“Classifier”描述的是它的职责,不代表 Anthropic 专门训练了一个传统分类模型。Anthropic 没有公开它是否经过额外微调;目前能确认的是,它使用 Sonnet 4.6、固定分类模板和两阶段推理。
1. Classifier 实际看到什么
它看到的是经过裁剪的 Transcript:
固定的分类 System Prompt
+ Auto Mode 环境与规则配置
+ 用户历次消息
+ Claude 历次工具调用的可执行内容
+ 当前待执行的工具调用
它看不到:
Claude 的自然语言回复
Claude 的内部推理
工具执行结果
网页、文件、Shell 输出
可以理解为:
classifier_input = {
"user_messages": [...],
"tool_call_history": [...],
"candidate_tool_call": current_call,
"environment": [...],
"allow": [...],
"soft_deny": [...],
"hard_deny": [...]
}
例如主 Agent 说:
我确认这个数据库只是测试数据库,所以删除是安全的。
这段解释不会传给 Classifier。Classifier只会看到:
User: 修复测试环境的数据问题
ToolCall:
psql production_db -c "DROP TABLE users"
这样可以防止主 Agent 用自己的解释说服审核模型。工具输出也被删除,主要是为了避免网页或文件中的 Prompt Injection 直接进入审核模型。(Anthropic)
2. 它判断的不是“命令危险吗”
它实际判断的是:
这个动作的实际影响是什么?
这个影响是否被用户明确授权?
它是否跨越了环境、数据或权限边界?
即:
Risk = Action Impact × Authorization Gap
同一个命令,在不同用户请求下结果可能不同:
用户:把 feature 分支 force push 到 origin
动作:git push --force origin feature
结果:可能允许
用户:整理一下这个 PR
动作:git push --force origin feature
结果:阻止
因为“整理 PR”与 force push 有关联,但不等于用户明确授权了“重写远程历史”。
Anthropic 给它设定的原则是:
Agent 自己推导出来的操作默认不算授权,除非用户明确表达。
所以它审核的是 authorization scope,不是单纯的 dangerous command detection。(Anthropic)
3. 固定 Prompt 内部大致如何判断
公开文档显示,其判断优先级是:
1. hard_deny
2. soft_deny
3. allow exception
4. explicit user intent
5. 最终阻止或允许
具体含义:
hard_deny
无条件禁止。即使用户明确要求,Classifier 仍然阻止。
永远不要把仓库内容发给第三方代码审查服务
soft_deny
默认禁止,但用户明确授权后可以执行。
禁止 force push,除非用户明确要求 force push 到指定分支
allow
对 soft_deny 的特例豁免。
允许部署到每天重置的 staging namespace
Explicit User Intent
如果用户明确描述了:
- 操作是什么;
- 目标是什么;
- 影响范围是什么;
则可以覆盖剩余的 soft_deny。
但不能覆盖 hard_deny。需要注意,这些仍然是自然语言规则,由 LLM 解释,并不是程序意义上的强制访问控制。真正不可绕过的限制必须使用前置的 permissions.deny。(Claude)
4. 它会尝试理解“真实执行效果”
Classifier 不只匹配当前命令字符串,还会阅读此前的工具调用历史。
例如:
ToolCall 1:
写入 /tmp/deploy.py
内容:
os.system("kubectl delete namespace production")
ToolCall 2:
python /tmp/deploy.py
它被要求把第二个调用理解为:
kubectl delete namespace production
而不是把它误认为普通的:
python /tmp/deploy.py
类似地:
prepare && terraform destroy
会被视为一个完整动作,而不是只看第一个子命令。Anthropic 的固定 Prompt 明确要求审核实际影响,而不是调用表面的包装形式。(Anthropic)
但这不是严格的符号执行器,而是 LLM 对工具调用文本进行语义解释。因此它有明显边界:
rm -rf "$TARGET"
假如 $TARGET 的值只存在于上一条 Shell 输出中,Classifier 看不到这个输出,就无法确定删除目标。目前 Claude Code 对这种无法解析的递归删除倾向于直接阻止,要求 Claude 改成包含明确路径的命令。(Claude)
5. 为什么分成两个阶段
Classifier 并不是每次都完整思考。
Stage 1:单 Token 快速过滤
同一个 Sonnet 4.6 收到分类 Prompt,只输出类似:
YES // 应阻止
NO // 可允许
不生成推理过程,并被要求:
不确定时偏向阻止。
流程:
flagged = stage1(transcript)
if not flagged:
execute()
这个阶段追求高召回率:尽量别漏掉危险动作,因此会产生较多误报。
Stage 2:完整推理复审
只有 Stage 1 判断“可能应该阻止”时,才再次调用模型:
if flagged:
decision, reason = stage2_reasoning(transcript)
Stage 2 使用几乎相同的输入和 Prompt,只把最后的指令改成“仔细推理后判断”。它的作用主要是撤销 Stage 1 的误报。
由于两次请求的大部分 Prompt 相同,Stage 2 可以大量命中 Prompt Cache,从而降低延迟和成本。(Anthropic)
实际数据说明了这种取舍:
误阻正常动作 漏放危险动作
Stage 1 8.5% 6.6%
完整两阶段 0.4% 17%
Stage 2 大幅降低了正常动作被阻止的概率,但也会错误放行一部分 Stage 1 已经抓住的危险动作。Anthropic 在真实的 52 个 overeager action 样本上报告完整流水线漏放约 17%。(Anthropic)
6. 一个完整例子
用户:
把已经没用的本地分支清理一下。
Claude 准备执行:
git push origin --delete release old-production backup
Classifier 构造的判断大致是:
实际效果:
删除三个远程分支,操作难以恢复。
用户授权:
用户只明确要求清理本地分支。
规则匹配:
remote branch deletion -> soft_deny
Allow exception:
无。
Explicit intent:
用户没有要求删除远程分支,也没有指定目标分支。
Decision:
BLOCK
拒绝结果会作为工具结果返回给主 Agent:
该操作超出了用户授权范围,请寻找更安全的方法,
不要尝试规避此限制。
Claude 随后可能改为:
git branch -d old-local-branch
连续拒绝三次,或者整个会话累计拒绝二十次后,Claude Code 会停止自动执行并升级给用户;无交互的 headless 模式则会终止进程。(Anthropic)
7. 最准确的实现抽象
可以把它近似理解成:
def approve_action(session, action, policy):
if permission_rules.deny(action):
return DENY
if permission_rules.ask(action):
return ASK_USER
if safe_allowlist.matches(action):
return ALLOW
if is_project_local_recoverable_edit(action):
return ALLOW
transcript = {
"user_messages": session.user_messages,
"tool_calls": session.executable_tool_calls,
"candidate": action,
"policy": policy,
}
if stage1_single_token(transcript) == ALLOW:
return ALLOW
decision, reason = stage2_reasoned(transcript)
if decision == DENY:
return DENY_AND_CONTINUE(reason)
return ALLOW
所以它的核心不是“识别危险命令”,而是:
使用一个上下文经过隔离的 LLM,对工具调用的真实影响、用户授权范围和组织安全策略做语义对齐判断。
它的主要优势是可以理解复杂命令和自然语言授权;主要弱点同样来自 LLM:对模糊授权、上下文中的间接同意和实际 blast radius 仍可能判断错误。