随着 AI 智能体(AI Agent)的能力日益强大,开发者开始将越来越复杂的任务交给它们——这些任务往往需要数小时甚至数天的持续工作。然而,如何让智能体在跨越多个上下文窗口(context window)时依然保持稳定的进展,至今仍是一个尚未解决的难题。

长时间运行智能体的核心挑战在于:它们只能在一个个独立的会话中展开工作,而每一次新会话都从一片空白开始,对之前发生的一切毫无记忆。想象一下,一个软件项目由多名工程师轮班完成,但每位新到岗的工程师对上一班发生了什么完全失忆。由于上下文窗口容量有限,而大多数复杂项目又无法在单个窗口内完成,智能体迫切需要一种方法来弥合编码会话之间的断层。

我们开发了一套双管齐下的方案,让 Claude Agent SDK 能够高效地跨越多个上下文窗口工作:一个初始化智能体(initializer agent)负责在首次运行时搭建环境,一个编码智能体(coding agent)负责在每次会话中推进增量进展,同时为下一次会话留下清晰的工作产出。相关代码示例可以在配套的快速入门项目中找到。

Tldr

长周期智能体的关键不是”无限长上下文”,而是跨会话的状态交接。用初始化智能体搭建功能列表、进度文件与 git 仓库,让后续编码智能体能够快速进入状态、增量推进、并将环境留在干净状态。

长时间运行智能体的困局

Claude Agent SDK 是一个功能强大的通用智能体编排框架(harness),擅长编码以及其他需要模型使用工具来收集上下文、规划和执行的任务。它具备上下文管理能力,比如上下文压缩(compaction)——自动精简旧上下文的机制——让智能体能够持续处理任务而不会耗尽上下文窗口。理论上,有了这样的机制,智能体应该能在任意长的时间内持续产出有价值的工作。

然而,仅靠上下文压缩还远远不够。在默认配置下,即使是像 Opus 4.5 这样的前沿编码模型,在 Claude Agent SDK 上跨多个上下文窗口循环运行,如果只给一个高层级的提示词——比如”克隆一个 claude.ai”——它也难以构建出一个生产级别的 Web 应用。

Claude 的失败表现为两种模式。第一种,智能体倾向于一次做太多事情——本质上是试图一把梭完成整个应用。这往往导致模型在实现过程中耗尽上下文,留给下一个会话一个半成品的功能和毫无文档的烂摊子。新会话的智能体只能靠猜测来理解之前发生了什么,然后花费大量时间试图让基础应用重新运行起来。即使有上下文压缩也无法完全避免这个问题,因为压缩后传递给下一个智能体的指令并不总是足够清晰。

第二种失败模式通常出现在项目后期。当一些功能已经实现后,后续的智能体实例四处查看,发现已有不少进展,便直接宣告任务完成。

由此,问题可以拆解为两个部分。首先,我们需要搭建一个初始环境,为给定提示词所要求的所有功能奠定基础,引导智能体一步一步、一个功能一个功能地推进。其次,我们应该提示每个智能体在每次会话中向目标做出增量进展,同时在会话结束时将环境留在一个干净状态(clean state)。所谓”干净状态”,指的是代码达到可以合入主分支的标准:没有重大 bug,代码整洁且有良好文档,开发者可以直接在此基础上开始新功能的开发,而不用先收拾一堆无关的烂摊子。

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

  1. 初始化智能体:第一个智能体会话使用专门的提示词,要求模型搭建初始环境——包括一个 init.sh 脚本、一个 claude-progress.txt 进度文件(progress file)用于记录各次智能体的工作日志,以及一个初始 git 提交来展示新增了哪些文件。
  2. 编码智能体:此后的每次会话都要求模型推进增量进展,然后留下结构化的更新记录。1

这里的关键洞察在于:找到一种方法,让智能体在面对全新的上下文窗口时能够快速摸清当前状况。这通过 claude-progress.txt 文件配合 git 历史记录来实现。这些实践的灵感来源于对高效软件工程师日常工作方式的观察。

环境管理

在更新后的 Claude 4 提示词指南中,我们分享了多上下文窗口工作流的一些最佳实践,其中包括一种编排框架结构——“在第一个上下文窗口使用不同的提示词”。这个”不同的提示词”要求初始化智能体搭建好环境,配备未来编码智能体高效工作所需的所有上下文信息。接下来,我们深入探讨这种环境的几个关键组成部分。

功能列表

为了解决智能体试图一把梭完成应用或过早认为项目已完成的问题,我们提示初始化智能体编写一份详尽的功能需求文件(feature list),对用户的初始提示词进行扩展细化。以克隆 claude.ai 为例,这意味着超过 200 个功能条目,例如”用户可以打开新对话、输入查询、按回车键并看到 AI 回复”。这些功能初始状态全部标记为”未通过”,让后续的编码智能体对完整功能的全貌一目了然。

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

我们提示编码智能体在编辑这份文件时只能修改 passes 字段的状态,并使用措辞强硬的指令,比如”删除或修改测试条目是不可接受的行为,因为这可能导致功能缺失或产生 bug”。经过多次实验,我们最终选择使用 JSON 格式来存储这份文件,因为相比 Markdown 文件,模型不太容易对 JSON 文件进行不当的修改或覆盖。

增量推进

在搭建好初始环境之后,下一轮迭代的编码智能体被要求每次只处理一个功能。事实证明,这种增量推进的方式对于解决智能体一次做太多事的倾向至关重要。

一旦开始增量工作,确保模型在每次代码修改后将环境留在干净状态同样至关重要。在我们的实验中,最有效的方法是要求模型将进展提交到 git 并附上描述性的提交信息,同时在进度文件中写下工作摘要。这使得模型可以利用 git 回滚糟糕的代码修改,恢复到代码库的正常工作状态。

这些做法也显著提升了效率——智能体不再需要费力猜测之前发生了什么,也不用把宝贵的时间花在让基础应用重新跑起来上面。

测试

我们观察到的最后一个重要失败模式是:Claude 倾向于在没有充分测试的情况下就将功能标记为完成。在没有明确提示的情况下,Claude 通常会修改代码,甚至会用单元测试或 curl 命令对开发服务器进行测试,但却无法识别出功能在端到端(end-to-end)层面并未真正生效。

在构建 Web 应用的场景中,一旦明确提示 Claude 使用浏览器自动化(browser automation)工具并像真实用户一样进行测试,它在端到端验证方面的表现就相当出色了。

Claude 通过 Puppeteer MCP 服务器截取的截图,展示了它测试 claude.ai 克隆应用的过程。

为 Claude 提供这类测试工具极大地提升了表现——智能体能够发现并修复那些仅从代码层面难以察觉的 bug。

当然,一些问题仍然存在。Claude 的视觉能力和浏览器自动化工具的局限性使得它无法识别所有类型的 bug。例如,Claude 无法通过 Puppeteer MCP 看到浏览器原生的 alert 弹窗,因此依赖这些弹窗的功能往往 bug 更多。

快速进入状态

有了以上所有机制,每个编码智能体在启动时都会按照一系列步骤来摸清当前状况。有些步骤看起来很基础,但确实很有帮助:

  1. 运行 pwd 查看当前工作目录。你只能编辑这个目录下的文件。
  2. 阅读 git 日志和进度文件,了解最近完成了哪些工作。
  3. 阅读功能列表文件,选择优先级最高且尚未完成的功能开始工作。

这套方法为 Claude 在每次会话中节省了不少 token,因为它不必自己去摸索如何测试代码。同时,让初始化智能体编写一个 init.sh 脚本来启动开发服务器也很有帮助——在实现新功能之前先跑一遍基础的端到端测试。

以克隆 claude.ai 为例,这意味着智能体总是先启动本地开发服务器,然后用 Puppeteer MCP 发起一个新对话、发送一条消息并接收回复。这确保了 Claude 能够迅速发现应用是否处于损坏状态,并立即修复已有的 bug。而如果智能体选择先实现新功能而非先测试,反而很可能让问题雪上加霜。

在这套机制下,一个典型的会话开始时会产生以下助手消息:

[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>

智能体失败模式与解决方案

问题初始化智能体的行为编码智能体的行为
Claude 过早宣告整个项目完成。创建功能列表文件:基于输入规格,建立一个结构化的 JSON 文件,包含端到端功能描述的完整列表。在会话开始时阅读功能列表文件,选择一个功能开始工作。
Claude 将环境留在有 bug 或进展未记录的状态。创建初始 git 仓库和进度记录文件。会话开始时阅读进度记录文件和 git 提交日志,在开发服务器上运行基础测试以捕获未记录的 bug。会话结束时提交 git 并更新进度记录。
Claude 过早将功能标记为完成。创建功能列表文件。自行验证所有功能。仅在经过仔细测试后才将功能标记为”通过”。
Claude 需要花时间弄清楚如何运行应用。编写 init.sh 脚本以启动开发服务器。会话开始时阅读 init.sh

长时间运行 AI 智能体中四种常见失败模式及解决方案一览。

未来方向

本研究展示了一组在长时间运行智能体编排框架中可能的解决方案,使模型能够跨越多个上下文窗口实现增量推进。然而,仍有一些开放性问题有待探索。

最值得关注的是:单一的通用编码智能体是否在跨上下文场景中表现最佳,还是通过多智能体架构(multi-agent architecture)能取得更好的效果?合理的推测是,专业化的智能体——比如测试智能体、质量保障智能体或代码清理智能体——在软件开发生命周期的各个子任务上可能做得更出色。

此外,本次演示针对全栈 Web 应用开发进行了优化。未来的方向是将这些发现推广到其他领域。这些经验中的部分甚至全部很可能适用于其他类型的长时间运行智能体任务,例如科学研究或金融建模。

相关笔记

致谢

本文由 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 能够安全地执行长周期的自主软件工程任务,特别是 code RL 和 Claude Code 团队。感兴趣的候选人欢迎在 anthropic.com/careers 提交申请。

脚注

1. 我们在此语境中将它们称为不同的智能体,只是因为它们具有不同的初始用户提示词。系统提示词、工具集和整体编排框架在其他方面完全相同。