从五层理解到可落地实践:我如何把 Harness 工程真正加进项目
模型越来越强,但 coding agent 在真实项目里依然经常翻车。跑了二十分钟说「做完了」,结果测试挂了、约定没遵守、新会话又要从头摸索。很多人第一反应是换更贵的模型。更有效的做法往往是:先修 harness。
这篇文章把前三讲的核心,连同我自己的五层理解,整理成一篇可直接落地的实践笔记:Harness 是什么、文档怎么放、工作流怎么跑、如何可观测、如何用诊断循环持续变强。
第一层:先搞清楚 Harness 是什么
Harness 不等于提示词。
它是模型权重之外的一切工程基础设施:指令、工具、环境、状态管理、验证反馈。OpenAI 说得更直白——在 harness 搭得好的仓库里,同一套模型可以从「不可靠」直接跳到「可靠」。Anthropic 的对照实验也证明了:同一个 Opus,裸跑和配上完整 harness,结果判若两马。
所以第一层的结论只有一句话:
模型能力强,不等于执行可靠。失败时先修 harness,再考虑换模型。
具体失败模式通常就这几类:
- 需求描述模糊,agent 只能猜
- 隐性约定没写进仓库,agent 无从遵守
- 环境有缺口,上下文浪费在修环境上
- 缺少验证手段,agent 自己觉得做完了就算完成
- 跨会话状态丢失,每个新会话都要重新探索
对应的排查方式,是把失败归因到五层防御:任务规范、上下文供给、执行环境、验证反馈、状态管理。不要笼统说「模型不行」。
想继续深入「仓库即规范」,可以看系列第三讲《让代码仓库成为唯一的事实来源》。
第二层:文档与知识安排,让仓库成为唯一事实来源
Agent 的工作世界只有三样输入:系统提示和任务描述、仓库文件、工具执行输出。Slack、Jira、Confluence、老工程师脑子里的规则,它都看不见。
所以第二层要解决的是知识可见性:
- 根目录放
AGENTS.md或CLAUDE.md - 它是目录页,不是百科全书
- 建议控制在 100 行左右,最多别超过 200 行
- 多出来的内容放到
docs/或模块旁的ARCHITECTURE.md、CONSTRAINTS.md - 从
AGENTS.md用链接导航过去 - 对话上下文有限,重要且跨会话必须保留的信息,持久化进文件
推荐结构:
project/
├── AGENTS.md
├── PROGRESS.md
├── Makefile
├── docs/
│ ├── ARCHITECTURE.md
│ └── CONSTRAINTS.md
└── src/
└── api/
└── ARCHITECTURE.md
AGENTS.md 至少写清:
- 项目是什么
- 技术栈和版本
- 怎么启动
- 硬约束
- 验证命令
- 详细文档入口
PROGRESS.md 至少写清:
- 当前目标
- 已完成
- 进行中
- 被阻塞
- 下次会话从哪里继续
验收方法很简单:做一次「全新会话测试」。开一个全新 agent 会话,只让它看仓库,问五个问题:
- 这是什么系统
- 代码怎么组织
- 怎么跑
- 怎么验证
- 现在进度到哪了
答不上来的地方,就是地图上的空白。
第三层:把 Agent 工作流做成固定协议
文档解决「它知道什么」,工作流解决「它怎么干活」。这一层最容易落地,也最容易被忽略。
1. 每次工作前先初始化
新会话开头强制执行:
- 读
AGENTS.md - 读
PROGRESS.md - 确认环境可启动
- 写出本次任务的完成定义
- 加载相关约束和功能清单
可以把它写进 AGENTS.md 顶部,也可以做成固定开场 prompt。核心是:冷启动不能靠猜。
关于初始化协议的更细拆解,可对照系列第六讲《让 agent 每次工作前先初始化》。
2. 任务边界必须画清楚
不要说「加个搜索功能」,要写成可验证的完成定义:
任务:添加搜索端点
完成标准:
- 新增 GET /api/search?q=xxx
- 支持分页,默认 20 条
- 返回结果包含高亮片段
- 走现有认证中间件
- pytest 全绿
- mypy --strict 通过
- 端到端 curl 一次成功
- 更新 PROGRESS.md 与相关文档
没有显式完成定义,agent 就会自己编一个,然后过早宣布完成。
3. 验证不能只靠单元测试
单元测试是必要的,但不够。完整验证应该尽量覆盖:
- 测试
- 类型检查
- lint
- build
- 端到端流程
在 AGENTS.md 里写死一条完整验证命令,例如 make check。agent 说「做完了」时,先跑命令,输出干净才算完成。
4. 结束会话时达到清洁状态
结束前 checklist:
- 改动已原子提交,或回滚干净
- 完整验证通过
- 更新
PROGRESS.md - 架构有变就更新对应文档
- 留下 handoff,让下一个全新会话五分钟内能接上
这其实就是把 ACID 借到 agent 状态管理上:
- 原子性:一次逻辑改动对应干净提交
- 一致性:验证不过不收工
- 隔离性:多 agent 时用分支或 worktree 隔离
- 持久性:跨会话知识写进仓库
第四层:让 Agent 运行可观测
不可观测,就只能靠感觉判断「它是不是又傻了」。可观测性属于反馈子系统和状态子系统的延伸。
最低配就能开始:
PROGRESS.md实时更新- 每次验证命令的完整输出留下来
- 记一行任务日志:
日期 | 任务 | 成功/失败 | 失败归因层 | 耗时
中配可以再加:
- 每次任务用独立 git worktree 或分支
- 把启动、测试、lint 日志写到固定目录
高配再考虑本地可观测栈。但对大多数团队,最低配已经能显著降低「黑盒感」。
可观测的目标不是炫技,而是让两件事变得可见:
- 它到底有没有完成
- 失败到底卡在哪一层
更完整的可观测实践,可参考系列第十一讲《让 agent 的运行过程可观测》。
第五层:从目标出发,跑诊断循环
第五层不是另起炉灶,而是把前面四层连成闭环。
官方更准确的叫法是诊断循环:
目标
→ 拆成小任务
→ 写完成定义
→ 执行
→ 观察验证结果与进度
→ 失败则归因到某一层
→ 只修那一层 harness
→ 再执行
→ 更新进度与日志
OpenAI 百万行代码实验也印证了这一点:不是模型突然变强,而是工程师不断把大目标拆成可执行积木,并补齐 agent 缺失的工具与结构。
几轮下来,你会逐渐看清瓶颈:
- 总是任务说不清,就先修完成定义
- 总是环境翻车,就先修依赖和启动脚本
- 总是「做完了但实际没做完」,就先修完整验证
- 总是新会话接不上,就先修
PROGRESS.md和 handoff
从手动驱动走向自动循环,可继续看系列第十三讲《从手动驱动到自动循环》。
今天就能做的最小闭环
如果只想先迈出一步,做这六件事就够:
- 写一个不超过 100 行的
AGENTS.md - 写一个
PROGRESS.md - 新会话强制先读这两个文件
- 每次任务先写完成定义
- agent 声称完成时,强制跑完整验证
- 失败按五层归因,修 harness,再跑
这不是玄学,是工程。同一个模型,空白仓库和完整 harness 仓库之间的差距,往往比「再换一个更贵的模型」更大。
核心结论
- Harness 是模型之外的一切,目标是让执行更可靠
- 文档要短、要近、要可导航,仓库才是唯一事实来源
- 工作前初始化,工作中约束边界,工作后清洁收尾
- 验证要跑通流程,不能只靠单元测试和自我感觉
- 可观测让完成与失败变得可见
- 用诊断循环持续修补 harness,而不是反复责怪模型
一句话收束:
千里马也得配好马具。agent 要稳定,先把仓库、流程、验证和反馈搭起来。
延伸阅读
- OpenAI: Harness Engineering
- Anthropic: Effective Harnesses for Long-Running Agents
- HumanLayer: Harness Engineering for Coding Agents
- SWE-bench Leaderboard
- 系列第一讲:模型能力强,不等于执行可靠
- 系列第二讲:Harness 到底是什么
- 系列第三讲:让代码仓库成为唯一的事实来源