子智能体的定义还是一次「Markdown 加 YAML 头」,字段只有四个:name、description、tools、model。 四份样本里两份能直接用。 问题都不是「写错了」,是「没写够」——少一个字段,行为就变成另一回事。
上一节讲为什么要有它,这一节讲怎么定义一个。 结构和技能几乎一样,差别全在「tools 比 allowed-tools 更要命」。 看完这一节,应该能写出一个不放开权限、也不至于干不成活的子智能体。
一、四个字段
name:内部标识,也是调用名。和技能一样,要和文件名一致,不然调用时找不到。 description:什么时候该派它出去。 注意它写的是场景,不是功能——「需要独立评审一段改动时」比「审查代码」有用。 tools:它能用哪些工具。这是最要紧的一个,因为不写等于继承全部。
model:用哪个模型。只读审查这种活可以用小模型,改代码、做设计的活得用大的。 四个字段之外还有可选的(版本、颜色、默认是否自动派),但行为和成本都由这四个决定。
二、tools 为什么比 allowed-tools 更要命
技能不写 allowed-tools,继承全局权限;子智能体不写 tools,也继承全局——看起来一样。 差别在「谁在跑」。技能是在主窗口里跑,人就在旁边看着,每一步都能拦。 子智能体是在另一个窗口里跑一长串动作,人看不到中间过程。 权限放开的代价,从「看见它干了什么」变成「事后才知道」。
所以技能里那条结论在这里要加重说一遍: 不写不是「没有权限」,是「全部权限」。而且这里连看都看不见。 一个实用的默认:只读型给 Read、Grep、Glob 三个就够;执行型再加 Edit 和指定的 Bash 子命令。
三、description 写场景不写功能
子智能体的 description 有两个读者:一个是模型(决定派不派),一个是人(决定用不用)。 写「审查代码」偏功能,模型得自己判断「这次算不算审查」; 写「需要独立评审一段改动、而且不想让评审过程占主窗口时」偏场景,判断依据就明确了。 场景描述顺带解决了「什么时候不该派」——如果这次评审只想快速看一眼, 那就不符合「不想占主窗口」这个条件。
这和 3.4 节技能描述那三条是同一个道理:做什么、什么时候用、什么时候不用。 只是子智能体的第三段常常被写成「什么时候不该派」——比如「改动小于三行时不要派」, 省得为一行改动开一个新窗口。
四、正文写什么
正文是它被派出去之后拿到的第一段话。比技能正文更短更硬:做什么、边界在哪、返回什么格式。 「返回什么格式」最容易被漏,也最值钱。不写清楚,它可能回一段散文,而散文回到主窗口还得再解析一遍。 「边界」也要写:能改哪些目录、能不能跑测试、遇到不确定的要不要停下来问。
注意「停下来问」这件事在子智能体这里更难:它在另一个窗口里,问谁? 所以更实际的做法是写「遇到 X 情况就返回 blocked,说明卡在哪」。 这句话把一个会卡住的活变成了一个能收口的活——这也是 4.8 节要讲的实战要点之一。
五、和技能定义的差别一览
结构一样:目录、Markdown、YAML 头。字段不一样:技能是 allowed-tools,子智能体是 tools。 读的人不一样:技能的 description 给模型判断「用不用」, 子智能体的 description 给模型判断「派不派」。 权限的后果不一样:技能放开的权限当场可见,子智能体放开的权限在一段看不见的过程里生效。
正文的落点不一样:技能正文是「执行的步骤」,子智能体正文是「交付的契约」。 记住这一条就够了:技能管怎么做,子智能体管在哪做、交什么。
六、动手 Demo:四份子智能体配置,三份不能直接用
造四份配置:一份规范的只读审查员、一份没写 tools 的改码员、一份 name 大小写不对的、 一份缺 description 的。 逐份解析 YAML 头、核四个字段,看哪份能直接用。
for fn in (u"reviewer", u"fixer", u"Reviewer2", u"reporter"):
d = yaml(u"\n".join(SUB_RAW[fn]))
if not d.get(u"name"):
bad.append(u"缺 name")
elif d[u"name"] != fn: # 文件名才是调用名
bad.append(u"name 与文件名不一致")
if u"tools" not in d:
bad.append(u"没写 tools(继承全部)")
实跑输出:
--------------------------------------------------------------------
四份子智能体配置,三份不能直接用
--------------------------------------------------------------------
子智能体的定义也是「一份 Markdown 加一段 YAML 头」,和技能同一个套路。
只是字段不同:这里管的是「它能用哪些工具、用哪个模型」。
① 四个字段各自管什么
--------------------------------------------------------------------
| 字段 | 管什么 | 注意 |
|---|---|---|
| name | 内部标识,也是调用名 | 必须与文件名一致 |
| description | 什么时候该派它出去 | 必填,写场景不写功能 |
| tools | 能用哪些工具 | 不写就继承全部,最危险的一种写法 |
| model | 用哪个模型 | 只读审查可以用小模型,改代码用大的 |
② 逐份检查
--------------------------------------------------------------------
| 文件名 | name | tools | 结论 |
|---|---|---|---|
| reviewer | reviewer | 有 | 通过 |
| fixer | fixer | 无 | 没写 tools(继承全部) |
| Reviewer2 | Reviewer2 | 有 | 通过 |
| reporter | reporter | 有 | 缺 description |
四份里只有 2 份能直接用。
另外 2 份的问题都不是「写错了」,是「没写够」——少一个字段,行为就变成另一回事。
③ 少写 tools 有多危险
--------------------------------------------------------------------
fixer 那份没写 tools。它叫「改代码的子智能体」,本意是只改 src 下的文件;
但没写 tools 就意味着继承父会话的全部工具——包括删除、包括写系统路径。
这和 3.6 节技能里那条结论是一样的:不写不是「没有权限」,是「全部权限」。
所以子智能体的 tools 是最该先写的一个字段,比 description 还急——description 写歪了顶多派错,
tools 没写是直接放开。
④ 正文写什么
--------------------------------------------------------------------
正文是它被派出去之后拿到的第一段话,比技能正文更短更硬:做什么、边界在哪、返回什么格式。
最容易被漏的是「返回什么格式」。
不写清楚,它可能回一段散文——而散文回到主窗口,主窗口还得解析一遍,
等于把省下来的活又做回去了(4.7 节细算)。
! 一句话:头部写「怎么找到它、它能干什么」,正文写「这一次要它交什么」。
头部是长期的,正文是每次委派时最该盯的。
①四个字段:name 是标识和调用名、description 管「什么时候派」、tools 管「能做哪些动作」、 model 管「用多大的模型」。 ②四份里两份能直接用。fixer 没写 tools,Reporter2 大小写不一致,reporter 缺 description。 注意 Reporter2 那个问题最隐蔽:它 name 和文件名是一致的(都叫 Reviewer2), 所以这一份其实「通过」了检查——真正该被挑出来的是它名字里的大写,不同平台对这个的容忍度不一样。 ③fixer 那份的问题最能说明这一节的落点:它叫「改代码的子智能体」,本意是只改 src 下的文件; 但没写 tools 就意味着继承父会话的全部工具。 这和 3.6 节技能那条结论一样:不写不是「没有权限」,是「全部权限」。 而且子智能体是在看不见的过程里用它。 ④正文里最该先写的是「返回什么格式」。 不写清楚它会回一段散文,而散文回到主窗口,主窗口还得解析一遍,等于把省下来的活又做回去了。 一句话总结头部和正文的分工:头部写「怎么找到它、它能干什么」,正文写「这一次要它交什么」。
30 秒实验
- 给 fixer 补一行 tools,只给 Read 和 Edit(src*),重跑第 ② 步。它还能干活吗? 少了哪个工具会让它卡住?
- 把 reviewer 的 description 改成「审查代码」,重跑一遍。它还能被正确判定为「该派」吗? 判断依据少了什么?
- 给 reporter 的正文加一句「返回 JSON:done/files/issues/blocked」, 这个改动影响的是它自己的行为,还是主窗口的成本?
常见误区
- 不写 tools 就发布。不写等于继承全部,而子智能体跑在看不见的过程里。
- description 写成功能清单(「能审查、能改、能测」)。 它要回答的是「什么时候派」,越全越没人能判断。
- 正文只写「做什么」,不写返回格式。回执变成散文,下游还得再解析一遍。
- 写「遇到不确定就问用户」。子智能体在另一个窗口里,问不到——该写「返回 blocked 并说明卡在哪」。
- 给子智能体配和主会话一样的模型。只读审查用小模型就够了,用大模型是把钱花在不需要的地方。
自测三问(点开对答案)
1. 子智能体的四个字段分别管什么? —— name 是标识和调用名、description 管什么时候派、tools 管能用哪些工具、model 管用多大的模型。 2. 为什么子智能体的 tools 比技能的 allowed-tools 更要紧? —— 因为子智能体跑在另一个窗口里,一长串动作人看不到中间过程。 权限放开的代价从「看得见」变成「事后才知道」。 3. 「遇到不确定就问用户」这句话为什么不能写进子智能体正文? —— 因为它在另一个窗口里,问不到人。 该写成「返回 blocked 并说明卡在哪」,把会卡住的活变成能收口的活。定义会写了,下一节看五种常见的分工形状,各自适合什么活。
- ☐ (本篇完,下一篇 4.4 5 种子智能体模式)
相关笔记
- allowed-tools:为什么不写就是全开
- 五种模式:五种模式
- Skill 提效实战 · 索引
- 🐎 Claude Code 实战 · 索引