Anthropic 分享长时应用开发的 Harness 设计:从生成器加评估器到三智能体架构
Harness design for long-running application development
Anthropic 工程师撰文介绍其长时自主编码的 Harness 设计,借鉴 GAN 思路构建生成器与评估器分离的多智能体结构,并最终形成规划器、生成器、评估器三智能体架构,可在数小时自主会话中产出完整全栈应用。
Anthropic 工程师复盘从 GAN 借鉴的生成器与评估器多智能体结构,并给出随模型升级逐步删减组件的实测过程。
过去几个月里,我一直在研究两个相互关联的问题:让 Claude 产出高质量的前端设计,以及让它无需人工干预就能构建完整的应用程序。这项工作源于此前在前端设计技能和长时间运行的编码智能体框架上的努力,我和同事们通过提示工程和框架设计,将 Claude 的表现提升到远超基线水平——但两者最终都遇到了瓶颈。
为了突破瓶颈,我寻找了新颖的 AI 工程方法,这些方法在两个截然不同的领域中都成立:一个由主观品味定义,另一个由可验证的正确性和可用性定义。受生成对抗网络(GAN)的启发,我设计了一种包含生成器和评估器智能体的多智能体结构。构建一个能够可靠且有品味地给输出打分的评估器,意味着首先要开发一套标准,将“这个设计好吗?”这类主观判断转化为具体、可评分的术语。
随后我将这些技术应用于长时间运行的自主编码,并沿用了此前框架工作中的两条经验:将构建过程分解为可处理的块,以及使用结构化产物在会话之间传递上下文。最终结果是一个三智能体架构——规划器、生成器和评估器——它在长达数小时的自主编码会话中产出了丰富的全栈应用程序。
为什么朴素实现难以奏效
我们此前已经证明,框架设计对长时间运行的智能体编码的有效性有重大影响。在早先的一项实验中,我们使用一个初始化智能体将产品规格分解为任务列表,并使用一个编码智能体一次实现一个功能,然后交接产物以跨会话传递上下文。更广泛的开发者社区也得出了类似的见解,例如“Ralph Wiggum”方法使用钩子或脚本让智能体保持在持续的迭代循环中。
但一些问题仍然存在。对于更复杂的任务,智能体仍然倾向于随着时间推移而偏离正轨。在分解这一问题时,我们观察到智能体执行这类任务时存在两种常见的失败模式。
首先,随着上下文窗口被填满,模型在冗长任务上往往会失去连贯性(参见我们关于上下文工程的文章)。一些模型还表现出“上下文焦虑”,即当它们接近自认为的上下文限制时,会过早地开始收尾工作。上下文重置——完全清空上下文窗口并启动一个全新的智能体,同时结合结构化交接来传递前一个智能体的状态和后续步骤——可以同时解决这两个问题。
这与压缩(compaction)不同:压缩是就地总结对话的较早部分,让同一个智能体在缩短的历史上继续工作。压缩保留了连续性,但没有给智能体一个干净的开端,这意味着上下文焦虑仍可能存在。重置则提供了一个干净的开端,代价是交接产物必须包含足够的状态,以便下一个智能体能够干净地接手工作。在早期的测试中,我们发现 Claude Sonnet 4.5 表现出的上下文焦虑足够强烈,以至于仅靠压缩不足以实现强大的长任务性能,因此上下文重置成为 harness 设计的关键。这解决了核心问题,但为每次 harness 运行增加了编排复杂性、token 开销和延迟。
第二个问题我们此前未曾讨论,即自我评估。当被要求评估自己产出的工作时,智能体往往会自信地赞美这些工作——即使对人类观察者而言,质量明显平庸。这个问题在诸如设计之类的主观任务上尤为突出,因为这类任务没有等同于可验证软件测试的二元检查。布局是显得精致还是千篇一律是一种主观判断,而智能体在给自己的作品打分时总是倾向于正面评价。
然而,即使在确实有可验证结果的任务上,智能体有时仍会表现出糟糕的判断力,从而妨碍其在完成任务过程中的表现。将执行工作的智能体与评判工作的智能体分开,被证明是解决这一问题的有力手段。这种分离本身并不能立即消除那种宽容;评估者仍然是一个 LLM,倾向于对 LLM 生成的输出给予宽容。但将一个独立的评估者调教得具有怀疑精神,远比让生成者对自己的工作持批判态度要容易得多,而且一旦存在这种外部反馈,生成者就有了具体的依据来进行迭代。
前端设计:让主观质量可评分
我从前端设计入手进行实验,因为自我评估问题在那里最为明显。在没有任何干预的情况下,Claude 通常会倾向于安全、可预测的布局,这些布局在技术上功能可用,但视觉上平淡无奇。
两个洞见塑造了我为前端设计构建的 harness。第一,虽然美学无法完全归结为一个分数——而且个人品味总是因人而异——但可以通过编码设计原则和偏好的评分标准来改进。“这个设计美吗?”很难一致地回答,但“这个设计是否遵循了我们关于良好设计的原则?”给了 Claude 一个具体的评分依据。第二,通过将前端生成与前端评分分离,我们可以创建一个反馈循环,推动生成者产出更强的输出。
基于此,我编写了四条评分标准,并将它们放入生成者和评估者智能体的提示词中:
- 设计质量:设计是否感觉像一个连贯的整体,而不是各个部分的拼凑?在这方面表现出色意味着颜色、字体排印、布局、图像和其他细节结合在一起,创造出独特的情调和身份。
- 原创性:是否有自定义决策的证据,还是模板布局、库默认值和 AI 生成的模式?人类设计师应该能识别出刻意的创意选择。未经修改的现成组件——或 AI 生成的明显迹象,比如白色卡片上的紫色渐变——在此项上不合格。
- 工艺:技术执行:排版层级、间距一致性、色彩和谐度、对比度。这是一项能力检查,而非创造力检查。大多数合理的实现在这里默认都能做得不错;失败意味着基础出了问题。
- 功能性:独立于美学的可用性。用户能否理解界面的用途、找到主要操作,并在无需猜测的情况下完成任务?
我强调设计质量和原创性,而非工艺和功能性。Claude 在工艺和功能性上默认得分已经很高,因为所需的技术能力往往对模型来说自然而然。但在设计和原创性上,Claude 常常产出充其量只是平庸的结果。评分标准明确惩罚高度通用的“AI 垃圾”模式,并且通过更重地加权设计和原创性,推动模型承担更多美学风险。
我用带有详细分数细项的少样本示例来校准评估器。这确保了评估器的判断与我的偏好一致,并减少了跨迭代的分数漂移。
我在 Claude Agent SDK 上构建了这个循环,这让编排保持简单直接。一个生成器代理首先根据用户提示创建 HTML/CSS/JS 前端。我给评估器配置了 Playwright MCP,让它能在评分每项标准并撰写详细评语之前直接与实时页面交互。在实践中,评估器会自行浏览页面,截图并仔细研究实现,然后给出评估。这些反馈作为下一轮迭代的输入流回生成器。每次生成我运行 5 到 15 轮迭代,每一轮通常都会推动生成器朝更具特色的方向发展,以回应评估器的评语。由于评估器是在主动浏览页面,而不是对静态截图评分,每个周期都耗费真实的实际时间。完整运行最长可达四小时。我还指示生成器在每次评估后做出战略决策:如果分数趋势良好,就完善当前方向;如果该方案不奏效,就转向完全不同的美学。
在多次运行中,评估器的评估随迭代而改善,随后趋于平稳,仍有提升空间。有些生成是渐进式完善的。另一些则在迭代之间发生了急剧的美学转向。
评分标准的措辞以我未能完全预料的方式引导了生成器。加入“最好的设计是博物馆级”之类的短语,将设计推向某种特定的视觉趋同,这表明与评分标准相关的提示词直接塑造了输出的特征。
虽然分数总体上随迭代而提高,但模式并不总是干净的线性关系。后期的实现整体上往往更好,但我经常看到我更偏爱中间某轮迭代而非最后一轮的情况。实现复杂度也往往随轮次增加,生成器会响应评估器的反馈而追求更宏大的方案。即使在第一轮迭代,输出也明显优于完全没有提示词的基线,这表明评分标准及相关语言本身就在任何评估器反馈带来进一步完善之前,引导模型远离了通用默认值。
在一个值得注意的例子中,我提示该模型为一家荷兰艺术博物馆创建一个网站。到第九次迭代时,它已经为一座虚构的博物馆生成了一个干净、深色主题的落地页。页面在视觉上很精致,但基本符合我的预期。然后,在第十个周期,它完全放弃了这一方案,将网站重新构想为一种空间体验:一个用 CSS 透视渲染出棋盘格地板的 3D 房间,艺术品以自由形式的位置挂在墙上,画廊房间之间通过门洞导航,而不是滚动或点击。这是我此前从未在单次生成中见过的创造性飞跃。
扩展到全栈编码
有了这些发现,我将这种受 GAN 启发的模式应用于全栈开发。生成器-评估器循环自然地映射到软件开发生命周期,其中代码审查和 QA 承担着与设计评估器相同的结构性角色。
架构
在我们早先的长时间运行 harness 中,我们通过初始化器智能体、一次只处理一个功能的编码智能体,以及会话之间的上下文重置,解决了连贯的多会话编码问题。上下文重置是一个关键突破:该 harness 使用了 Sonnet 4.5,它表现出前面提到的“上下文焦虑”倾向。创建一个能在上下文重置之间良好工作的 harness,是让模型保持任务专注的关键。Opus 4.5 基本自行消除了这种行为,因此我能够从这个 harness 中完全去掉上下文重置。这些智能体在整个构建过程中作为一个连续会话运行,由 Claude Agent SDK 的自动压缩来处理沿途的上下文增长。
在这项工作中,我在原始 harness 的基础上构建了一个三智能体系统,每个智能体都针对我在先前运行中观察到的特定缺口。该系统包含以下智能体角色:
规划器:我们之前的长时间运行 harness 要求用户预先提供详细规格。我想自动化这一步,因此创建了一个规划器智能体,它接收简单的 1-4 句提示,并将其扩展为完整的产品规格。我提示它在范围上要有雄心,并专注于产品上下文和高层技术设计,而不是详细的技术实现。这种强调是出于这样的担忧:如果规划器试图预先指定细粒度的技术细节并弄错了某些内容,规格中的错误会级联到下游实现中。约束智能体要交付的成果,让它们在工作过程中自行找出路径,似乎更明智。我还要求规划器寻找将 AI 功能融入产品规格的机会。(参见底部附录中的示例。)
生成器:早先 harness 中一次只处理一个功能的方法在范围管理方面效果很好。我在这里应用了类似的模式,指示生成器按冲刺工作,一次从规格中选取一个功能。每个冲刺都用 React、Vite、FastAPI 和 SQLite(后来是 PostgreSQL)技术栈实现应用,并且指示生成器在每个冲刺结束时先自我评估,然后再交给 QA。它还有用于版本控制的 git。
评估器:早期测试框架生成的应用往往看起来令人印象深刻,但实际使用时仍存在真实缺陷。为了捕捉这些问题,评估器使用 Playwright MCP 像用户一样点击运行中的应用,测试 UI 功能、API 端点和数据库状态。随后,它根据发现的缺陷以及一套参照前端实验建模的标准对每个冲刺进行评分,这些标准在此经过调整,涵盖产品深度、功能、视觉设计和代码质量。每项标准都有硬性阈值,任何一项低于阈值,该冲刺即告失败,生成器会收到关于问题所在的详细反馈。
在每个冲刺开始前,生成器和评估器会协商一份冲刺契约:在编写任何代码之前,就先就这部分工作的“完成”标准达成一致。之所以这样做,是因为产品规格有意保持在高层次,我希望有一个步骤来弥合用户故事与可测试实现之间的差距。生成器提出它将构建什么以及如何验证成功,评估器审查该提案以确保生成器在构建正确的东西。双方反复迭代,直到达成一致。
沟通通过文件进行:一个智能体写入文件,另一个智能体读取该文件并在该文件中回复,或创建一个新文件供前一个智能体依次读取。随后,生成器按照商定的契约进行构建,再将工作交给 QA。这样既能让工作忠实于规格,又不会过早过度指定实现细节。
运行测试框架
对于这个测试框架的第一个版本,我使用了 Claude Opus 4.5,针对完整测试框架和单智能体系统分别运行用户提示以进行比较。我使用 Opus 4.5 是因为在我开始这些实验时,它是我们最好的编码模型。
我编写了以下提示来生成一个复古视频游戏制作器:
创建一个 2D 复古游戏制作器,功能包括关卡编辑器、精灵编辑器、实体行为和可玩的测试模式。
下表显示了测试框架类型、运行时长和总成本。
该测试框架的成本高出 20 倍以上,但输出质量的差异立竿见影。
我期望的是一个可以构建关卡及其组成部分(精灵、实体、图块布局),然后点击播放来实际游玩关卡的界面。我先打开了单智能体运行的输出,初始应用似乎符合这些期望。
然而,当我点击浏览时,问题开始浮现。布局浪费空间,固定高度的面板让大部分视口空着。工作流程僵化。尝试填充关卡时,系统提示我先创建精灵和实体,但 UI 中没有任何内容引导我按这个顺序操作。更关键的是,实际游戏是坏的。我的实体出现在屏幕上,但没有任何东西响应输入。深入代码后发现,实体定义与游戏运行时之间的连接是断的,而界面上没有任何迹象表明问题出在哪里。
在评估了单独运行的结果后,我把注意力转向了 harness 运行。这次运行同样从一句提示词开始,但规划器步骤将这句提示词扩展成了一份包含 16 项功能、跨越十个冲刺的规格说明。它远远超出了单独运行所尝试的范围。除了核心编辑器和游玩模式外,规格还要求实现精灵动画系统、行为模板、音效与音乐、AI 辅助的精灵生成器和关卡设计器,以及带可分享链接的游戏导出。我让规划器访问了我们的前端设计技能,它阅读并利用该技能为应用创建了一套视觉设计语言,并将其纳入规格说明。在每个冲刺中,生成器和评估器都会协商一份契约,明确该冲刺的具体实现细节,以及用于验证完成情况的可测试行为。
这款应用立刻显得比单独运行更精致、更流畅。画布占满了整个视口,面板尺寸合理,界面具有一致的视觉识别,与规格中的设计方向保持一致。单独运行中看到的一些笨拙之处仍然存在——工作流仍然没有明确说明应该先构建精灵和实体,再尝试填充关卡,我不得不自己摸索才弄明白。这更像是基础模型产品直觉上的缺口,而不是 harness 设计要解决的问题,不过它确实指出了 harness 内部有针对性的迭代可以帮助进一步提升输出质量的地方。
在使用各个编辑器的过程中,新运行相对于单独运行的优势变得更加明显。精灵编辑器更丰富、功能更完整,工具面板更简洁,颜色选择器更好,缩放控制也更易用。
因为我要求规划器将 AI 功能融入其规格,应用还内置了 Claude 集成,让我可以通过提示词生成游戏的不同部分。这显著加快了工作流。
最大的差异在游玩模式。我居然能够移动我的实体并游玩游戏。物理效果有一些粗糙之处——我的角色跳上了一个平台,但最终与平台重叠,这在直觉上是错误的——但核心功能是有效的,而单独运行没能做到这一点。在移动了一会儿之后,我确实遇到了 AI 游戏关卡构建的一些限制。有一堵大墙我跳不过去,所以被困住了。这表明 harness 可以处理一些常识性改进和边缘情况,以进一步优化应用。
通读日志可以清楚地看到,评估器让实现始终与规格保持一致。每个冲刺,它都会走查冲刺契约的测试标准,并通过 Playwright 操作运行中的应用,对任何偏离预期行为的地方提交缺陷。契约非常细粒度——仅 Sprint 3 就有 27 条针对关卡编辑器的标准——评估器的发现足够具体,无需额外调查即可直接处理。下表展示了我们的评估器识别出的几个问题示例:
让评估器达到这种水平并非易事。开箱即用的 Claude 是个糟糕的 QA 代理。在早期运行中,我看着它识别出合理的问题,然后说服自己这些问题没什么大不了,最终还是批准了工作。它还倾向于进行表面测试,而不是探查边缘情况,因此更隐蔽的 bug 常常溜过去。调优循环的做法是阅读评估器的日志,找出它的判断与我的判断出现分歧的例子,并更新 QA 提示词来解决这些问题。经过几轮这样的开发循环,评估器的评分方式才达到我认为合理的程度。即便如此,harness 的输出仍显示出该模型 QA 能力的局限:小的布局问题、某些地方交互感觉不直观,以及评估器未充分测试的更深层嵌套功能中未被发现的 bug。显然还有更多验证空间可通过进一步调优来挖掘。但与单次运行相比——那次运行中应用的核心功能根本无法工作——提升是显而易见的。
迭代 harness
第一组 harness 结果令人鼓舞,但它也笨重、缓慢且昂贵。合乎逻辑的下一步是找到简化 harness 而不降低其性能的方法。这在一定程度上是常识,也在一定程度上源于一个更普遍的原则:harness 中的每个组件都编码了一个关于模型自身无法完成什么的假设,而这些假设值得进行压力测试,既因为它们可能不正确,也因为随着模型改进它们可能很快过时。我们的博客文章 Building Effective Agents 将这一基本思想表述为“找到尽可能简单的解决方案,只在需要时增加复杂性”,这是任何维护 agent harness 的人都会反复遇到的模式。
在我第一次尝试简化时,我大幅削减了 harness 并尝试了一些有创意的新想法,但未能复现原始版本的性能。同时也变得难以判断 harness 设计中哪些部分实际上是承重的,以及以何种方式承重。基于那次经验,我转向更系统的方法,一次移除一个组件,并审视它对最终结果的影响。
在我进行这些迭代循环时,我们还发布了 Opus 4.6,这为降低 harness 复杂性提供了进一步动力。有充分理由预期 4.6 需要的脚手架比 4.5 少。从我们的发布博客:“[Opus 4.6] 规划更谨慎,能更长时间持续 agentic 任务,在更大的代码库中运行更可靠,并具有更好的代码审查和调试技能来发现自己的错误。”它在长上下文检索方面也有大幅改进。这些都是 harness 原本为补充而构建的能力。
移除 sprint 结构
我首先完全移除了 sprint 结构。sprint 结构曾有助于将工作分解成块,让模型连贯地工作。鉴于 Opus 4.6 的改进,有充分理由相信模型可以原生处理这项工作,而无需这种分解。
我保留了规划器和评估器,因为两者都持续带来明显的价值。没有规划器,生成器会范围界定不足:给定原始提示词,它会不先规划工作就开始构建,最终创建的应用功能不如有规划器时丰富。
移除冲刺结构后,我把评估器改为在运行结束时进行一次单轮评估,而不是按冲刺评分。由于模型的能力强得多,评估器在某些运行中的关键程度发生了变化,其有用性取决于任务相对于模型能可靠独立完成的范围处于什么位置。在 4.5 上,这个边界很近:我们的构建处于生成器能独立做好的边缘,评估器在整个构建过程中发现了有意义的问题。在 4.6 上,模型的原始能力提升了,因此边界向外移动。过去需要评估器检查才能连贯实现的任务,现在往往落在生成器能独立处理好的范围内,而对于该边界内的任务,评估器变成了不必要的开销。但对于构建中仍处于生成器能力边缘的部分,评估器继续带来真正的提升。
实际含义是,评估器不是一个固定的“是或否”决策。当任务超出当前模型能可靠独立完成的范围时,它值得付出成本。
除了结构简化之外,我还增加了提示词,以改进 harness 将 AI 功能构建到每个应用中的方式,具体是让生成器构建一个合适的 agent,能够通过工具驱动应用自身的功能。这需要真正的迭代,因为相关知识足够新,Claude 的训练数据对其覆盖很薄。但经过足够的调优,生成器能够正确构建 agent。
更新后 harness 的结果
为了测试更新后的 harness,我使用以下提示词生成一个数字音频工作站(DAW),一个用于作曲、录音和混音的音乐制作程序:
使用 Web Audio API 在浏览器中构建一个功能齐全的 DAW。
这次运行仍然漫长且昂贵,大约 4 小时,token 成本为 124 美元。
大部分时间花在构建器上,它在没有 Opus 4.5 所需的冲刺分解的情况下连贯运行了两个多小时。
与之前的 harness 一样,规划器将一行提示词扩展为完整规格。从日志中我可以看到,生成器模型在规划应用和 agent 设计、连接 agent 以及在移交给 QA 之前进行测试方面做得很好。
话虽如此,QA agent 仍然发现了真正的缺口。在其第一轮反馈中,它指出:
这是一个强大的应用,具有出色的设计保真度、可靠的 AI agent 和良好的后端。主要失败点是功能完整性——虽然应用看起来令人印象深刻,AI 集成也运行良好,但几个核心 DAW 功能只是展示性的,没有交互深度:片段无法在时间线上拖动/移动,没有乐器 UI 面板(合成器旋钮、鼓垫),也没有视觉效果编辑器(EQ 曲线、压缩器电平表)。这些不是边缘情况——它们是使 DAW 可用的核心交互,而规格明确要求它们。
在其第二轮反馈中,它再次发现了几个功能缺口:
剩余缺口:
- 音频录制仍然只是存根(按钮可切换但没有麦克风采集)
- 通过边缘拖动调整片段大小和片段分割未实现
- 效果可视化是数字滑块,不是图形化的(没有 EQ 曲线)
生成器在自行其是时仍然容易遗漏细节或留下存根功能,而 QA 仍然在捕捉这些最后一英里的问题以供生成器修复方面增加了价值。
根据提示词,我原本期待的是一个可以创作旋律、和声和鼓点模式、将它们编排成一首歌,并在过程中得到集成智能体帮助的程序。下面的视频展示了结果。
这个应用远非专业音乐制作程序,智能体的作曲能力显然还有很大提升空间。此外,Claude 实际上无法听见声音,这使得在音乐品味方面的 QA 反馈循环效果大打折扣。
但最终的应用具备了功能性音乐制作程序的所有核心组件:在浏览器中运行的编曲视图、混音器和走带控制。除此之外,我能够完全通过提示词拼凑出一段简短的歌曲片段:智能体设定了速度和调性,铺了一段旋律,构建了鼓轨,调整了混音器电平,并添加了混响。作曲的核心原语都已具备,智能体可以自主驱动它们,使用工具端到端地完成一个简单的制作。你也许会说它还不够完美——但它正在接近。
接下来是什么
随着模型不断改进,我们可以大致预期它们能够工作更长时间、处理更复杂的任务。在某些情况下,这意味着围绕模型的脚手架随时间推移变得不那么重要,开发者可以等待下一个模型,看某些问题自行解决。另一方面,模型越好,开发能够完成超出模型基线能力的复杂任务的 harness 的空间就越大。
考虑到这一点,这项工作中有几点经验值得延续。始终好的做法是:对你正在构建所针对的模型进行实验,阅读它在真实问题上的轨迹,并调整其表现以达到你期望的结果。在处理更复杂的任务时,有时通过分解任务并对问题的每个方面应用专门的智能体,可以获得额外的提升空间。而当新模型发布时,通常好的做法是重新审视 harness,剥离那些不再对性能起承重作用的部分,并添加新的部分以实现以前可能无法达到的更强能力。
从这项工作中,我的信念是:有趣的 harness 组合空间并不会随着模型的改进而缩小。相反,它会移动,而 AI 工程师的有趣工作就是不断寻找下一个新颖的组合。
附录
规划智能体生成的示例计划。
来源:Anthropic Engineering · anthropic.com