第17部分:Qwen Code 钩子:工作流自动化
Qwen Code 钩子是在会话的预定义时刻运行的脚本:启动时、用户请求后、工具使用前、工具使用后、工具出错时或响应完成前。
在 SDD 中,钩子不是用来替代规范的。它们的作用是减少对人类记忆的依赖:提醒智能体遵守规则、记录重要事件、阻止危险命令、添加上下文或收集痕迹以供后续检查。
基本流程:
flowchart TD
A["Qwen Code 事件"] --> B["匹配器过滤器"]
B --> C["钩子<br/>command 或 http"]
C --> D{"可以继续吗?"}
D -- "是" --> E["Qwen Code 继续工作"]
D -- "否" --> F["Qwen Code 显示停止原因"]
C --> G["额外上下文"]
G --> E何时适合使用钩子
如果某个动作需要定期且一致地执行,则适合使用钩子:
- 记录工具使用的事实;
- 在
/clear后添加简短的 SDD 提示; - 在执行前检查潜在危险的命令;
- 保存工具错误以供回顾分析;
- 发送事件到内部日志;
- 在上下文中添加指向当前规范的链接;
- 在文件更改后启动轻量级后台检查。
如果规则只需写入 QWEN.md 即可,则不需要钩子。例如,"先阅读规范"更适合作为行为规则。但"每次运行包含危险命令的 Bash 都必须被阻止"则适合作为钩子。
最常用的事件
对于学习过程,理解以下几个事件就足够了。
| 事件 | 触发时机 | 在 SDD 中的典型含义 |
|---|---|---|
SessionStart | 会话启动或恢复时 | 添加关于项目的简短提醒 |
UserPromptSubmit | 用户提交请求后 | 检查请求并添加相关上下文 |
PreToolUse | 工具使用前 | 阻止危险操作 |
PostToolUse | 工具成功使用后 | 记录事实,启动轻量级后台检查 |
PostToolUseFailure | 工具出错后 | 保存错误以供分析 |
Stop | 智能体完成响应前 | 记录会话摘要或提醒检查 |
| PreCompact | 上下文压缩前 | 在丢失细节前保存重要结论 |
无需一次性连接所有事件。先从一个或两个事件开始,否则流程会变得不透明。
钩子类型
Qwen Code 支持多种执行器类型。
command 运行本地命令。这是项目钩子的主要选项:Python 脚本、shell 脚本或小工具。
http 发送事件到 HTTP 地址。这适合集中式日志或内部审计系统,但需要仔细配置密钥和允许的地址。
function 用于会话级别的内部 JavaScript 函数。对于普通项目,command 或 http 几乎总是足够。
钩子接收的内容
命令式钩子通过标准输入接收 JSON。其中包含通用字段:会话标识符、当前目录、事件名称、事件时间。对于工具事件,还会添加工具名称、工具输入数据、结果或错误。
钩子可以通过标准输出返回 JSON。最常见的情况是以下三种之一:
- 不做任何更改,直接退出;
- 添加
additionalContext,让 Qwen Code 在下一步看到简短消息; - 在工具使用前禁止操作并解释原因。
退出代码也很重要。0 表示钩子成功运行。2 用于阻塞性错误。其他代码被视为非阻塞性错误:Qwen Code 的主流程继续,详细信息可在调试中查看。
最小文件集
示例已从课程中分离到单独的文件:
- examples/hooks/settings-workflow.example.json — 钩子连接示例;
- examples/hooks/pre_tool_guard.py — 危险命令前的保护钩子;
- examples/hooks/log_tool_result.py — 工具调用成功和失败的日志记录;
- examples/hooks/inject_sdd_context.py — 添加简短 SDD 上下文;
- examples/hooks/README.md — 示例的简要说明。
在学习项目中的连接方式:
mkdir -p .qwen/hooks
cp sdd-qwen-code-ru/examples/hooks/pre_tool_guard.py .qwen/hooks/pre_tool_guard.py
cp sdd-qwen-code-ru/examples/hooks/log_tool_result.py .qwen/hooks/log_tool_result.py
cp sdd-qwen-code-ru/examples/hooks/inject_sdd_context.py .qwen/hooks/inject_sdd_context.py
chmod +x .qwen/hooks/*.py
将设置示例单独复制,并与现有的 .qwen/settings.json 手动合并:
cp sdd-qwen-code-ru/examples/hooks/settings-workflow.example.json .qwen/settings-hooks.example.json
不要覆盖模型、认证和 MCP 服务器的工作设置。
工具前的保护钩子
PreToolUse 适合需要在执行前检查的操作。最容易理解的例子是 shell 命令。
文件 examples/hooks/pre_tool_guard.py 检查 Bash 的输入,匹配多个危险模式:删除根目录或主目录、git reset --hard、git clean -fd、通过 shell 运行下载的脚本。这不是完整的沙箱。这是在明显危险操作前的最后一道检查。
重要:保护钩子必须解释停止的原因。如果智能体只看到"命令被禁止",它会开始猜测绕过方法。如果它看到具体原因,就能提出安全的替代方案。
工具日志记录
PostToolUse 和 PostToolUseFailure 适合事件日志。在 SDD 中,这种日志本身不是目的,而是回顾分析的素材:
- 哪些命令经常失败;
- 智能体在出错前修改了哪些文件;
- 哪些检查是手动运行的;
- 哪些操作应该移到
validation.md; - 哪些规则应该写入
QWEN.md。
文件 examples/hooks/log_tool_result.py 将紧凑的记录写入 .qwen/hooks/logs/tool-events.jsonl。这是本地技术日志。不要在其中存储密钥、大型模型响应和完整的环境转储。
日志记录通常启用异步模式,这样主工作流程无需等待日志写入。
添加 SDD 上下文
SessionStart 和 UserPromptSubmit 适合添加上下文。这在 /clear 后特别有用:聊天历史已清除,但项目流程应该保持可见。
文件 examples/hooks/inject_sdd_context.py 不会读取整个项目。它检查 QWEN.md、specs/mission.md、specs/tech-stack.md 和 specs/roadmap.md 的存在,然后添加简短的提示。这种钩子不应该变成隐藏的规范。它只是引导智能体前往存放真相来源的文件。
钩子与检查
人们容易想在每次文件更改后运行 npm test。这通常是个坏主意:智能体会变慢,错误会在不合适的时机出现。最好将检查分开:
- 轻量级检查可以自动异步运行;
- 重量级检查通过
validation.md中的显式步骤运行; - 阻塞性钩子仅用于危险操作;
- 自动检查的结果应该进入报告或日志,而不是消失在噪音中。
如果钩子启动检查,它应该只回答一个问题。例如:"TypeScript 文件更改后,快速类型检查是否失败?"不要把一个钩子变成完整的分支合并流程。
安全规则
钩子在你的环境中以你的权限运行。因此请像对待普通自动化代码一样对待它们。
最低规则:
- 将项目钩子存放在仓库中,像代码一样进行审查;
- 设置
timeout,防止挂起的钩子阻塞会话; - 对日志和后台检查使用异步模式;
- 不要在命令行中传递密钥;
- 对于 HTTP 钩子,设置允许的环境变量列表;
- 未经团队明确决定,不要将源代码和提示发送到外部服务;
- 不要编写静默修改项目文件的钩子;
- 在阻止操作时添加清晰的消息。
项目钩子只应在受信任的目录中启用。如果你打开了别人的仓库,请先阅读 .qwen/settings.json 和 .qwen/hooks/,然后再允许自动运行。
什么不应该自动化
不好的想法:
- 每次工具出错后自动修复代码;
- 阻止任何不在预先编制列表中的命令;
- 在每个请求中添加大段规范到上下文;
- 将完整模型响应写入永久日志;
- 在一个脚本中混合记忆、检查、格式化和安全;
- 将钩子用作
requirements.md、plan.md和validation.md的隐藏替代品。
钩子应该小而清晰。如果你无法用一句话解释它的用途,那它很可能做得太多。
实践练习
- 将钩子示例复制到学习项目中。
- 将
pre_tool_guard.py仅连接到Bash的PreToolUse。 - 将
log_tool_result.py连接到PostToolUse和PostToolUseFailure。 - 将
inject_sdd_context.py连接到SessionStart和UserPromptSubmit。 - 在项目中启动 Qwen Code 并执行
/clear。 - 让智能体阅读路线图并建议下一个功能,但不修改文件。
- 检查日志是否出现在
.qwen/hooks/logs/tool-events.jsonl中。 - 在安全测试环境中尝试危险命令,确认保护钩子解释了阻止原因。
练习后书面回答:
- 哪个钩子真正帮助了流程;
- 哪个钩子成了噪音;
- 什么最好移到
QWEN.md; - 什么最好作为
validation.md中的手动步骤保留。
与后续部分的联系
下一部分从安全角度审视钩子:它们可以保护流程,但自身也需要审查。之后关于 SQLite 记忆的部分,将使用同一机制收集事件、进行后台汇总并在新会话中添加简短记忆。