上周,Google Cloud / Gemini 工程师 Addy Osmani 写了一篇文章,题目叫《Agent Harness Engineering》。
只看标题的话,Harness Engineering 这个话题其实已经不算新鲜了。从年初到现在,Harness Engineering 这个词在国内外技术圈反复被提及。国内也有不少企业实践文章,比如阿里云的那篇《Harness Engineering:耗时一周,我是如何将应用的 AI Coding 率提升至 90% 的》(可见文末延伸阅读)。如果只是解释“什么是 Harness”,这篇文章不会有太多新信息。
但 Addy 这篇文章出现以后,再加上 Anthropic 之前连续发布的几篇关于长程 Agent、长程应用开发、Managed Agent 和 Agent Eval 的工程分享,以及 OpenAI 关于 Codex 团队如何用 Agent 交付内部产品的案例,御三家的 Harness 思路刚好拼到了一起。
如果说 Gemini 这边的 Addy 负责把 Harness Engineering 讲成一个清晰的方法论,OpenAI 展示了 Codex 进入生产级代码库的案例,那么 Anthropic 更像是在把 Harness 拆成一整套 Agent 操作系统。
合起来看,它们说的是同一层东西:模型之外的工程系统。
这层系统,现在常被叫作 Harness。
Harness 要解决什么问题
一个 Agent 连续跑几个小时以后,真正麻烦的地方,常常不是它能不能继续往下跑,而是它是否还知道自己在做什么。
它怎么知道刚才做到哪一步?怎么判断任务真的完成了?上下文变长以后,怎么避免跑偏?下一轮 Agent 接手时,怎么知道哪些已经做完,哪些只是半成品?同一个错误反复出现时,怎么把它变成系统里的规则,而不是每次都重新碰壁?
这些问题看起来像是模型能力问题,但放到真实工程里,很多其实是系统问题。
人类工程师接手长任务时,也不会只靠记忆。我们会看需求文档、任务列表、提交记录、测试结果、代码规范和运行日志,也会通过 CI、Code Review 和线上指标判断修改是否真的生效。Agent 也是一样。它要持续完成任务,不能只靠一次 prompt 和一段上下文,而需要一套外部环境来承接它的行动。
所以,Harness 要解决的不是“怎么让模型更聪明”,而是:怎么让模型在一个可持续、可验证、可恢复、有边界的环境里工作。
Addy:给这件事一个名字
Addy Osmani 在《Agent Harness Engineering》里引用了一个很短的公式:
Agent = Model + Harness
这个公式有用,因为它把很多混在一起的问题拆开了。
我们平时说“这个 Agent 好不好用”,大多时候都会归因到模型:模型聪不聪明,代码写得好不好,推理稳不稳。
但一个编码 Agent 的表现,还取决于它有什么工具、能读到什么上下文、在哪里运行、是否有测试反馈、有没有权限边界、出错后能不能回到一个干净状态。
Addy 的文章把 Harness 拆成很多组成部分:System Prompt、AGENTS.md / CLAUDE.md、工具、MCP、文件系统、Git、沙箱、Hooks、子 Agent、上下文策略、日志、追踪、成本和延迟观测。
但重点不在记名词,而在换一种看 Agent 的方式。
一个 Agent 要完成工作,至少需要下面的条件:
-
它需要一个地方放状态。文件系统和 Git 就是最基础、也最清楚的选择。没有它们,Agent 就只能把所有东西塞进上下文里;上下文一长,丢失和误读就会出现。有了文件和版本历史,Agent 才能留下计划、记录修改、回滚错误,也能让下一轮接着上次中断的地方继续推进。
-
它需要安全地行动。Shell、代码执行、浏览器、MCP 工具都让 Agent 能做事,但行动总要发生在某个边界内。沙箱、命令 allowlist、权限确认、网络隔离,都是 Harness 的一部分。
-
它需要反馈。测试、lint、类型检查、浏览器截图、日志和指标,可以把“我觉得完成了”变成“系统验证过了”。如果测试失败,错误信息回到 Agent 的循环里,它才有机会修正。
-
它还需要规则。但规则不能无限膨胀。Addy 提到一个很实用的原则:每次 Agent 犯错,都把它当成一个信号。Agent 忘了项目约定,就把约定写进 AGENTS.md;Agent 跳过测试,就让 Hook 或 Reviewer 卡住;Agent 执行危险命令,就在工具层拦掉。这一步不能只靠堆提示词。更准确地说,是把真实失败沉淀成工程约束。
这也间接地解释了为什么 Harness 很难“下载即用”。通用框架能提供循环、工具、沙箱和接口,但真正有用的规则,往往来自某个团队自己的失败历史。一个好的 AGENTS.md 不应该是愿望清单,更像飞行检查单:短,明确,每一条最好都能追溯到某个真实风险。
Addy 那篇文章还有一个判断,适合放到后面一起看:Harness 不会随着模型变强而消失,它只会跟着模型能力的边界一起演变。
如果模型已经能稳定做某些事,原来补这块短板的脚手架就该删掉,否则它会变成负担和噪音。与此同时,更强的模型会让更复杂的任务进入可做范围,这些任务会暴露新的失败模式,于是新的 Harness 结构又出现了。
这就让 Harness 像是一层活的工程系统,而不是一次性配置。
Anthropic:把 Harness 拆成一套 Agent 操作系统
在这三家里,Anthropic 是把 Harness 拆得最细的一家。
它不只是讨论“怎么让 Agent 写代码”,还从 Claude Code 的具体使用方式,一直讲到 Claude Agent SDK、Context Engineering、Tool Design、MCP Code Execution、Long-Running Harness、Managed Agents 和 Agent Eval 等多个工程角度。
看起来 Anthropic 这些文章主题都很分散,但其实都在补同一套系统:上下文怎么进入,工具怎么暴露,状态怎么保存,反馈怎么回流,权限和执行环境怎么隔离,以及最后怎么判断 Agent 真的做对了。也就是上面提到过的 Harness 所要解决的问题。
长程任务
先看长程任务。
在《Effective harnesses for long-running agents》里,Anthropic 观察到一个很具体的问题:当 Agent 要跨多个上下文窗口做长任务时,任务很容易散掉。
第一个原因是 Agent 想一次做太多。给它一个大目标,比如做一个完整 Web 应用,它会试图一口气完成。结果常常是在上下文快耗尽时留下一堆半成品。下一轮 Agent 进来,都不知道哪些已经做完,哪些只是看起来做了,只能先花时间重新判断当前进度。
第二个原因是过早宣布完成。项目已经有一些文件和功能以后,后续 Agent 容易看到“进展不少”,然后判断任务差不多结束了。但真实情况可能是核心功能没跑通,测试没跑,边界情况没处理。
这两个问题不只是“模型不够聪明”,还有过去记录缺失的问题。
我们接手长项目时,尚且需要任务列表、提交记录、进度说明、验收标准和测试环境。Agent 会更依赖这些东西,因为每一轮上下文都可能不完整。
Anthropic 的一个解法,是拆出 Initializer Agent 和 Coding Agent。
Initializer Agent 先做地基:设置运行环境,生成 Feature List,写 Progress File,留下初始提交。后续 Coding Agent 每次都只做增量工作,从 Git History、Progress File 和 Feature List 中理解当前任务状态,选一个还没完成的功能推进,并在结束时留下干净状态。
Feature List 的设计很关键。它不能停在一句“做一个像 claude.ai 的应用”这种概述性需求,而是要将概述性需求拆解成一组可检查的功能要求。每个功能有步骤,有 Pass / Fail 状态。Anthropic 后来选择用 JSON 存 Feature List,也明确要求 Coding Agent 不要删除或改写测试要求,只能更新状态。
这说明一件事:长程 Agent 的问题,很大一部分是交接问题。
Harness 要让下一轮 Agent 不必靠猜。
再往前一步,是上下文怎么进入 Agent。
上下文工程
在 Context Engineering 相关实践里,Anthropic 讨论的不是“把更多的内容塞进上下文”,而是如何让 Agent 在需要时拿到正确的信息。上下文不是越多越好。入口太长、工具太多、说明太杂,都会挤占模型处理真正任务的空间。
比较好的方式是让信息保持可导航:短入口、结构化文档、按需读取、必要时通过工具查询。Agent 不需要一开始读完整本手册,它更需要一张地图,知道什么时候该去哪里找信息。
这和长程 Agent 里的 Progress File、Feature List 是同一个逻辑:重要的信息不能只留在上下文里,而要放到 Agent 能稳定发现、稳定读取的位置。
然后是工具怎么设计。
工具的设计
Anthropic 在 Tool Design 和 MCP Code Execution 相关内容里强调过一个问题:工具不是越多越好。工具描述、参数结构、返回格式和错误信息,都会影响 Agent 的行动质量。
如果工具的描述含糊不清,Agent 可能根本不知道什么时候该用;如果返回结果太长,关键信息会被淹没;如果错误信息不可读,Agent 就很难进行自我修正。MCP 工具一多,还会带来新的上下文开销:光是工具定义和中间结果,就可能占掉大量 token。
所以 Harness 不只是“给 Agent 接工具”。更重要的是:把工具设计成 Agent 能理解、能选择、能验证的行动接口。
另一个问题是自评。
反馈机制
在《Harness design for long-running application development》里,Anthropic 讨论了 Planner、Generator、Evaluator 的结构。
这个结构的价值不在于多拆了几个 Agent,而在于解决了一个很具体的问题:生成者评价自己时,经常偏乐观。
尤其是前端设计、产品体验、架构质量这类任务,没有一个简单的单元测试能告诉你交付质量“好不好”。Agent 自己做完之后,很容易就给自己一个不错的评价。
Anthropic 的做法是把生成和评价拆开,让 Evaluator 按明确标准检查结果,并用 Playwright 去操作真实页面。
他们的例子很直观。同一个 retro game maker 任务,Solo Agent 跑了 20 分钟,成本约 9 美元;完整 Harness 跑了 6 小时,成本约 200 美元。后者明显更贵更慢,但输出质量高很多,至少核心玩法能跑起来。
此外,真正有用的是这个机制:Planner 把一句话扩展成多 Sprint 的 Spec,Generator 按 Contract 实现,Evaluator 根据可测试标准操作应用、提交具体 bug。
这套结构后来也被 Anthropic 重新裁剪优化。随着模型的变强,一些原来必要的 Sprint Decomposition 可能变成开销;但 Planner 和 Evaluator 在边界复杂的任务上仍然有价值。
Anthropic 的判断很克制:每个 Harness 组件都编码了一个关于“模型现在还做不好什么”的假设。模型变了,假设就要重新检查。
到《Managed Agents》这篇,Anthropic 又把问题往基础设施层推了一步。
被管理的 Agent
Anthropic 把 Agent 系统拆成三个部分:Session、Harness、Sandbox。
-
Session 是事件日志,记录发生过什么。
-
Harness 是调用 Claude、组织上下文、路由工具调用的循环。
-
Sandbox 是执行代码、编辑文件、运行工具的环境。
这套 Agent 系统的拆解要解决的是长期运行时的可恢复性和安全边界问题。如果 Harness 和 Sandbox 绑在同一个容器里,容器挂了,Session 可能也丢;如果生成代码和凭证在同一个环境里,安全风险也会变大。
Anthropic 用 “Brain” 和 “Hands” 来形容这件事:Harness 更像负责思考和调度的 Brain,Sandbox 更像负责执行动作的 Hands,Session 则记录整个过程。把这三者拆开以后,执行环境可以失败重建,Harness 可以无状态恢复,Session Log 也可以作为上下文窗口之外的可查询记忆。
这跟普通应用架构很像。系统一旦要长期运行,就不能把状态、执行和控制逻辑混在一起。
Anthropic 的 Agent Eval 文章补上了最后一块:怎么知道 Agent 真的变好了?
Agent 评估
他们把 Agent Eval 拆成 Task、Trial、Grader、Transcript、Outcome。
这里的重点是 Outcome。一个 Agent 说“已经订好机票”没有意义,真正要看环境里的数据库是否出现了预订记录。一个编码 Agent 说“我修好了漏洞”也不够,要看测试、静态分析、日志状态和工具调用轨迹。
这让评估也成了 Harness 的一部分。
Agent 的质量不能只看最终回答,还要看它在环境中的行动和结果。
所以,Anthropic 这组文章真正完整的地方在于:它不是只解决一个“长任务怎么跑完”的问题,而是在把 Agent 拆成一套操作系统。
Agent 操作系统
Claude Code 解决具体工作流;Claude Agent SDK 把这套能力抽象成可复用的开发接口;Context Engineering 解决信息进入方式;Tool Design 和 MCP Code Execution 解决工具效率;Long-Running Harness 解决跨上下文交接;Managed Agents 解决 Session、Harness、Sandbox 的基础设施拆分;Agent Eval 负责判断系统是否真的变好了。
这些内容合在一起,Anthropic 讲的其实不是某个单点技巧,而是一个更完整的问题:当 Agent 不再只是回答问题,而是要长期运行、调用工具、修改环境并接受评估时,外部系统应该怎么承接它。
OpenAI:展示生产级代码库要怎样变形
OpenAI 的 Codex 文章,最容易被记住的是几个数字:他们说团队在五个月里做了一个内部 beta 产品,没有人工手写代码;代码库大约百万行;约 1,500 个 PR;估计用手写代码十分之一左右的时间完成。
这些数字很醒目,但文章真正有价值的地方,不在“Agent 写了多少代码”。更值得看的是:为了让 Codex 能持续工作,他们把代码库改造成了什么样。
第一点是 Repo 成了记录系统。
OpenAI 试过一个巨大的 AGENTS.md,后来认为这个方式不行。原因很简单:上下文是稀缺资源,一个巨大说明文件会挤掉任务、代码和相关文档;规则太多以后,所有规则都变轻;大文件也会迅速腐烂,难以验证新鲜度。
OpenAI 后来没有把所有信息都塞进一个巨大的 AGENTS.md,而是把 AGENTS.md 当成 Agent 的入口导航:它只告诉 Agent 应该去哪里找信息。真正的知识则放进仓库里的 docs/ 文档目录,比如设计文档、执行计划、产品规格、参考资料、质量标准、可靠性说明和安全规则。计划和决策日志也会进入仓库,成为 Agent 可以读取的工程记录。
这里有一个很实际的判断:Agent 看不见的东西,就等于不存在。
Google Docs、Slack 讨论、人的脑子里的隐性知识,如果没有进入它能读取的“可见”范围,就不能指望它稳定遵守。
第二点是应用本身要对 Agent 可观察。
OpenAI 提到,他们让 Codex 可以按 Git Worktree 启动应用实例,也把 Chrome DevTools Protocol 接入 Agent 运行时,让 Codex 能操作页面、看 DOM、截图、复现问题和验证修复。此外,日志、指标、trace 也会暴露给 Codex,让它能用 LogQL、PromQL 之类接口查询运行状态。
这很关键。很多时候,Agent 写错代码,是因为它没有看到真实运行结果。把 UI、日志和指标变成 Agent 可读的反馈,等于把 QA 的一部分还给了系统。
第三点是架构约束和品味被编码。
OpenAI 说,文档本身不足以维持一个 Agent 生成代码库的连贯性。他们用自定义 lint、结构测试、命名规则、文件大小限制、结构化日志要求等方式,机械地强制约束 Agent。比如,在模块边界处校验传入数据的结构和字段类型,但不强行规定一定使用哪个校验库;规定业务域内的依赖方向,越界就由工具拦下。
这和人类团队里的“代码规范”有点像,但对 Agent 更重要。
人类可以根据上下文关联自行获得边界,Agent 却需要明确边界。规则一旦写进工具,就能在每个 PR 上重复执行。
OpenAI 还写到了“熵”和“垃圾回收”。Agent 会复制代码库里已有模式,不管那些模式好不好。吞吐量越高,漂移也越快。于是他们把一些“黄金原则”编码到仓库里,并定期让后台 Codex 任务扫描偏差、更新质量评分、打开重构 PR。
这里也要保留边界。OpenAI 文中明确说,这些能力高度依赖特定代码库结构和工具投入,不能假设没有类似投入的团队也能直接得到同样结果。
它不是一句“让 Agent 自动写代码”就能完成的事。真正的工作,是把仓库变成 Agent 可以理解、验证和维护的工作场。
可以把 Harness 看成五层
把 Addy、Anthropic 和 OpenAI 的文章放在一起,可以抽出一个比较实用的诊断框架:Harness 至少可以看成五层。
第一层是 Context。
Context 不能只求多,关键是可导航。短入口、结构化文档、渐进式披露,比一个巨大的说明文件更适合 Agent。
Addy 讲 AGENTS.md 不要太长,OpenAI 把它当目录,Anthropic 用 Progress File 和 Feature List 让下一轮接得上。它们本质上都在处理同一个问题:Agent 需要地图,不需要被一整本手册淹没。
第二层是 Action。
Agent 要能行动,就要有工具。Shell、文件系统、Git、浏览器、MCP、数据库、标准开发 CLI,都是 Action 层。
工具也不能只求多。工具描述、参数结构、返回格式和错误信息都会进入 Agent 的工作循环。一个好工具,应该让 Agent 更容易做对,而不是给它更多模糊选择。
第三层是 Persistence。
长程任务不能靠上下文硬撑。Git History、Progress File、Session Log、计划文档、决策记录,都在把状态从短暂对话里拿出来,放到可恢复、可查询的位置。
Anthropic 的 Session Log、OpenAI 的 repo-as-system-of-record、Addy 提到的 FileSystem / Git,其实都在强调这一层。
第四层是 Feedback。
没有反馈,Agent 很容易停在“看起来完成”。
测试、lint、类型检查、静态分析、浏览器自动化、截图、日志、指标、Trace、Eval Grader,都是反馈。Anthropic 的 Evaluator 和 Agent Eval,OpenAI 的可观察性栈,Addy 提到的 Hooks 和 Reviewer Subagent,都在把反馈接回循环里。
第五层是 Governance。
Governance 包括权限、沙箱、安全边界、Hooks、审批、人工判断和定期清理。
Agent 越能行动,越需要边界。Anthropic 把 Sandbox、Harness、Session 拆开,是为了可靠性和安全;OpenAI 用 lint 和结构测试维持一致性;Addy 说失败要变规则,也是在把治理从口头提醒变成系统行为。
这五层不适合作为采购清单,更适合当作诊断框架。
当 Agent 做不好一件事时,可以先问:它是没看到信息,不能行动,没保存状态,缺少反馈,还是边界不清?
很多问题不一定要换模型。也许只是某一层 Harness 没搭好。
一个克制的判断
Harness 工程并不否认模型重要。更强的模型当然会减少一些脚手架,也会让某些复杂机制变得多余。但模型变强以后,问题不一定消失,只是任务边界会继续外移。
以前 Agent 做不了长任务,我们关心的是上下文恢复;后来它能做长任务了,我们开始关心进度交接、外部评价和状态持久化;再往后,当它能处理更大的代码库时,仓库可读性、架构漂移、安全边界和持续清理又会变成新的问题。
所以,Harness 工程更像一种正在成形的工程语言。它把提示词、工具、文档、测试、沙箱、评估、权限和工作流放到同一张图里,让我们可以更系统地讨论:一个 Agent 到底需要怎样的外部环境,才能持续、稳定地完成任务。
对普通开发者来说,最直接的启发可以更小:让项目入口更短、更清楚;把隐性规则写到 Agent 能发现的位置;让任务有可检查的完成条件;把测试、lint、运行结果接回 Agent 循环;给危险操作加边界;把重复失败沉淀成工具或规则。
工程师过去主要写代码。现在多了一项工作:设计一个能让 Agent 持续做对事的环境。
这就是 Harness 工程目前最值得关注的地方。
延伸阅读
-
阿里开发者
- Harness Engineering:耗时一周,我是如何将应用的AI Coding率提升至90%的:mp.weixin.qq.com/s/rlIyIIZOX…
-
Gemini:x.com/addyosmani/…
-
OpenAI:openai.com/zh-Hans-CN/…
-
Anthropic 核心 Harness 文章:
-
Anthropic 相关工程实践文章: