← cd ../posts

Harness Coding:与其调教模型,不如设计模型的工作环境

2026-05-21

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,从最便宜的三步开始:

  1. 审计最近 5 个 agent 写的 PR——找重复出问题的模式
  2. 挑 3 条模式编码成 lint / type 规则——记得报错文案要写给 agent 看
  3. 在 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

$ ls related/