Effective harnesses for long-running agents

Anthropic is an AI safety and research company that's working to build reliable, interpretable, and steerable AI systems.

www.anthropic.com

随着 AI 智能体(Agents)能力的增强,开发者开始要求它们处理跨越数小时甚至数天的复杂任务。然而,让智能体在多个上下文窗口(Context Windows)中保持一致的进度仍是一个难题。核心挑战在于,长时运行的智能体必须以离散的“会话”形式工作,而每个新会话开始时都没有之前的记忆,就像一群轮班工作的工程师,每个人到岗时都不知道前一班发生了什么。

为了解决这一“失忆”问题,Anthropic 开发了一套双重方案,并集成在 Claude Agent SDK 中。该方案包含两个核心角色:初始化智能体(Initializer Agent)编码智能体(Coding Agent)。初始化智能体负责在首次运行时搭建环境,包括创建功能列表(JSON 格式)、初始化 Git 仓库、编写环境启动脚本(init.sh)以及进度记录文件(claude-progress.txt)。编码智能体则负责在后续的每个会话中进行增量开发,确保每次只处理一个功能,并在结束时留下清晰的工件(Artifacts)供下一班次使用。

研究发现,智能体常见的失败模式包括:试图一次性完成所有工作(One-shotting)导致上下文耗尽、在功能未完成时过早宣布胜利、以及缺乏端到端测试。通过引入结构化的 JSON 功能清单、强制性的 Git 提交记录以及基于 Puppeteer 的浏览器自动化测试,Claude 能够更有效地识别 Bug 并保持代码库的整洁。这种方法不仅提高了开发效率,还确保了智能体在进入新会话时能通过运行 pwd、阅读日志和执行初始化脚本快速进入状态。尽管仍存在视觉识别局限等挑战,但这一框架为长时运行的 AI 协作提供了可行的工程路径。


长期运行智能体的核心挑战与失败模式

在开发复杂的软件项目时,AI 智能体面临的最显著障碍是上下文窗口的局限性。尽管 Claude Agent SDK 具备上下文压缩(Compaction)功能,但这不足以支撑跨越数天的大型任务。长时运行的智能体本质上是在进行“离散会话”,每个新会话就像是一个没有任何前序记忆的新员工。如果缺乏有效的衔接机制,智能体往往会陷入几种典型的失败模式。

首先是“过度尝试”模式。智能体倾向于尝试一次性完成整个应用程序(One-shotting),而不是分步骤进行。这会导致它在实现过程中耗尽上下文空间,留下半成品且无文档的代码。当下一个会话开始时,新的智能体必须猜测之前的进度,浪费大量时间修复基础功能。其次是“过早宣布胜利”。在项目后期,智能体看到已经有部分代码存在,可能会误以为任务已完成,从而停止工作。此外,智能体还经常在没有进行端到端测试的情况下标记功能为“已完成”。它们可能通过了单元测试,但由于没有模拟真实用户的操作流程,导致应用在实际运行时崩溃。这些问题的根源在于缺乏一个能够跨会话传递的、清晰的“环境状态”和“工作蓝图”。

为了克服这些问题,必须将任务分解,并建立一套严密的“交接棒”机制。这要求环境在每个会话结束时都处于“干净状态”——即代码整洁、有文档记录、无重大 Bug,且能够直接合并到主分支。只有这样,后续的智能体才能在不清理前人留下的烂摊子的情况下,直接开始新功能的开发。

双智能体协作架构:初始化与增量编码

Anthropic 提出的解决方案是将任务分配给两个具有不同职责的智能体角色(本质上是使用不同提示词的同一模型)。第一部分是初始化智能体(Initializer Agent)。它的唯一任务是为整个项目奠定基础。在首次运行时,它会根据用户的原始需求,生成一份详尽的功能需求清单。为了防止智能体随意修改或遗漏需求,这份清单被设计为 JSON 格式,因为实验证明模型在处理 JSON 时比处理 Markdown 更严谨,不容易发生误删或覆盖。

初始化智能体还会创建几个关键工件:一个 init.sh 脚本(用于一键启动开发服务器和环境)、一个 claude-progress.txt 文件(记录详细的操作日志)以及初始的 Git 提交。这种做法借鉴了人类软件工程师的最佳实践,确保项目从第一天起就具备版本控制和进度追踪能力。

第二部分是编码智能体(Coding Agent)。在后续的每一个会话中,编码智能体都会遵循一套标准化的“入场流程”:首先运行 pwd 确认目录,接着阅读 Git 日志和进度文件以获取最新动态,然后从 JSON 清单中挑选优先级最高且未完成的功能进行开发。这种增量式的方法强制智能体每次只专注于一个任务,极大地降低了上下文溢出的风险。在会话结束前,编码智能体必须更新 JSON 清单中的功能状态,提交 Git 记录,并撰写进度总结。这种结构化的反馈循环确保了无论任务持续多久,每个会话都能在坚实的基础上继续推进。

环境管理、自动化测试与自我修复

为了确保智能体不仅是在写代码,而且是在构建可用的软件,环境管理和自动化测试至关重要。在功能清单的管理上,Anthropic 采用了“失败驱动开发”的逻辑。初始化智能体生成的 200 多个功能点(以 claude.ai 克隆版为例)最初都被标记为 passes: false。编码智能体只有在完成开发并通过验证后,才能将该字段改为 true。这种明确的量化指标防止了智能体因“感觉工作已完成”而产生的懈怠。

在测试方面,单纯的命令行工具(如 curl)往往无法捕捉前端交互中的复杂 Bug。因此,该方案引入了基于 Puppeteer MCP 服务器的浏览器自动化工具。智能体被要求像真实用户一样操作浏览器:打开页面、点击按钮、输入文字并观察反馈。通过视觉能力,Claude 可以截取屏幕截图并分析 UI 是否符合预期。这种端到端的测试能力显著提升了性能,使智能体能够发现那些仅凭代码逻辑难以察觉的视觉或交互错误。

此外,智能体的“自我修复”流程也被标准化。每个会话开始时,智能体都会运行 init.sh 启动服务器,并执行一次基础的功能检查。如果发现当前代码库处于损坏状态(Broken state),它会优先修复现有 Bug,而不是盲目开发新功能。这种“先稳固再扩张”的策略,配合 Git 的回滚能力,使得智能体在面对复杂项目时表现出极强的韧性和稳定性。虽然目前在处理浏览器原生弹窗(如 Alert 模态框)等方面仍有局限,但这种基于“环境感知”的开发模式已为长时运行 AI 树立了新的标杆。


原文摘录

  • "The core challenge of long-running agents is that they must work in discrete sessions, and each new session begins with no memory of what came before."(长时运行智能体的核心挑战在于它们必须在离散的会话中工作,且每个新会话开始时都没有之前的记忆。)
  • "Imagine a software project staffed by engineers working in shifts, where each new engineer arrives with no memory of what happened on the previous shift."(想象一个由轮班工程师组成的软件项目,每个新到岗的工程师都不知道前一班发生了什么。)
  • "The agent tended to try to do too much at once—essentially to attempt to one-shot the app."(智能体倾向于一次尝试做太多事情——本质上是试图‘一键生成’整个应用。)
  • "It is unacceptable to remove or edit tests because this could lead to missing or buggy functionality."(删除或编辑测试是不可接受的,因为这可能导致功能缺失或产生 Bug。)
  • "The key insight here was finding a way for agents to quickly understand the state of work when starting with a fresh context window."(这里的核心洞察是找到一种方法,让智能体在开启全新上下文窗口时能快速理解工作状态。)

问答

问:为什么简单的上下文压缩(Compaction)不足以解决长时运行智能体的问题? 答:因为压缩并不总能向下一个会话传递完美清晰的指令。如果没有结构化的进度记录,智能体在面对半成品代码时仍需猜测前人的意图,容易导致重复劳动或引入新 Bug。

问:为什么在功能清单中使用 JSON 格式优于 Markdown? 答:实验发现,模型在处理 JSON 时更不容易发生误操作、意外覆盖或删除关键信息,其结构化的特性强制模型遵循更严格的编辑逻辑。

问:初始化智能体(Initializer Agent)具体创建了哪些关键文件? 答:主要包括:1. feature_list.json(详细的功能需求清单);2. init.sh(环境启动脚本);3. claude-progress.txt(进度日志);4. 初始 Git 仓库。

问:编码智能体在每个会话开始时必须执行哪些步骤? 答:1. 运行 pwd 确认路径;2. 阅读 Git 日志和进度文件;3. 运行 init.sh 启动服务器并进行基础功能测试;4. 从清单中选择最高优先级的未完成任务。

问:浏览器自动化(如 Puppeteer)对智能体有什么帮助? 答:它允许智能体进行端到端(E2E)测试,模拟真实用户行为并利用视觉能力发现代码逻辑之外的 UI 或交互 Bug,防止智能体在功能未真正可用时过早标记为完成。