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