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

浙公网安备 33010602011771号