你已经知道 Claude Code 内置了三种子代理:Explore、Plan、General-purpose,分别覆盖搜索、分析、执行三个环节。用了一段时间后你会发现,这三种"通用型选手"处理大部分任务没问题,但一旦遇到具体的、带领域知识的场景,它们就显得不够用了。
比如:代码审查时,你希望 Claude 自动关注 SQL 注入、N+1 查询、命名规范这些团队约定的检查点,而不是每次手动交代一遍。写测试时,你希望它知道项目用的是 pytest 而不是 unittest,文件要放在 __tests__/ 目录下。生成 API 文档时,你希望它遵循团队的 OpenAPI 模板格式。
这些"带领域知识的子代理",Claude Code 不会替你内置,但它给了你自己造的能力。
一、自定义子代理是什么
自定义子代理就是一个 Markdown 文件。例如,我们在这里自定义了一个code-reviewer Agent。
---
name: code-reviewer
description: 专注代码质量审查的子代理,检查安全漏洞、性能问题和代码规范
model: sonnet
tools:
- Read
- Glob
- Grep
- Bash
---
你是一个严格的代码审查员。审查代码时重点关注:
1. **安全漏洞**:SQL 注入、XSS、命令注入、硬编码密钥
2. **性能问题**:N+1 查询、不必要的循环、内存泄漏风险
3. **代码规范**:命名一致性、错误处理完整性、资源释放
4. **可维护性**:函数长度、圈复杂度、重复代码
输出格式按严重程度分三级:
- 🔴 **严重**:必须修复,有安全风险或会导致线上故障
- 🟡 **警告**:建议修复,影响性能或可维护性
- 🔵 **建议**:可以改进,属于最佳实践
每个问题附上文件路径、行号和修复建议。
审查结束后给出整体评分(1-10)和一句话总结。
没有复杂的 SDK,没有要编译的插件,就是一个 .md 文件,放在约定的目录下,Claude Code 启动时自动识别。文件内容分两部分:顶部的 YAML frontmatter 定义元信息(名字、模型、工具、权限),正文就是系统提示词,你希望这个子代理"怎么干活"的指令。
上图展示了一个自定义子代理文件的完整结构。上半部分是 YAML frontmatter,用三个横线 --- 包裹,定义了子代理的"身份证":叫什么名字、用什么模型、能用哪些工具。下半部分是系统提示词,就是你平时在对话里反复跟 Claude 说的那些话,现在固化成文件,一劳永逸。
二、放在哪里
2.1 常见放置位置
自定义子代理文件有两个放置位置,对应两种作用范围:
-
项目级
.claude/agents/:只在当前项目生效。最大的好处是可以提交到 Git,团队成员 clone 下来就能用,不需要额外配置。 -
全局级
~/.claude/agents/:所有项目都能用。适合放你个人的通用工具,比如一个万能的 code-reviewer 或 doc-writer。优先级上,项目级覆盖全局级,如果两个目录下有同名文件,项目级的生效。
2.2 临时加载
除了这两个固定目录,还有两种"临时加载"的方式。
-
通过CLI falg 临时加载指定目录下的子代理
claude --agents /path/to/my-agents/ -
通过插件分发
插件的
agents/目录会被自动扫描,适合团队统一分发标准化的子代理集合。
三、Frontmatter 字段详解
Frontmatter 是子代理的配置中心,每个字段控制一个维度,我们逐个看。
3.1 name 和 description:身份与触发条件
name: code-reviewer
description: 专注代码质量审查,检查安全漏洞、性能问题和代码规范
name 是调用时的标识符,你在对话里 @code-reviewer 就靠这个名字匹配。description 更关键,Claude 会读这段描述来决定是否自动调用这个子代理。比如你说"帮我检查一下这段代码的质量",Claude 看到 description 里有"代码质量审查",就可能自动选中它。所以 description 写得越精确,自动匹配越靠谱。
3.2 model:选哪个大脑
model: sonnet # 快且便宜,适合审查、搜索类任务
model: opus # 最强推理,适合复杂分析、架构设计
model: haiku # 最快最便宜,适合简单的格式化、分类任务
model: inherit # 继承主对话的模型,默认行为
不是每个子代理都需要最强模型。代码审查用 sonnet 就够了,跑得快还省钱。只有需要深度推理的场景(比如设计复杂的重构方案)才需要 opus。
3.3 tools:工具白名单
tools:
- Read
- Glob
- Grep
- Bash
这是一个 allowlist,只有列出的工具才能被子代理使用。这个字段非常重要,它是你控制子代理"能力边界"的手段。一个 code-reviewer 不需要 Edit 权限(它只审查,不改代码),一个 test-writer 则需要 Edit 来写测试文件。最小权限原则在这里同样适用。
3.4 permission:权限模式
permission: default # 默认,该问用户就问
permission: acceptEdits # 自动接受文件编辑,其他操作仍需确认
permission: dontAsk # 不问用户,直接执行所有操作
permission: bypassPermissions # 绕过所有权限检查(慎用)
permission: plan # 只做规划,不执行任何操作
这五档权限从严格到宽松排列。对于审查类子代理,default 就行;对于需要大批量自动写测试的场景,acceptEdits 能免去你反复点确认的麻烦。bypassPermissions 只建议在完全可控的 CI 环境中使用。
3.5 isolation 和 background:高级选项
isolation: worktree # 在独立的 Git worktree 中工作
background: true # 默认以后台任务方式运行
isolation: worktree让子代理在一个独立的 Git 工作区中操作,不会影响你当前的代码。适合"让它去独立尝试一个方案,不满意就扔掉"的场景。background: true让子代理默认在后台运行,不阻塞你的主对话。你可以继续跟主 Claude 聊其他事情,后台任务完成后会通知你结果。
四、实战示例一:code-reviewer
来看一个完整的代码审查子代理。在项目根目录下创建 .claude/agents/ 目录,然后把下述内容保存为 code-reviewer.md:
---
name: code-reviewer
description: 专注代码质量审查的子代理,检查安全漏洞、性能问题和代码规范
model: sonnet
tools:
- Read
- Glob
- Grep
- Bash
---
你是一个严格的代码审查员。审查代码时重点关注:
1. **安全漏洞**:SQL 注入、XSS、命令注入、硬编码密钥
2. **性能问题**:N+1 查询、不必要的循环、内存泄漏风险
3. **代码规范**:命名一致性、错误处理完整性、注释质量
4. **可维护性**:函数长度、圈复杂度、重复代码
输出格式按严重程度分三级:
- 🔴 **严重**:必须修复,有安全风险或会导致线上故障
- 🟡 **警告**:建议修复,影响性能或可维护性
- 🔵 **建议**:可以改进,属于最佳实践
每个问题附上文件路径、行号和修复建议。
审查结束后给出整体评分(1-10)和一句话总结。
- model 选 sonnet:代码审查不需要最强推理能力,sonnet 足够且速度更快。审查一个模块可能就 30 秒搞定,用 opus 反而浪费。
- tools 没给 Edit:审查员只看不改,这是刻意的限制。如果你想让它审查完自动修复,那就加上 Edit,但这是另一个子代理的职责了。
- 输出格式写在提示词里:三级分类不是装饰,是让输出结构化、可扫描。团队成员看到红色就知道必须处理,蓝色可以以后再说。
4.1 Step 1:准备一个练习项目
# 创建项目并初始化 git
mkdir -p playground/src && cd playground && git init
4.2 Step 2:写一段"有问题的"代码作为审查目标
创建 src/user_service.py,故意埋几个典型问题:
import sqlite3
import os
DB_PASSWORD = "admin123" # 硬编码密码
def get_user(user_id):
conn = sqlite3.connect("users.db")
query = "SELECT * FROM users WHERE id = " + user_id # SQL 注入
result = conn.execute(query).fetchone()
return result
def get_all_users():
conn = sqlite3.connect("users.db")
users = []
for user in conn.execute("SELECT * FROM users").fetchall():
# N+1 查询:循环内执行 SQL
for role in conn.execute("SELECT * FROM roles WHERE user_id = " + str(user[0])).fetchall():
users.append({"user": user, "role": role})
return users
def delete_user(user_id):
conn = sqlite3.connect("users.db")
conn.execute("DELETE FROM users WHERE id = " + user_id)
os.system("echo User " + user_id + " deleted") # 命令注入
这段代码包含:SQL 注入、命令注入、硬编码密码、N+1 查询、连接未关闭。正好覆盖 code-reviewer 提示词里的各个检查项。
4.3 Step 3:创建子代理文件
mkdir -p .claude/agents
将上面的code-reviewer.md 内容保存到 .claude/agents/code-reviewer.md。
注意路径:
.claude/agents/必须位于项目根目录(即git init所在的目录)下。如果放到了子目录里(比如src/.claude/agents/),Claude Code 启动时不会扫描到,你的子代理就像不存在一样,不报错,也不生效,排查起来很容易浪费时间。
4.4 Step 4:启动并调用
(1) 全局模式
整个会话都是reviewer身份
claude --agent code-reviewer
之后进入直接说:检查src/user_service.py。

(2) 正常启动后@提及


预期结果:你应该会看到结构化的审查报告,包含 🔴🟡🔵 三级问题列表,每个问题带文件路径和行号。
五、实战示例二:test-writer
写测试的子代理和审查的关键区别在于,需要写文件的权限:
---
name: test-writer
description: 根据源码自动生成单元测试,覆盖正常路径和边界条件
model: sonnet
tools:
- Read
- Glob
- Grep
- Edit
- Bash
permission: acceptEdits
---
你是一个测试工程师。给定源码文件,按以下步骤工作:
1. 先检查项目的测试框架(看 package.json 或 pyproject.toml)
2. 分析目标函数的输入输出类型和边界条件
3. 生成单元测试,覆盖:正常路径、边界值、异常输入、空值处理
4. 测试文件放在与源文件同级的 __tests__ 目录下
5. 写完后自动运行测试,确保全部通过
如果测试失败,分析原因并修复,最多重试 3 次。
- 注意两个不同:
- tools 多了 Edit:因为它需要创建和修改测试文件。
- permission 设为 acceptEdits:自动接受文件编辑操作,省去你每次点确认。写测试是相对安全的操作(它不会改你的源码),所以放宽权限是合理的。
4.1 Step 1:创建 test-writer 子代理
将上面的 test-writer 内容保存到 .claude/agents/test-writer.md。现在你的 agents 目录下有两个子代理了:
.claude/agents/
├── code-reviewer.md ← 只读审查
└── test-writer.md ← 可写,自动补测试
4.2 Step 2:让 test-writer 给代码补测试

观察它的行为:它会先读源码,分析函数签名,然后创建测试文件并运行。因为 permission: acceptEdits,它创建文件时不会逐个问你确认。
4.3 Step 3:串联两个子代理
这是自定义子代理最有意思的用法,让不同角色协作。

- 首先让reviewer进行审查
- 根据审查报告手动修复代码
- 修复完后,让test-writer补测试
先审查、再修复、再补测试。两个子代理各司其职,一个只读,一个可写,权限边界清晰。
六、三种调用方式
子代理定义好了,怎么用?三种方式各有适用场景:
6.1 自然语言:最直觉
> 用 code-reviewer 检查 auth 模块
你正常说话,Claude 根据语意和子代理的 description 匹配。大多数时候能正确触发,但偶尔 Claude 会把它当成普通问题来回答,而不是调用子代理。
6.2 @提及:保证触发
> @code-reviewer 检查最近的 PR 改动
@ 前缀是硬触发,Claude 一定会调用对应的子代理,不存在"理解偏差"的问题。当你需要确定性时,用这种方式。
6.3 全局模式:整个会话都是这个代理
claude --agent code-reviewer
启动时指定 --agent,整个会话都以 code-reviewer 的身份运行。适合你就想开一个专门的审查会话,从头到尾检查多个文件,不需要反复 @。
三种方式的选择逻辑很简单:日常随手用就自然语言;需要确定性就 @提及;专项工作就全局模式。
七、总结
自定义子代理的核心思路就一句话:把你反复对 Claude 说的话,固化成一个可复用的 Markdown 文件。
就像你不会每次 code review 都重新写一份 checklist,而是把 checklist 贴在团队 wiki 上一样,自定义子代理做的是同样的事情,只不过读 checklist 的不是人,是 AI。
473



被折叠的 条评论
为什么被折叠?



