原文: English original · Anthropic/OpenAI 官方

长时间运行 agents 的有效 harness

发布于 2025 年 11 月 26 日

Agents 在跨多个 context windows 工作时仍然面临挑战。我们从人类工程师的工作方式中获得启发,为长时间运行的 agents 创建了更有效的 harness。

随着 AI agents 能力不断增强,开发者越来越希望它们承担复杂任务,而这类任务往往需要持续数小时,甚至数天。然而,如何让 agents 在多个 context windows 之间持续取得稳定进展,仍然是一个未解决的问题。

长时间运行 agents 的核心挑战在于:它们必须在离散的 sessions 中工作,而每个新的 session 开始时,都不记得之前发生过什么。可以想象一个由工程师轮班参与的软件项目:每位新工程师到岗时,都不知道上一班发生了什么。由于 context windows 有限,而大多数复杂项目又无法在单个 window 内完成,agents 需要一种方式来弥合 coding sessions 之间的断层。

我们开发了一套两部分方案,使 Claude Agent SDK 能够跨多个 context windows 有效工作:一个 initializer agent 在首次运行时设置环境;一个 coding agent 负责在每个 session 中取得增量进展,并为下一个 session 留下清晰的 artifacts。你可以在配套的 quickstart 中找到代码示例。

长时间运行 agent 的问题

Claude Agent SDK 是一个强大、通用的 agent harness,擅长 coding,也适用于其他需要模型使用工具来收集上下文、制定计划并执行的任务。它具备 context management 能力,例如 compaction,这使 agent 能够在不耗尽 context window 的情况下处理任务。理论上,在这样的设置下,agent 应该可以无限期地持续做有用的工作。

然而,compaction 并不够。开箱即用时,即使是像 Opus 4.5 这样的前沿 coding model,在 Claude Agent SDK 上跨多个 context windows 循环运行,如果只给它一个高层级 prompt,例如“构建一个 claude.ai 的克隆”,它也无法构建出生产质量的 web app。

Claude 的失败主要表现为两种模式。首先,agent 往往会试图一次做太多事,本质上是在尝试 one-shot 整个应用。很多时候,这会导致模型在实现过程中耗尽 context,让下一个 session 面对一个只实现了一半、且没有文档记录的功能。随后,agent 不得不猜测之前发生了什么,并花费大量时间试图让基础应用重新正常运行。

即便有 compaction,这种情况也会发生,因为 compaction 并不总是能把足够清晰的指令传递给下一个 agent。

第二种失败模式通常出现在项目后期。在一些功能已经构建完成后,后续某个 agent instance 会查看当前项目,看到已经取得了一些进展,然后宣布任务完成。

这把问题拆成了两个部分。第一,我们需要设置一个初始环境,为给定 prompt 所要求的全部功能打好基础,让 agent 能够一步一步、逐个功能地工作。第二,我们应该 prompt 每个 agent 朝目标取得增量进展,并在 session 结束时让环境保持干净状态。

所谓“干净状态”,指的是适合合并到 main branch 的那类代码:没有重大 bug,代码有条理、文档清晰;通常情况下,开发者可以直接开始一个新功能,而不必先清理无关的混乱。

在内部实验中,我们用一个两部分方案解决了这些问题:

  1. Initializer agent:第一个 agent session 使用专门的 prompt,要求模型设置初始环境:一个 init.sh 脚本、一个记录 agents 已完成事项的 claude-progress.txt 文件,以及一个展示新增文件的初始 git commit。
  2. Coding agent:之后的每个 session 都要求模型取得增量进展,然后留下结构化更新。1

这里的关键洞见是:找到一种方式,让 agents 在以全新的 context window 启动时,能够快速理解当前工作状态。这是通过 claude-progress.txt 文件和 git history 共同实现的。这些实践的灵感,来自我们对高效软件工程师日常工作方式的观察。

环境管理

在更新后的 Claude 4 prompting guide 中,我们分享了一些 multi-context window workflows 的最佳实践,其中包括一种 harness 结构,会使用“a different prompt for the very first context window”。这个“different prompt”会要求 initializer agent 设置环境,并纳入未来 coding agents 有效工作所需的全部必要上下文。在这里,我们会更深入地介绍这类环境的几个关键组成部分。

功能列表

为了解决 agent one-shot 一个应用,或过早认为项目已经完成的问题,我们 prompt initializer agent 编写一份全面的功能需求文件,对用户最初的 prompt 进行展开。

claude.ai 克隆示例中,这意味着超过 200 个功能,例如“用户可以打开一个新聊天,输入查询,按下回车,并看到 AI 回复”。这些功能最初全部标记为“failing”,这样后续 coding agents 就能清楚了解完整功能应该是什么样子。

{
  "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
}

我们 prompt coding agents 只能通过更改 passes 字段的状态来编辑这个文件,并使用措辞强硬的指令,例如“It is unacceptable to remove or edit tests because this could lead to missing or buggy functionality.” 经过一些实验后,我们最终选择使用 JSON 来做这件事,因为与 Markdown 文件相比,模型不太容易不恰当地更改或覆盖 JSON 文件。

增量进展

有了这个初始环境脚手架后,下一轮 coding agent 会被要求一次只处理一个功能。事实证明,这种增量方法对于纠正 agent 一次做太多事的倾向至关重要。

即使开始增量工作后,模型在完成代码修改后让环境保持干净状态仍然很重要。在我们的实验中,引导这种行为的最佳方式,是要求模型用描述性的 commit messages 把进展提交到 git,并在进展文件中写下进展摘要。这让模型可以使用 git 回滚糟糕的代码修改,并恢复代码库的可工作状态。

这些方法也提高了效率,因为 agent 不再需要猜测之前发生了什么,也不必把时间花在让基础应用重新跑起来上。

测试

我们观察到的最后一个主要失败模式,是 Claude 倾向于在没有充分测试的情况下把功能标记为完成。如果没有明确 prompt,Claude 往往会修改代码,甚至通过 unit tests 或针对 development server 的 curl 命令做测试,却没能意识到这个功能并没有 end-to-end 地工作。

在构建 web app 的场景中,一旦明确 prompt Claude 使用 browser automation tools,并像人类用户一样完成所有测试,它通常能够很好地 end-to-end 验证功能。

Claude 通过 Puppeteer MCP server 测试 claude.ai 克隆时截取的屏幕截图。

Claude 通过 Puppeteer MCP server 测试 claude.ai 克隆时截取的屏幕截图。

为 Claude 提供这类测试工具显著提升了表现,因为 agent 能够识别并修复那些仅从代码本身并不明显的 bug。

仍然存在一些问题,例如 Claude 的视觉能力和 browser automation tools 的局限,会让识别每一种 bug 变得困难。举例来说,Claude 无法通过 Puppeteer MCP 看到浏览器原生的 alert modals,因此依赖这些 modals 的功能往往更容易出 bug。

快速进入状态

在上述所有设置就位后,每个 coding agent 都会被 prompt 按一系列步骤熟悉情况,其中有些步骤非常基础,但仍然有帮助:

  1. 运行 pwd,查看你正在其中工作的目录。你只能编辑这个目录中的文件。
  2. 阅读 git logs 和进展文件,了解最近完成了哪些工作。
  3. 阅读功能列表文件,并选择尚未完成的最高优先级功能来处理。

这种方法在每个 session 中都能为 Claude 节省一些 tokens,因为它不需要自己弄清楚如何测试代码。要求 initializer agent 编写一个可以运行 development server 的 init.sh 脚本,也很有帮助;随后在实现新功能之前,先跑一遍基础 end-to-end test。

在 claude.ai 克隆的例子中,这意味着 agent 总是会先启动本地 development server,并使用 Puppeteer MCP 开始一个新聊天、发送消息并接收回复。这确保 Claude 能够快速识别应用是否被留在了损坏状态,并立即修复任何既有 bug。如果 agent 反而直接开始实现新功能,它很可能会让问题变得更糟。

考虑到这些,典型 session 会从以下 assistant messages 开始:

[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 失败模式与解决方案

问题Initializer agent 行为Coding agent 行为
Claude 过早宣布整个项目已经成功。设置功能列表文件:基于输入规格,设置一个结构化 JSON 文件,其中包含 end-to-end 功能描述列表。在 session 开始时读取功能列表文件。选择单个功能开始处理。
Claude 让环境处于有 bug 或进展未记录的状态。写入一个初始 git repo 和进展 notes 文件。在 session 开始时阅读进展 notes 文件和 git commit logs,并在 development server 上运行基础测试,以捕获任何未记录的 bug。在 session 结束时写入 git commit 和进展更新。
Claude 过早把功能标记为完成。设置功能列表文件。自行验证所有功能。只有经过仔细测试后,才将功能标记为“passing”。
Claude 必须花时间弄清楚如何运行应用。编写一个能够运行 development server 的 init.sh 脚本。在 session 开始时阅读 init.sh

总结长时间运行 AI agents 的四种常见失败模式和解决方案。

未来工作

这项研究展示了长时间运行 agent harness 中一组可能的解决方案,使模型能够跨多个 context windows 取得增量进展。然而,仍然存在一些开放问题。

最值得注意的是,目前仍不清楚单个通用 coding agent 是否在跨 contexts 时表现最佳,还是可以通过 multi-agent architecture 获得更好的性能。看起来,像 testing agent、quality assurance agent 或 code cleanup agent 这样的专门 agents,也许可以在软件开发生命周期的各类子任务中做得更好。

此外,这个 demo 针对 full-stack web app development 进行了优化。未来方向之一,是把这些发现泛化到其他领域。很可能其中一部分或全部经验,可以应用到例如科学研究或金融建模所需的长时间运行 agentic tasks 中。

致谢

作者 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 能够安全地完成 long-horizon autonomous software engineering,尤其是 code RL 和 Claude Code 团队。有兴趣贡献的候选人,欢迎通过 anthropic.com/careers 申请。

脚注


  1. 在这个语境中,我们把它们称为独立的 agents,仅仅是因为它们有不同的初始 user prompts。除此之外,system prompt、工具集合和整体 agent harness 都是相同的。 ↩︎