← 返回 FEED
AGENT2026-05-16

Agent Hooks:给 Agent 工作流装上确定性控制

Nader Dabit 在 X 上发布了一篇关于 Agent Hooks 的深度文章,提出了一种让 Agent 工作流变得可编程、可控制的新机制。核心思路很简单:把「应该每次都执行的规则」从提示词里抽出来,挂到 Agent 生命周期的固定节点上,变成代码层面的确定性控制。

问题:提示词不是控制机制

如果你曾经反复提醒 Agent「不要改 generated 目录」「提交前跑测试」「别读 .env 文件」,你已经遇到了提示词的极限。提示词是建议性的——模型可能记住,可能忘记,可能在复杂任务中偏离。Hooks 解决的是同一个问题,但用完全不同的方式:不是请求模型遵守,而是在关键节点插入代码拦截。

六个核心生命周期节点

Dabit 定义了六个覆盖主要开发流程的钩子:

SessionStart —— 会话开始时加载项目上下文。包括目录结构、测试命令、受保护路径、活跃事件或分支特定说明。这比放在提示词里更可靠,因为每次会话都会自动注入。

UserPromptSubmit —— 模型看到用户输入前,先检查并路由。比如提到「退款」「支付」「账单」时自动追加支付相关的约束上下文,提到「迁移」时追加迁移检查清单。

PreToolUse —— 工具调用前拦截。这是最强的预防机制:检查文件路径、shell 命令、MCP 工具参数,阻止对 generated/、.env、.git 等保护路径的写入,拦截 rm -rf、drop table 等危险命令。

PostToolUse —— 工具调用后验证。跑测试、格式化、静态分析、秘密扫描,把结果写入状态文件供后续钩子读取。这是「检查发生了什么」的地方。

Stop —— 阻止 Agent 结束回合。读取 PostToolUse 留下的质量门状态,如果测试失败就阻止完成,强制修复后才能继续。

SessionEnd —— 会话结束时清理。写审计日志、刷指标、导摘要、删临时文件。

执行模型:事件 → 匹配器 → 处理程序 → 结果

每个钩子的运行逻辑统一:

  1. 事件:生命周期时刻(如 PreToolUse)
  2. 匹配器/过滤器(可选):缩小触发范围,比如「仅文件编辑」「仅 shell 命令」
  3. 处理程序:shell 命令、HTTP 请求、MCP 工具调用、LLM 提示或子 Agent
  4. 结果:返回的上下文、决策、日志条目或状态更新

关键认知:Hooks 不是让 Agent 整体变得确定性——模型仍然可以选择不同的计划、编辑、工具调用和恢复路径。Hooks 让的是「特定检查点和副作用」变得确定性:当匹配的生命周期事件发生时,你的处理程序运行,其结果可以作为上下文、决策、副作用或记录状态应用。

实用主义的分层策略

Dabit 给出了清晰的分工建议:

  • 项目说明:编码风格、架构指导、命名约定、测试偏好、示例
  • Hooks:必需上下文、行动前策略、行动后验证、完成门、日志
  • CI:Agent 产生 diff 后的独立验证
  • 人工审查:产品判断、权衡、不可逆风险、最终所有权

把一切放进 Hooks 会造成不必要的自动化。把一切放进提示词会让必需行为依赖模型遵守。实用的分割是:提示词用于指导,Hooks 用于控制。

落地路径:从一条规则开始

不要一上来就建完整的治理系统。Dabit 建议的实施顺序:

  1. 第一条:PreToolUse 钩子,阻止对 generated/、.env、敏感 fixture 的编辑。容易解释、容易测试、立即有价值。
  2. 第二条:PostToolUse 质量门,编辑后跑最快的有用测试命令,写入 .hook-state/last_quality_gate.json
  3. 第三条:Stop 钩子,读取质量门状态,失败时阻止完成。
  4. 之后:SessionStart 上下文、Prompt 路由、最终审计记录。

这个顺序让开发者快速获得价值:更少的重复提醒、更少的意外编辑、更快的变更反馈、更少的完成前手动检查。

为什么这很重要

Hooks 让 Agent 工作流更可靠,通过将可重复规则从模型记忆移到已知生命周期点的代码中。这对三类人意义重大:

  • 个人开发者:想要更少的重复指令
  • 团队:想要共享的仓库行为
  • 公司:想要 Agent 在现有工程控制内运行

Agent 仍然可以推理、写代码、从错误中恢复,但测试、策略、日志和完成门作为工作流的确定性部分运行。

目前 Claude Code、Devin for Terminal、OpenAI Codex、Cursor 都已支持 Hooks 机制,具体实现细节各有差异,但生命周期模型基本一致。