首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >万字深研 |Harness 工程实践:指令遵从率 20%,Hook 执行率 100%

万字深研 |Harness 工程实践:指令遵从率 20%,Hook 执行率 100%

作者头像
技术人生黄勇
发布2026-04-24 11:20:42
发布2026-04-24 11:20:42
940
举报
文章被收录于专栏:技术人生黄勇技术人生黄勇

最近在研究 harness ,AI 不是在抢我的工作:Harness 正在重构软件工程|让 Agent 完成任何复杂任务。

刷到这么一个项目:wow-harness,它是一个基于 Claude Code 的治理层框架,用于管理 AI 模型的行为。

我好奇它的具体实现,因为想用在自己的开发项目中:怎么把6周一次版本更新提升到1天8次部署?从用 AI 到 AI 优先


wow-harness 使用介绍

wow-harness 是为 Claude Code 打造的治理层(Governance Layer)框架。

核心主张:指令改变不了 AI 行为(遵从率 ~20%),但机械约束可以(执行率 100%)。


它解决什么问题

AI 坏毛病

表现

危害

假装完成

"测试全过了"(实际没跑)

上线出生产事故

跳过审查

"这个改动很简单"

引入未审查代码

任务漂移

修一个 bug,顺手重构三个文件

变更不可控

自我评价偏差

永远回答"做得好"

无法发现自身错误

并行污染

多 session 互相影响

代码冲突


核心架构(四大组件)

1. 16 个生命周期 Hook(实时拦截) 横跨 7 个阶段,AI 每次调用工具前都会被拦截,条件不满足则工具调用直接失败:

代码语言:javascript
复制
SessionStart → 加载上下文、重置风险状态
PreToolUse   → 拦截危险部署、门控审查 agent
PostToolUse  → 编辑时路由上下文、检测循环
Stop         → 验证完成候选品(transcript × git diff)
SessionEnd   → 反思、持久化进度

2. 8 门状态机(8-Gate State Machine)

代码语言:javascript
复制
G0 问题 → G1 设计 → G2 审查★
  → G3 方案 → G4 审查+锁定★
  → G5 任务 → G6 审查★
  → G7 执行 → G8 终审★

★ = 独立审查者(独立上下文、只读工具)

偶数关启动新 agent 审查,审查 agent 的工具清单物理上没有 Edit/Write,所以不能改

3. 15 个自动验证器 — 文件变更时运行,捕获 API 类型不一致、文档过期、安全模式等

4. 16 个专业化 Skill — 架构设计(arch)、失败模式提取(crystal-learn)、Bug 分诊(bug-triage) 等


安装方法

代码语言:javascript
复制
git clone https://github.com/NatureBlueee/wow-harness.git
cd wow-harness
python3 scripts/install/phase2_auto.py /path/to/your/project --tier drop-in

三个安装层级:

层级

适合场景

说明

drop-in

想先试试

原样安装 hook + skill

adapt

正式项目

读项目 README/文档,适配 skill

mine

团队协作

读工作 transcript,深度适配

适用建议

  • 小项目:drop-in 层级 + CLAUDE.md 简化模式
  • 大型项目/团队协作:adapt 或 mine 层级
  • 推荐试法:先用 drop-in 跑一周看效果

安装后目录结构:

代码语言:javascript
复制
your-project/
├── .claude/
│   ├── settings.json    # Hook 注册(追加模式,不覆盖已有)
│   ├── skills/          # 16 个 agent 行为定义
│   └── rules/           # 路径作用域上下文规则
├── scripts/
│   ├── hooks/           # 16 个生命周期 hook
│   └── checks/          # 15 个自动化验证器
└── CLAUDE.md            # 治理指南(自动生成,可编辑)

wow-harness 技能系统详解

一、技能的元数据结构

每个技能都以 SKILL.md 文件形式存在,开头是 YAML frontmatter:

代码语言:javascript
复制
---
name: lead                           # 技能名称
description: 开发流程统领...           # 描述(用于触发匹配)
status: active                       # 状态
tier: entry                          # 层级
owner: nature                        # 维护者
last_audited: 2026-04-09             # 最后审计日期
triggers:                            # 触发条件
  - 新功能
  - 方向讨论
outputs:                             # 输出契约
  - Gate 包
  - 决策缺口
truth_policy:                        # 真相策略
  - 不复制实时仓库事实
---

关键字段解析

  • tier: 分为 entry(入口)、execution(执行)、meta(元层)
  • triggers: 用于技能发现和自动激活
  • outputs: 定义技能必须产出的内容(Output Contract)
  • truth_policy: 定义技能如何处理信息源冲突

二、技能层级架构

代码语言:javascript
复制
meta 层(自省与进化)
  crystal-learn    → 提取失败模式,形成不变量
  skill-discovery  → 发现重复模式,提议新技能

entry 层(入口与编排)
  lead             → 9 Gate 状态机,流程阻塞者
  arch             → 架构设计,本质判断
  harness-dev-handoff → 新 session 接手入口

execution 层(执行与实现)
  harness-dev      → 全栈开发,代码实现
  guardian-fixer   → Guardian issue 自动修复管道
  task-arch        → WP 拆分
  plan-lock        → 计划冻结

三、职责分层

四、为什么这样分层?

1. 分离"判断"与"执行"

这是针对 LLM agent 的一个结构性偏见设计的:

LLM 在压力下会主动跳门("这个简单,不用审查也能过")

如果把判断和执行放在同一个 skill 里,agent 会倾向于"边做边判断",最终变成"做了再找理由"。

分层后

  • lead 只判断 Gate 转移,不写代码
  • harness-dev 只执行已冻结的计划,不做架构决策
2. meta 层的"免疫系统"隐喻
代码语言:javascript
复制
# crystal-learn 的定位
"""
我是 harness 的适应性免疫系统。
我不修具体 bug,也不写产品代码。
我提取"这类错误为什么总会回来",把它们压成不变量。
"""

meta 层不参与日常开发,但在系统运行一段时间后,它会:

  1. 1. 分析失败模式
  2. 2. 提取不变量
  3. 3. 注入到 execution 层

这种设计让系统能够从错误中学习,避免每次犯同样的错误。

3. entry 层的"导航"角色

harness-dev-handoff 的核心设计:

代码语言:javascript
复制
## Truth Policy

我不是新的权威副本。我只负责把新 agent 引到当前仍然活着的真相源上。

entry 层不维护知识副本,只维护导航规则

这避免了"skill 里的描述和代码实际状态不一致"的问题。

五、技能间的协作关系

六、技能系统的核心设计思想

  1. 1. 结构化约束:非 prompt 约束,而是可验证的门禁
  2. 2. 不变量注入:教训不留在 memory,注入到执行层
  3. 3. 真相源优先级:避免信息漂移和幻觉
  4. 4. 独立审查:审查门用独立上下文,防止污染
  5. 5. 可指认的反模式:每个失败模式都有名字,便于检测和讨论

应用案例

1. Towow(通爻)代理协作协议 — 6 个月生产实践

这是 wow-harness 的创作团队实际项目案例

他们在开发 Agent 协作协议项目 Towow 时,逐步迭代出当前的 hook/gate/隔离体系,命名为 wow-harness。

核心经验:每一条规则都是"先被烧伤,再建防护"。

AI agent 找到了创造性的方式不遵守上一条规则,才有了下一条规则。


设计精髓

  1. 1. Schema 级隔离:审查者的工具清单里没有写入工具 → 物理上不可能越权
  2. 2. Fail-open 安全方向:读不到数据就注入更多检查,绝不静默跳过
  3. 3. Session 隔离:并行 session 间零共享可变状态
  4. 4. Hook 优于指令:重要的事不靠说,靠执行

注入机制如何生效?

wow-harness 不是 Skill,它是基于 Claude Code 的 hooks 系统的原生消费者,在工具调用的前后拦截点注入。

它能生效,是因为 Claude Code 在每次工具调用的前后、session 的开始和结束、以及 compaction 之前,都会调用注册在 .claude/settings.json 里的脚本。

这些脚本的输出直接注入 AI 的上下文,exit code 直接决定工具调用是否被放行。

它的注入时机是机械的、不可绕过的。


Claude Code Hooks 协议

Claude Code 有 7 个生命周期阶段,每个阶段可以注册 hook 脚本:

代码语言:javascript
复制
SessionStart  →  session 开始时
PreToolUse    →  每次工具调用之前
PostToolUse   →  每次工具调用之后
PreCompact    →  上下文压缩之前
Stop          →  agent 尝试停止时
SessionEnd    →  session 结束时
PostToolUseFailure → 工具调用失败后

Hook 协议的核心规则:

hook 输出

效果

exit 0

放行,不注入任何内容

exit 0 + stdout 有内容

放行,stdout 内容注入 AI 上下文(作为 additionalContext)

exit 2 + stderr 有内容

阻止当前操作,stderr 内容注入 AI 上下文作为反馈

exit 1

硬阻断(deploy-guard 用)

1. 完整的 Hook 事件清单(28 种)

根据项目文档 ADR-038 的记录,Claude Code 源码中有 28 种 hook 事件

代码语言:javascript
复制
Claude Code 原生 Hook 事件

会话生命周期
  SessionStart     ← 会话开始时触发
  SessionEnd       ← 会话结束时触发
  Stop             ← AI 回复完成后触发
  PreCompact       ← 上下文压缩前触发

工具调用
  PreToolUse       ← 工具调用前触发
  PostToolUse      ← 工具调用后触发
  PostToolUseFailure ← 工具调用失败时触发

用户交互
  UserPromptSubmit ← 用户提交 prompt 时触发
  PermissionRequest ← 权限请求时触发

文件/环境
  FileChanged      ← 文件变更时触发
  WorktreeCreate/Remove ← Worktree 生命周期

2. 配置方式

.claude/settings.json 中配置:

代码语言:javascript
复制
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          { "type": "command", "command": "python3 scripts/hooks/session-start-reset-risk.py" }
        ]
      }
    ],
    "PreToolUse": [...],
    "PostToolUse": [...]
  }
}

3. SessionStart 的触发时机

代码语言:javascript
复制
用户打开新对话
      ↓
Claude Code 初始化会话
      ↓
读取 .claude/settings.json
      ↓
执行 SessionStart hooks
      ↓
hook 脚本的 stdout 被注入到会话的初始上下文
      ↓
会话正式开始,AI 可以看到 hook 输出的内容
这就是 wow-harness 所有魔法的根基——它不是"建议 AI 做什么",而是在 AI 调用工具的瞬间,物理上允许或拒绝,同时在上下文中注入信息。

模拟一次完整开发过程

假设任务:给 API 路由层添加一个新端点

阶段 0:启动 Session

你打开 Claude Code,输入任务描述。

Hook 触发顺序:

代码语言:javascript
复制
① session-start-reset-risk.py
  → 删除上次 session 的 risk-snapshot.json
  → exit 0(静默,不注入)
  → 作用:每个 session 从 R0 风险起步

② session-start-magic-docs.py
  → 检查自动生成的文档是否与源码同步
  → 如果有漂移:stdout 输出漂移告警 → 注入 AI 上下文
  → 如果无漂移:exit 0(静默)
  → 作用:防止 AI 基于过期文档工作

③ session-start-toolkit-reminder.py
  → 输出可用 skills 和工具清单
  → stdout 注入 → AI 知道自己有什么技能
  → 作用:防止 AI 忘记自己能做什么

此时 AI 的上下文可能长这样:

代码语言:javascript
复制
[SessionStart 注入]
=== ADR-038 D5 Magic Doc Drift Alert ===
  DRIFT: docs/magic/api-routes.md (source: backend/product/routes/ changed)

[toolkit-reminder 注入]
可用 Skills: lead, arch, plan-lock, bug-triage, crystal-learn ...

阶段 1:AI 读取路由文件

AI 决定先看看现有路由代码,调用 Read backend/product/routes/protocol.py

PreToolUse 触发:

代码语言:javascript
复制
④ tool-call-counter.py
  → 计数器 +1(第 1 次调用)
  → 每 50 次调用才注入 Objective Recitation
  → 第 1 次:exit 0(静默)

⑤ sanitize-on-read.py
  → 读取目标文件,扫描敏感内容
  → 无 SECRET/TRADE_SECRET:exit 0
  → 有 PII/NETWORK:warn 但放行
  → 作用:防止密钥/密码进入 AI 上下文

PostToolUse 触发:

代码语言:javascript
复制
(Read 操作不触发 guard-feedback.py,因为它只监听 Edit/Write)

AI 看到了路由代码,开始规划。

阶段 2:AI 编辑路由文件

AI 调用 Edit backend/product/routes/protocol.py 添加新端点。

PreToolUse 触发:

代码语言:javascript
复制
⑥ tool-call-counter.py
  → 计数器 +1,仍不是 50 的倍数 → 静默

⑦ review-agent-gatekeeper.py
  → 检查是否在 spawn 审查 subagent
  → 当前是 Edit 不是 Task → exit 0(放行)

PostToolUse 触发(关键!三个 hook 同时运行):

代码语言:javascript
复制
⑧ guard-feedback.py
  → 机制 A:上下文路由
    路由表查 "backend/product/routes/" → 匹配 "contract-consumers" 片段
    加载 context-fragments/contract-consumers.md
    → 注入 AI 上下文:"改这个文件会影响以下消费方..."

  → 机制 B:guard 检查
    路由表查 "backend/product/routes/" → 匹配 "check_doc_freshness"
    运行 check_doc_freshness.run() → 如果文档过期,报告 finding
    → 注入 AI 上下文:"文档可能需要同步更新"

  → Fragment 去重:同一 session 内同一片段只注入一次
  → exit 2(有输出,注入上下文)

⑨ loop-detection.py
  → 检查 backend/product/routes/protocol.py 被编辑次数
  → 第 1 次编辑:不触发告警 → exit 0
  → 如果同一文件编辑 ≥5 次:
    注入 "[LoopDetection] 你已经编辑 X 5 次了。考虑换方法。"

⑩ risk-tracker.py
  → 分析被编辑文件的路径
    "backend/product/routes/" → 匹配 RISK_ELEVATORS → R2
    → 写入 .towow/state/risk-snapshot.json:
      {"risk_level": "R2", "files_touched": [...]}
  → exit 0(不注入,纯记录)
  → 作用:风险只升不降(棘轮机制)

此时 AI 的上下文多了:

代码语言:javascript
复制
[guard-feedback 注入]
## Context
--- 此文件是 API 契约定义点,以下模块消费此契约:
- backend/product/bridge/bridge_client.py
- mcp-server/towow_mcp/client.py
- website/app/api/ 代理层
修改此文件时必须同步更新所有消费方。

## Guard Findings
- P2 doc_integrity: routes/protocol.py 变更后文档可能需要同步更新

阶段 3:AI 编辑更多文件(任务漂移场景)

AI 改了路由文件后,又去改了 mcp-server/ 的客户端代码,然后顺手改了 CLAUDE.md 想加点注释。

每次 Edit 都触发 guard-feedback + loop-detection + risk-tracker:

  • • 改 mcp-server/:路由表匹配 → 注入 mcp-parity 片段(提醒 MCP 双端一致性)
  • • 改 CLAUDE.md:路由表匹配 → 注入 truth-source-hierarchy 片段
  • risk-tracker:CLAUDE.md 路径匹配 R3 → 风险从 R2 升到 R3
  • • 同时改了 4+ 个文件 → R1 多文件风险叠加 → 风险升到 R3

这些注入直接出现在 AI 的工具调用返回中,和工具调用结果混在一起,AI 必须处理。

阶段 4:AI 尝试直接部署到生产(危险操作场景)

AI 觉得改完了,想直接 scp 文件到生产服务器。

PreToolUse Bash 触发:

代码语言:javascript
复制
⑪ deploy-guard.py
  → 解析 Bash 命令,发现包含受保护 IP "47.118.31.230"
  → 检测到 scp 上传操作
  → exit 1 + stderr: "BLOCKED: 禁止手动 scp 上传到受保护服务器"
  → Claude Code **物理阻止**这个 Bash 调用
  → AI 看到错误信息,被迫使用 deploy.sh

阶段 5:AI 循环编辑同一文件

AI 改了 protocol.py 5 次,还在反复修改。

PostToolUse Edit 触发:

代码语言:javascript
复制
⑨ loop-detection.py
  → 计数器显示 protocol.py 已编辑 5 次
  → 注入:"你已经编辑 protocol.py 5 次了。考虑换方法。"
  → AI 被迫停下来重新思考方案

阶段 6:AI 声称完成,尝试 Stop(假装完成场景)

AI 说"我完成了",尝试停止。

Stop 触发(最核心的拦截点):

代码语言:javascript
复制
⑫ stop-evaluator.py  →  整体流程:

  Step -1: 检查 stop_hook_active(CC 防循环字段)
           → 如果上一次 stop 已经注入过反馈 → 放行,避免无限循环

  Step 0: D8 机械化第一关(零 LLM 成本)
           → 调用 initializer-agent.py stop-check
           → 读取 .towow/progress/current.json
           → 检查所有 feature 的 status 是否 == "passing"
           → 检查所有 passing feature 是否有 evidence

           如果有 feature 不是 passing:
             → exit 2 + stderr: "D8 机械化第一关失败,以下 features 未 passing..."
             → **AI 被迫继续工作,不能 Stop**

           如果所有 feature 都 passing 且有 evidence:
             → 进入 Step 1

  Step 1: Completion Candidate 判定
           → 读取 session transcript(CC 提供的 .jsonl 文件)
           → 提取本 session 用 Edit/Write 写过的文件集合 A
           → 运行 git diff --name-only 获取未提交变更集合 B
           → A ∩ B 非空 → 是 completion candidate → 进入 Step 2
           → A ∩ B 为空 → 不是 completion candidate → 放行(纯聊天/研究场景)

  Step 2: 注入 stop-evaluator.md 检查清单
           → exit 2 + stderr: 完整的 completion review 流程

stop-evaluator.md 注入的内容要求 AI:

  1. 1. 写 Completion Proposal(JSON 文件,必须包含 git diff 证据)
  2. 2. Spawn 独立 Reviewerreview-readonly subagent)
  3. 3. Reviewer 用只读工具审查(不能修改任何文件)

阶段 7:独立审查

AI 被 Stop hook 拒绝后,按照注入的指令 spawn 一个审查 agent。

PreToolUse Task 触发:

代码语言:javascript
复制
⑬ review-agent-gatekeeper.py
  → 检测到 spawn 的是 review subagent
  → 检查 prompt 中是否包含只读指令
  → 如果没有:exit 2,**阻止 spawn**
  → 如果有:记录 active-review-agent 标记 → exit 0
  → 作用:物理确保审查 agent 的 prompt 包含只读约束

审查 agent 在独立上下文中运行,工具清单里没有 Edit/Write/Bash。

它只能 Read + Grep + ListFiles,然后给出 PASS/FAIL 评分。

阶段 8:上下文压缩时的保护

对话很长时,Claude Code 会压缩上下文。

PreCompact 触发:

代码语言:javascript
复制
⑭ precompact.sh
  → 输出必须保留的信息:
    - 当前 PLAN/TASK 状态
    - Sprint Contract 验收标准
    - 不可降级规则(guard > memory, 一个事实一个定义...)
    - Objective Recitation:从 progress.json 读取原始目标

  → 作用:压缩后 AI 不会丢失关键约束
  → 防止 "改着改着忘了原始目标" 的问题

阶段 9:Session 结束

SessionEnd 触发:

代码语言:javascript
复制
⑮ session-reflection.py
  → 收集 guard 命中统计 + loop 统计
  → 写入 metrics JSONL
  → 如果有频繁编辑的文件:输出改进建议

⑯ trace-analyzer.py
  → 聚合 trace 数据用于 harness 优化

⑰ deploy-progress-on-session-end.py
  → 持久化部署进度

8-Gate状态机在什么时机生效?

8-Gate 状态机是由skill 驱动的流程框架,不依赖 hook 自动触发。

Hook 是守门员,Gate 是流程。

Gate

时机

谁触发

Hook 保障

G0 问题定义

任务开始时

lead skill 或人工

G1 设计方案

G0 完成后

执行 agent

G2 独立审查

G1 完成后

lead skill spawn 审查 agent

review-agent-gatekeeper 确保只读

G3 实现方案

G2 PASS 后

执行 agent

G4 审查+锁定

G3 完成后

lead skill spawn 审查 agent

review-agent-gatekeeper + plan-lock skill

G5 任务拆分

G4 PASS 后

lead skill

initializer-agent 生成 progress.json

G6 独立审查

G5 完成后

lead skill spawn 审查 agent

review-agent-gatekeeper

G7 执行+日志

G6 PASS 后

执行 agent

guard-feedback + risk-tracker 实时监控

G8 终审

G7 完成后

lead skill spawn 审查 agent

stop-evaluator + review-agent-gatekeeper

流程有效 的关键:不是同一个 agent 审查自己

审查 agent 是新创建的,有独立上下文,工具清单里没有写入工具。


为什么"指令遵从率 ~20%,hook 执行率 100%"?

代码语言:javascript
复制
指令方式(CLAUDE.md 写 "修改后必须跑测试"):
  AI 读取 → 理解 → 决定是否遵守 → ~20% 概率遵守
  ↑ 失败原因:AI 可能忘记、误解、或"创造性"忽略

Hook 方式(stop-evaluator.py 检查 progress.json):
  AI 尝试 Stop → hook 运行 → 检查结果 → 100% 执行
  ↑ 无法绕过:hook 在 AI 的工具调用路径上,物理拦截

CLAUDE.md 是门上的告示牌"请敲门",Hook 是门锁——没钥匙就是进不来。


各组件分工一览

组件

解决什么问题

机制

stop-evaluator

假装完成

机械化检查 transcript ∩ git_dirty + 独立 reviewer

review-agent-gatekeeper

审查者越权

Schema 级工具隔离,审查者没有 Edit/Write

initializer-agent (D8)

自我评价偏差

progress.json objective SHA256 不可篡改 + 机械化第一关

loop-detection

循环修改

文件编辑计数 ≥5 次注入提醒

risk-tracker

风险积累不可见

路径计算风险等级,棘轮只升不降

guard-feedback

上下文缺失

编辑文件时自动注入相关约束和消费方信息

context_router

注意力漂移

文件路径 → 上下文片段路由

deploy-guard

危险部署

物理阻止 scp/ssh 写操作到生产服务器

sanitize-on-read

敏感信息泄露

Read 前扫描,SECRET 硬阻断

tool-call-counter

目标遗忘

每 50 次调用注入 Objective Recitation

precompact.sh

压缩丢失关键信息

压缩前注入不可降级规则 + 原始目标

session-reflection

经验无法积累

SessionEnd 记录 guard 统计和失败模式


工具清单没有写入工具保证审查者只读

Claude Code 启动一个 subagent 时,有两种方式限制它的行为:

方式一:Prompt 级约束(提示词里说"别改")

代码语言:javascript
复制
你是审查 agent。请只读代码,不要修改任何文件。

AI 读了这句话 → 理解了 → 可能遵守,也可能不遵守

实测遵从率 ~70%。

它会"好心"地顺手修个 typo、改个 import,因为它觉得"这明显是错的,我顺手修了更好"。

方式二:Schema 级约束(工具定义里根本没有 Edit/Write)

Claude Code 的 agent 系统支持在 agent 定义文件(如 .claude/agents/review-readonly.md)的 frontmatter 中声明 tools: 白名单:

代码语言:javascript
复制
---
name: review-readonly
tools:
  - Read
  - Search  
  - Grep
  - ListFiles
  # 注意:没有 Edit、Write、Bash、NotebookEdit
---

这个 tools: 字段就是 Schema——它定义了这个 agent 能调用的工具的 JSON Schema。

当 Edit 不在 schema 里时,agent "根本不知道 Edit 的存在"

就像你给一个人一把只有读权限的钥匙。

从源码 review-agent-gatekeeper.py 中可以清晰看到这两层的对比:

代码语言:javascript
复制
# 来源: ADR-038 D11
# 审查 agent must use schema-level tool isolation (frontmatter `tools:` whitelist),
# not prompt-level constraint. OpenDev arXiv 2603.05344 showed:
# prompt约束 ~70% adherence vs schema-level 100%.

# 对于本地 agent(frontmatter 可修改)→ 直接在 tools 白名单里排除
# 对于插件 agent(frontmatter 不可修改)→ 在 spawn 边界用 hook 强制检查

"Schema " 是什么

这里的 Schema工具调用的 JSON Schema

即定义"这个 agent 能调用哪些工具、每个工具接受什么参数"的规范。

层级

类比

效果

Prompt 级

墙上贴"禁止入内"

看到的人可能遵守,可能不遵守

Schema 级

门上根本没有门把手

物理上无法进入,非意愿问题

代码语言:javascript
复制
Prompt 级:你的手机上有微信,但老板说"上班别刷微信"
           → 你可能忍住,也可能偷偷刷

Schema 级:你的手机上根本没装微信
           → 想刷也刷不了

为什么需要两层保障

看源码 review-agent-gatekeeper.py 的设计,它处理了两种 agent:

1. 本地 agent.claude/agents/review-readonly.md)→ frontmatter 里已经写了 tools: 白名单,物理隔离,不需要 hook 干预。hook 直接放行:

代码语言:javascript
复制
LOCAL_REVIEW_EXEMPT = ("review-readonly",)
# 本地 agent 的 frontmatter 已经强制了 → 免检放行

2. 插件 agent(如 pr-review-toolkit:code-reviewer)→ 这些 agent 来自 .claude/plugins/,作者无法修改它们的 frontmatter。

所以 wow-harness 在 spawn 边界加了一道 hook 拦截:

代码语言:javascript
复制
# 当 AI 尝试 spawn 一个审查 subagent 时
# hook 检查 prompt 中是否包含只读指令
REQUIRED_DIRECTIVES = (
    "MUST NOT call Edit",
    "MUST NOT use Edit", 
    "read-only reviewer",
    "read-only mode",
    "schema-level read-only",
    "ADR-038 D11",
)

# 如果 prompt 里没有这些指令 → 阻止 spawn(exit 2)
# 如果 prompt 里有 → 放行,但记录一个标记让下游 hook 知道

这里用 prompt 级约束是退而求其次

因为插件 agent 的 frontmatter 无法修改,只能在 spawn 时强制 AI 在 prompt 里写上只读指令。

虽然不如 Schema 级完美,但在 spawn 边界拦截比运行时拦截强得多。

总结

"Schema 级隔离":在工具定义的 schema 层面把写入工具从白名单中删除,使 agent 物理上无法调用这些工具。

对比维度

Prompt 级

Schema 级

约束方式

自然语言"请不要"

工具白名单里没有

遵从率

~70%

100%

能否绕过

能("我觉得改了更好")

不能(工具不存在)

类比

门上贴"请勿入内"

门上没把手


Claude Code 的 Task 工具

Claude Code 的主 agent 有一个内置工具叫 ,它的作用就是 spawn 一个子 agent 去执行特定任务。

调用方式长这样(从 stop-evaluator.mdreview-agent-gatekeeper.py 源码中可以看到完整结构):

代码语言:javascript
复制
{
  "tool_name": "Task",
  "tool_input": {
    "subagent_type": "review-readonly",
    "description": "Completion review",
    "prompt": "你是独立的 Completion Reviewer(ADR-044 L4)。你的任务是验证..."
  }
}

三个关键字段:

字段

含义

subagent_type

用哪种 agent 定义来 spawn

description

任务简述

prompt

给子 agent 的具体指令

Agent 定义文件

每种 subagent_type 对应一个 agent 定义文件,存放在:

代码语言:javascript
复制
.claude/
├── agents/           # 本地自定义 agent
│   ├── review-readonly.md    # 只读审查 agent
│   └── ...
└── plugins/          # 插件提供的 agent
    └── pr-review-toolkit/
        ├── code-reviewer.md
        ├── silent-failure-hunter.md
        └── ...

每个定义文件有 YAML frontmatter:

代码语言:javascript
复制
---
name: review-readonly
model: claude-opus-4-6      # 指定用哪个模型
tools:                       # ← 这就是 Schema 级隔离的关键
  - Read
  - Search
  - Grep
  - ListFiles
  # 没有 Edit / Write / Bash / NotebookEdit
---

你是一个独立的审查 agent...

执行流程

代码语言:javascript
复制
主 agent 判断"这个任务需要子 agent"
  ↓
调用 Task 工具(subagent_type + prompt)
  ↓
  PreToolUse Task hook 触发
  review-agent-gatekeeper.py
  检查:是不是审查类 agent?
  是 → prompt 里有没有只读指令?
  没有 → exit 2 阻止 spawn
  有 → exit 0 放行
  ↓
Claude Code 按照定义文件 spawn 子 agent
  - 加载 agent 定义文件的 frontmatter(tools 白名单、model 等)
  - 创建独立上下文(不是主 agent 的对话历史)
  - 子 agent 只能用 tools 白名单里的工具
  ↓
子 agent 执行任务,返回结果给主 agent

两个关键特征

1. 独立上下文:子 agent 不继承主 agent 的完整对话历史。

它只拿到 prompt 里写的内容。这是"独立审查"能生效的前提——审查者看不到执行者的"借口"。

2. 工具白名单在 spawn(生成) 时就固定

子 agent 一旦被 spawn 出来,它的工具集就锁死了。

Edit 这个工具对它来说不存在:调用时会直接报"tool not available"。

这和 WorkBuddy 的 Task 工具(就是我在用的 task 工具来启动 code-explorer subagent),本质上是同一个模式:

  • • 主 agent 遇到需要分工的任务 → 调用 Task 工具 → spawn 子 agent
  • • 子 agent 在独立上下文中运行 → 返回结果给主 agent
  • • 子 agent 的能力范围由定义文件约束

wow-harness 做的就是:

在这个 spawn 的必经之路上加了 hook 检查站,确保审查类子 agent 拿不到写入工具,在spawn 时工具清单里就没有。


能否迁移到其他 AI 编程工具

依赖项

具体机制

wow-harness 怎么用的

7 阶段 Hook 协议

SessionStart/PreToolUse/PostToolUse/PreCompact/Stop/SessionEnd/PostToolUseFailure

全部 16 个 hook 的存在基础

Hook 注入协议

exit 0 + stdout → 注入上下文;exit 2 + stderr → 阻止 + 注入

stop-evaluator 阻止 Stop,guard-feedback 注入上下文

Task 工具

spawn 子 agent + 独立上下文

独立审查 agent

Agent 定义文件

.claude/agents/*.md frontmatter tools: 白名单

Schema 级隔离

Transcript

每次 session 自动生成 .jsonl

stop-evaluator 提取"本次 session 写过哪些文件"

stdin JSON payload

hook 脚本从 stdin 读取结构化事件数据

所有 hook 的输入来源

settings.json

hook 注册表

hook 的安装入口

7 层依赖,每一层都是 wow-harness 运行的必要条件。

是"运行在某个操作系统上"级别的依赖。

各AI Code 工具适用性

能力

Claude Code

Codex (OpenAI)

Cursor

Trae

CodeBuddy

生命周期 Hook

✅ 7 阶段完整

❌ 无 hook 系统

❌ 无 hook

❌ 无 hook

❌ 无 hook

Hook 注入协议

✅ exit code + stdin/stdout

Task 子 agent

✅ 原生工具

✅ 有 sub-agent

✅ 有 agent

❓ 不确定

✅ 有 Task 工具

Agent 工具白名单

✅ frontmatter tools:

❓ 沙箱模式

Session Transcript

✅ 自动 .jsonl

可编程阻止操作

✅ exit 2

结论:目前只有 Claude Code 具备 wow-harness 所需的全部能力。

为什么其他工具做不到

Codex(OpenAI)

Codex 有自己的 harness 机制(sandbox + 指令),但架构完全不同:

  • • 没有 hook 系统——它靠沙箱隔离(文件系统沙箱 + 网络沙箱)来约束 agent
  • • 没有"工具调用前后注入代码"的机制
  • • Codex 的安全模型是"执行后再审查",不是"执行前拦截"

wow-harness 的核心价值——在工具调用瞬间拦截——在 Codex 上没有对应接口。

Cursor

  • • 有 agent 模式,但没有 hook/拦截系统
  • • 无法在 Edit/Write 前注入检查逻辑
  • • 无法物理阻止一个操作
  • • Agent 的工具权限是全量或零,没有白名单机制

CodeBuddy

  • • 有 Task 工具可以 spawn subagent
  • • 但没有生命周期 hook 系统
  • • 没有 tools: 白名单机制来限制 subagent 能力
  • • 无法在工具调用前后注入代码
  • • 我自己的运行机制就是最好的证明——我没有任何 hook 可以拦截我的工具调用

能迁移吗

把 wow-harness 的理念迁移可以,但机制几乎不可迁移:

wow-harness 理念

能否迁移

怎么迁移

Hook 优于指令

⚠️ 降级

降级为"指令 + 人工检查",遵从率从 100% 回到 ~20%

Schema 级隔离

❌ 大部分工具不支持

只有 Claude Code 有 tools: 白名单;其他工具只能靠 prompt

机械化完成验证

⚠️ 部分可以

可以写外部脚本手动检查 git diff + progress.json,但不能自动拦截 Stop

独立审查 agent

⚠️ 部分可以

可以 spawn 子 agent 审查,但无法限制它的工具集

上下文路由

⚠️ 可以迁移

可以通过 CLAUDE.md / system prompt 实现,但不是自动的

风险追踪

⚠️ 可以迁移

纯文件操作,不依赖 hook

循环检测

❌ 依赖 PostToolUse hook

无法在编辑后自动检测

部署保护

❌ 依赖 PreToolUse hook

无法在 Bash 执行前拦截

目前,Claude Code 是唯一提供完整 hook 协议 + agent 工具白名单 + transcript 访问的编程 agent。

其他工具要达到同等效果,需要先在平台层面补齐这些能力。

得到的启示

wow-harness 的本质是:把"你应该如何做"从自然语言指令,转化为工具调用路径上的机械拦截点。

它的这套设计原则也值得我学习运用

  1. 1. 约束优于指令:能用机制强制的,不靠自然语言
  2. 2. Schema 级隔离优于 Prompt 级:删除工具比"请别用"有效
  3. 3. 机械化验证优于自评:检查 git diff 比"测试过了吗?"可靠
  4. 4. 拦截优于审计:在执行前阻止,不是执行后发现
  5. 5. 独立审查优于自我审查:不同上下文 + 只读工具

这些原则可以迁移,但实现方式完全取决于目标工具提供了什么接口。

你觉得能否提升 AI Code 的效率?评论区留言。

-END-

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术人生黄勇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • wow-harness 使用介绍
    • 它解决什么问题
    • 核心架构(四大组件)
    • 安装方法
    • 适用建议
  • wow-harness 技能系统详解
    • 一、技能的元数据结构
    • 二、技能层级架构
    • 三、职责分层
    • 四、为什么这样分层?
      • 1. 分离"判断"与"执行"
      • 2. meta 层的"免疫系统"隐喻
      • 3. entry 层的"导航"角色
    • 五、技能间的协作关系
    • 六、技能系统的核心设计思想
    • 应用案例
    • 设计精髓
  • 注入机制如何生效?
  • Claude Code Hooks 协议
    • 1. 完整的 Hook 事件清单(28 种)
    • 2. 配置方式
    • 3. SessionStart 的触发时机
  • 模拟一次完整开发过程
    • 阶段 0:启动 Session
    • 阶段 1:AI 读取路由文件
    • 阶段 2:AI 编辑路由文件
    • 阶段 3:AI 编辑更多文件(任务漂移场景)
    • 阶段 4:AI 尝试直接部署到生产(危险操作场景)
    • 阶段 5:AI 循环编辑同一文件
    • 阶段 6:AI 声称完成,尝试 Stop(假装完成场景)
    • 阶段 7:独立审查
    • 阶段 8:上下文压缩时的保护
    • 阶段 9:Session 结束
  • 8-Gate状态机在什么时机生效?
  • 为什么"指令遵从率 ~20%,hook 执行率 100%"?
  • 各组件分工一览
  • 工具清单没有写入工具保证审查者只读
    • 方式一:Prompt 级约束(提示词里说"别改")
    • 方式二:Schema 级约束(工具定义里根本没有 Edit/Write)
  • "Schema " 是什么
  • 为什么需要两层保障
  • 总结
  • Claude Code 的 Task 工具
  • Agent 定义文件
  • 执行流程
  • 两个关键特征
  • 能否迁移到其他 AI 编程工具
  • 各AI Code 工具适用性
  • 为什么其他工具做不到
    • Codex(OpenAI)
    • Cursor
    • CodeBuddy
  • 能迁移吗
  • 得到的启示
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档