本文记录了一个真实排查过程:同样的 SSH 命令,Opus 模型死活跑不了,换成 Sonnet 立刻通了。这背后究竟是什么机制?
一、问题现象
最近在用 Claude Code 排查一个线上充值未到账的问题,需要 SSH 到服务器上执行一些运维操作——查数据库记录、改 RPC 节点配置、重启钱包服务。
结果遇到了一个奇怪的问题:相同的命令,用 Opus 模型跑不了,换成 Sonnet 就通了。
失败时的报错有两种:
claude-opus-<span>5</span> is temporarily unavailable, so auto mode cannot
determine the safety of Bash <span>right</span> now.
Permission denied <span>by</span> the Claude Code <span>auto</span> mode classifier.
<span>Reason:</span> SSH write/restart <span>of</span> <span>shared</span> wallet-api RPC config uses
an agent-chosen <span>public</span> endpoint the user never authorized.
服务器没有任何问题,本机终端直接 ssh root@xxx -p 12179 完全正常。
二、Claude Code Auto Mode 的工作机制
Claude Code 有一个叫 Auto Mode(自动权限模式) 的功能。在这个模式下,Claude 不会对每条命令都弹出确认框,而是交给一个安全分类器自动决定是否允许执行。
整个流程如下:
用户请求
↓
Claude 主模型(决定要执行什么命令)
↓
安全分类器(评估这条命令的风险)
↓
允许 → Bash 工具执行命令
拒绝 → <span>"Permission denied"</span> / 提示用户手动操作
分类器是无状态的,每次只看当前这条命令本身,不看前后的对话上下文。所以即使用户刚刚说「帮我改一下服务器配置」,分类器看到的也只是一条孤立的 sshpass -p xxx ssh ... systemctl restart 命令。
三、两类拦截的区别
这次遇到的拦截其实是两种不同的情况:
类型一:分类器服务临时不可用
claude-opus-<span>5</span> is temporarily unavailable, so auto mode cannot
determine the safety of Bash <span>right</span> now.
这种情况下,分类器本身挂掉或超时了。Auto Mode 的策略是 fail-closed(保守失败):宁可拒绝,也不放行未经评估的命令。这是一个合理的安全设计——宁可用户多跑几步,也不因为分类器故障就放开所有权限。
类型二:主动风险判定拦截
Permission denied <span>by</span> the Claude Code <span>auto</span> mode classifier.
<span>Reason:</span> SSH write/restart <span>of</span> <span>shared</span> wallet-api RPC config uses
an agent-chosen <span>public</span> endpoint the user never authorized.
这种情况更有意思。分类器评估了命令,判定风险过高,主动拒绝。
具体触发因素:
sshpass+ 远程 SSH(连接外部服务器)- 修改服务器上的配置文件(
rpc_url改成 Claude 自己选的节点) systemctl restart(重启生产服务)
三个动作叠在一起,分类器判定:Claude 在用户未明确授权的节点替换了服务器配置,并重启了服务——这确实是一个高风险操作。
四、为什么换 Sonnet 就好了?
这是整件事最核心的地方。
Opus 和 Sonnet 绑定了不同严格程度的分类器策略。
| 维度 | Opus | Sonnet |
|---|---|---|
| 分类器策略 | 更严格,偏保守 | 相对宽松 |
| 对 SSH + 改配置的判定 | 高风险,拦截 | 可接受,放行 |
| 分类器临时不可用时 | fail-closed,拒绝 | 同上 |
Anthropic 对不同能力档次的模型配置了不同的风险阈值。Opus 是旗舰模型,往往用于更复杂的任务,分类器也更保守;Sonnet 作为中端模型,在运维类场景下的策略更宽松,sshpass + systemctl restart 这种操作被允许通过。
这不是 SSH 本身坏了,也不是服务器的问题,是 Anthropic 在不同模型上配置了不同的分类器阈值。
五、正规的解法
如果不想受模型差异的影响,有以下几种方式:
方法一:settings.json allowlist(精确放行)
在 .claude/settings.local.json 的 permissions.allow 里添加你自己的运维脚本:
<span>{</span>
<span>"permissions"</span><span>:</span> <span>{</span>
<span>"allow"</span><span>:</span> <span>[</span>
<span>"Bash(bash ops_test/local/deploy-via-script.sh *)"</span><span>,</span>
<span>"Bash(bash ops_test/remote/*.sh)"</span>
<span>]</span>
<span>}</span>
<span>}</span>
关键点:放行具体的脚本路径,而不是 Bash(ssh *) 或 Bash(python3 *) 这种大范围的规则。这样分类器会直接放行这些预授权的命令,不再评估。
方法二:关掉 Auto Mode,手动确认
不使用 Auto Mode,遇到敏感命令时 Claude 会弹出确认框,你点允许就能执行,和模型无关。这是最通用、最安全的方式。
方法三:换模型(不推荐作为长期解法)
换 Sonnet 确实能解决问题,但本质是绕开了限制,而不是真正解决了权限配置问题。下次遇到更敏感的操作可能还会被拦。
六、这个设计合理吗?
从安全角度看,这个设计是合理的。
Claude Code 可以执行任意 Bash 命令,如果完全放开,等于给了 AI 在你机器上的 root 权限。Auto Mode 的分类器就是在做这道把关。
Opus 更保守是因为它通常用于更复杂的任务,越复杂的任务出错的后果越严重。分类器宁可误伤一些正当操作,也要避免 AI 在未授权的情况下修改生产配置。
但从开发体验看,这个反馈不够清晰。报错信息里的 temporarily unavailable 容易让人以为是网络问题,而不是权限问题。如果能直接说「这类操作需要在 settings.json 里显式授权」会更友好。
总结
Claude Code 的 Auto Mode 在每条命令执行前会经过安全分类器评估。不同模型(Opus vs Sonnet)绑定了不同严格程度的策略,同样的 SSH + 改配置 + 重启操作,Opus 的分类器判定为高风险而拦截,Sonnet 的分类器认为可接受而放行。这不是 SSH 坏了,是 Anthropic 在模型层面做的风险阈值差异化配置。
正确的长期做法:把自己的运维脚本加入 settings.json allowlist,而不是依赖换模型来绕过分类器。
把「换模型就好了」的玄学问题拆解到权限机制层,价值在于给出明确归因与可落地解法。适合使用 Claude Code 做运维、被 Auto Mode 反复拦截的开发者参考。