Agent Harness Engineering

@addyosmani
英语2个月前 · 2026年5月09日
798K
3.2K
458
77
7.8K

TL;DR

Harness Engineering 将 AI 模型周围的架构视为一种动态演进的产物。通过将每一次 Agent 故障转化为永久性的规则或工具调整,开发者能够构建出远超原始模型性能的系统。

一个编程 Agent 是模型加上围绕它构建的一切。Harness 工程(Harness engineering)将这种脚手架视为一种活的产物,每当 Agent 出错时,就对其进行加固。

简单来说:每当 Agent 失败时,你都要设计一个永久性的解决方案,确保它永远不会再犯同样的错误。

在过去的两年里,行业一直在争论模型:哪个最聪明,哪个写的 React 最简洁,或者哪个幻觉最少。虽然这些讨论很重要,但它忽略了系统的另一半。

模型仅仅是运行中的 Agent 的一个输入。剩下的部分就是 Harness:提示词、工具、上下文策略、Hook、沙箱、子 Agent、反馈循环以及围绕模型封装的恢复路径,正是这些让它能够真正完成任务。

一个配备优秀 Harness 的普通模型,表现总是优于一个配备糟糕 Harness 的顶尖模型。越来越多有趣的工程工作不再是选择模型,而是设计其周围的脚手架。

这一学科现在有了名字。@Vtrivedy10 提出了 Harness 工程(harness engineering)一词,清晰地分解了 Harness 究竟是什么以及每一部分存在的原因。其他行业声音——如追踪新兴模式的 @dexhorthy、将 Agent 失败归结为配置“技能问题”的 HumanLayer、发布长期运行应用设计指南的 Anthropic 工程团队,以及探索用户侧体验的 Birgitta Böckeler——都大致汇聚到了同一个想法上。

这篇文章将这些线索汇集在一起。

Harness 到底是什么?

Trivedy 的核心定义承担了大部分解释工作:

Agent = 模型 + Harness。如果你不是模型,你就是 Harness。

Harness 涵盖了除模型本身之外的每一段代码、配置和执行逻辑。原始模型不是 Agent。只有当 Harness 为其提供状态、工具执行、反馈循环和可强制执行的约束时,它才会成为一个 Agent。

Addy Osmani - inline image

具体来说,Harness 包括:

  • 系统提示词、CLAUDE.md、AGENTS.md、技能文件和子 Agent 指令。
  • 工具、技能、MCP 服务器及其技术描述。
  • 捆绑的基础设施,如文件系统、沙箱和无头浏览器。
  • 用于生成子 Agent、处理移交和路由模型的编排逻辑。
  • 用于确定性执行的 Hook 和中间件,如 lint 检查或上下文压缩。
  • 用于日志、追踪、成本和延迟计量的可观测性工具。

从核心来看,Agent 是一个通过循环运行工具来实现目标的系统。真正的技能在于设计工具和那个循环。

虽然这代表了一个巨大的覆盖面,但这是你的领域,而不是模型提供商的。Claude Code、Cursor、Codex、Aider 和 Cline 都是 Harness。底层模型在不同平台上可能完全相同,但你体验到的行为是由 Harness 主导的。

让我们重新定义“技能问题”

当 Agent 做出一些荒谬的事情时,工程师们通常会责怪模型,往往将其归类为“等待下一个版本”来解决的问题。

Harness 工程思维拒绝这种默认态度。失败通常是某种程度上可解释的。如果 Agent 忽略了一个约定,就把它添加到 AGENTS.md 中。如果它运行了一个破坏性的命令,就写一个 Hook 来拦截它。如果它在一个 40 步的任务中迷失了方向,就将架构拆分为计划者(planner)和执行者(executor)。如果它总是以错误的代码结束,就在循环中接入一个类型检查的背压信号。

正如 HumanLayer 所说:“这不是模型问题。这是配置问题。” 考虑一下性能基准测试:在一个现成的框架中运行的领先模型,其得分往往大大低于在自定义、高度调优的 Harness 中运行的完全相同的模型。将模型移入一个拥有更好代码库工具、更严密提示词和更敏锐背压的环境中,可以释放出原始设置所遗漏的能力。

如今模型理论上的能力与你实际看到的能力之间的差距,很大程度上是 Harness 的差距。

棘轮效应:每个错误都变成一条规则

Harness 工程中最至关重要的习惯是将 Agent 的错误视为永久性的信号——而不是一次性重试然后忘掉的偶然。

如果 Agent 提交了一个带有被注释掉的测试的 PR,并且被意外合并了,这就是一个输入。下一版的 AGENTS.md 必须注明:“永远不要注释掉测试;删除或修复它们。” 下一个 pre-commit hook 应该自动标记 diff 中的 .skip(。必须更新子 Agent 评审员以拦截被注释掉的测试。

只有当你观察到真正的失败时才应添加约束,并且只有当能力更强的模型使这些约束变得多余时才将其移除。一个好的系统提示词中的每一行都应该能追溯到一个具体的、历史性的失败。

正因如此,Harness 工程是一门学科,而不是一个通用的框架。针对特定代码库的正确 Harness 完全是由其独特的失败历史塑造的。

从行为出发反向推导

设计 Harness 最有效的方法是从期望的行为开始,并构建交付该行为的组件:我们想要的行为 → 实现它的 Harness 设计。

Harness 的每一部分都必须有明确的工作。如果你无法说出一个组件存在的具体行为目的,就应该将其移除。

Addy Osmani - inline image

文件系统和 Git —— 持久化状态

文件系统是基础。模型只能处理其上下文窗口内的数据。文件系统提供了一个读取数据的空间、一个存放中间工作的场所,以及一个供多个 Agent 协作的界面。

加入 Git 提供了免费的版本控制,允许 Agent 跟踪进度、分支实验并回滚错误。

Bash 和代码执行:通用工具

大多数 Agent 在 ReAct 循环中运行:推理、通过工具调用采取行动、观察、重复。与其为每一个可能的动作预先构建工具,不如赋予 Agent Bash 访问权限,让它能够即时构建所需的东西。

Agent 通常擅长 Shell 命令,这使得 Bash 和代码执行成为自主解决问题的默认策略。

沙箱和默认工具

Bash 只有在安全运行的情况下才有用。沙箱为 Agent 提供了一个隔离的环境来运行代码、检查文件和验证工作,而不会危及宿主机。

一个好的沙箱带有强大的默认设置:预装的语言运行时、测试 CLI 和无头浏览器,允许 Agent 观察自己的工作并完成自我验证循环。

记忆与搜索:持续学习

除了训练权重和当前上下文,模型没有任何知识。Harness 通过记忆文件(如 AGENTS.md)弥补了这一差距,将知识注入到每一个会话中。

对于像新库版本或实时数据这样的即时信息,Web 搜索和 MCP 工具被直接集成到 Harness 中。

对抗上下文腐化

随着上下文窗口的填满,模型的推理能力会下降。Harness 使用三种主要技术来管理这种稀缺性:

  • 压缩:智能地总结并卸载旧的上下文,以防止 API 错误。
  • 工具调用卸载:将海量的工具输出(如 2000 行的日志)存储在文件系统中,而在上下文中仅保留核心的头部和尾部。
  • 渐进式披露:仅在任务明确需要时才展示指令和工具,而不是在启动时加载所有内容。

长周期执行

自主的、长期运行的工作容易受到提前停止和问题分解能力差的影响。Harness 通过结构化设计来应对:

  • 循环:拦截模型的退出尝试,并强制它在新的上下文窗口中继续朝着完成目标努力。
  • 计划:强制模型将目标分解为逐步的计划文件,并在每一步后通过自我验证 Hook 检查其工作。
  • 拆分:将生成和评估分离到不同的 Agent 中,防止模型在对自己的工作评分时产生固有的正面偏见。

Hook 是你的执行层

Hook 弥补了请求动作与强制执行之间的差距。它们在特定的生命周期运行:在工具调用之前、文件编辑之后或提交之前。Hook 拦截破坏性命令,强制执行自动格式化以节省 Token,并运行测试套件。

理想情况下,成功是无声的,失败是冗长的。如果类型检查通过,Agent 什么也听不到;如果失败,错误会直接注入回循环中进行自我修正。

这是规则手册和工具选择

仓库根目录下的一个扁平 Markdown 文件仍然是杠杆率最高的配置点。然而,必须像对待飞行员的检查清单一样对待它,而不是风格指南。保持简短,并确保每条规则都是从过去的失败中总结出来的。

同样的原则也适用于工具。十个高度专注的工具表现总是优于五十个重叠的工具。

此外,由于工具描述会填充到提示词中,恶意或粗糙的外部集成(如未经核实的 MCP 服务器)可能会在 Agent 开始工作之前就向其注入糟糕的提示词。

生产环境中的样子

我见过的关于成熟 Harness 最清晰的公开描述是 Fareed Khan 对 Claude Code 架构的(推测性)分解。

Addy Osmani - inline image

前一节中的几乎每个概念都在这张图中作为一个命名组件出现。上下文注入是知识层。循环状态存在于记忆存储和工作树隔离器中。破坏性动作 Hook 位于权限门禁之后。子 Agent 上下文防火墙是整个多 Agent 层。工具分发注册表是 MCP 服务器和 Bash 接入的地方。Claude Code 的发展轨迹至少与其底层的模型一样,更多地关乎 Harness。

Harness 不会萎缩,只会转移

随着模型的改进,对 Harness 的需求并不会消失——它只是发生了转移。

人们很容易假设更好的模型会使脚手架变得过时。例如,最近的模型升级大幅减少了对“上下文焦虑”缓解措施的需求。但随着底线的提高,天花板也在提高。以前无法触及的任务现在变得可行,从而带来了全新的失败模式。

Harness 中的每个组件都编码了一个关于模型无法独立完成什么的假设。当模型改进时,过时的脚手架应该被移除,并且必须构建新的脚手架以触及下一个地平线。

那么训练循环呢?

Harness 设计与模型训练之间存在着活跃的反馈循环。

如今的模型在训练后期通常会将特定的 Harness 纳入循环中,从而产生一定程度的过拟合。模型在 Harness 设计者优先考虑的特定动作(例如文件系统操作、Bash、子 Agent 分发)上变得异常出色。

这使得 Harness 成为一个活的系统,而不是一个静态的配置文件,并证明了“最佳”的 Harness 是针对你独特的任务和工作流进行专门优化的那一个。

Harness 即服务 (HaaS)

行业正在从基于 LLM API(提供补全)构建转向基于 Harness API(提供运行时)构建。SDK 现在直接提供循环、工具、上下文管理、Hook 和沙箱。

现代的默认做法不再是从头开始构建编排,而是选择一个 Harness 框架,配置其核心支柱,并纯粹专注于特定领域的提示词和工具设计。

这就是使故障排除具有可扩展性的原因:你是在调整一个分解良好的配置面,而不是重新发明整个 Agent 架构。

未来走向

如果你观察当今顶尖的编程 Agent,它们彼此之间的相似程度超过了它们底层模型的相似程度。模型各异,但 Harness 模式正在趋同。行业正在迅速识别将生成式文本转化为可交付软件所需的承重脚手架。

最令人兴奋的开放性问题正在超越单个 Agent:并行编排多个 Agent,使 Agent 能够分析自己的追踪记录以修复 Harness 级别的失败,以及构建能够即时动态组装工具的环境。

最终,在这个阶段,Harness 不再是静态的配置文件,而开始表现得更像编译器。

如果你正在寻找一个优秀的 Agent Harness 框架,@FredKSchott 编写了 Flue。它很扎实,显然是受到了这篇文章早期版本的启发!

一键保存

使用 YouMind AI 深度阅读爆款文章

保存原文、追问细节、总结观点,并在一个 AI 工作空间里把爆款文章沉淀成可复用笔记。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章