长时间运行 Agent 的有效 Harness
发布于 2025 年 11 月 26 日
Agent 在跨多个上下文窗口工作时仍面临挑战。我们从人类工程师那里获得灵感,为长时间运行的 agent 创建了更有效的 harness。
核心挑战
随着 AI agent 能力不断增强,开发者越来越期望它们承担需要数小时甚至数天工作的复杂任务。然而,让 agent 在多个上下文窗口中持续取得进展仍是一个开放性问题。
"长时间运行 agent 的核心挑战在于它们必须在离散的会话中工作,而每个新会话开始时都没有对之前内容的记忆。"想象一个由轮班工程师组成的软件项目,每位新工程师到来时都不记得上一班发生了什么。由于上下文窗口有限,且大多数复杂项目无法在单个窗口内完成,agent 需要一种方法来弥合编码会话之间的鸿沟。
两部分解决方案
Anthropic 开发了一套解决方案,使 Claude Agent SDK 能够在多个上下文窗口中有效工作:
- 初始化 Agent - 在首次运行时设置环境
- 编码 Agent - 在每个会话中取得增量进展,同时为下一个会话留下清晰的产物
代码示例可在配套的快速入门指南中找到。
长时间运行 Agent 的问题
Claude Agent SDK 是一个强大的通用 agent harness,擅长编码以及其他需要模型使用工具来收集上下文、规划和执行的任务。它具有上下文管理能力(如压缩),使 agent 能够在不耗尽上下文窗口的情况下完成任务。
然而,仅靠压缩是不够的。即使是 Opus 4.5 这样的前沿编码模型,如果在 Claude Agent SDK 上跨多个上下文窗口循环运行,仅给定一个高层提示词(如"构建 claude.ai 的克隆"),也无法构建出生产级质量的 Web 应用。
两种关键失败模式
第一种失败模式: agent 倾向于一次做太多事情——本质上试图一气呵成完成整个应用。这通常导致模型在实现过程中耗尽上下文,使下一个会话从一个功能实现到一半且无文档记录的状态开始。然后 agent 必须猜测发生了什么,并花费大量时间试图让基本应用重新运行起来。
第二种失败模式: 在一些功能已经构建完成后,后续的 agent 实例会环顾四周,看到已经取得进展,然后宣布任务完成。
拆解解决方案
这种分解解决了两个问题:
设置一个初始环境,为给定提示词所需的所有功能奠定基础,这使 agent 能够逐步、逐功能地工作。
提示每个 agent 向目标取得增量进展,同时在会话结束时使环境处于干净状态。所谓"干净状态",我们指的是适合合并到主分支的代码:没有重大 bug,代码有序且文档完善,开发者可以轻松开始新功能的开发,而不必先清理无关的混乱。
环境管理
在更新的 Claude 4 提示指南中,分享了多上下文窗口工作流的最佳实践,包括一种 harness 结构,该结构"对第一个上下文窗口使用不同的提示词"。这个"不同的提示词"要求初始化 agent 用未来编码 agent 有效工作所需的所有必要上下文来设置环境。
功能列表
为了解决 agent 一气呵成完成应用或过早认为项目完成的问题,初始化 agent 编写一个全面的功能需求文件,对用户的初始提示词进行扩展。在 claude.ai 克隆示例中,这意味着超过 200 个功能,如"用户可以打开新对话,输入查询,按回车,并看到 AI 响应"。这些功能最初都被标记为"失败",以便后续的编码 agent 对完整功能是什么样子有清晰的轮廓。
{
"category": "functional",
"description": "New chat button creates a fresh conversation",
"steps": [
"Navigate to main interface",
"Click the 'New Chat' button",
"Verify a new conversation is created",
"Check that chat area shows welcome state",
"Verify conversation appears in sidebar"
],
"passes": false
}编码 agent 被提示只能通过更改 passes 字段的状态来编辑此文件。"删除或编辑测试是不可接受的,因为这可能导致功能缺失或存在 bug。"经过一些实验后,选择 JSON 格式,因为与 Markdown 文件相比,模型不太可能不恰当地更改或覆盖 JSON 文件。
增量进展
有了这个初始环境脚手架,编码 agent 的下一次迭代被要求一次只处理一个功能。这种增量方法对于解决 agent 一次做太多事情的倾向至关重要。
一旦开始增量工作,模型在做出代码更改后使环境处于干净状态仍然至关重要。引发这种行为的最佳方式是要求模型用描述性的提交信息将其进度提交到 git,并在进度文件中编写其进展摘要。这使模型能够使用 git 还原糟糕的代码更改并恢复代码库的工作状态。
这些方法还提高了效率,因为它们消除了 agent 必须猜测发生了什么并花时间试图让基本应用重新运行的需要。
测试
观察到的最后一个主要失败模式是 Claude 在没有适当测试的情况下将功能标记为完成的倾向。在没有明确提示的情况下,Claude 倾向于进行代码更改,甚至用单元测试或对开发服务器的 curl 命令进行测试,但未能识别出该功能端到端不工作。
在构建 Web 应用的情况下,一旦明确提示使用浏览器自动化工具并像人类用户那样进行所有测试,Claude 在端到端验证功能方面表现得相当不错。
为 Claude 提供这类测试工具显著提高了性能,因为 agent 能够识别和修复仅从代码看不容易发现的 bug。
一些问题仍然存在,比如 Claude 的视觉能力和浏览器自动化工具的限制,使得难以识别每种类型的 bug。例如,Claude 无法通过 Puppeteer MCP 看到浏览器原生的警告模态框,依赖这些模态框的功能因此往往有更多 bug。
进入状态
有了以上所有内容,每个编码 agent 都被提示运行一系列步骤来了解情况,有些相当基础但仍有帮助:
运行
pwd查看你正在工作的目录。你只能编辑此目录中的文件。读取 git 日志和进度文件以了解最近的工作内容。
读取功能列表文件,选择尚未完成的最高优先级功能来处理。
这种方法在每个会话中为 Claude 节省了一些 token,因为它不必弄清楚如何测试代码。还可以要求初始化 agent 编写一个可以运行开发服务器的 init.sh 脚本,然后在实现新功能之前运行基本的端到端测试。
在 claude.ai 克隆的案例中,这意味着 agent 总是启动本地开发服务器并使用 Puppeteer MCP 开始新对话、发送消息并接收响应。这确保 Claude 能够快速识别应用是否处于损坏状态,并立即修复任何现有 bug。如果 agent 转而开始实现新功能,它可能会使问题变得更糟。
一个典型的会话以以下助手消息开始:
[Assistant] I'll start by getting my bearings and understanding the current state of the project.
[Tool Use] <bash - pwd>
[Tool Use] <read - claude-progress.txt>
[Tool Use] <read - feature_list.json>
[Assistant] Let me check the git log to see recent work.
[Tool Use] <bash - git log --oneline -20>
[Assistant] Now let me check if there's an init.sh script to restart the servers.
<Starts the development server>
[Assistant] Excellent! Now let me navigate to the application and verify that some fundamental features are still working.
<Tests basic functionality>
[Assistant] Based on my verification testing, I can see that the fundamental functionality is working well. The core chat features, theme switching, conversation loading, and error handling are all functioning correctly. Now let me review the tests.json file more comprehensively to understand what needs to be implemented next.
<Starts work on a new feature>Agent 失败模式与解决方案
| 问题 | 初始化 Agent 行为 | 编码 Agent 行为 |
|---|---|---|
| Claude 过早宣布整个项目完成。 | 设置功能列表文件:根据输入规范,设置一个包含端到端功能描述列表的结构化 JSON 文件。 | 在会话开始时读取功能列表文件。选择一个功能开始处理。 |
| Claude 使环境处于存在 bug 或进度未记录的状态。 | 编写初始 git 仓库和进度笔记文件。 | 通过读取进度笔记文件和 git 提交日志开始会话,并在开发服务器上运行基本测试以捕获任何未记录的 bug。通过编写 git 提交和进度更新结束会话。 |
| Claude 过早将功能标记为完成。 | 设置功能列表文件。 | 自我验证所有功能。仅在仔细测试后将功能标记为"通过"。 |
| Claude 必须花时间弄清楚如何运行应用。 | 编写一个可以运行开发服务器的 init.sh 脚本。 | 通过读取 init.sh 开始会话。 |
未来工作
这项研究展示了长时间运行 agent harness 中可能的一组解决方案,使模型能够在多个上下文窗口中取得增量进展。然而,仍存在开放性问题。
最值得注意的是,单个通用编码 agent 是否在跨上下文方面表现最佳,还是通过多 agent 架构可以实现更好的性能,这仍不清楚。专用 agent(如测试 agent、质量保证 agent 或代码清理 agent)在软件开发生命周期中的子任务上可能做得更好,这似乎是合理的。
此外,此演示针对全栈 Web 应用开发进行了优化。未来的方向是将这些发现推广到其他领域。这些经验中的部分或全部很可能可以应用于其他领域所需的长时间运行 agentic 任务,例如科学研究或金融建模。
致谢
由 Justin Young 撰写。特别感谢 David Hershey、Prithvi Rajasakeran、Jeremy Hadfield、Naia Bouscal、Michael Tingley、Jesse Mu、Jake Eaton、Marius Buleandara、Maggie Vo、Pedram Navid、Nadine Yasser 和 Alex Notov 的贡献。
这项工作反映了 Anthropic 多个团队的集体努力,他们使 Claude 能够安全地进行长时域自主软件工程,特别是代码 RL 和 Claude Code 团队。有兴趣贡献的候选人欢迎在 anthropic.com/careers 申请。
脚注
- 我们在此上下文中将它们称为独立的 agent,仅因为它们具有不同的初始用户提示词。系统提示词、工具集和整体 agent harness 在其他方面是相同的。