Martin Fowler

Are Harnesses Worth the Cost?

8.5内容质量
Are Harnesses Worth the Cost?

TL;DR · AI 摘要

行为Harness使成本优化模型可靠性提升至100%,单次运行成本降低33%。前沿模型使用Harness无显著收益,但成本优化模型依赖Harness实现稳定输出。

核心要点

  • GPT-6 Luna使用Harness后单次运行成本$0.273,比未使用时降低33%
  • 行为Harness使成本优化模型10次运行全部成功,而未使用时仅3次成功
  • 前沿模型GPT-6 Sol使用Harness增加7倍成本但可靠性无提升

结构提纲

按章节快速跳转。

  1. 通过对比实验验证行为Harness对不同模型的效果差异

  2. 使用GPT-6 Sol和Luna进行有无Harness的对比测试

  3. 成本优化模型使用Harness后可靠性提升至100%

  4. Harness使Luna单次运行成本降低33%

  5. GPT-6 Sol使用Harness无可靠性提升但成本增加7倍

  6. Harness对成本优化模型有显著效益但对前沿模型无必要

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 行为Harness的成本效益分析
    • 实验对比
      • GPT-6 Sol vs Luna
      • 有Harness vs 无Harness
    • 关键发现
      • Luna可靠性提升至100%
      • 成本降低33%
      • 前沿模型无收益

金句 / Highlights

值得收藏与分享的关键句。

#AI#模型优化#成本效益#软件工程
打开原文

行为约束是否值得成本?

本文属于系列文章:探索生成式AI。

我对比了使用和不使用行为约束的编码代理在构建相同API服务时的表现。前沿模型GPT-6 Sol无论是否使用约束都通过了所有外部评估。但成本优化模型GPT-6 Luna在未使用约束的10次运行中仅成功3次,而在使用约束的10次运行中全部成功。虽然添加约束增加了Luna的token使用量和运行时间,但使用约束的Luna运行在可靠性上与GPT-6 Sol达到相同10/10的水平,且每次运行成本降低了33%(0.273美元 vs 0.406美元)。该实验表明,行为约束可能是从小型成本优化模型中获得可靠结果的实用方法。

2026年10月13日

Naresh Jain

Naresh Jain是Specmatic、Xnsio和ConfEngine的创始人,也是印度敏捷运动的早期先驱。他与软件团队和工程领导者合作,改进产品开发和技术卓越性。

目录

  • 实验设置
  • 应用程序简要说明
  • 内部循环:行为约束
  • 保持指南和传感器同步
  • 外部循环:评估约束
  • 测试成本优化模型
  • 超出预期的改进点
  • 未使用约束运行的失误之处
  • 约束作为可执行注意力
  • 一致结果的经济学
  • 本实验的边界
  • 实际意义
  • 结论

我原本期望行为约束能帮助编码代理更可靠地满足需求,节省token并避免浪费工作。在编码过程中为代理提供清晰的架构契约和确定性测试反馈似乎是一个显而易见的方法,以帮助其首次尝试就正确实现。

对于GPT-6 Sol,使用约束时消耗的token数量约为无约束情况的10.5倍,耗时几乎为3倍,成本约为7倍,但两种情况在10次运行中都全部成功。

结果完全推翻了这一预期并让我感到意外。在低推理努力下使用Codex与GPT-6 Sol配合,代理在有无约束的情况下都成功通过了每次运行中的所有178个自动化验收测试。按此衡量,约束对最终应用没有产生可观察的改进。

GPT-6 Sol(10次运行的token、时间和成本平均值):

| 约束 | Token | 时间 | 估计成本 | 通过运行 | |------|-------|------|----------|----------| | 有 | 11,331,970 | 19分53秒 | ~2.679美元 | 10/10 | | 无 | 1,076,371 | 6分51秒 | ~0.406美元 | 10/10 |

约束并未改变观察到的验收结果,但增加了平均时间和成本。在探索性运行中,Claude Sonnet 4.6、Claude Opus 4.6和Gemini 3.8 Flash(所有低推理努力模型)都首次尝试就成功完成了任务。

这些前沿模型在有无约束的情况下都能一致处理该任务。可执行反馈能否帮助成本优化模型实现同样一致的结果?

在查看成本优化模型的结果之前,以下是实验设置方式:

实验设置

借用Birgitta Böckeler的框架,行为约束结合了指南和传感器。指南预测代理可能出错的地方,并在行动前引导其修正,从而提高首次尝试正确的可能性。传感器在行动后观察结果,并提供帮助其自我修正的反馈。

对于每个模型,我比较了使用和不使用行为控制装置的代理表现。两种条件均从独立的私有工作区开始,按照应用简介和基线仓库说明进行初始化。使用控制装置的代理还接收了下文内循环部分中描述的API规范、示例和工具。

图1:两种开发条件及其独立评估

实验将开发与评估分离为两个独立循环。内循环在代理构建过程中提供反馈。当代理完成构建后,外循环会对其生成的服务运行178个自动化验收测试。两种条件面临相同的评估标准,且内循环控制装置从未接触过评估套件的答案密钥。最后,我汇总了通过的成果、令牌使用量、耗时和预估成本。

在本实验中,只有应用能成功启动并通过所有178个外部验收测试时才被视为合格。可靠性指模型在重复运行中持续生成合格应用的一致性。令牌使用量、耗时和预估成本是衡量运行效率的三个独立指标。

应用简介

每次尝试都始于详细的应用简介。我描述了服务应实现的功能,但将代码级实现细节交由代理处理。

任务是构建一个前端产品发现的后端(BFF)。它需要暴露面向消费者的HTTP API,验证入站请求和下游响应,并调用订单API。在成功完成可用性搜索后,还需仅将第一个返回产品发布到Kafka。如果发布所有产品,代理可以通过简单传递数据而无需实现选择行为。

图2:简介中描述的应用架构

简介还规定了更隐蔽的行为要求。超时的产品创建必须转换为带有202响应码和响应头中可轮询链接的延迟请求。瞬时搜索失败必须返回带可用恢复间隔的429状态码;不可用依赖项或事件发布失败必须返回503;下游成功响应仍需遵守请求的产品过滤条件,否则返回502。

图3:成功的可用性搜索及其Kafka发布

简而言之,该服务不仅仅是CRUD端点的集合:代理需要同时协调HTTP语义、异步事件、模式边界和容错策略。

这对无辅助代理来说也是一个有利的起点:简介详细说明了功能需求、架构和技术约束,对外部接口、响应格式和故障行为进行了非同寻常的详细描述。目前我还未知晓如果简介不够完整,结果会如何变化。

内循环:行为控制装置

在此次实验中,指南包含OpenAPI和AsyncAPI规范,以机器可读的形式表达了接口协议,为可执行检查提供了基础。这些指南是对简要说明的补充,而非定义另一组独立的要求。指南中还包含了这些接口的请求-响应示例,示例涵盖了下游超时、格式错误的有效负载、过滤器违规、重试序列和Kafka事件确认。一种API开发技能提供了实现实践指导,包括依赖项模拟、行为验证以及如何诊断和应对故障。

传感器检查了协议一致性,使用API测试验证HTTP响应值,并断言可观测的副作用,包括对下游模拟的调用和Kafka发布。测试结果、CTRF报告和API覆盖率报告在开发过程中将这些观察结果返回给代理。

Birgitta还区分了由确定性工具执行的计算控制与依赖模型解释或判断的推断控制。该框架结合了这两者。行为检查产生了计算反馈,而无需LLM判断正确性。根据技能指令的指导,代理仍需解释这些结果并决定如何修复故障。

图4:行为测试框架及其反馈路径

一个代理插件提供了技能和MCP工具,并附带了合同和示例。OpenAPI规范涵盖了BFF和下游订单API;AsyncAPI规范涵盖了Kafka。

在实现服务之前,代理会阅读简要说明以及规范和示例。技能指导其映射应用程序的组件,并将每个所需行为链接到其下游交互和验证检查。辅助脚本搭建了这些文档、验证证据记录以及构建、启动和测试服务的命令;代理完成了特定于行为的细节。

配置工具将合同连接到应用程序和依赖项模拟。基于合同的依赖项模拟使下游交互可执行,使代理能够根据定义的下游响应、故障和恢复序列测试其实现。其他辅助工具验证了时间约束。这些工具共同为代理提供了实现指导和可执行环境,使其能够验证自己的决策。

代理通过项目的测试命令调用框架。该命令验证配置和示例,运行所需的构建和单元检查,启动下游模拟,并针对它们启动应用程序。然后运行上述检查。

报告摘要识别了具体的合同、响应值和交互不匹配。代理使用技能指令进行诊断,修改实现或执行设置,并使用辅助工具重新运行受影响的场景。一旦这些场景通过,代理就会运行完整的测试套件作为最终的验证环节。反馈循环依赖于代理在开发过程中调用这些工具;它不会在每次代码编辑后自动运行。

图5:内环测试和反馈序列

保持指南和传感器同步

设计此类行为框架的一大挑战是确保引导器和传感器之间不产生矛盾,以免混淆代理。我通过以下方法解决了这个问题:

在运行任何测试之前,一个“examples validate”命令会检查示例负载是否符合相应的API规范。随后的测试使用这些规范和示例来验证实现,使传感器始终与源引导器保持一致。

这些检查的来源至关重要。如果代理需要同时编写实现和测试用例,相同的误解或遗漏可能同时出现在两者中。当测试失败时允许其修改预期结果,反而可能掩盖缺陷。在这里,契约和示例以可执行形式代表了人类达成一致的预期。契约检查从提供的规范中确定性生成,而提供的示例结合行为固定装置则定义了值和副作用的断言。代理被要求保留这些输入和技能的验证辅助工具,调查失败原因,并修正实现或执行设置,而不是弱化预期。

这使验证预期拥有了独立于实现代理解释的来源。作为确定性计算控制工具,它们无需依赖代理自身的声明或LLM的判断即可进行正确性检查,从而让人类能够专注于合同未覆盖的领域进行审查。

因此,这些传感器根据运行时机承担着两种截然不同的功能:

  • 在开发阶段:传感器结果以可执行注意力的形式反馈给代理,引导构建过程并帮助其从失误中恢复。
  • 在完成阶段:传感器结果成为验收工作的基础:对代理解释与人类预期进行独立核对,这对每个模型都至关重要。

该技能还要求可审查的依赖项交互证据和最终验证结果,因此完成阶段依赖记录的观察结果而非代理的声明。

在本次实验中,我使用Specmatic实现了行为框架,尽管等效的契约测试和服务虚拟化工具也能提供相同功能。

外层循环:评估框架

为确保比较的公平性,每次尝试都在一个隔离的Docker容器中运行,每个容器都有自己的工作区和特定于此次尝试的Codex主目录。除了共享的认证和语言依赖缓存外,每个代理在启动时都不包含之前运行产生的会话、记忆、插件、技能或其他状态。

两种条件的区别在于开发过程中代理可使用的资源;在每次比较中,完成的应用程序都面临相同的外部评估。

开发结束后,外层循环评估框架会将每个应用程序与包含178个综合功能检查的相同测试集进行比对,包括无效输入、下游故障、恢复序列以及成功请求生成的消息。这些检查会验证应用程序简介中规定的操作行为,包括面向客户端的API、下游交互和Kafka发布。评估框架通过控制自己的下游固定装置和消息捕获来执行这些检查,而不是依赖应用程序的开发测试。

测试成本优化模型

OpenAI 将 GPT-6 Sol 定位为复杂专业工作的旗舰模型,而 GPT-6 Luna 则针对成本敏感、高负载工作进行了优化,其性能大致对应早期 GPT-5 系列的 nano 级别。

在方法论确定后,核心问题是能力配置较小的模型是否会表现出不同行为。

我在 GPT-6 Luna 上以低推理努力度重复了完全相同的实验。没有工具支持时,10 次运行中有 3 次成功;使用工具后,10 次运行全部成功。

GPT-6 Luna(10 次运行平均值):

22,933,648

35 分钟

约 0.273 美元

5,860,736

15 分 56 秒

约 0.086 美元

3/10

在这个案例中,工具并未解锁 Luna 本身不具备的能力;它将原本 3/10 的成功率提升至 10/10 的可靠性。

提供该反馈平均增加了 17,072,912 个 token、19 分 4 秒的自主运行时间和约 0.187 美元的预估 API 等效成本。使用工具的尝试总体消耗的 token 数量约为未使用工具的 Luna 尝试的 3.9 倍。但看经济性对比:即使考虑工具开销,使用工具的 Luna 尝试成本仍比未使用工具的 Sol 尝试低约 33%(0.273 美元 vs 0.406 美元),且两种情况在本案例中都达到了 10/10 的接受率。

超出预期的表现

深入代码库查看通过率后,一些实现表现尤为突出:

  • GPT-6 Sol 在无需辅助的情况下一次性解决了任务。单个 /goal 提示就足够了。所有 10 次未使用工具的 GPT-6 Sol 应用在首次尝试中就通过了所有功能检查,无需人工调试或后续修正。
  • GPT-6 Luna 独立完成时表现惊人。未使用工具的 GPT-6 Luna 运行通过了 94.8% 的功能检查。它在细微边缘案例上出现了一些问题,但并未完全偏离任务目标。
  • 异步 202 工作流实现了端到端整合。返回 202 Accepted 状态码本身并不复杂。令我惊讶的是,代理自动连接了监控端点,跟踪待处理请求,使用原始幂等性密钥重试下游创建,并在轮询 URL 上展示最终有效负载。
  • Kafka 发布始终保持与搜索事务的关联。与立即发送消息并返回 200 不同,已接受的应用程序在收到 Kafka 确认后才响应,并正确将发布失败或超时转换为 503 Service Unavailable 状态码。
  • 边界验证始终具有防御性。两个模型都先对传入的有效负载进行模式验证,再对下游响应结构和业务约束进行验证,而不是盲目信任下游服务。

未使用工具运行的失误点

未使用工具的失败 Java 应用程序并未包含语法错误或对任务的根本性误解。每个应用仍通过了至少 144 个联合功能检查中的 178 个。它们的失败集中在延迟创建工作流和较小的协议细节上:

观察到的缺陷出现在协议边界、弹性路径和集成接缝处,这些地方即使实现看起来合理,也可能因系统层面的问题而失败。

  • 延迟创建在超时边界处失效。当下游产品的创建时间超过配置的超时时间时,BFF(Backend for Frontend)应返回202 Accepted状态码并附带监控链接,在后台重试,最终暴露下游的201响应。但实际情况是,4个未受控的应用程序返回了503,2个返回了400,1个返回了429。一个之前已统计到的应用程序在某些场景中创建了监控,但其重试从未达到最终的201响应。多个实现通过匹配狭窄的异常类型或因果链形状来识别超时。这些实现导致了错误响应,但通常不会记录实际的客户端异常,因此这种机制很可能是导致问题的原因,而非已被证明的普遍原因。
  • 缺失的监控链接导致了二次故障。在7次运行中,超时创建的错误响应也意味着未返回监控URL。后续的评估器检查尝试使用该缺失URL时失败。我将这些错误视为202流程失效的后果,而非独立的应用缺陷。
  • Kafka投递成功但契约一致性失败。在3次运行中,所有预期消息都成功到达Kafka,但评估器仍拒绝了发布。两个应用使用了Spring的JSON序列化器并添加了意外的__TypeId__头。另一个应用发出"categories": null,尽管该可选字段在存在时必须包含数组。集成在机械层面运作,但仍违反了通信契约。
  • 错误响应未满足精确的HTTP契约。其他观察到的遗漏更为细微。虽然415 Unsupported Media Type是处理不支持媒体类型的常规响应,但应用简要说明明确要求此类无效请求必须返回400,因此评估器将415视为契约违规。在其他情况下,无效请求到达了通用的500处理器,缺失的监控返回了错误的表现形式。这些是代码中的微小差异,但足以使应用在外部评估中不可接受。
  • 配置名称在集成接缝处出现分歧。普通产品创建返回了503而非201。生成的客户端读取ORDER_API_API_KEY,而记录的启动配置提供了ORDER_API_KEY。这种不匹配可能是下游故障的合理解释。在受控运行中,契约驱动的依赖项模拟和配置检查使这些环境变量在部署前得以验证。

作为可执行关注的测试框架

行为测试框架将书面需求转化为环境反馈,当传感器出现异常时,能将被忽视的细节重新聚焦到视野中。

我倾向于用"可执行关注"这一概念来思考这种动态。

这些失败背后的行为在提供的需求中已明确说明。应用简要说明明确指定了延迟创建工作流、Kafka消息契约和精确的错误响应。需求可能在简要说明中明确,但在实现过程中仍可能失去影响力。我认为这属于"关注缺失":最终代码省略或未完整实现代理已知的需求。

在上下文不断扩展的情况下,权衡库选择、样板设置、依赖注入和异步连接可能导致此类疏漏,尽管该实验并未确定具体原因。可执行注意力使这些差距变得可见,为代理提供了再次根据需求采取行动的机会。

  • 超时创建不会延迟到响应包含监控链接且轮询最终到达下游结果时才进行。
  • Kafka 发布仅当消息到达时并不成立;其有效载荷和标头必须同时符合协议。
  • 当协议仅允许数组或省略时,可选字段不能序列化为 null。
  • 错误响应只有在状态、内容类型和正文均符合客户端协议时才算正确。

GPT-6 Sol 在所有观察运行中都保留了书面简报中的这些细节。GPT-6 Luna 在没有工具的情况下也正确实现了大部分行为,但其接受结果存在差异。Luna 的遗漏与实现过程中需求影响力减弱一致。我的理解是,工具充当了外部记忆和注意力辅助工具,每当传感器变为红色时,将被遗漏的需求重新带回焦点。

一致结果的经济性

将两个模型样本并排对比,可以直观看到这种反馈的成本。这些是基于记录的令牌使用量和模型价格的 API 等效估算,而非实际计费成本。

图 6:两个模型的平均预估成本和时间

在 GPT-6 运行中,使用工具的 Luna 每次尝试平均成本约为 0.273 美元,而未使用工具的 Sol 每次尝试平均成本为 0.406 美元;两者在 10 次尝试中均接受了 10 个申请。因此,在此样本中,使用工具的 Luna 尝试平均成本降低了约 33%。

所有 10 个使用工具的 GPT-6 Luna 申请都通过了外部评估,实现了 100% 的成功率。这个小样本无法告诉我们长期失败率或实现可接受申请的总成本。

这些数据仅衡量自主生成成本和机器时间。它们不包括编写、审查和维护协议、示例、断言和工具的前期工作量。它们也未计入查找、诊断和修复不可接受结果所需的努力。跨实现重用接口协议和检查可能将设置成本分摊到时间上,但我没有测量这种重用或由此产生的总成本。

Sol 的 10 次全部成功结果仍然依赖于独立评估。这表明另一个对比:仅在最终验证关卡向代理提供传感器,而非在整个开发过程中提供。最终关卡工作流程可以在首次实现通过时最小化开销,同时提供独立的接受检查。然而,失败仍可能需要诊断和修复周期。我没有测量该工作流程的成本。

本实验的边界

该实验涵盖了每个模型在 1 个全新 Java 服务上的 10 次配对运行,且两个模型的推理努力均较低。该样本描述了观察到的结果;它无法证明长期可靠性。

更苛刻的架构或更复杂的弹性场景可能会暴露 Sol 中需要工具的缺陷。相反,更简单的任务可能在没有这种行为工具的情况下在 Luna 上可靠运行。

该规格说明以不寻常的详细程度指定了功能行为、架构、技术及接口。我尚未测试该模式在修改遗留代码、使用其他语言或推理设置、或基于模糊不完整需求进行开发时是否依然适用。一个不够完整的规格说明可能同时影响未借助工具的实现效果,以及提供给测试框架的契约和示例的质量。我对将这些具体数据直接套用于不同规格说明、架构、代码库或团队工作流程持谨慎态度。

由于测试框架同时添加了引导和传感器,因此该实验无法单独区分它们的个体贡献。

实际意义

我将这些结果视为选择特定任务模型和反馈频率的起点。随着模型能力的变化,改变的是传感器运行的时机和频率,而非是否需要独立检查。

模型能力的变化影响的是传感器运行的时机和频率,而非是否需要独立验证关卡。

  • 对于成本优化型模型:当成本优化型模型产生不一致结果时,在开发过程中全程运行行为测试框架。它能起到可执行的注意力作用,实时捕捉偏差,将不一致的尝试转化为可靠的交付。
  • 对于前沿型模型:即使模型首次尝试就持续通过,也应保留独立的验收检查。不要在开发过程中持续运行检查,而是在验收前作为确定性最终验证关卡一次性运行自动化测试,以最小的开销提供独立检查。
  • 投资清晰的规格说明和示例:检查只能执行人类编码的预期。在实现过程中同步审查和维护这些预期,并利用人工审查弥补覆盖率的不足。

结论

我最初的假设过于武断。行为测试框架并非对每个模型在每个任务上都能自动带来优势。对于Sol,在开发过程中全程运行测试框架增加了开销但未发现验收效益;在Luna的样本中,使用测试框架的尝试比未使用框架的Sol尝试更一致且平均成本更低。

这让我形成了修正后的条件性假设:

随着模型能力的变化,改变的不是是否需要独立传感器,而是它们运行的时机。对于未借助工具尝试会产生不一致结果的模型,在开发过程中持续运行传感器能提供可执行的注意力,从而扩大团队可成功使用的模型范围。对于能够一次性解决任务的前沿型模型,将这些传感器作为独立的最终验收关卡运行一次,可以在不增加开发开销的情况下提供每个系统都需要的验证。

实际上,工程团队很少仅根据原始基准智能选择模型。单位经济效益、延迟预算、数据隐私以及能否在本地运行等因素通常主导决策。如果行为测试框架能够将已满足这些运营约束的更便宜、更轻量的模型转化为可靠交付的方案,这将是一个极具吸引力的选择。

到目前为止,我仅在一个具有异常详细需求说明的全新服务上进行了测试。下一步是针对前沿模型测试“仅最终关卡”条件,以衡量其开销以及关卡捕捉差异的频率。除此之外,我计划改变需求说明的质量和未满足需求的后果,然后测试这一假设在修改现有代码库、切换编程语言或本地运行开源权重模型时的适用性。

致谢

Joel Rosario 帮助我设计了测试框架,Yogesh Nikam 和 Sufiyan Khan 帮助我执行了实验。我也非常感谢 Specmatic 的同事们提供的讨论、反馈和建议。

我特别感谢 Martin Fowler 的鼓励和详细反馈,这些帮助我完善了本文的论点和表述。

在审阅过程中,Shunjiro Yatsuzuka 提出了传感器双重角色的概念。Birgitta Böckeler 的《面向代码代理用户的测试框架工程》为我提供了“指南”和“传感器”的语言表述,帮助构建了本次实验的框架。Giles Edwards-Alexander 的《重构的经济效益》影响了我实验的结构设计和对令牌使用量的度量方式。

我使用了生成式 AI 进行主题研究并构建了测试框架的部分内容。在本文撰写过程中,我使用它来修正语法错误并构思各部分内容的逻辑顺序和排列方式。

重大修订记录

2026年10月13日:首次发布

最新文章(10月13日):

[支架是否值得成本?](#)

上一篇文章:

[意外的黑板](#)