长期运行智能体的有效机制

随着 AI 智能体能力不断提升,开发者越来越希望它们能承担那些需要耗时数小时甚至数天的复杂任务。然而,让智能体在多个上下文窗口之间持续稳定地推进任务,仍然是一个未解决的问题。

长期运行的智能体面临的核心挑战在于:它必须以离散的会话(session)形式工作,而 每个新会话都从零记忆开始。想象一个软件项目被分配给倒班工程师,每位工程师上岗时都完全不了解上一班发生了什么。由于上下文窗口是有限的,而大多数复杂项目无法在单一窗口内完成,因此智能体必须具备某种“桥接机制”来跨越多轮会话推进任务。

为此,我们为 Claude Agent SDK 设计了一套两部分组成的方案,使智能体能够在极多的上下文窗口中持续有效地工作:

  • 初始化智能体(initializer agent):仅在首次运行时执行,用于搭建环境。
  • 编码智能体(coding agent):在之后的每个会话中执行,负责逐步推进任务,并留下清晰的进度记录。

对应的示例代码可在 quickstart 项目中找到。

长期运行智能体的问题

Claude Agent SDK 是一个强大的通用代理框架,擅长编码,也适用于需要模型使用工具构建上下文、规划和执行的各种任务。SDK 具备上下文管理能力,如“压缩(compaction)”,使智能体能够在不耗尽上下文窗口的情况下继续处理任务。从理论上说,给定这些机制,智能体应该能够无限期地持续产生有效工作。

然而,仅靠 compaction 并不足够。即使是像 Opus 4.5 这样的前沿编码模型,在 Claude Agent SDK 中跨多个上下文窗口循环执行时,如果只给予诸如“构建一个 claude.ai 的克隆”这样的高度抽象提示,它仍无法构建出生产质量的 Web 应用。

我们在实验中观察到 Claude 存在两类常见失败模式:

失败模式一:智能体试图“一次性完成整个应用”

模型往往会尝试一次性构建整个应用。
这种情况下,模型通常会在实现过程中耗尽上下文,导致新会话从“半完成、无文档”的代码状态开始。接班的智能体需要猜测之前发生了什么,并花大量时间试图让应用重新运行。即便启用了上下文压缩,这个问题仍然会发生,因为压缩后的信息并不总是足够清晰。

失败模式二:智能体过早宣布任务完成

在项目进入中后期后,某些轮次的智能体会看到已有部分功能完成,然后误认为“项目已经完成”,从而停止继续开发。

我们将问题分解为两个部分:

  1. 搭建一个为后续所有功能奠定基础的初始环境,确保智能体以逐步、按功能推进的方式工作。
  2. 每轮智能体都必须在保持环境整洁的前提下做出增量进展
    “整洁状态(clean state)”意味着代码达到可以合并到主分支的质量:
    • 没有重大 bug
    • 结构清晰、有良好文档
    • 开发者可以直接基于该状态继续工作,而无需先清理混乱的环境

我们内部实验采用的两阶段方案如下:

  1. 初始化智能体(Initializer agent)
    在首次会话中,使用一个特殊提示,让模型搭建初始环境,包括:
    • 生成 init.sh 脚本
    • 创建 claude-progress.txt 记录进度
    • 创建首个 git 提交(记录初始文件)
  2. 编码智能体(Coding agent)
    在之后每次会话中:
    • 让模型推进一个小功能
    • 并留下结构化的更新记录

核心洞察是:
必须找到一种方法,让智能体在“全新上下文窗口”中能迅速理解当前项目状态,这由 claude-progress.txt 和 Git 历史共同实现。
这些实践灵感来自优秀软件工程师的日常工作方式。

环境管理

在新版 Claude 4 prompt 指南中,我们提出了多上下文窗口工作流的最佳实践,其中包括在“首个上下文窗口使用特别提示”的方法。这个“特别提示”会要求初始化智能体搭建未来所有编码智能体需要的环境。下面我们更深入地讲解环境中的关键组成部分。

功能列表(Feature list)

为解决智能体一口气完成应用或过早宣布完成的问题,我们让初始化智能体生成一个详尽的“功能需求文件”,扩展用户初始提示。在克隆 claude.ai 的示例中,这意味着生成超过 200 个功能,例如:

“用户可以新建对话、输入内容、按下回车并看到 AI 回复。”

所有功能初始都标记为 "passes": false,使后续编码智能体明确完整应用应包含什么功能。

示例:

{
    "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 内容。

增量式进展

在环境搭建完成后,每个编码智能体会被要求 一次只实现一个功能(feature)
这种增量式方式对解决“一次做太多”的问题至关重要。

在逐步工作时,智能体仍必须保持环境整洁。
我们发现实现这一点的最佳方式是:

  • 要求模型使用 Git 提交代码
  • 生成清晰的 commit 信息
  • 更新进度文件(progress file)

这使模型可以通过 Git 恢复稳定状态,也避免了需要猜测之前发生了什么。

此外,这大大提升了效率,因为减少了“智能体必须花大量 token 去理解上一次做了什么”的情况。

测试(Testing)

我们观察到另一个主要失败模式是:

Claude 会在没有充分测试的情况下将功能标记为“完成”。

如果没有显式提示,Claude 虽然会执行代码修改,也可能运行单元测试或使用 curl 对开发服务器发请求,但常常无法意识到功能未真正端到端工作。

对于 Web 应用,当我们显式要求它使用浏览器自动化工具模拟真实用户操作时,它在端到端测试方面表现良好。

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

通过提供这些测试工具,性能显著提升,模型能修复许多从代码视角难以察觉的 bug。

仍然存在一些限制,例如:

  • Claude 无法通过 Puppeteer MCP 看到浏览器原生弹窗
  • 依赖这些弹窗的功能会更容易出问题

进入状态(Getting up to speed)

在上述机制就绪后,每轮编码智能体都会按以下步骤进入状态:

  1. 运行 pwd 查看当前目录(模型只能编辑此目录中的文件)
  2. 读取 git 日志和 progress 文件,了解最近进展
  3. 读取 feature list 文件,选择最高优先级且未完成的功能来实现

这种方式可节省每轮的 token,因为模型无需重新思考如何运行测试。

我们也要求初始化智能体生成 init.sh 用于启动开发服务器,并在实现新功能前执行一次端到端基本测试。

例如在 claude.ai 克隆项目中,智能体总是:

  • 启动本地开发服务器
  • 使用 Puppeteer MCP
    • 新建对话
    • 发送消息
    • 收到回复

这确保智能体能立即发现环境是否损坏,并快速修复。如果智能体直接开始实现新功能,可能会导致问题恶化。

下面是典型的会话开始示例(原格式保留):

[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 过早宣布项目已完成 创建功能列表文件,包含完整端到端功能描述 读取功能列表,选择单一功能进行实现
Claude 将环境置于混乱 / 有 bug 状态 写入初始 Git repo 和 progress 文件 会话开始时读取 progress 和 git log,并执行基本测试;会话结束时提交 commit
Claude 提前将功能标记为“通过” 创建功能列表文件 严格自我验证,仅在完整测试通过后标记 "passes": true
Claude 花大量时间摸索如何运行应用 写入 init.sh 脚本 会话开始时读取并执行 init.sh

未来方向(Future work)

本研究展示了一种在长期运行的智能体框架中,使模型在众多上下文窗口中取得增量进展的可行方案。但仍存在开放问题。

最突出的是:

在跨多会话任务中,是单一通用编码智能体效果最佳?还是多智能体协作效果更好?

例如:

  • 测试智能体
  • 质量保障(QA)智能体
  • 代码清理智能体

这些更专业的智能体可能在各自子任务中表现更强。

此外,当前示例主要针对全栈 Web 应用开发进行了优化。未来方向包括:

  • 将这些经验推广到其他领域
  • 包括科学研究、金融建模等需要长程 agent 的任务

我们相信这些经验对这些领域同样适用。

鸣谢

本文作者: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 多个团队的共同努力,尤其是 code RL 与 Claude Code 团队。
如果你希望参与我们的工作,欢迎加入:anthropic.com/careers

注释

  1. 此处之所以称为“两个智能体”,仅因为它们的初始用户提示不同。系统提示、工具集合以及整体框架保持一致。

来源:https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents