K1.5.1 Task 1.5

五种 Hook 类型覆盖完整会话生命周期

Agent SDK 的 hook 在会话生命周期的五个点拦截事件。每种在特定时刻触发,这决定了它能做什么。用错 hook 类型是常见错误——PreToolUse 无法转换输出(输出还不存在),SessionStart 无法校验逐工具的输入(它只触发一次)。

五种 hook 类型

SessionStart

会话开始时触发一次。 用于:加载配置、初始化上下文、搭建环境。

示例:会话开始时从 .pipeline.yml 加载仓库专属的 CI 配置到 agent 上下文中。

UserPromptSubmit

用户提交消息时触发,在 agent 处理之前。用于:输入清洗、上下文注入、语言检测、逐消息元数据。

示例:在每个 prompt 中注入客户的账户等级(gold/silver/bronze),让 agent 应用正确的策略。

诊断提示:如果上下文注入只在 API 请求时失败(聊天界面正常),hook 可能只注册在了聊天路径上。确保所有请求路径都经过 hook 管线。

PreToolUse

工具执行前触发。 可以检查参数、阻止执行或修改输入。用于:阻止未授权操作、执行先决条件、参数校验、输入修改(沙箱重定向)。

示例:当金额 > $500 时阻止 process_refund。在 backup_file 完成前阻止 delete_file

做不到的事:转换工具输出(还不存在)、加载一次性配置(每次工具调用都触发,不是只触发一次)。

PostToolUse

工具执行后触发,在 agent 看到结果之前。可以检查和转换输出。用于:数据标准化、PII 脱敏、输出增强、密钥脱敏、结果审计日志。

示例:在 agent 处理工具结果之前,把所有时间戳格式转成 ISO 8601。

做不到的事:阻止工具执行(已经发生了)、会话级初始化。

SessionEnd

会话终止时触发。 用于:清理、归档日志、生成会话摘要。

示例:删除会话期间创建的临时分析文件。归档审计日志。

完整生命周期映射

一个 CI/CD 流水线 agent 有 5 个需求,每个映射到正确的 hook:

需求Hook 类型为什么选这个时机
加载 CI 配置SessionStart开始时一次性设置
往 prompt 注入 PR 上下文UserPromptSubmit逐消息上下文
阻止部署到生产环境PreToolUse必须在执行前拦截
从工具输出中脱敏密钥PostToolUse必须在执行后访问结果
会话结束时归档日志SessionEnd所有工作完成后清理

为什么只用 PreToolUse 不行

一个团队提议:“所有事都用 PreToolUse——在坏事发生前拦住。”

五个常见需求中有两个搞不定:

  • 输出清洗:PreToolUse 在工具运行前触发。没有输出可清洗。工具结果中的密钥脱敏需要 PostToolUse。
  • 完整审计日志:PreToolUse 捕获请求了什么,但不知道返回了什么。尝试但失败的工具调用和成功的看起来一样。PostToolUse 捕获完整画面。

完整审计:Pre + Post 一起用

合规要求记录每次工具调用的输入和输出。同时注册 PreToolUse(记录工具名、参数、时间戳)和 PostToolUse(记录结果、状态、耗时)来捕获完整的请求-响应周期。只用一个就丢了一半审计痕迹。

基于 SessionEnd 的批量日志在会话崩溃时有数据丢失风险——通过 Pre+Post 的实时逐调用日志更可靠。

SessionStart ≠ PreToolUse

SessionStart 触发一次。PreToolUse 每次工具调用都触发。用 SessionStart 做逐工具输入校验不行——它拦不住单个工具调用。反过来,用 PreToolUse 加载一次性配置也浪费处理(每次工具调用都跑加载检查,但它只需要跑一次)。


一句话总结: 五种 hook 覆盖生命周期:SessionStart(一次性设置)、UserPromptSubmit(逐消息上下文)、PreToolUse(执行前阻止/修改)、PostToolUse(执行后转换/记录)、SessionEnd(清理)——Pre+Post 一起用做完整审计,PreToolUse 绝不能做输出转换。