Claude Code Agent Loop 研究系列(01)—— 从 tool 声明到执行前的批准
内容提要
本文探讨Claude Code中工具从声明到执行前的权限批准机制。LLM仅能调用tools段中声明的工具,输出tool_use后需经权限检查。批准规则分6级来源,按优先级判断,通过await Promise阻塞循环等待用户、hook或分类器竞速决定,并采用ResolveOnce防重复。Subagent不继承主对话权限,默认保守安全。
延伸解读
权限批准是自动循环中的必要例外
Claude Code 的 agent loop 设计为自动流转,中间无需用户参与,但权限批准是唯一例外。它通过阻塞 loop 等待用户、hook 或分类器竞速决定,确保危险操作(如 rm -rf)不会在用户来不及反应时执行。这种设计在自动性与安全性之间取得平衡,是 agent 系统安全机制的关键一环。
竞速机制与 ResolveOnce 的设计巧思
批准流程中,用户点击、hook 和 AI 分类器三个来源同时判断,谁先返回就采用谁的结果,避免串行等待带来的延迟。同时,ResolveOnce 机制防止 Promise 被重复 resolve,确保竞速不会导致崩溃。这种将 race condition 转化为特性的做法,体现了对用户体验的极致追求。
Subagent 权限隔离的安全考量
Subagent 不继承主对话的 session 级权限,而是清空后使用自己的 allowedTools。这是因为用户对主对话的信任不能自动扩展到子代理,默认保守更安全。虽然可能导致子代理需要重新批准,但这是安全优先的合理取舍,防止权限滥用。
Q&A
Claude Code 中 LLM 如何知道可以调用哪些工具?
LLM 通过 API 请求中的 tools 段来了解可用的工具。tools 段是一个数组,每个元素声明一个工具,包含 name、description 和 input_schema。LLM 只能调用 tools 段中列出的工具,并且根据 description 来决定是否调用某个工具。
Claude Code 中工具从声明到执行前需要经过哪些步骤?
LLM 输出 tool_use 后,并不会直接执行工具,而是先经过权限批准。权限系统根据规则判断是否允许执行,如果规则无法自动决定,则会阻塞循环并等待用户、hook 或分类器竞速决定。只有批准通过后,工具才会真正执行。
Claude Code 的权限批准规则有哪些来源?优先级如何?
权限批准规则有 6 级来源,按优先级从高到低为:abortController(已中断)、denyRule(明确拒绝)、askRule(明确要问)、classifier(AI 分类器自动判断)、alwaysAllow(用户总是允许)、defaultMode(系统默认)。系统按此顺序检查,命中即得出结论。
Claude Code 中权限批准是如何阻塞循环的?
权限批准通过 await 一个 Promise 来阻塞循环。当需要用户批准时,循环会停在批准这一步,等待 Promise resolve。UI 层弹出批准对话框,用户点击后 resolve Promise,循环才继续。用户思考的时间不计入 API 成本。
Claude Code 中用户、hook 和分类器如何竞速决定批准结果?
用户点击、PermissionRequest hook 和 AI classifier 三个来源同时开始判断,谁先返回结果就采用谁的结果,并结束等待。这是 race 机制,旨在提高响应速度。同时使用 ResolveOnce 机制防止 Promise 被多次 resolve。
Claude Code 中 subagent 的权限是否继承主对话的权限?
不继承。subagent 启动时会清空主对话的 session 级批准,只保留 CLI 参数级配置,并设置 subagent 自己的 allowedTools。这是为了安全,因为用户对 subagent 的信任度较低,默认保守。