把子代理路由写成生产规则

· 约 5 分钟阅读

子代理用得越久,越容易撞上同一个问题:你精心养了一批 .claude/agents,主模型却常常不派它们,自己开个通用代理把活干了;偶尔又乱点鸳鸯,把写库的活交给一个只该读库的代理。根子在于委托决定是模型根据 description 现场做的判断,[1] 而你把它当成了可以依赖的调度器。想让”派谁干活”变得可靠,就得把它从即兴发挥改造成结构约束:description 当路由表、工具列表当能力边界、模型和权限分开调、per-agent hook 当审计员。四件事都有明确答案,路由才算上了生产。

description 是路由表,写清”什么时候别用”#

官方文档对 description 的定位一句话讲完:Claude 靠它决定何时把任务委托给某个子代理。[1] 它是整个路由系统的入口,但它有一个硬约束:每条 description 都常驻主上下文,所有自定义子代理的 description 合计超过一万五千 tokens 时,Claude Code 启动就会告警。[1] 所以路由表必须短,能力细节全部挪进正文——正文只在代理真正被派发时才加载,不占主会话的便宜。[1]

怎么写?看官方快速入门给的范例:description: Scans files and suggests improvements for readability, performance, and best practices. Use after writing or modifying code.。[1] 动词开头,说明做什么,再点出触发时机。光写”帮助提升代码质量”等于没写:模型看不出它比通用代理强在哪,自然想不起来派。边界条件也要写清:只审不修的代理,注明不处理测试执行和依赖升级。

自动路由再准也是概率,所以官方保留了显式点名的通道:提示里直接写”Have the code-reviewer subagent look at my recent changes”,或者用 @code-reviewer (agent) 语法指名道姓。[1] 关键路径上的审查、需要固定流程的检查,别赌自动路由,直接点名。

工具列表是能力边界#

description 管”什么时候派”,tools 管”派了能干什么”。省略 tools 字段时,代理继承子代理可用的全部工具;只做审查就显式列出 Read, Grep, Glob 这类只读集合。[1] 注意这个设计是闭失败(fail-closed)的:如果 tools 里的条目一个都解析不到,代理通常会启动失败并报错,而不是带着残缺权限静默开跑。[1]

想反向剔除也行:disallowedTools: Write, Edit 表示继承全部工具但拿掉写文件的能力。[1] 不过提示词里的”只读”终究是请求,不是保证。要硬约束,官方在文档里给了标准答案——per-agent hook:代理文件里挂一个 PreToolUse 钩子,比如一个只允许 SELECT 的数据库代理,其 Bash 调用先过校验脚本,命中 INSERT、UPDATE、DELETE 这类写库关键词就打印 Blocked 并以退出码 2 收场。[1]

为什么用 hook 而不是再补一句提示词?官方指南点明,hook 跑在生命周期的固定点上,提供的是确定性控制:某些动作必然发生,而不是依赖模型选择去执行。[3] 退出码 2 在 Claude Code 的语义里就是阻断性错误,在能阻断的事件上,即使 stdout 输出 JSON 说 allow 也无法覆盖。[2]

模型和权限:成本与信任分开调#

工具之外的旋钮还有两个。model 字段把代理路由到指定模型,省略时按官方预设的子代理模型顺序走;想全场统一,设 CLAUDE_CODE_SUBAGENT_MODEL 环境变量即可。[1] 大批量、低风险的扫描任务压到 haiku 上,省下的钱比优化提示词来得快;但模型路由只该动成本,不该用来替代工具白名单——一个能写文件的代理,换成再便宜的模型也还是能写。

permissionMode 控制批准粒度:plan 是只读探索模式,default 是逐次询问,bypassPermissions 跳过全部确认。[1] 只读审查代理配 plan 或显式只读工具集,写代码的代理保持 default 让人过目,bypassPermissions 永远别给会碰生产数据的角色。某个内置代理你不想要,也不必删文件:permissions.deny 里写 Agent(Explore) 就能禁用它,命令行对应 claude --disallowedTools "Agent(Explore)"。[1]

快速上手:两个代理加一个校验脚本#

第一步,建项目级只读审查代理,随仓库走:

<!-- .claude/agents/code-reviewer.md -->
---
name: code-reviewer
description: Reviews code for quality, security, and best practices. Use immediately after writing or modifying code. Never edits files.
tools: Read, Grep, Glob, Bash
model: haiku
---

You are a senior code reviewer. Run git diff to inspect recent changes,
report issues by severity with file and line references. Do not edit files.

第二步,建只读数据库代理,挂 per-agent 钩子:tools 只给 Bash 还不够,真正的闸门在脚本里。

<!-- .claude/agents/db-reader.md -->
---
name: db-reader
description: Executes read-only SQL queries for data analysis. Use when analyzing data or generating reports.
tools: Bash
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/validate-readonly-query.sh"
---
# scripts/validate-readonly-query.sh — 只允许 SELECT
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if echo "$CMD" | grep -qiE '\b(INSERT|UPDATE|DELETE|DROP|ALTER|TRUNCATE)\b'; then
  echo "Blocked: write SQL is not allowed" >&2
  exit 2
fi
exit 0

chmod +x scripts/validate-readonly-query.sh。第三步,脱离会话先测钩子:echo '{"tool_input":{"command":"DELETE FROM users"}}' | ./scripts/validate-readonly-query.sh,应该打印 Blocked 且 echo $? 返回 2;把命令换成 SELECT 再试,应当放行。第四步,进会话敲 /agents 确认两个代理已加载,然后显式点名调用一次,别等自动路由。

收尾建议#

代理文件的作用域有优先级:托管设置最高,其次 --agents 命令行传入(只对当前会话生效,适合临时试跑),再往下是项目级 .claude/agents/ 和用户级 ~/.claude/agents/,插件目录最低。[1] 新代理先用 --agents 的 JSON 格式跑几天,顺手了再落成项目文件入库,别人 checkout 就能用同一套路由。

这套心智模型正在跨工具收敛:GitHub Copilot CLI 的自定义代理同样是带 YAML frontmatter 的 Markdown 文件,声明 name、description、prompt 和 tools,主代理可以把它们作为子代理在独立上下文窗口里运行,合适时并行执行。[4] 规则不是为了消灭模型判断,而是把”派谁、能碰什么、花多少钱”从每次会话的随机变量变成可审查的常量。剩下真正需要判断的事,依然值得你自己拍板。

Sources#

[1] https://docs.anthropic.com/en/docs/claude-code/sub-agents — Claude Code Create custom subagents [2] https://docs.anthropic.com/en/docs/claude-code/hooks — Claude Code Hooks reference [3] https://docs.anthropic.com/en/docs/claude-code/hooks-guide — Claude Code Automate actions with hooks [4] https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-custom-agents — GitHub Docs: About custom agents (Copilot CLI)