Harness Engineering(四):把工程规则变成可执行约束
Agent 不会因为读过一次规范,就在此后始终遵守。可靠的 Harness 会把关键架构边界、质量要求和工程原则变成系统能够自动检查并强制执行的规则。
Jonathan
创始人
文档可以告诉 Agent 应该怎样工作,却不能保证它每次都这样工作。
即使把“服务层不能依赖 UI 层”写进 AGENTS.md,Agent 也可能只在大多数时候遵守。面对一个急需修复的问题,它仍有可能选择局部看来最短的路径。代码审查可以发现这次越界;但如果经验只停留在一条审查意见里,下一个 Agent 仍可能犯同样的错误。
OpenAI 在 Harness Engineering 实验中采用了更严格的做法:不逐步规定 Agent 应该怎样实现,而是把真正重要的不变量写成自定义 lint 规则和结构测试。Agent 可以自行选择局部实现,却不能跨越系统明确禁止的架构边界。
这条原则可以概括为:
用文字解释意图,用代码守住边界。
反复出现的审查意见,说明系统缺少约束
团队常常把代码审查当作质量控制的最后一道关口。工程师指出命名不一致、日志缺少字段,或外部数据没有在边界完成解析;作者修正后合并代码。眼前的问题解决了,这条判断却没有成为可复用的能力。
当 Agent 大幅提高代码产出速度后,这种工作方式很快就难以维持。同一种意见可能出现在十个 Pull Request 中,资深工程师不得不反复解释同一条原则。
可以把审查意见分成三类:
- 一次性判断:只与当前需求、用户体验或特殊取舍有关,保留在人类审查中。
- 需要解释的原则:适用于一类问题,但难以完全自动判断,写入架构或产品文档。
- 可以执行的不变量:只要违反就一定不接受,转化成类型、lint、测试或 CI 检查。
如果同一种审查意见反复出现,就不应再只修正当前代码,而要判断这条规则能否进入 Harness,由系统持续执行。
架构只有能够被检查,才真正构成边界
画一张架构图并不难,难的是在日常修改中始终守住依赖方向。
OpenAI 的案例把每个业务领域划分为固定层次,代码只能沿 Types → Config → Repo → Service → Runtime → UI 的方向依赖。认证、连接器、遥测和功能开关等跨领域能力,统一通过明确的 Provider 接口进入,其他依赖关系会被结构测试直接拒绝。这类约束在人类主导的团队中,往往要等到代码库足够庞大才会建立;面对高速产出代码的 Agent,它却从一开始就很重要。
团队还通过自定义 lint 检查结构化日志、schema 和类型的命名方式、文件大小,以及平台特定的可靠性要求。这些都不是对具体实现逐行发号施令,而是在所有改动进入代码库之前,统一守住少数不可破坏的原则。
一个项目可以从几个简单问题开始:
- 哪些目录可以互相依赖,哪些绝对不允许?
- 哪些外部输入必须先经过数据结构验证?
- 哪些模块只能通过公开入口导入?
- 哪些横切能力必须使用统一接口?
- 哪些文件大小、命名、日志和可靠性规则属于硬性要求?
其中能够通过静态分析判断的部分,应尽量交给工具执行。如果架构边界只能靠阅读文档得知,代码生成得越快,违规依赖就越容易混入代码库。
错误信息也是 Agent 理解规则的接口
传统 lint 错误往往只报告规则名称,例如“禁止跨层依赖”。人类工程师可以查阅文档或询问同事,再决定如何修改。Agent 也可以搜索,但每一次额外搜索都会消耗时间和上下文空间。
面向 Agent 的检查应该尽量同时回答三个问题:
违反了什么规则
为什么这条规则存在
允许采用哪些修复路径
例如,不只返回:
service-must-not-import-ui
而是返回:
Service 层不能导入 UI 层。
请把共享类型移动到 types/,或通过 Provider 接口注入跨层能力。
参见 docs/architecture/dependency-rules.md。
这样的错误信息会把修复指导直接送入 Agent 当前的上下文,减少它猜测规则意图的空间。检查工具不再只是拦截错误,也能在本次运行中告诉 Agent 应该如何修正。
边界越明确,局部实现越可以自由
把规则写进系统,不等于规定所有实现细节。
如果团队要求 Agent 始终使用某个具体库、某种循环写法和固定的文件结构,很快就会得到一套僵化的脚手架。当模型能力或项目需求发生变化,这些约束反而会阻碍更好的方案。
更耐用的做法是约束结果和边界:
- 要求外部数据在边界完成解析,但不强制指定验证库。
- 要求日志结构化并包含 trace ID,但不规定函数内部怎样组织。
- 要求领域之间只通过公开接口通信,但允许领域内部自由重构。
- 要求关键行为有验证证据,但不要求每个任务使用完全相同的测试方法。
系统统一守住正确性、可重复性和架构方向;在边界以内,Agent 可以选择合适的实现。约束越清楚,留给 Agent 的自主空间反而越安全。
让工程判断成为系统可以复用的能力
并非所有工程判断都能立刻写成规则。团队可以循序推进:
- 人在代码审查中指出问题并解释理由。
- 同类问题再次出现时,把原则写进相关文档。
- 能够判断的部分转化成 lint、测试或评分器。
- 错误信息提供明确修复方向和文档入口。
- 定期检查规则是否仍然必要,删除已经过时的脚手架。
这套过程把一次性的专家判断变成可复用能力,同时避免过早把模糊偏好固化为僵硬规则。
Harness Engineering 的目标不是消除人的工程判断,而是让高价值的判断不必由人反复表达。下一篇会继续讨论:当这些检查让 Agent 能够更独立地完成工作后,Pull Request、代码审查和合并策略为什么也必须改变。
本文整理自 OpenAI 的文章 Harness engineering: leveraging Codex in an agent-first world,核心观点来自原文。
Harness Engineering 系列
- (一)当工程师开始设计 Agent 的工作环境
- (二)给 Agent 一张代码库地图
- (三)让软件运行状态对 Agent 可读
- (四)把工程规则变成可执行约束(本文)
- (五)当 Agent 的产出超过人的注意力
- (六)Agent 也会复制技术债务
相关阅读
- 智能体需要 Harness,不只是更强的模型 —— 为什么约束、验证和纠正属于 Harness,而不是模型本身。
- 生产级 Agent 的评估与监控 —— 如何把任务失败转化为可重复的系统评估。