Harness engineering
本文字数:1.2k 字 | 阅读时长 ≈ 4 min

Harness engineering

本文字数:1.2k 字 | 阅读时长 ≈ 4 min

OpenAI 在 Harness engineering 中提出了一个很有意思的观点:与其要求 Agent 永远不犯错,不如把测试、Lint、架构约束和评估工具接入开发流程,让错误能够被及时发现并自动反馈给 Agent。本文结合一个机器学习任务和一个 Codex Skill,记录一下我对这个概念的理解。

1. Harness 是什么

Harness 可以理解为 Agent 周围的一套反馈和约束系统。Agent 修改代码后,系统会自动运行单元测试、集成测试、类型检查、安全检查和 Evals,再把结果反馈给 Agent:

              Agent
                │
              修改代码
                │
                ▼
        ┌─────────────────┐
        │ Feedback System │
        ├─────────────────┤
        │ Unit tests      │
        │ Integration     │
        │ Lint            │
        │ Type check      │
        │ Architecture    │
        │ Security        │
        │ Evals           │
        └────────┬────────┘
                 │
              pass/fail
                 │
                 ▼
               Agent

检查通过,任务才能继续;检查失败,Agent 根据错误信息修改方案并重新验证。Harness 的目标不是让 Agent 一次写对,而是让错误变得可见、可检测、可修复

2. 约束结果,而不是实现

假设我们让 Agent 优化一个 IP 分类器,并告诉它“Precision 优先”。这是一个比较模糊的要求。Agent 可能得到下面的结果:

Precision: 0.90
Recall:    0.20

Precision 确实提高了,但 Recall 可能已经无法接受。更合适的方式是把目标写成可以验证的验收条件:

assert precision >= 0.90
assert recall >= 0.70

如果本次实验结果为:

Precision: 0.93
Recall:    0.58

Eval Harness 会直接返回失败:

FAIL: Recall 0.58 < required 0.70

Agent 由此知道当前方案不能接受,需要继续优化。至于是调整 threshold、加入 hard negatives、修改 classifier,还是增加 cascade 和 rerank,可以由 Agent 自己决定。

这里的 Precision >= 0.90Recall >= 0.70 就是 Invariant,也可以理解为必须满足的 Acceptance Criteria。我们只约束结果,不规定具体实现,这就是:

Enforce invariants, not implementations.

3. Skill 负责指导,CI 负责约束

再看一个更接近 Codex Skill 的例子。假设我们创建了一个 analyze-badcase Skill,并在 SKILL.md 中规定:

分析 badcase 时:

1. 计算 FP 和 FN;
2. 按类别归因;
3. 输出 Precision、Recall 和 F1;
4. 不允许修改 test set。

前三条属于工作流程,写在 Skill 中很合适。第四条如果非常重要,就不应该只依赖文字提醒,还需要增加机械约束。例如,将测试数据设置为只读,或者在 CI 中检查相关文件:

eval/data/test.json 被修改
            │
            ▼
         CI FAIL

这样,SKILL.md 负责告诉 Agent 为什么不能修改 test set,CI 则保证违反规则后任务一定失败。两者并不是互相替代,而是分别负责指导和执行。

4. Harness 的三个层次

一个完整的 Harness 通常包含三个层次:

Knowledge
“为什么这样做”
        │
        ▼
AGENTS.md / Docs

Guidance
“应该怎么做”
        │
        ▼
Skill / Instructions

Enforcement
“不这样做就失败”
        │
        ▼
Lint / Test / CI

例如,AGENTS.md 可以告诉 Agent 项目采用单向依赖架构,并指向对应文档;ARCHITECTURE.md 负责解释 UI → Service → Repo 的设计原因;最后由结构测试保证 Repo → UI 这样的反向依赖无法进入代码库。

因此,Harness Engineering 并不意味着以后不需要 AGENTS.md 或 Skill,而是让不同组件承担不同职责:

5. 什么时候应该使用机械约束

并不是所有要求都值得写成 Lint。一个规则同时满足以下条件时,通常比较适合机械化:

  1. 规则非常重要;
  2. 经常被违反;
  3. 可以明确判断对错;
  4. 违反后的成本较高;
  5. 能够自动检测。

例如,“不能提交 API Key”适合使用 secret scanner;“test dataset 不能被训练代码读取”适合通过权限和测试限制;“所有 API endpoint 必须鉴权”也可以写成自动化测试。

但“函数命名应该清晰优雅”很难完全机械判断,更适合保留在文档、Skill 或 Review 中。可以把这些规则看成一个连续的谱系:

主观、模糊
    │
    │  Docs
    │  Skill
    │  Review
    │
    │  Lint
    │  Structural Test
    │  Unit Test
    │  Integration Test
    │
客观、可验证

规则越客观、越容易判断,就越适合下沉为机械约束。

6. 总结

以前遇到重要规则,我们可能只会提醒 Agent:“千万不要犯这个错误。”Harness Engineering 更进一步,它希望把规则变成系统能力:

发生错误
   ↓
系统检测
   ↓
返回明确反馈
   ↓
Agent 修复并重新验证

所以 Harness Engineering 追求的并不是一个永远不犯错的 Agent,而是一套不会让 Agent 带着错误继续向前的工程系统。