GitHub周趋势2026W25 | Headroom 压缩 95% Token、NVIDIA 开源 AI Agent 安全扫描器、…
2026-07-28
2026-08-03 0
Claude code tools 研究系列第三篇。前两篇拆了 AskUserQuestion 和 EnterPlanMode —— 决策流水线的前两环:澄清 · 展开。这篇聊最后一环 —— ExitPlanMode:提交方案让用户批准。

从表面看,这可能是 Claude Code 三个交互 tool 里最不起眼的一个。它没有 AskUserQuestion 的多选卡片,也没有 EnterPlanMode 的模式切换戏剧性 —— 它只做一件事:触发一次「批准 / 驳回」的确认。
但正是这个「什么都不做」的克制,让整套三工具流水线得以闭合。
ExitPlanMode 是 Claude Code 内置的「规划模式退出 · 请求批准」工具。它的职责就一句话:在 plan mode 里写好完整方案后,调用这个工具,让用户看到 plan 全文并做出决定 —— 批准执行 / 让 Claude 修改 / 驳回换方向。
它解决的核心问题是「AI 从规划切回执行时,如何得到用户显式的批准」:
场景:承接上一篇 [EnterPlanMode](Claude code tools 研究系列(二)EnterPlanMode) 里那个 auth 重构例子 —— 用户说「把 JWT 换成 session cookies」,Claude 已经进 plan mode 探索完、跟用户 Ask 澄清完(只换 web 端 · session 用 Redis)、写好了 plan 文件,现在准备开始写代码。
问题来了:Claude 怎么让用户知道 plan 写完了,可以开始执行了?
Claude 只能在聊天里说:「我方案写好了,大概是这样... [几百字的方案描述] ... 可以开始了吗?」
用户会遇到几个问题:
最深层的问题:如果 Claude 想通过 AskUserQuestion 问「方案 OK 吗?」来解决这个 —— 上一篇提过,在 ExitPlanMode 触发之前,用户根本看不到 plan 全文。用 Ask 问「OK 吗?」等于让用户在真空里投票,毫无意义。
Claude 写完 plan 文件后,直接调用 ExitPlanMode(入参也是空的 —— 见下文技术实现)。UI 层做几件事:
Step 1 · 展示 plan 全文
界面会从 plan mode 指定的 plan 文件路径读取内容,渲染成一个独立、结构化、可滚动的方案视图。用户看到的不是「聊天里飘过的一段话」,而是一份正式的方案文档:范围 / 影响文件 / 迁移步骤 / 风险 / 回滚。
Step 2 · 提供三种明确的响应通道
Step 3 · 模式切换是原子的
用户按下批准的一刻,runtime 做几件事:
没有语义歧义、没有滑坡、没有 Claude 抢跑。
| 反例痛点 | ExitPlanMode 的解法 |
|---|---|
| plan 淹没在聊天里 | UI 独立渲染 plan 文件全文,不是聊天消息 |
| 没有明确的批准动作 | 用户必须点批准 / 修改 / 驳回,枚举明确 |
| Claude 需要解析同意语义 | 返回值是结构化状态(批准 / 未批准),不是自然语言 |
| 模式切换没有仪式感 | 批准触发原子性的工具白名单切换 |
| 驳回成本高 | 「修改」是一等公民入口,不需要用户手写「你改改」 |
工具官方说明写得很直接:「只在你在 plan mode 里 · 写完 plan 文件 · 准备好接受用户批准的时候用」。
该用的场景:
不该用的场景:
一个有意思的判断线:能被引用的方案才配触发 ExitPlanMode。如果你的方案还没到「一份可读、可审阅、可反驳的文档」的程度,那就先继续在 plan mode 里探索,别急着 exit。
ExitPlanMode
和 EnterPlanMode 完全对偶 —— Enter/Exit 是标准的进出配对,暗示"有始有终"的状态操作,而不是单向切换。命名直接借用文件描述符 open/close、锁 acquire/release 这种约定俗成的对偶范式,语义无需解释。
如果叫 SubmitPlan 或 RequestApproval,语义会滑向"提交某个数据 / 请求某个权限",反而弱化了它作为模式退出信号的核心语义。
ExitPlanMode 的描述围绕三件事:什么时候用 / 参数不传 plan 内容 / 禁止用 Ask 问元问题。
严格的适用边界(开篇)
三个条件叠加:在 plan mode 里 + plan 文件已写完 + 准备接受批准。任一不满足都不该调。
参数机制的透明化
明确告诉 Claude:别想着把 plan 内容塞进 tool call 参数。UI 会自己从 plan 文件读。这是防止 Claude 冗余复制 —— 既省 tokens 也确保「UI 展示的和 plan 文件一致」。
批准的隐含语义
关键词 signal —— 这个 tool 不做实际渲染逻辑、不做批准判定,它只发一个信号。渲染、投票、状态切换都由 runtime 处理。tool call 是最轻量的「信号发射器」 —— 一个非常 Unix 哲学的设计。
与研究任务的边界
这条呼应 EnterPlanMode 那篇也强调过的:plan mode 是「实现前的规划」,不是「理解现有代码的调研」。研究性任务应该用 Agent tool 派 subagent 去调研。
禁止元问题反模式
这条特别精妙 —— 它不是简单说「用 ExitPlanMode 别用 Ask」,而是从语义等价性角度指出:Ask 问「plan OK 吗」和 ExitPlanMode 是同一个语义,用后者才是正确表达。前两篇都提过这条反模式的存在,本篇给出了描述层的根本禁令。
澄清 vs 请求批准的顺序
官方 Examples 第 3 条:
明确了 Ask 和 ExitPlanMode 在 plan mode 里的执行顺序:先澄清具体分叉,再统一拿方案去批准。不要边澄清边请求批准,让流程线性收敛。
空。
有一个字段 allowedPrompts 但已被标记 deprecated("Deprecated: no longer used"),实际不使用。
这个字段的历史痕迹本身很有意思:从字段名反推,早期版本可能允许 Claude 在请求批准的同时声明一批「用户批准后自动放行的操作类型」(比如 run tests / install dependencies),让 Claude 一次性拿到复合权限。现在被弃用了,说明 Claude Code 团队后来选择了更保守的路径:批准就是批准 plan 本身,权限扩展走别的机制(比如 permissions.yaml)。这是一个权限设计从「批准即授权」演进到「批准归批准 · 授权归授权」的痕迹。
空。
和 EnterPlanMode 一样 —— input_schema 只有一个 deprecated 字段,无实际约束。调用行为本身 = 提交意图,不需要传任何数据。
空 schema 的运行时职责:
这几件事都是 runtime 干的,不需要 Claude 传参 —— 又一次呼应 EnterPlanMode 的空 schema 设计:权限和状态收敛在 runtime,Claude 只发信号。
决策流水线的最后一环 —— 三个工具的完整闭环:
复制代码用户: 「帮我重构 auth · JWT 换 session」 ↓Claude: 有几个分叉需要确认 ↓AskUserQuestion (澄清: 只换 web 端 · Redis session store) ↓Claude: 好 · 让我先做个规划 ↓EnterPlanMode (用户批准进入) ├─ Grep / Read / Glob 探索 ├─ Ask 澄清子问题 (中间可能再问几次) └─ 写 plan 文件 ↓ExitPlanMode (用户看到完整 plan) ├─ 批准 → 默认模式 · 按 plan 执行 ├─ ️ 修改 → 回 plan mode 调整 · 完成后再 Exit └─ 驳回 → 结束三个工具各司其职,组合起来才构成一次完整的「协作对齐」:
ExitPlanMode 的精妙之处,不在于它「让用户批准方案」这个功能本身,而在于它的信号分布跟 EnterPlanMode 高度镜像 —— 命名对偶(Enter/Exit)、工具描述堆行为约束、字段和 schema 都是空的。
如果说 AskUserQuestion 是「让用户点选项」、EnterPlanMode 是「进入规划模式」,那 ExitPlanMode 就是这套系统里最谦逊的一环:它什么都不做,只发一个信号,却让整个流程有了终点、让整套协作有了「拍板」的仪式感。
三工具流水线到此闭合:
下一篇继续拆 [Grep + Glob](Claude code tools 研究系列(四)Grep + Glob) —— 从"协作对齐"三工具切换到"代码探索"两工具,看看信息搜索类 tool 是怎么编码"搜什么 / 怎么搜 / 返回多少"的。