Harness Coding:与其调教模型,不如设计模型的工作环境
Harness Coding:与其调教模型,不如设计模型的工作环境
过去半年我换了三次 AI coding agent,从 Cursor 到 Claude Code 再到自己拼的 编排器。结论很反直觉——真正影响产出质量的从来不是换更强的模型,而是模型 周围那一层我一开始压根没意识到存在的东西。
这层东西有个名字:Harness。
一、Agent = Model + Harness
业界这两年逐渐形成一个共识公式:
Agent = Model + Harness
模型(GPT / Claude / Gemini …)只是 Agent 的一部分。模型之外的所有东西—— 工具集、规则文件、反馈机制、工作流编排、上下文组装策略、CI 门禁—— 统称为 Harness。
Addy Osmani 引过一个挺震撼的数据点:在 Terminal Bench 2.0 上,同一个 Claude Opus 4.6,套在某通用 CLI 里只能排到 Top 30,套到一个精心设计的定制 harness 里能跳到 Top 5。模型一字没改,只换了它工作的"环境"。
口号:
一个体面的模型 + 出色的 harness,能打败出色的模型 + 糟糕的 harness。
这意味着,当你抱怨"AI 写的代码不行"的时候,大概率不是模型不行,是你给它的 环境不行——这件事现在叫 Harness Engineering(或 Harness Coding)。
二、三大支柱:约束 / 反馈 / 门禁
一个完整的 harness 大致三层:
┌────────────────────────────────────────────────┐
│ ① Feed-forward Constraints(前馈约束) │
│ 在代码生成前缩小解空间 │
│ → AGENTS.md / Cursor Rules / 类型系统 / 架构图 │
├────────────────────────────────────────────────┤
│ ② Feedback Loops(反馈循环 / Sensors) │
│ 让 agent 在你看之前自己发现问题并自我纠正 │
│ → Linter / 类型检查 / 测试 / Hook │
├────────────────────────────────────────────────┤
│ ③ Quality Gates(质量门禁) │
│ 阻止不合格代码进入主干 │
│ → CI / pre-commit / Required Reviews │
└────────────────────────────────────────────────┘
这三层的本质差别是约束生效的时机:
- 前馈是"开始写之前先告诉它规矩"
- 反馈是"写完之后立刻让它知道错了"
- 门禁是"错了的不许合"
很多人只做了第一层(写 prompt / 写 rules 文件),结果发现"AI 老是不听话"。 原因是只有前馈、没有反馈和门禁——LLM 是概率模型,告诉它"请遵守 X", 它大概率会遵守,剩下那 5% 就是你的事故来源。
Prompt 里说 vs Lint 里卡
举个最经典的对照:
告诉 agent:「请遵守我们的编码规范」 ← 概率性合规
写一条 linter 规则,违规直接 fail PR ← 确定性合规
这两件事是根本不同的东西。Harness 思维就是:能用确定性手段卡住的, 绝不留给概率性手段。
三、把 AGENTS.md 当代码维护
AGENTS.md(OpenAI / Cursor / Claude Code 都认这个文件名,逐渐成为跨工具
标准)是 harness 最常被忽视的入口。常见的几条反模式:
❌ 600 行的风格指南——LLM 实际上读不完,注意力会被稀释 ❌ "请尽量"、"建议"、"考虑"这种软措辞——概率性表达,不可执行 ❌ 没有人维护,半年没更新——和代码漂移之后越用越坑 ❌ 每条规则都是凭空写的——没有来源,没人记得为什么有这条
正确的几条原则:
✅ 保持在 60 行以内——超过这个数说明该拆成 lint 规则了 ✅ 每条规则可以追溯到一个具体失败事件("棘轮原则",下一节细讲) ✅ 用三级边界:必须做 / 先请示 / 禁止做——别让 LLM 自己拿捏 ✅ 把 AGENTS.md 当代码:进 PR、过 review、定期重构
口诀:AGENTS.md is code, treat it like code.
四、棘轮原则(Ratchet Principle)
这是 harness engineering 最重要的一条操作方法论:
每一次失败都应该被转化为一条永久规则。
每一条 AGENTS.md 的规则都应该可以追溯到一个具体的失败事件。
为什么叫"棘轮"——棘轮只能向一个方向转。你的 harness 应该是单调收紧的: 出过的错不能再出第二次。
实操循环:
1. Agent 出了一个错(比如建了个我不想要的 helper class)
2. 别只在当前 PR 里改掉,问自己:这个错该怎么"在源头"防住?
3. 三个选项,按强度排序:
a) 加一条 AGENTS.md 规则(最弱,前馈)
b) 加一条 linter / 类型规则(中等,反馈)
c) 加一条 CI 门禁(最强,门禁)
4. 选能用的最强那一档,提交进 harness 仓库
5. 下次同样的错不会再发生
这个循环跑顺了,你的 agent 就会随着时间越来越好用,而不是反过来。
五、让错误信息本身成为 prompt
Harness 的反馈层有个非常容易被忽视的细节:报错文案要写给 LLM 读。
对照:
# 普通 lint 错误(写给人看)
error: max-complexity exceeded (12 > 10)
# 写给 agent 看的 lint 错误
error: Function complexity is 12 (limit: 10).
Refactor by extracting the early-return validation block into
a separate `validateInput(...)` helper, or by collapsing the
nested switch into a lookup table.
See: docs/complexity.md#how-to-fix
第二种写法里,错误信息就是修复指南。Agent 拿到这条 lint 输出,下一轮 就有 70% 概率能自己改对。
这件事的转变是:Linter / 类型检查器 / 测试报错文案,从给 reviewer 看的 工件,变成给 agent 看的反馈接口。 这是 harness 时代的新职业素养。
附带一条相关的反模式:
禁止 agent 使用 inline disable(
// eslint-disable-next-line一类)。
不然 agent 会把"违规"压成"抑制违规"——表面看 lint 过了,本质上规则被 绕过去了。Harness 必须堵死这个口子。
六、Plan → Execute → Verify
别让 agent 一口气把多步任务做完。强制走 PEV:
Plan — 先输出明确的 step list,人/工具过一下
Execute — 按 plan 走,每一步独立可观察
Verify — 跑测试 / 对照 plan / 跑 sensor,确认对了再下一步
每个转换点(plan → execute / execute → verify)都是一个插入约束的 机会——是写"必须先 plan 再写代码"的 hook、还是写"verify 不过就回退到 plan 重做"的循环,看你的场景。
经验:把 PEV 写进 harness 之后,最大的好处不是 agent 写得更对,而是 你能在 plan 阶段截停——省下一堆"已经写了 200 行才发现方向错了"的痛苦。
七、工具集:10 个比 50 个好
很多人给 agent 接 MCP 接到 50 个工具,觉得"能力越多越好"。实测反过来—— 工具菜单太长,LLM 选错工具的概率显著上升。
经验法则:
- 同类工具不要超过 2 个("读文件"不要既有
Read又有Cat又有FileGet) - 每个工具的 description 必须和别的工具有明确区分
- 危险工具(删除 / 推送 / 调外部 API)单独放一组,加确认
- 周期性 audit:看 trace 里哪些工具 90 天没被调用过,删掉
口诀:10 个聚焦工具 > 50 个重叠工具。
八、长任务:双层 agent + 进度文件
跨多个上下文窗口的长任务(比如让 agent 跑两周建一个项目),单 agent 跑不动。 Anthropic 推荐的双层架构:
Init Agent — 只跑一次,搭骨架:
- 生成 init.sh(一键起开发环境)
- 生成 features.json(200+ 任务清单 + 状态)
- 建初始 git 仓库 + 第一条进度记录
Coding Agent — 每次 session 跑一轮:
1. 读 git log + progress.md → 知道上次到哪
2. 从 features.json 挑一个未完成的最高优先级项
3. 跑 init.sh 起环境 + 冒烟测试
4. 做这一项 → 测试 → commit → 更新 progress
5. 退出
关键设计:
- 进度文件是 agent 的"持久记忆"——不依赖上下文窗口
- 一次 session 只做一个 feature——防止"宣告完成幻觉"
- 会话开始先验证环境——防止"在脏环境里写代码"
- 会话结束必须 commit——防止下次 session 看到不一致状态
把这套搬到非 coding 场景也成立——研究 / 数据建模 / 写作,都能用同一套 "init agent + work agent + 进度文件"模式跑。
九、度量你的 harness
Harness 是软件,软件就该有指标。几个 Augment Code 在用的:
| 指标 | 怎么测 | 为什么有用 |
|---|---|---|
| 任务解决率 | 自动化测试通过率 | Harness 整体健康度 |
| 代码变更率 | 两周内被重写的代码 % | 衡量"agent 写的代码站不站得住" |
| 验证开销 | 审计时间 / 首次提交时间差 | 衡量人工 review 负担 |
| 缺陷逃逸率 | 上线后按 commit 来源标记的 bug | 终极指标 |
没有指标的 harness 优化,约等于凭感觉调 prompt。
十、心智模型转变
我感觉 harness coding 真正难的地方是心智模型的转变:
| 旧思路 | 新思路 |
|---|---|
| 我在让 AI 写代码 | 我在设计让 AI 写代码的环境 |
| Prompt 没写好,再调 prompt | Prompt 一次性的,规则要进 harness |
| Agent 又出错了,骂它一顿 | Agent 又出错了,问 harness 哪里漏了 |
| 模型不行,等下一代 | 模型够用,harness 还差很多 |
| 写代码 | 写 harness |
最后一行我觉得最重要——未来工程师的核心产出,从代码本身,逐渐转移到 "约束代码生成过程的那套系统"。代码是 agent 在 harness 边界内的副产品。
怎么开始
如果你完全没动过 harness,从最便宜的三步开始:
- 审计最近 5 个 agent 写的 PR——找重复出问题的模式
- 挑 3 条模式编码成 lint / type 规则——记得报错文案要写给 agent 看
- 在 CI 里硬卡这 3 条——并记录修改前后的"人工 review 时长"
跑两周。如果 review 时间下降,恭喜,你已经在做 harness engineering 了。
剩下的事情就是把"棘轮"持续转下去。
相关阅读:
- Effective harnesses for long-running agents — Anthropic
- Agent Harness Engineering — Addy Osmani
- Harness Engineering for AI Coding Agents — Augment Code
- Harness engineering for coding agent users — Martin Fowler