🐎 第5章 防微杜渐:Hooks 事件驱动自动化
📄 一句话概括

子智能体也有两个钩子:启动时注入上下文,结束时验收输出。一道管进去,一道管出来。 注入的难点是精度:全局注入一次配好、所有子智能体都读,但每个都读进了不属于自己的规矩。

📝 本章和前面几章的关系

上一节的质量钩子挂在主窗口的工具调用上,这一节把钩子挂到第 4 章那个「隔离区」的门口。 这一节和 4.3 节(定义)、4.8 节(回执)是同一条线的三段:怎么定义、进去给什么、出来验什么。

一、两道口

启动时(SubagentStart):它还没有开始干活,这时候注入的上下文会跟着它整段工作。 结束时(SubagentStop):它已经干完、回执还没交回主窗口。这时候能验、能拦、能打回。 两道口的分工很自然:进去给「它需要知道的」,出来验「它交的合不合格」。

这和 4.5 节「技能管怎么做、子智能体管在哪做」是配套的:技能的内容怎么进到子智能体那儿? 靠启动时注入。 所以注入这件事,本质上是「把技能或者规范搬到隔离区门口」。

二、全局注入与 frontmatter 注入

全局注入:在全局配置里写一条启动钩子,所有子智能体启动时都跑。一次配置,人人受益。 frontmatter 注入:在某个子智能体的定义里声明它要什么。只有它跑,别人不跑。 演示里三种情况:全局注入八百 token、frontmatter 注入两百、完全不注入。

全局那份花八百送了两百有用的,另外六百是别的子智能体的规矩——它读了,但用不上。 更要紧的是噪声:它读到的规矩里有一半不适用自己的活,而模型分不清哪条适用。

三、精度的代价

全局注入好写:一次配置,所有子智能体都受益。 代价是每个子智能体都读一遍全部内容。五个子智能体,就是五份。 而「读进不属于自己的规矩」不只是浪费,还可能误导:它可能照着一份不属于它的规范干活。

所以默认应该走 frontmatter:谁需要什么,谁自己声明。 全局只放「所有子智能体都必须知道的」——比如「不许改 migrations 下已提交的脚本」。 这条判据和记忆层一样:范围越大放得越靠上,但靠上的内容必须真的通用。

四、SubagentStop 验什么

常见的三条:回执是不是合法 JSON、必填字段在不在、返回值有没有超过大小限制。 这三条全是规则,用 command 处理器就够,不需要模型(5.4 节的阶梯第一级)。 第一条对应 5.5 节的协议,第二条对应 4.7 节的四个字段,第三条对应 4.8 节的坑一。

所以子智能体的两道口,其实是前面几节所有约定在门口的落点:进去靠注入,出来靠校验。 如果校验不过怎么办?打回。 SubagentStop 能阻止,所以可以让它重做一次——但要有次数上限,否则会转成 4.8 节那个循环。

五、什么时候不需要这两道口

只读型子智能体不需要注入太多:它的活就是「读并判断」,给太多规矩反而干扰。 一次性的探索型子智能体不需要严格校验:它交的东西你只看一眼就丢。 所以两道口也是按需的。挂得越多,隔离区门口的检查越慢,而慢会抵消掉隔离的好处。

判据:这道口如果不挂,出问题会不会被发现?不会 → 挂。会 → 先别挂,等真出事再说。 这条和 5.11 节的四个判据是一路的:先问「漏了会不会出事」,再决定挂不挂。

六、动手 Demo:三个子智能体,注入方式不同,产出合规率差多少

三个子智能体:一个靠全局钩子注入、一个在定义里声明注入、一个完全不注入。 比较注入的 token 和实际需要的 token,再看产出合规率。

SUBS = [(u"全局注入", 800, 200, 1),      # 注入 800,其实只需要 200
        (u"frontmatter 注入", 200, 200, 1),
        (u"不注入", 0, 200, 0)]

实跑输出:

--------------------------------------------------------------------
三个子智能体,注入方式不同,产出合规率差多少
--------------------------------------------------------------------

  子智能体也有钩子:SubagentStart 在它启动时注入上下文,SubagentStop 在它结束时验证输出。

  ① 三种注入方式
  --------------------------------------------------------------------
| 方式 | 作用范围 | 特点 |
|---|---|---|
| 全局 Hooks | 所有子智能体都注入 | 一份通稿,谁都得读 |
| frontmatter 里声明 | 只有这个子智能体注入 | 精准,按需 |
| 不注入 | 什么都不给 | 它只能靠通用知识 |


  ② 三份产出对比
  --------------------------------------------------------------------
| 注入方式 | 注入 token | 需要的 token | 合规率 | 结果 |
|---|---:|---:|---:|---|
| 全局注入 | 800 | 200 | 100% | 合规 |
| frontmatter 注入 | 200 | 200 | 100% | 合规 |
| 不注入 | 0 | 200 | 0% | 漏关键约定 |

  全局注入那份花八百 token 送了两百有用的,另外六百是别的子智能体的规矩——它读了,但用不上。

  ③ 全局注入的问题:精度
  --------------------------------------------------------------------
  全局注入好写:一次配置,所有子智能体都受益。
  代价是每个子智能体都读一遍全部内容。五个子智能体,就是五份。
  更要紧的是「噪声」:它读到的规矩里有一半不适用自己的活,
  而模型分不清哪条适用——它可能照着一份不属于它的规范干活。

  ④ SubagentStop 验证什么
  --------------------------------------------------------------------
  它发生在子智能体结束、回执还没交回主窗口的那一刻。能阻止,所以可以在这里卡一道。
  常见的三条验证:回执是不是 JSON、必填字段在不在、返回值有没有超过大小限制(4.8 节的坑一)。
  这三条全是规则,用 command 处理器就够,不需要模型。
  ! 所以子智能体的两道口是:进去时注入什么(精度问题),出来时验收什么(格式问题)。
  两道都是钩子,都不归模型决定。

①三种注入方式:全局钩子(所有子智能体都跑)、frontmatter 声明(只有它跑)、不注入。 ②全局注入那份花八百 token 送了两百有用的,另外六百是别的子智能体的规矩——它读了,但用不上。 更麻烦的是噪声:它读到的规矩里有一半不适用自己的活,而模型分不清哪条适用, 可能照着一份不属于它的规范干活。 ③全局注入好写,代价是每个子智能体都读一遍全部内容;五个就是五份。 所以默认应该走 frontmatter:谁需要什么,谁自己声明。 ④SubagentStop 验三条:回执是不是合法 JSON、必填字段在不在、返回值有没有超大小限制。 三条全是规则,用 command 处理器就够。 这三条正好对应前面几节的约定:第一条是 5.5 的协议、第二条是 4.7 的四个字段、第三条是 4.8 的坑一。 所以子智能体的两道口,是前面所有约定在门口的落点:进去靠注入,出来靠校验。

30 秒实验

  1. 把全局注入的内容砍到只剩通用的三条(从八百降到三百),重跑第 ② 步。合规率会掉吗? 这说明「哪些规矩真该全局」怎么判?
  2. 给「不注入」那个加上 frontmatter 注入两百 token,重跑一遍。它和全局注入的差距在哪?
  3. 给 SubagentStop 加一条「回执超过五百 token 就打回」,重跑一遍。这条校验对应的是哪个坑?

常见误区

  1. 什么都往全局注入里塞。每个子智能体都读一遍,读到的绝大部分用不上,还可能误导。
  2. 完全不注入。子智能体不知道项目规矩,只会按通用做法来,产出不合规。
  3. 用 prompt 处理器做格式校验。回执是不是合法 JSON 是一行命令的事,用模型是浪费。
  4. SubagentStop 打回不设上限。会转成 4.8 节那个循环:一遍遍重做,你不知道它在转。
  5. 给只读型子智能体注入一大堆规矩。它的活就是读并判断,规矩太多反而干扰。
自测三问(点开对答案) 1. 子智能体的两个钩子分别管什么? —— SubagentStart 在它启动时注入上下文(进去给什么), SubagentStop 在它结束时验收输出(出来验什么)。 2. 全局注入的问题是什么? —— 精度。所有子智能体都读同一份通稿,每个都读进不属于自己的规矩,既浪费又可能误导。 3. SubagentStop 通常验哪三条? —— 回执是不是合法 JSON、必填字段在不在、返回值有没有超过大小限制。 三条都是规则,用命令处理器就够。

两道口讲完了,下一节解决一个很现实的问题:钩子慢怎么办——异步。

相关笔记