7. 综合练习
这是什么:迷你 Harness = 一个项目最小可用的六层底座——目录、约束、状态、工具、验证、恢复,各有一个能跑的例子。
为什么用:六层听着吓人,但每层都能单独加。一次全上容易卡在半路,不如从最缺的那一层开始补。
如何用:本章按六步走,每步都有验收标准和「什么时候可以停」的判断,做完你就有了自己的 Level 1~2 Harness。
7.1 目标与验收清单
目标:给一个真实项目(用本文的博客仓库当例子)配出一套 Level 1 → Level 2 的 Harness。
| 层 | 本次要落的东西 |
|---|---|
| L1 信息边界 | 一个目录式 AGENTS.md,指向 docs/ 下的分册 |
| L6 约束 | 一个能机械执行的检查(不是提示词) |
| L4 状态 | 一个进度文件模板 + 一个任务交接文档模板 |
| L2/L3 工具与编排 | 一份工具清单 + 一份权限清单 |
| L5 验证 | 一个「跑完能给出修复建议」的检查命令 |
验收清单:
- 第 1 步:写出现在处于 Level 0~4 的哪一级,缺哪两层
- 第 2 步:
AGENTS.md不超过 100 行,每条规则都能指向一个文件 - 第 3 步:检查脚本的报错信息里带修复方法
- 第 4 步:进度文件和交接文档各有一份模板,且已提交进仓库
- 第 5 步:权限清单里
git push、rm、curl都有明确档位 - 第 6 步:有一条命令能一键验证,且失败时能指出改哪儿
贯穿全程的例子:这个博客仓库本身就适合当练手对象——它已经有
doc/architecture.md、doc/authoring.md这样的分册文档,也有tools/下的校验脚本,正好对应 L1 和 L6。
7.2 第 1 步:先定位,别急着搭
对照第 1.6 节的分级表,给自己的项目诚实地打个分:
| 检查项 | 有 / 没有 |
|---|---|
有 AGENTS.md(或等价的项目说明) |
|
| 有能自动跑的检查(lint / 测试 / 结构检查) | |
| 有任务状态文件 | |
| CI 里跑着 Agent 相关的检查 | |
| 有独立的验收环节(不是自己写自己验) |
- 全没有 → Level 0
- 只有第 1 项 → Level 1
- 前三项都有 → Level 2
- 再加多 Agent 分工与持久化记忆 → Level 3
这一步的产出是一句话,写进 PR 描述或 issue:
当前 Level 1,缺 L6(机械化约束)和 L5(独立验证)。本次先补 L6。
有了这句话,后面每加一件东西都知道自己在第几层,不会无限膨胀。
7.3 第 2 步:L1 —— 目录式 AGENTS.md
不要新建一堆规则,直接把已有的文档重新组织成索引。
以本仓库为例,doc/ 下已经有四份文档,天然就是分层结构:
# AGENTS.md(约 60 行,只做索引)
## 这个仓库是什么
个人博客的静态站点,用 `v2/` 下的 Python 脚本构建(无 VitePress / Node)。目录说明见 `README.md`。
## 改内容前必读
- 写作规范(章节模板、链接规范、风格要求):`doc/authoring.md`
- 架构与变更流程(先文档后代码):`doc/architecture.md`
- AI 操作边界(允许区 / 禁区):`doc/ai-ops.md`
- 内容规划(新增技术栈的批次与章节):`doc/roadmap.md`
## 常用命令
- 构建并监听:`python v2/build.py --all --watch`
- 本地预览:`python -m http.server 8931 --directory v2/dist`
- 构建验证:`python v2/build.py --all` + `python v2/tools/check_site.py`
- 校验章节开头格式:`node tools/check-three-step.mjs`
- 校验改动范围:`node tools/check-region-only.mjs`
## 硬约束
- 涉及站点结构的改动,**先改 `doc/` 再改代码**,同一次提交
- `server/**` 与 `v2/dist/` 构建产物是禁区,改动需用户确认
- 构建不通过不算完成
## 提交约定
- 中文 commit message 用文件 + `git commit -F <file>`
- `git commit` / `git push` 须经用户确认
注意三点:
- 每条都指向文件,没有一条是「你要注意 X」这种空话
- 硬约束单独一节,且都是可执行的(改流程、禁区、构建)
- 行数可控,正文可以再长,但索引这一层保持在百行内
7.4 第 3 步:L6 —— 一个能机械执行的检查
挑一条最容易违反、也最值得自动化的规则。博客仓库里有个现成例子:每个教程章节开头必须符合「三步思维」三段式。这条规则完全可以脚本化。
# tools/check-three-step.mjs(简化示意)
const LABELS = ['**这是什么**:', '**为什么用**:', '**如何用**:']
for (const rel of changedFiles) {
const lines = readFileSync(rel, 'utf8').split(/\r?\n/)
const region = regionBetweenH1AndFirstH2(lines)
const found = LABELS.map(l => region.findIndex(x => x.startsWith(l)))
if (found.some(i => i < 0)) {
report(rel, '缺少三步思维三段之一')
}
// 段间空行、字数区间、H2 数量不变……依次检查
}
跑起来:
node tools/check-three-step.mjs
你会看到(示意):
通过 12 / 12
有问题的文件则长这样:
docs/ai/harness/practice.md
- 标签数=2(应为 3)
- **如何用**:前缺空行
重点是报错信息:它说清了「哪个文件、缺什么、怎么改」。这就是第 5 章说的「报错要能指导下一步」。
同类可做的检查还有:
| 检查 | 抓什么 |
|---|---|
死链检查(v2/tools/check_site.py) |
链接到不存在的页面、锚点缺失 |
| 章节模板检查 | 开头格式、结尾「下一章」链接 |
| 目录一致性检查 | v2/nav.json 的章节和实际 md 文件对不上 |
| 章节数一致性检查 | README 写的章数和实际文件数不符 |
这类检查一旦写出来就一劳永逸——每次提交自动跑,不用人记。
7.5 第 4 步:L4 —— 状态文件与交接文档
建两个模板,进仓库:
.agent/progress.md(当前任务进度):
# 当前任务
<一句话>
## 状态
进行中
## 已完成
- <input type='checkbox' disabled> ...
## 当前卡在哪
<卡点 + 已排除的可能>
## 关键决策
- <决策>:<理由>
## 验证命令
```bash
<一条能验证的命令>
```
.agent/handoff.md(交接文档,四件套):
# 任务交接:<任务名>
## 目标
<目标 + 验收标准>
## 已完成
- ✅ <改动>(文件:<路径>)
## 未完成
- ⬜ <下一步>(卡在:<原因>)
## 改过的文件
- `<路径>`(新增 / 修改 / 删除)
## 失败原因(别重蹈)
- 试过 <方案>,失败于 <原因>。正确做法是 <方案>。
## 下一步验证命令
```bash
<命令>
```
交接文档里最值钱的是「失败原因」那一节——它把「试错」从一次会话的易失记忆变成仓库里的长期资产。
配套约定写进 AGENTS.md:
## Agent 协作约定
- 开工前先读 `.agent/progress.md`;每完成一块就更新它
- 上下文快满或需要换会话时,按 `.agent/handoff.md` 的格式交接
- 交接文档只记决策和卡点,不记流水账
7.6 第 5 步:L2/L3 —— 工具清单与权限清单
写一份角色 → 工具的表,再给每个工具定权限档位:
| 角色 | 允许的工具 | 禁止 |
|---|---|---|
| 规划 Agent | 读文件、搜索、列目录 | 写文件、跑命令 |
| 实现 Agent | 读文件、写文件、跑测试 | 推送、部署 |
| 验收 Agent | 跑应用、跑测试、截图 | 改代码 |
规划与实现分成两个角色(哪怕是同一个 Agent 分两轮跑),规划阶段不给写工具,能挡住「边想边改」。
权限清单:
{
"permission": {
"bash": {
"git status": "allow",
"git diff": "allow",
"git log *": "allow",
"npm test": "allow",
"python v2/build.py *": "allow",
"python v2/tools/check_site.py": "allow",
"git commit *": "ask",
"git push *": "ask",
"rm *": "deny",
"curl *": "deny",
"wget *": "deny"
}
}
}
三条挑法:
- 只读操作直接 allow,别浪费确认机会
- 有副作用但可逆的 ask(commit、push)
- 不可逆或外发的 deny(
rm、curl、wget)
7.7 第 6 步:L5 —— 一条能验证的命令
验证闭环的入口是一条一键命令:
node tools/check-three-step.mjs \
&& node tools/check-region-only.mjs \
&& python v2/build.py --all \
&& python v2/tools/check_site.py
把它写进一个脚本或 Makefile,就能做到「一条命令验证全部」。
这条命令要满足三个条件:
- 能自动跑——不依赖人记得执行
- 失败时指出改哪儿——不是「校验失败」,是「哪个文件、哪一行、怎么改」
- 和提交挂钩——放进 pre-commit 钩子或 CI,让不合格的改动进不了主干
再加一个独立验收环节。哪怕只有一个问题,也值得让「实现」和「验收」分属两轮:
实现 Agent 写完 → 验收 Agent 只做三件事:
1. 跑应用,看功能能不能用
2. 对照需求清单逐条核对
3. 只提「能不能用 / 不能用」,不提「代码写得丑」
刻意不让验收 Agent 提代码风格意见——风格由 Linter 管,验收只管功能。两件事混在一起,验收就会变成代码审查,注意力被稀释。
7.8 常见翻车现场
| 症状 | 原因 | 改法 |
|---|---|---|
AGENTS.md 越写越长 |
把它当手册用 | 只留索引,细节进 docs/ |
| 检查脚本没人跑 | 没挂钩子 | 挂 pre-commit 或 CI |
| 报错只说「不合法」 | 缺修复建议 | 报错里写清改哪个文件、怎么改 |
| Agent 反复试同一个错 | 工具返回不可行动 | 改返回格式,补下一步建议 |
| 状态永远没更新 | 没约定 | 写进 AGENTS.md,开工前先读 |
| 交接后接着走错方向 | 交接文档漏了失败原因 | 交接模板强制带「失败原因」 |
| 权限弹窗太烦 | 全设成 ask | 只读 allow,不可逆 deny |
| 一上来就搭全自动 | 目标过大 | 先做 Level 1:AGENTS.md + 一个检查 |
动手改
- 给你的项目写一句定位:「当前 Level X,缺 Y、Z,本次先补 Y」,贴进 issue 或
AGENTS.md - 把项目里现有的文档重组成索引 + 分册,建一个不超过 100 行的
AGENTS.md - 挑一条「你希望 Agent 永远别犯」的错,写成一个校验脚本,让它的报错带上修复建议
- 建
.agent/progress.md和.agent/handoff.md两个模板,约定开工先读、做完更新 - 写一份权限清单,把
git push、rm、curl三个先定了档
小结
- 先定位再动手:诚实地给自己打 Level 0~4 的分,缺哪层补哪层
- L1:
AGENTS.md只做索引,指向分册文档,硬约束单独一节 - L6:把最容易违反的规则写成校验脚本,报错必须带修复建议,并挂进 pre-commit / CI
- L4:
progress.md记进度和决策,handoff.md记四件套 + 失败原因 - L2/L3:角色分工(规划只读、实现能写、验收只验功能)+ 三档权限
- L5:一条一键验证命令 + 一轮独立验收
- 一次只补一层,Level 1 已经能覆盖大部分高频错误
下一站:技能 Skills,把「怎么做事」也封装成可复用的资产 🐸