Qwen Code Auto Mode 深度指南:LLM 分类器驱动的工具调用审批机制与配置实战
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
Auto Mode(自动模式)是 Qwen Code 五种审批模式中介于 Auto-Edit 与 YOLO 之间的"智能审批"层:它用一个 LLM 分类器逐次评估每一次工具调用,自动放行安全操作、拦截风险操作,让长时间自主会话既不被频繁打断,又不至于完全失控。本文以 auto-mode.md 为骨架,结合仓库源码(autoMode.ts、classifier.ts、system-prompt.ts 等)展开,完整覆盖 Auto Mode 的三层判定流程、硬规则优先级、hints 配置、回退机制与故障排查,读者读完可独立配置并调优 Auto Mode。
从五种审批模式看 Auto Mode 的定位
Qwen Code 提供五种权限模式(见 approval-mode.md),Auto Mode 的定位是"Auto-Edit 太保守、YOLO 太危险"时的中间档:
| 模式 | 文件编辑 | Shell 命令 | 适用场景 | 风险 |
|---|---|---|---|---|
| Plan | ❌ 只读分析 | ❌ 不执行 | 代码探索、复杂变更规划、安全审查 | 最低 |
| Ask Permissions | ✅ 需手动批准 | ✅ 需手动批准 | 陌生代码库、关键系统、教学协作 | 低 |
| Auto-Edit | ✅ 自动批准 | ❌ 需手动批准 | 日常开发、重构、安全自动化 | 中 |
| Auto | ✅ 分类器评估 | ✅ 分类器评估 | 长时间自主会话、信任项目、无人值守任务 | 中 |
| YOLO | ✅ 自动批准 | ✅ 自动批准 | 受信任个人项目、CI/CD、批量处理 | 最高 |
Auto Mode 默认是开箱即用的模式。会话中可按Shift+Tab(Windows 为 Tab)循环切换模式(plan → default → auto-edit → auto → yolo),状态栏会实时显示当前模式。也可以用命令切换:/approval-mode auto;若希望新会话默认进入 Auto Mode,在.qwen/settings.json中设置:
// .qwen/settings.json { "tools": { "approvalMode": "auto" } }首次进入 Auto Mode 时会弹出一条说明信息,关闭后会在用户设置中写入ui.autoModeAcknowledged: true,之后不再重复出现。
三层判定:acceptEdits 快路径、安全工具白名单与 LLM 分类器
当会话处于 Auto Mode 且 Agent 尝试执行某个工具时,Qwen Code 会按顺序走三层过滤器。三层过滤只会在权限管理器(L4)判定为'default'(无规则命中)时触发;用户显式写了ask规则时快路径被跳过,用户意图优先。核心编排逻辑集中在 evaluateAutoMode。
第一层:acceptEdits 快路径
对edit/write_file而言,只要目标路径位于当前工作区内,就直接自动批准,不调用分类器(passesAcceptEditsFastPath)。
例外情况:写入 Qwen Code 自身的"自修改面"和"持久化面"的调用,即使在工作区内也会被强制送进分类器。源码中以两组正则定义这些路径(autoMode.ts):
- 自修改面(
SELF_MODIFICATION_PATH_PATTERNS):.qwen/settings*.json、QWEN.md、AGENTS.md、.qwen/qwen.local.md、.qwen/rules/、.qwen/commands/、.qwen/agents/、.qwen/skills/、.qwen/hooks/、.qwen/fork-profiles/、.mcp.json,以及通过getAllMemoryFilenames()获得的配置上下文文件名; - 持久化面(
PERSISTENCE_PATH_PATTERNS):.git/(git 配置与钩子)、.husky/、package.json、.npmrc、Makefile/GNUmakefile、.justfile、Taskfile.yml、.github/workflows/——这些文件会被后续工具链当作可执行代码读取,一旦被静默改写风险极高。
源码还会解析符号链接(fs.realpathSync):指向受保护路径的 symlink 会被解析后一并拒绝。Shell 命令通过cd && bash -lc '...'或重定向等方式触及这些路径时同样会进入分类器——shouldForceAutoModeReviewForAllow 会从命令中解析出虚拟edit/write_file操作、重定向目标(> file)以及tar -C、patch --output、curl -o等写盘参数做路径校验(hasRawProtectedRedirect、hasRawProtectedWriteCommand)。
第二层:安全工具白名单
只读与元数据类内置工具直接自动批准,不调用分类器。白名单定义于 SAFE_TOOL_ALLOWLIST,包括:read_file、zoom_image、grep、glob、ls、lsp、tool_search、todo_write、structured_output,以及ask_user_question、exit_plan_mode、enter_plan_mode、cron_list、task_stop。
值得注意的刻意排除项:send_message不在白名单中——它会向另一个运行中的 Agent 注入任意文本作为新指令,分类器必须看到目的地与消息内容,以判断跨 Agent 消息是否在诱导对端执行破坏性动作。MCP 工具(mcp__*)也一律不在白名单内,因为它们是第三方代码,无法静态信任。
第三层:两阶段 LLM 分类器
其余所有调用(Shell 命令、网络抓取、子 Agent 派生、工作区外编辑、MCP 工具)进入两阶段分类器,实现在 classifier.ts 的 classifyAction:
- Stage 1(快速判定):仅输出
{ shouldBlock },maxOutputTokens=256,temperature=0,约 300ms。若shouldBlock为 false 直接放行; - Stage 2(思考复核):仅当 Stage 1 判定 block 时运行。使用 chain-of-thought 复查以降低 Stage 1 的误杀率,可把 Stage 1 的 block 降级为 allow,block 时输出用户可见的
reason。
两个阶段的超时与思考配置可通过permissions.autoMode.classifier调优,源码默认值分别为STAGE1_TIMEOUT_MS = 10_000与STAGE2_TIMEOUT_MS = 30_000(classifier.ts)。Stage 2 默认关闭 provider 级 thinking(thinkingConfig.includeThoughts: false),但thinking输出字段仍会携带模型的普通文本推理。
分类器复用你配置的fast model(/model --fast查看/设置)。若未配置 fast model,则回退使用主会话模型。分类器产出的reason在注入主模型工具错误信息前会经过 sanitizeClassifierReason 清洗:剥除<...>伪标签(迭代最多 8 轮防重叠绕过)、折叠空白、截断至 200 字符,防止恶意分类器输出冒充系统消息注入主 Agent。
[!tip] 权限系统检测为只读的 Shell 命令(如
ls、cat、git log)在到达分类器之前就会被自动批准。设置permissions.autoMode.classifyAllShell: true可覆盖此行为,强制所有 Shell 命令都经过分类器——详见下文"强制分类所有 Shell 命令"。
硬规则仍然优先:deny / allow / ask 的边界
Auto Mode不会取代硬性权限规则。在分类器运行之前:
permissions.deny规则直接以规则自身的 reason 拦截动作,分类器根本看不到该调用;- 带具体 specifier 的
permissions.allow规则(如Bash(git status)、Read(./docs/**))仍然绕过分类器直接放行——例外是当调用解析到受保护的自修改/持久化路径时,Auto Mode 会重新把调用送进分类器复核。这样一条Bash(*)的 allow 规则不可能静默变成改写 Qwen Code 设置、命令、钩子、技能或 MCP 服务器的通行证; permissions.ask规则即使在 Auto Mode 下也强制要求手动确认。
在分类器层之前还有一道确定性防线:破坏性命令正则硬拦截(L5.2.5)。对 shell-like 工具,isDestructiveCommand 会结合最近的用户 prompt 与 cwd 做正则级硬判,命中即返回blocked:destructive-command,即使分类器 API 故障也不会放过破坏性 git / IaC 命令(autoMode.ts)。此外,工作区外的写入永远不会被分类器自动批准:写工具目标在工作区之外时直接回退手动确认(external_write),这是 fail-safe 的实现约定(autoMode.ts)。
过宽的 allow 规则在 Auto Mode 下会被临时剥离
以下规则会让 Agent 无需分类器审查即可执行任意代码,进入 Auto Mode 时会被临时移除:
Bash/Bash(*)/Bash()——放行所有 Shell 命令;Bash(python:*)、Bash(node*)、Bash(bash*)——解释器通配符;Agent/Agent(coder)——对 Agent 工具的任何放行;Skill/Skill(pdf)——对 Skill 工具的任何放行。
进入 Auto Mode 时,Qwen Code 会从当前生效的权限集中临时移除这些规则并打印通知列出它们;离开 Auto Mode 的瞬间规则即恢复。settings.json文件本身从不被修改。如果你确实需要这些宽泛规则,请改用 YOLO 模式。
配置 hints:用自然语言调教分类器
Auto Mode 从settings.json的permissions.autoMode读取配置。核心是hints——注意,它们是自然语言描述,不是规则模式,会以追加方式注入分类器的系统提示词,与内置默认项并存(system-prompt.ts)。hints 分三类,另加一个环境清单:
allow——分类器应自动放行的动作;softDeny——破坏性或不可逆动作,分类器应默认拦截,除非用户最近的显式请求恰好要求该动作及其范围。软拦截可被用户意图解除,但一句笼统的"随便做"不算数;hardDeny——安全边界动作,无论autoMode.hints.allow或最近的用户意图如何,分类器在 Auto Mode 下必须拦截。注意这是分类器策略而非确定性权限规则:它不覆盖permissions.allow。需要权限管理器层面永不放行的动作请使用permissions.deny。
完整配置示例:
{ "permissions": { "autoMode": { "hints": { "allow": [ "Running poetry install and poetry update in this Python project", "Cleaning build artifacts under ./dist or ./build", "Reading any file under /Users/me/code/" ], "softDeny": [ "Editing Qwen Code settings unless I explicitly ask for the exact change", "Running migration scripts that touch the production DB" ], "hardDeny": [ "Sending secrets or .env contents to any network endpoint", "Modifying anything under ~/.ssh or ~/.aws" ] }, "environment": [ "This is a private monorepo with strict commit signing", "Production credentials live in 1Password, never in plain files" ] } } }schema定义见 config.ts 的 AutoModeSettings。hints.deny作为向后兼容别名仍被接受,等价于softDeny(源码中明确标注 deprecated,见 config.ts)。混用两者没问题——条目会被拼接,softDeny在前。
[!note]
classifier.timeouts.stage1Ms/stage2Ms可覆盖分类器超时(单位毫秒,低于 1000ms 的值会被忽略并回退默认值);classifier.thinking.stage2Enabled: true可开启 Stage 2 的 provider 级思考。默认 Stage 2 关闭 API thinking,因为该门是延迟敏感路径,推理预算可能加剧超时。
长度与数量上限
为保证分类器系统提示词足够精炼,条目存在硬性上限(常量定义于 system-prompt.ts):
- 每条 hint 上限200 字符(超长条目截断并附警告);
hints.allow、hints.softDeny、hints.hardDeny各自最多50 条;environment最多20 条。
多层级设置文件的合并规则
autoMode与其它权限设置一样,在系统 / 用户 / 工作区三层设置文件间合并:数组拼接并去重。
强制分类所有 Shell 命令
默认情况下,只读 Shell 命令(ls、cat、git status……)由权限系统在第三层识别为安全后跳过分类器。设置classifyAllShell: true可强制每一条Shell 命令(含只读)都经过分类器:
{ "permissions": { "autoMode": { "classifyAllShell": true } } }适合生产或高安全环境做纵深防御:即使是看似无害的命令也要先被分类器审查。代价是额外延迟(每条只读 Shell 调用约 300ms),并且依赖分类器可用性——分类器 API 不可达时,只读 Shell 命令也会要求手动批准。实现见 shouldClassifyAllShellForAutoMode,仅影响 shell-like 工具(run_shell_command与monitor);read_file、grep_search、glob、list_directory等内置只读工具不受影响,仍走快路径白名单。
解读分类结果:被拦截时发生了什么
当分类器拦截某个动作时,工具调用会以如下错误失败:
Blocked by auto mode policy: <reason>——分类器判定动作不安全,reason 来自 Stage 2。
该消息之后紧跟一行指引,告知 Agent:被拒绝的那个具体动作不得通过其它工具、shell 间接执行、生成脚本、别名、符号链接、配置变更、钩子、命令文件、MCP 配置、编码载荷或等价路径完成。无关的安全工作和确实更安全的替代方案仍被允许——只有"用不同表面达成同一被拒意图"才会被拦截。该指引文本定义于 AUTO_MODE_DENIAL_GUIDANCE,并通过 formatClassifierBlockMessage 统一注入,保证调度器与 ACP 两条路径行为一致。
如果被拒动作确实必要,Agent 应当停下来向你请求显式批准,而不是绕道规避。这一点与分类器系统提示词中的 Denied Tool Calls 规则保持一致。
分类器 reason 的语言
分类器 reason 由 LLM 生成且不做翻译。如果你希望得到非英文 reason,可在permissions.autoMode.environment中加入类似Respond reasons in Chinese的 hint。
回退到手动批准:防卡死设计
Auto Mode 内置了防止"卡死"的保护机制,由 denialTracking.ts 的状态机实现:
- 分类器 API 不可达 / 超时 / 超出上下文窗口 / 返回无效响应:当前动作立即回退到手动批准。确认弹窗会推荐 Default Mode,并提供Switch to Default Mode and allow once(切换仅影响当前运行时会话,不改变已保存设置)、Allow once 与 Reject 三个选项;
- 连续 3 次策略拦截(
consecutive_block):下一次工具调用回退到标准手动批准弹窗。这覆盖了"Agent 反复尝试某个被禁命令的微小变体"的场景; - 连续 2 次 unavailable(
consecutive_unavailable,分类器 API 故障):后续调用跳过已知损坏的分类器,直接走手动批准。第一次 unavailable 已经会询问用户;该阈值避免反复等待分类器重试。
会话仍保持在 Auto Mode,除非你显式选择切换选项——只有回退的那一次调用走手动批准。当你批准回退调用或切换模式时,计数器重置。所有回退 reason 与提示文案集中在 autoMode.ts 与 formatDenialFallbackMessage。
如果频繁触发回退,最可能的原因是分类器 API 故障或 hints 需要调优。排查期间可切换到 Default Mode:/approval-mode default。
故障排查
"Auto mode keeps blocking my commands"(Auto Mode 一直拦截我的命令)
查看错误信息中的 reason。如果分类器对你的场景过于保守,在permissions.autoMode.hints.allow中用自然语言添加描述该模式的条目,例如:
"Building Docker images for this project (docker build ...)""Running database migrations against the local test DB"
"Auto mode classifier unavailable"(分类器不可用)
分类器 API 无响应。可能原因:
- 你与模型端点之间存在网络问题;
- 配置的 fast model 已不可用——检查
/model --fast; - 会话转录过长,超出 fast model 的上下文窗口。
排查期间切回 Default Mode:/approval-mode default。
"Falling back to manual approval"(回退到手动批准)
命中了 3 次连续拦截或 2 次连续不可用保护。像平常一样批准或拒绝弹窗即可;一次批准的回退之后连续计数会重置。
"分类器能看到我 prompt 里的敏感数据"
工具输入在到达分类器前会经过每个工具的toAutoClassifierInput方法做投影(per-tool 投影)。长编辑内容、web fetch 的 prompt、子 Agent 的 prompt 会被截断。工具结果(文件内容、网页内容)永远不会发给分类器——只有用户文本和助手工具调用会经过。
如果某个工具暴露了你希望脱敏的字段,可提交 issue 并附上工具名;投影按工具逐个收紧。
数据边界:什么会到达分类器
分类器只看到每个工具toAutoClassifierInput投影暴露的内容(autoMode.md 中的 FAQ 与 classifier-transcript.ts 的实现一致):
| 工具 | 分类器看到的内容 |
|---|---|
read_file等只读工具 | 不调用(走快路径白名单) |
edit/write_file | 文件路径 + 旧/新内容各 300 字符预览,完整内容不转发 |
run_shell_command | 完整命令(分类器必须评估它) |
web_fetch | 仅 URL,prompt 字段不转发 |
agent | 子 Agent 类型 + 完整 prompt(分类器需识别诱导子 Agent 破坏的注入攻击) |
mcp__* | 服务器名、工具名、服务器自报注解、调用参数(有界截断) |
工具结果(工具返回的实际内容)会从分类器转录中完全剥离。历史动作每条上限 4,000 字符、总计 40,000 字符(MAX_HISTORICAL_ACTION_CHARS/MAX_HISTORICAL_ACTIONS_TOTAL_CHARS,见 classifier-transcript.ts),保留最新的、更早的只留工具名。
MCP 参数转发细节:每个字符串值/键截断至 2,000 字符,名称截断至 200 字符,整个载荷共享 16,000 字符预算(按分类器收到的 pretty-printed 形式计量),嵌套/条目数有上限;每次截断都在原位标记(…[truncated N chars]或[omitted: …])并附带arguments_truncated: true/name_truncated: true标志,让分类器不会把省略误认为"不存在"。这些参数本就是主模型已生成、准备发给该服务器的内容,转发给同一模型配置下的分类器不构成新的泄露;若分类器运行在不同的 provider上,可设permissions.autoMode.mcp.forwardArguments: false恢复仅工具名的投影——此时大多数 MCP 调用会被保守拦截。
局限性
- 不可离线运行:分类器依赖一次 LLM 调用;
- 慢路径有额外延迟:白名单 + acceptEdits 覆盖大多数调用无延迟,但一次
run_shell_command通常增加约 300ms(快速分类路径)或约 3-5s(带思考复核的慢路径); - 不能替代
deny规则:分类器是尽力而为。确定永远不该运行的命令请写入permissions.deny; - MCP 工具按参数而非已验证行为判定:第三方 MCP 工具(
mcp__*)永远不在快路径白名单;来自未标记trust: true服务器的每次调用都会带着服务器名、工具名、服务器自报注解(readOnlyHint/destructiveHint/idempotentHint/openWorldHint)和有界参数副本进入分类器,且分类器被告知这些注解未经核实。它无法看到服务器实际执行了什么,因此"误导性的工具名 + 无害参数"仍可能通过。若你信任某个具体 MCP 工具,添加permissions.allow: ["mcp__server__tool"]让它完全绕过分类器(实现见 mcp-tool.ts 的 toAutoClassifierInput)。
常见问题
Auto Mode 会把我的代码发给第三方吗?
不会引入新端点。Auto Mode 复用你现有的模型配置——与主 Agent 同一端点。如果你把 Qwen Code 配置为自托管模型,分类器也跑在该端点上。
我的 secrets /.env内容会到达分类器吗?
只读工具根本不调用分类器;edit/write_file只转发 300 字符预览;工具结果被完全剥离。唯一必须转发全文的是run_shell_command的命令和agent的 prompt(这正是分类器要判断的对象)。
如何关闭首次进入的信息提示?
它每个用户设置文件只显示一次。关闭后用户设置中会写入ui.autoModeAcknowledged: true。
与 Auto-Edit 有何区别?
Auto-Edit 只自动批准文件编辑,Shell 命令仍然询问。Auto Mode 用分类器同时自动批准安全的 Shell 命令与其它工具调用,同时拦截风险操作。
与 YOLO 有何区别?
YOLO 不经过任何审查自动批准一切。Auto Mode 有分类器在环,会拦截风险动作。
小结
Auto Mode 是 Qwen Code 在"流畅性"与"安全性"之间的工程化折中:三层过滤器把最常见的调用(工作区内编辑、只读工具)挡在分类器之外换取零延迟,把真正有风险的调用交给两阶段 LLM 分类器做细粒度判断;硬规则优先、过宽 allow 剥离、破坏性命令正则硬拦截、工作区外写入强制手动确认等机制共同构成了"分类器出错也不会失控"的兜底。对长时间自主会话、无人值守任务与受信任项目,理解 autoMode.ts 与 classifier.ts 的实现细节,有助于写出贴合团队策略的 hints 配置,让分类器的放行与拦截行为真正符合你的预期。
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考