跳至主要内容
返回博客
  • AI
  • Agent

Agent 的 Harness 是什么:模型之外的工程系统

从一次 Coding Agent 的修复任务出发,拆解 System Prompt、Tools、Agentic Loop 与模型适配层。

Agent 的 Harness 是什么:模型之外的工程系统

同一个模型放在聊天页面里,可能只能告诉你“这个测试为什么会失败”;放进 Coding Agent 后,却可以读取仓库、修改代码、运行测试,再根据报错继续修复。

差别不只来自模型。模型外面还有一套软件负责准备上下文、提供工具、执行调用、保存状态、控制循环并判断什么时候停止。这套承载模型运行的 Agent 工程系统,通常被称为 Harness

这个词原本指攀岩时固定身体、连接绳索并挂载装备的安全带,也有“控制并利用某种力量”的意思。Agent Harness 做的事情很像:它没有替代模型的能力,而是决定这些能力如何连接外部世界,又被限制在什么边界内。

模型提供能力,Harness 负责组织、约束和验证这些能力。

Harness 解决的不是文本生成

一次普通的模型调用很直接:准备输入,发送给模型,拿回输出。如果任务只需要改写一段文字或解释一个概念,这已经够用。

Agent 面对的通常是另一类任务。它需要先观察环境,再决定下一步动作;动作产生的新结果又会改变后续判断。一次请求可能变成多次模型调用和多次工具执行,直到任务完成、需要人工确认,或者触发某个停止条件。

可以把最小过程写成:

理解任务 → 选择工具 → 执行动作 → 读取结果 → 验证结果
                ↑                         ↓
                └──── 继续处理 ← 不满足 ──┘

                                满足条件后结束

模型只负责其中需要语言理解和决策的部分。谁来执行工具、把结果放回上下文、限制循环次数、记录运行状态,以及阻止危险操作,都属于 Harness 的职责。

因此,Agent = Model + Harness 是一个方便理解的简写,但不是严格公式。现实中的 Harness 边界并不统一:有的只是一个轻量命令行工具,有的还包含沙箱、审批、会话持久化、追踪系统和完整的用户界面。

它不只是 Prompt 和工具集合

给模型一段 System Prompt,再注册几个工具,已经具备了 Agent 的基本形状,但还没有解决真实运行中的问题。

工具调用可能超时,参数可能不合法,读取的文件可能太大,测试可能连续失败,任务可能花掉远超预期的 Token。某些操作可以自动执行,删除文件、发布代码或发送邮件则应该等待批准。应用退出后,还要决定这次任务能不能恢复。

所以 Harness 不是一个静态配置对象,而是模型与环境之间的运行层。它既向模型描述“你能做什么”,也在模型发起动作后真正执行代码,并把可观察到的结果组织成下一次模型输入。

Earendil 的原文把 Harness 拆成 System Prompt、Tools、Agentic Loop 和 Translation Layer 四部分。这不是唯一标准,但很适合建立第一层认识。

System Prompt 定义工作边界

System Prompt 是 Harness 交给模型的高优先级说明。它可以描述 Agent 的角色、任务原则、输出格式、工具使用规则,以及遇到不确定情况时应该怎么处理。

如果把模型看成刚加入项目的开发者,System Prompt 更像入职时拿到的工作说明。它告诉模型当前环境与目标,却不会因为写得足够长,就让模型自动拥有仓库知识或可靠执行能力。

真正的 Harness 还会动态组装说明。例如进入一个仓库时读取 AGENTS.md,发现项目使用 Bun 后调整测试命令,或者在用户只授权只读操作时隐藏写文件工具。这些信息未必全部写死在同一段 Prompt 中,但都会影响模型这一步看到的工作边界。

System Prompt 可以引导行为,不能保证行为。权限控制、参数校验和结果验证仍然应该由代码完成,不能只写一句“不要执行危险操作”就交给模型自觉遵守。

Tools 把意图变成环境中的动作

模型本身不会直接打开本地文件、运行命令或访问数据库。Harness 会把这些能力包装成 Tools,并向模型提供名称、用途和参数结构。模型输出工具调用请求后,真正执行动作的仍然是 Harness。

一个读取文件工具至少包含两层:模型看到的工具描述,以及运行时真正读取文件的实现。完整系统还会处理路径范围、文件大小、编码、超时和错误返回。工具描述决定模型是否容易选对工具,执行层则决定这个工具是否安全可靠。

“让模型自己选择工具”也只说对了一半。模型可以在 Harness 给定的候选项里做决定,但 Harness 可以隐藏工具、强制调用某个工具、拒绝参数、限制并发,或者在执行前暂停等待人工审批。

这也是为什么工具数量不是越多越好。名字相近、描述含糊的工具会增加选择成本;权限过大的通用 Shell 虽然灵活,也会扩大误操作范围。好的 Harness 会让能力足够完成任务,同时保持接口清楚、权限最小。

Agentic Loop 让结果成为下一步输入

Agentic Loop 是 Harness 最容易被忽略的部分。模型调用工具后,这一轮生成通常已经结束。Harness 需要执行工具,把结果追加到上下文,然后再次调用模型。模型读取新结果,才能决定继续调用工具还是给出最终答案。

假设用户让 Coding Agent 修复一个失败的权限测试。一次完整运行可能经过下面几步:

  1. Harness 读取用户请求、仓库规则和当前工作区状态,把必要上下文交给模型。
  2. 模型调用搜索与读文件工具,找到失败测试及对应实现。
  3. Harness 执行工具,并把代码片段和搜索结果返回给模型。
  4. 模型提出修改,Harness 应用补丁后运行指定测试。
  5. 测试仍然失败,Harness 把退出码和错误信息加入下一轮上下文。
  6. 模型根据新证据调整实现,再次运行测试。
  7. 测试通过后,Harness 继续执行约定的检查,并让模型总结改动与验证结果。

这里并不是模型在一次调用里持续工作。真正让任务延续下去的,是 Harness 不断完成“调用模型—执行工具—返回结果—再次调用模型”的循环。

循环也不能只由模型决定何时结束。Harness 通常还需要设置最大轮数、时间和成本预算,识别需要审批的操作,并在工具持续失败时停止。没有这些边界,Agentic Loop 很容易变成昂贵的重复尝试。

Translation Layer 降低模型切换成本

不同模型供应商对消息、工具调用、流式事件和错误的表达并不完全相同。Translation Layer 会把 Harness 内部使用的统一格式转换成供应商协议,再把响应还原成系统能够继续处理的事件。

有了这一层,同一个 Harness 可以通过相近的接口连接多个模型,也可以根据任务选择不同模型。模型配置不再散落在工具、会话和界面代码中,迁移时需要改动的范围会更小。

但 Translation Layer 只是降低适配成本,不会让模型变得可以无损互换。模型支持的工具协议、上下文长度、推理方式和对 Prompt 的敏感度都有差异。换一个模型后,同一套 System Prompt 和工具描述仍然需要重新评估,任务结果也不能假设完全等价。

上下文和状态决定 Agent 看见什么

原文的四部分解释了 Harness 的主要骨架,真实系统还需要处理几类贯穿整个运行过程的能力。首先是上下文与状态。

上下文不是把所有聊天记录、文件和工具输出一股脑塞给模型。Harness 需要选择当前步骤真正相关的内容,裁剪过长输出,在必要时生成可追溯摘要,并避免把密钥、无关日志或不可信指令带进模型输入。

状态则让任务跨步骤保持连续。当前修改过哪些文件、哪个命令正在运行、工具是否等待审批、已经消耗多少预算,都不能只依赖模型“记住”。模型上下文是某一步的输入,运行状态则应该由 Harness 用结构化数据保存。

同一个模型在两个 Coding Agent 里表现不同,很多时候不是模型突然变聪明了,而是一个 Harness 给了准确的仓库规则、相关代码和完整报错,另一个只塞进了用户最初的一句话。

权限和验证不能交给模型自觉

工具让 Agent 能够行动,也让错误从“答错一句话”升级成“真的改变了外部系统”。Harness 必须明确哪些操作可以自动执行,哪些需要批准,哪些永远不该暴露。

读取项目文件、修改工作区、访问工作区之外的目录、调用外部网络、发布部署和发送消息,应该是不同等级的权限。即使模型认为某个操作有帮助,也只能在当前授权范围内选择。

验证同样属于 Harness。对于修复代码的任务,“模型说已经完成”不是停止条件,测试退出码、类型检查和最终差异才是可观察证据。测试通过也不是绝对正确,它只能证明约定的检查没有发现问题,所以 Harness 还要如实保留执行记录,而不是把一次成功命令包装成完整保证。

一套可靠的 Harness 至少应该回答这些问题:

  • 每一步给模型看了什么,哪些内容被省略了?
  • 模型能调用哪些工具,每个工具拥有什么权限?
  • 工具失败、超时或返回异常数据时会发生什么?
  • 哪些动作自动执行,哪些动作必须由用户批准?
  • 系统根据什么证据判断任务完成?
  • 会话、工具结果、修改记录和成本能否追踪与导出?

这些问题没有统一答案,但比默认用了哪个模型更能说明一个 Agent 在真实任务中是否可靠。

拥有 Harness 不自动等于拥有控制权

原文进一步强调了开放、可修改的 Harness 对用户自主权的价值。这个方向成立的前提是,用户确实能控制模型选择、System Prompt、工具权限、运行数据和会话保存方式。

如果 Harness 运行在本地,但每次都把完整仓库发送给云端模型,数据边界仍然经过外部服务。如果项目开源,却把会话锁在无法导出的托管平台中,用户也没有完整掌握自己的记录。即使 Translation Layer 支持多个供应商,切换模型后的质量、成本和行为仍然需要重新验证。

因此,控制权不是“开源”或“本地”两个标签自动带来的结果,而是一组可以具体检查的能力:能否修改指令、限制工具、替换模型、查看真实执行记录、导出数据,以及在不满意时离开当前服务。

模型越来越强之后,Harness 的作用不会消失。模型能力越能触达真实系统,越需要明确它通过什么接口行动、谁能批准动作、失败后怎样恢复,以及最终结果如何验证。

小结

Harness 不是模型的另一个名字,也不只是 System Prompt 或工具列表。它是模型与真实环境之间的运行系统,负责准备上下文、描述并执行工具、维持 Agentic Loop、适配模型协议,同时管理状态、权限和验证。

攀岩安全带不会替人完成攀爬,但它决定攀登者如何连接绳索、携带装备并承受失误。Agent Harness 也一样:真正可复用的能力不只在模型权重里,也在模型外面这套系统如何把能力组织起来,又如何阻止它越过边界。

参考资料