Skip to content
zzekelan
English
返回博客列表

Harness Engineering

为你的 agent 构建可协作、可反馈、可约束、可持续迭代的运行环境。

模型毫无疑问是 agent 的发动机,但近来,尤其是在模型性能普遍越过某些瓶颈后,我们越来越能够意识到:外围设计的重要性也许并不比模型本身要低

在进入正题前,稍微歪一下题。目前,领域中确实存在强造新名词的风气。Prompt / Context / Harness Engineering,很难不让人觉得有反复炒冷饭的嫌疑。如果你有关注一些研究员/工程师的社媒,你也会看到他们对此发表自己的看法。如果将它们讨论的问题统一到“为 LLM 构建脚手架/运行环境”,那么很明显,这些名词都是在用同样的内容反复炒作。在这个问题上,本文不作展开——名词定义和解释的游戏真的很无聊。我们仅讨论:这些东西具体关注的问题到底是什么?目前,我认为主要涉及到两个方面:

  • 如何让 agent team 像人类团队一样,通过不同角色的协作,不断自主迭代,最终更 solid 地完成任务?

  • 如何构建一个让 agent 能够持续获得更真实、更接近人类世界的验收标准的反馈,且能持续迭代优化的环境?

我们以此让 agent 获得更强大的能力。

这篇博客将通过分析 Anthropic, OpenAI 的工程博客,结合我最近的实践,介绍目前 harness engineering 中我认为值得关注的核心部分。


通过实现与审查分离提升 One-Shot 前端能力

3 月 24 日,Anthropic Labs 发布了工程博客 Harness Design for long-running application development,文章由 Prithvi Rajasekaran 撰写。他分享了自己通过 harness 的设计,使得 agent 的能力从运行 20 分钟但只产出了几乎不可用的结果,提升到能够自主持续运行 4 ~ 6 小时,最终产出了基本功能较为完善的产品的实践经历。

Prithvi 从让 Claude 自主生成高质量的前端页面的任务入手。

受到 GAN 的思路启发,他构建了一个由 Generator + Evaluator 组成的 agentflow——Generator 生成 HTML / CSS / JS 前端,Evaluator 通过 Playwright MCP 直接跟跑起来的页面交互——这个组合对于 agentic coding 重度使用者来说大概已经完全不陌生,其原因和目的也很容易理解:LLM 总是会沿着上下文中已有的模式来进行后续的推理和生成,让 Generator 去挑自己写的代码的毛病是很困难的。因此,我们需要设置一个 agent,并对其提示词进行专门的调优,使其专注于自己的 review 任务中。

简言之,这里的首要思想就是为每一类 agent 构建干净的上下文空间,在减少了角色切换导致的幻觉和额外开销的同时,也让单独对某类任务的提示词调优变得方便许多。

提示词设计的重要性是无法否认的。尤其在前端审美方面,不同的场景,不同的客户要求,你几乎不可能找到通用标准。Prithvi 让 evaluator 按 design quality、originality、craft、functionality 四个维度对页面设计打分,其中,尤其明确对高度通用(如典中之典蓝紫渐变等)的 AI Slop 模式进行惩罚,并加大对设计和原创性的权重,促使模型在美学上采取更具冒险性的尝试。通过将主观的设计品味尽可能地变成可评分的标准,就可以以 “开发-评分-再开发” 的流程进行多轮迭代,使得结果尽可能脱离“原生 AI 味”。

  • 设计质量(Design Quality): 设计是否感觉像是一个连贯的整体,而不是各个部分的简单拼凑?优秀的设计意味着色彩、字体、布局、图像和其他细节能够完美融合,营造出独特的氛围和风格。
  • 原创性(Originality): 是否有明显的定制化设计痕迹,还是使用了模板布局、库默认设置或人工智能生成的图案?一位优秀的设计师应该能够识别出精心设计的创意。未经修改的现成组件,或者像白色卡片上叠加紫色渐变这样的人工智能生成痕迹,都无法通过这项考验。
  • 工艺(Craft): 技术执行:字体层级、间距一致性、色彩和谐、对比度。这更多的是一项能力测试,而非创意测试。大多数合理的实现方式都能做到这一点;如果失败,则意味着基本功出现了问题。
  • 功能性(Functionality): 可用性,与美观无关。用户能否理解界面功能、找到主要操作并完成任务而无需猜测?

这样的迭代是有效的。Prithvi 也提到,即使是只迭代一轮,也比直接生成的效果要好得多。不过,在我自己的实践当中,我对目前 LLM 的前端设计仍然是不满意的。无意冒犯,我在优化我的个人网站的过程中尝试使用了广受好评的 impeccable 的 frontend-design skill,第一轮就把我原来辛苦迭代的成果覆盖了一大半,几轮过后直接倒向了一个(我认为)完全错误的方向。当然,也可能只是恰巧我不喜欢这种风格,亦或是 LLM 摸奖特性导致了这样的结果。但无论如何,在之后的页面迭代中,我都避免直接让 agent 自己分析并实施改动,更不会让其一轮修改多个内容,而是通过持续的交互,每次只迭代一小块内容(往往是某个组件),及时验证改动是否符合我的目标,同时 commit 自己满意的优化,以免这样的情况再次出现。

commit and commit
“一句话生成一个 APP”是巨大的谎言

引入计划/调研流程

进一步地,Prithvi 以 coder + reviewer 的 harness 为基础,构建了一个 3 个 agent 的系统,将实验拓展到了全栈场景。

新增加的一个 agent,就是在动手前负责计划的 Planner Agent。其主要职责是将用户 1 - 4 句话的 prompt 展开成完整的 product spec。Prithvi 提到自己在 prompt 中加入的关键要素:

要对产品范围抱有野心,并专注于产品背景和高层次的技术设计,而不是详细的技术实现。

在这之中,我认为澄清产品背景是容易被忽略的:你的产品的定位是什么?受众是谁?规模多大?是打算本地部署还是提供线上开箱即用的服务? 诸如此类的问题,都会对技术路线产生非常大的影响。在计划调研阶段,加入一句:澄清产品背景,关注产品语义。agent 就会向你提出许多有助于收敛开发边界的问题,以减少生成一堆硬编码、通过 mock 跑通流程就算完成的失误。

与此同时,就像上文提到的我在前端修改时的情况那样:不要随意 be ambitious about scope。每睡醒一觉起来看到的都是几乎不一样的东西,这对于仅仅想体验 AI 写代码,并且不需要对代码进行维护的朋友们来说是非常 amazing 的事情,但对于需要持续开发维护的产品来说则完全是一场灾难。 不过,如果你的项目是在 MVP 的头脑风暴阶段,你大可以尝试让 agent 将搜索、总结等的强度拉满,有时会有意料之外的收获。

压力你的 harness

Prithvi 的思路中和我有些不同的是,他在每个 feature 开始前,先让 gener 和 eval 讨论,讨论结果一致后才允许 generator 开始写代码。当然,这本质上仍然是 plan mode 的思路,不过是将犯错后 review 再修改的成本再次提前到一个小型 plan 的阶段。但我个人并不认为这是一种好的做法。毕竟,“计划总是赶不上变化”,如果提前写死了粒度过小的细节,反而可能影响到 agent 在实现途中的自主分析和解决问题的能力。另外,我也不太确定这对代码的质量的影响到底有多大,但我可以肯定的是,这一定非常烧 token 和时间。

人生苦短,没有那么多钱,更没有那么多时间可烧怎么办?实际上,我们未必要这么做,也完全不应该必须这么做。这篇博客中我认为最重要的思想——也是我认为在 agent 时代更会被大量包括但不限于 AI 批量生产的文字和代码淹没的思想是:在增加任何复杂度之前,你必须谨慎地考虑和验证这是否是必须要增加的。 也就是说,你应该在每次模型能力得到提升时,对你的 harness 进行压力测试,看看是否有哪些部分已经是不再需要的。

Prithvi 的前半部分实验,是基于 Claude 4.5 的。当他进行后半部分实验时,Anthropic 刚好推出了 Claude 4.6。于是,他更有了对自己的 harness 进行简化的理由。他将 per task 分解,让 coder 和 reviewer 先对当前任务的实现达成一致的步骤删除了,转而只在整个 plan 完成后进行统一的 review。

这一优化显著降低了单个计划的耗时和费用。最初的 solo harness(即最简陋的,开头提到运行 20 分钟产出几乎不可用的版本)升级到 3 agents harness 后,同样的 2D 复古像素游戏任务变成了花费 6 个小时以及 200 刀。但在优化了流程后的 harness 下,完成一个 DAW(数字音频工作站)的 lite-neo-mini 版花费在 4 个小时及 125 刀左右。

Harness 版本 代表任务 耗时 费用
Solo harness 2D retro game maker 20 mins $9
Full harness 2D retro game maker 6 hrs $200
V2 harness browser DAW 3 hrs 50 mins $124.70
案例的任务不完全相同,只是大概展示 harness 复杂度、耗时和费用的量级变化

在我阅读这篇博客前,我的 agentflow 和他在 4.5 期间的有些类似。我将我的 agent 主要分为 3 类: Research、implement、review,每个 session 只做一件事:

  • Research: 跟 agent 头脑风暴,讨论可能的技术选型,是否有成熟的参考,架构上会如何设计等问题。完成这个阶段后,将完整的计划分解为多个 task,每个 task 都带有 “目标、非目标、影响范围、约束、验收标准”等内容
  • Implement: 根据 task 的约束,开始具体实现;
  • Review: 每个 task 实现结束,对其修改范围进行审查,包括代码整体质量,是否按照 task 的约束进行实现等

每个任务都会经历 “实现 -> 审查 -> 根据意见修改直至无新增意见”这一流程,直到所有任务完成,一个计划结束。

agent flw
Research 时写出计划;每个 task 在实现和审查之间闭环

阅读之后,我开始重新思考这个问题,尤其是因为我在大多数任务中都在使用 codex 。做出这样的判断的理由是:GPT-5.2 系列以来,GPT 的 review 以及后端能力已经超过了 Claude(有意思的是,Prithvi 在博客中也提到"Out of the box, Claude is a poor QA agent.",so who's the great one?),既然 Anthropic 的团队成员都认为 claude 4.6 opus 的性能已经完全可以将 review 的任务移到计划的收尾阶段,对于 GPT 而言自然是更加没有问题了。

于是,我弃用了之前复杂的流程,转而尝试单个窗口、多次压缩、review 后置的。或许和 Codex 的特殊压缩机制和更加出色的指令遵循等有关,总之,在这个流程中,GPT-5.3-codex 表现出的能力依旧比较稳定,而且在 token 的节省程度方面和 Prithvi 展示的还比较贴合,大概就是原有流程消耗的 2 / 3。

但我不得不多提一嘴,大概是由于 GPT 的强推理、低幻觉路线以及后训练风格,而 5.3-codex 又是面向长时自主编程任务的,或许也因为这个 pre-train 基座已经被 oai 薅太久了,总之,跟 5.3-codex 在 research 阶段的沟通实在是比较痛苦。这个问题在 GPT-5.4 里得到了一些改善,但依然是我认为 OpenAI 目前的旗舰模型仍然称不上好的人类助手的重要原因——它们更像是指哪打哪的顶级工具(暂且抛开过度工程的倾向不谈),如果你已经有清晰的思路,它们的确能想尽办法 24 小时不停歇帮你快速实现和完善细节。

GPT is absolutely great
OK 懂你意思兄弟

软件工程中的一些转变

接下来是 OpenAI 团队分享的出色的工作,Harness engineering: leveraging Codex in an agent-first world

文章作者是 Ryan Lopopolo,他们团队从 2025 年 8 月开始进行了一次纯粹 agentic coding 实验。从一个空的 git 仓库起步,由 Codex 负责写所有代码。五个月后,仓库包含了将近一百万行代码,涵盖了应用逻辑、基础设施、工具链、文档和内部开发者实用工具。三名工程师组成的小团队在这段时间里提交并合并了约一千五百个 PR——平均每位工程师每天 3.5 个。比较诡异的事情是,团队增加到七名工程师后平均吞吐量非但没有减少,反而还增多了。

一般来说,团队中加入新人,人均的产出大概是会下降的。新成员需要建立这个仓库的上下文,适应团队的协作模式。这里我的思考是:agentic coding 通过将工程师与直接代码产出分开,让情况变得有所不同了。工程师不再直接输出代码,而是为输出效率极高的 agent 维护能力边界,每多一个人手,agent 的能力边界就能在更多的迭代轮次中得到更快更多的提升。因此,吞吐量反而上升了。

不过,Ryan也表示,早期的进展比他们所预期的要慢。原因不在于 codex 的能力不足以解决这些问题——就像本文开头提到的,模型是大脑,但模型如果只是运行在一个没有趁手工具,也没有充分定义的环境当中,则难免巧妇难为无米之炊了。因此,工程团队的首要工作变成了建造这个环境,工程师开始将更多的精力投入在规范和品味的约束上。

让 agent 看到需要看到的东西

如果你的 agent 需要面对动辄几十上百万行代码,你不可能让 agent 每次都从头开始理解你的代码库。这里不得不提到一些“老派工程师”常用的论调:“agent 不行,是因为上下文受限,无法完成大型代码库中的工作。”我认为,只要你稍微想一想,你就会发现这是一个非常不公平的比较。对于人类而言,理解一个巨型代码库中的一个模块要花费许多时间,阅读数不尽的注释和文档,为什么对于 agent 则希望其能够每次都从 0 开始完美地理解巨量上下文完成任务呢?这显然是非常荒谬的。

回到正题,为了建立这样的上下文,Ryan 他们早期尝试的方案,也是在 coding agent 大规模应用之初的就有的方案是——维护一个 AGENTS.md。但在之前,常见的做法是把所有的原则、规范全部塞进去。这看起来没有太大问题,但实际上,随着开发的推进,其效果会变得越来越糟糕且不可维护。原因是:

  1. 当“所有事情都重要”时,“所有事情都不重要”了。 一个巨大的指令文件会挤占任务本身、代码内容以及相关文档的空间。模型的注意力将被大量与当前任务无关的文字腐蚀,最终只会进行局部模式匹配,而不是有意图地导航。此时,agent 要么忽略关键约束,要开始为错误的目标优化。

  2. 屎山 AGENTS.md 完全无法维护。 把所有规则、约束塞到同一个 md 文件中,将使得文档维护变得极其困难,里面可能充满了过时甚至互相冲突的内容,agent 读到后便开始左右脑互搏。这种情况下,把 tokens 烧光了不说,最终做出来的也只会是一坨屎。

对于这样的问题的处理思路,实际上我们并不陌生:就像 skill 一样,采用渐进式披露,将 AGENTS.md 当作目录,而不是把所有东西都直接暴露到 agent 的上下文中。他们的仓库知识库存储在一个结构化的 docs/ 目录中,以此为唯一的事实来源。一份大约 100 行的简短 AGENTS.md 被注入到上下文中,主要充当一张索引,指向需要时再去查阅的完整文档。设计文档中包含验证状态和一套定义 agent 优先工作方式的核心原则。架构文档给出各领域和包分层的整体视图。质量文档对每个产品领域和架构层级打分,跟踪随时间推移的缺口。

另一方面,“看到”不仅指文档规范相关的东西,也涉及到系统行为的可观测性。

团队将 Chrome DevTools Protocol 接入 agent,创建了用于处理 DOM 快照、截图和导航的 skill。这使得 codex 可以直接复现 bug、验证修复、推理 UI 行为。同时,系统内部也做了同样的处理。Logs, metrics, trace 通过一个本地的可观测性栈暴露给 codex,每个 worktree 绑定一个隔离的实例。agent 可以用 LogQL 查询 logs,用 PromQL 查询 metrics。于是,类似“确保服务启动时间不超过 800ms”或“这四个关键用户旅程中没有跨度超过两秒”这样的需求,对 agent 来说就变成了可观测、可操作的任务。

在我自己的仓库中,虽然没有完全采用以上所有的方法,但也使用了类似的模式。我将 docs/ 按用途分目录(架构、开发测试规范、计划等),AGENTS.md 作为入口,只写“如果 xxx,就去找 xxx 文档来看”这样的引导,以此将不同的任务路由至相对应的文档。实际使用中效果非常明显:agent 在开始任何任务前都会先 read 架构文档,在生成代码前先 read coding-rules,review 前 read review-rules,诸如此类,在节省不必要的 token 开支之余,还能够让 agent 自主地找到当前任务需要的文档以构建清晰的上下文。

AGENTS.md
└─ routes tasks to the right docs, like 'if you need to ..., MUST read xxx.md first.'

docs/
├─ architecture/
│  └─ overview.md
├─ rules/
│  ├─ coding-rules.md
│  ├─ testing-rules.md
│  ├─ commit-rules.md
│  └─ review-rules.md
├─ dev/
│  ├─ TELEMETRY.md
│  └─ EVALS.md
└─ plans/
   └─ <YYYY-MM-DD-plan>.md

此外,我也将 Playwright 集成到了 agent harness 中,使得 agent 能够查看 UI 的真实行为,并对用户真实路径进行测试。比如:

  • 让 agent 将每个新增的按钮都点一点,看看按钮的功能是否正常;
  • 截图查看 UI 的布局是否如计划中那样;
  • 模拟用户交互,测试端到端运行效果。

如果你还没有将这些集成到你的 harness 中,相信我,这一定比你想象中重要得多——agent 能够从系统真实的表现和行为来验证自己的代码是否达成了任务的相关要求并遵守了约束,是 agent 自主运行的关键所在。

更强力的约束

显然,文档并不能完全阻止 agent 写出垃圾代码。到了一定规模,必须增加机械化的手段才能进一步增强代码库的一致性。Ryan 团队采用了强制执行不变式的方法。

他们将每个业务领域划分为一组固定的层次,每个层有严格的依赖方向和一组合法的边集。这些约束通过自定义 linter 和结构化测试得到机械化的执行。比如:代码只能向前依赖(Types → Config → Repo → Service → Runtime → UI),横切关注点(Auth, connector, telemetry 等)通过一个单一的显式接口 Providers 进入。除此之外的任何依赖都是非法的,会被直接拒绝。

这些约束通常只有在团队拥有数百名工程师之后才会考虑。但在 agentic coding 中,它成了一个早期前提条件:约束恰恰是让代码能在保持速度的同时避免衰退的关键

另外,他们也对品味(taste)进行了一些约束。Ryan 提到他们有一组小型的“品味不变量”——包括结构化的日志规范、schema 和类型命名约定、文件大小限制、平台特定的可靠性要求等,全部通过自定义 lint 来强制执行。由于这些 lint 是自定义的,他们把修复指令写进了错误信息中,让 agent 能直接在上下文中获取修复方法。

在人类优先的工作流中,这些规则可能容易显得约束过度。但有了 agent,它们就成了放大器:一旦编写完成,它们将同时适用于整个仓库甚至是更通用的场景。用结构检查来机械化地阻断违规,而不是期望靠“请保持代码的风格一致”“请确保命名规范”这样许愿一般的 magic prompt 来提升代码质量

agentic coding 的 PR 哲学与垃圾回收

随着 agent 吞吐量的增加,一些传统的工程规范反而可能变得适得其反了。

Ryan 提到他们的仓库采用了最小阻塞的合并门禁。PR 的生命周期很短。测试不稳定时,用后续运行来解决,而不是无限期地阻塞进度。在一个 agent 吞吐量远超人类注意力的系统中,修正是廉价的,等待是昂贵的

在低吞吐量的环境中,这样做是不负责任的。但在这里,它通常就是正确的权衡。

这个观点确实让我开始思考:我们习惯了质量优先的工作流——充分的 review、全绿的 CI、干净的 commit history。但如果 agent 一天就能产出几个 PR,人类的审查能力反而就变成了瓶颈。不过要注意,这并不意味着要降低质量标准,而是要把质量保障的手段前移:快速迭代,找到那些 agent 无法独自处理的边界,并将其加入到约束当中,将成本尽可能从事后审查转向事前约束。

但无论如何,我们也已经注意到 agentic coding 这种生产模式必定且正在带来全新的问题。agent 会无差别地复制仓库中已有的模式——哪怕这些模式是次优的,甚至是有缺陷的。随着时间推移,代码库不可避免地会出现质量下降。

openclaw
Peter Steinberger 在 2026 年 1 月 向 OpenClaw 提交了 6600+ commits,因此其质量我完全不感到意外

Ryan 团队的初始做法是人工处理——每周五花 20% 的时间清理 AI Slop。显然,这并不是一个长久之计。

于是他们将“黄金原则”(Golden Principles)直接记录到仓库中,并构建了定期清理流程。这些原则是有明确倾向的、可机械执行的规则,维护着代码库的可读性和一致性。例如:

  • 优先使用共享工具包而不是手写的辅助函数;
  • 在数据边界进行验证。

以固定的节奏,一组后台 Codex 任务会扫描偏差、更新质量评分并打开针对性的重构 PR。这些 PR 多数可以在不到一分钟内完成审查并自动合并。

技术债是非常可怕的,持续少量地偿还总是比任其在仓库中不断累计而后大返工要好得多(如果你完全不管 agent 到底在你的仓库里干了什么,在代码拥有一定规模后,项目随时可能在某一点爆炸,之后就只能彻底重构了。而这个规模,以 agent 的生成速度来看根本不值一提)。而且,同样的,人类的品味只需要被编码一次,之后就可以在相关任务上持续生效。

写在最后

LLM / Agent 毫无疑问已经有了相当大的影响力。按照目前的发展趋势,2026 年之后,大部分代码可能不再必须手动编写。那么,这是否就意味着——像各大热衷于“原子弹爆炸瘫软晕眩”的每天都在淘汰不同职业的“科技”“AI”自“媒体”和各大社交平台的草根科学家所说的,未来不再需要这些工程师了?

nuclear-explosion
前面忘了,后面忘了,总之原子弹又爆炸了

在我看来,情况可能恰恰相反。agent 的生成速度越快、解决问题的能力越强,人类的审美、品味、判断力、想象力就越是显得稀缺——你的确可以用 agent 做出不可思议的东西,但如果你连“不可思议的东西”是什么样的都想象不出来、描述不出来,也完全不知道什么样的东西才算得上“不可思议”,agent 再强又有什么用呢?同样的,那些用于垂直领域的 agent,最核心的部分一定是垂直领域的专家知识。agent 可以以人类难以望其项背的速度疯狂地产出,但其中仍有大量的边界需要人类的介入。而这些边界,至少目前看来,在未来相当一段时间里,agent 是不可能在没有人类专家的指引的情况下完全独立解决的。或许现在,我们更迫切需要思考的,不是如何构建一个完全自主、独立运行的系统,而是:人类的判断在哪些环节能带来最大的杠杆?如何使这些判断能够复利增长?随着模型能力的不断提升,这些系统将如何迭代升级?

因此,更有可能会看到的现象是:甚至工作量本身都没有减少,仅仅只是转移到了其他的地方。比如:你确实不再手写代码了,但你开始为不同任务、不同场景以及你的偏好等设计属于自己的 harness:通过上下文分治、制定评估标准、为 agent 建立良好的上下文、找出边界并设置约束、持续垃圾回收等方法, 让 agent 能够更高效且稳定地运作,这些也正是 harness engineering 所关注的问题。如果说模型本身的能力决定了上限,那么 harness 的设计大概决定了我们能够多接近这个上限。

随着模型的改进,有趣的 harness 组合空间并不会缩小。相反,它会不断扩展,而 AI 工程师的有趣工作就在于不断寻找下一个新颖的组合。

这个时代有很多糟糕透顶的地方,但好在仍然有一些乐趣。在这其中,我认为最有趣的,莫过于你可以一边把玩集人类尖端智慧于一体做出来的玩具,一边愉快地玩耍,一边近乎肆意地挥洒你的创意和灵感,专注于创造有价值的东西。只是,在这个过程之中,你需要时刻打起十二分精神,随时准备好和 agent 开始 battle,而不是让它们直接取代了你的大脑。

be careful, and enjoy it.

Neo coworker 对话截图

发布于

返回博客列表