(译)长期运行 Agents 的高效驾驭方式(harness)
Anthropic 工程团队分享了如何让 AI Agent 在多个上下文窗口中保持持续且一致的进展:通过初始化 Agent 设置环境与功能列表,编码 Agent 增量开发并保持干净状态,结合端到端测试与进度文件,解决 Agent 贪多嚼不烂、过早宣布完工等核心失败模式。
本文为转载翻译文章,原作者:Anthropic

Agent 在跨越多个上下文窗口进行工作时仍然面临着挑战。为了给长周期运行的 Agent 创建一个更高效的驾驭方式(harness),我们从人类工程师那里汲取了灵感。
随着 AI Agent 变得越来越强大,开发者越来越多地要求它们承担起那些需要数小时甚至数天才能完成的复杂任务。然而,如何让 Agent 在多个上下文窗口(Context Windows)中保持持续且一致的进展,仍然是一个悬而未决的问题。
长周期运行 Agent 的核心挑战在于:它们必须在离散的会话(Sessions)中工作,而每个新会话启动时,都缺乏对前序工作的记忆。想象一个由轮班工程师负责的软件项目,如果每位新接班的工程师都不记得上一班发生了什么,项目推进将举步维艰。由于上下文窗口是有限的,加上大多数复杂项目无法在单一窗口内完成,Agent 需要一种方法来弥合不同编码会话之间的认知断层。
我们开发了一套"双管齐下"的解决方案,使 Claude Agent SDK 能够在大量上下文窗口中高效运作:首先是一个 "初始化 Agent (Initializer Agent)" ,负责在首次运行时设置环境;其次是一个 "编码 Agent (Coding Agent)",负责在每个会话中取得增量进展,同时为下一个会话留下清晰的工件记录。您可以在配套的快速入门指南中找到相关的代码示例。
长周期 Agent 面临的难题
Claude Agent SDK 是一个强大、通用的 Agent 驾驭方式(harness),它精通编码,也擅长处理其他需要模型调用工具来收集上下文、进行规划和执行的任务。它具备如"上下文压缩 (Compaction)"之类的记忆管理能力,这使得 Agent 能够持续处理任务而不至于耗尽上下文窗口。理论上,在这种设置下,Agent 应该能够持续不断地进行有价值的工作。
然而,仅靠"上下文压缩"是不够的。在默认状态下,即使是像 Opus 4.5 这样在 Claude Agent SDK 上跨多窗口循环运行的前沿编码模型,如果只收到一句诸如"构建一个 claude.ai 的克隆版"的高层级提示,也无法成功构建出生产级别的 Web 应用。
Claude 的失败情况主要表现为两种模式:
贪多嚼不烂
Agent 往往试图一次性做太多事情——本质上就是想"一步到位"完成整个应用。通常情况下,这会导致模型在代码实现的中途就耗尽上下文,使得下一个会话面对的是一个实现了一半且没有文档说明的半成品特性。新会话的 Agent 不得不靠猜测来弄清楚之前发生了什么,并花费大量时间试图让基础应用重新跑起来。即使使用了上下文压缩技术,这种情况依然会发生,因为压缩过程并不能总是将完美清晰的指令传递给下一个 Agent。
过早宣布完工
第二种失败模式通常发生在项目后期。在已经构建了某些功能之后,后续的 Agent 实例环顾四周,看到项目已经取得了一些进展,就会单方面宣布工作已完成。
这促使我们将问题拆解为两个部分:
第一,我们需要建立一个初始环境,为给定提示词(Prompt)所需的所有功能奠定基础,从而引导 Agent 有步骤地、逐个功能地进行开发。
第二,我们需要向每个 Agent 发出提示,要求其在朝着目标取得增量进展的同时,在会话结束时让环境保持"干净状态 (Clean State)"。这里的"干净状态"指的是那些随时可以合并到主分支的高质量代码:没有重大 Bug,代码整洁且注释/文档完善;总而言之,下一位开发者可以轻松地开始新功能的开发,而无需先去收拾一堆无关的烂摊子。
在内部实验中,我们使用了一个包含两部分的解决方案来应对这些问题:
初始化 Agent (Initializer Agent)
在最初的 Agent 会话中,我们使用专门的提示词,要求模型设置初始环境:编写一个 init.sh 脚本,创建一个记录 Agent 历史操作的 claude-progress.txt 文件,以及执行一次展示了新增文件的初始 Git 提交 (Git Commit)。
编码 Agent (Coding Agent)
在随后的每一次会话中,要求模型取得增量进展,并在结束时留下结构化的更新日志。
这里的关键洞见在于:找到一种方法,让 Agent 在以全新的上下文窗口启动时,能够快速了解当前的工作状态。 这正是通过 claude-progress.txt 文件和 Git 历史记录来实现的。这些实践经验的灵感,正是来源于我们对高效软件工程师日常工作方式的观察。
环境管理
在更新版的 Claude 4 提示词指南中,我们分享了一些多上下文窗口工作流的最佳实践,其中包含一种 harness 结构,即"在第一个上下文窗口中使用截然不同的提示词"。这个"不同的提示词"会指示初始化 Agent 搭建环境,并提供未来编码 Agent 高效工作所需的所有必要上下文。接下来,我们将深入探讨这种环境设置中的几个关键组件。
功能列表 (Feature list)
为了解决 Agent 试图"一步到位"或过早认为项目完工的问题,我们提示初始化 Agent 根据用户的初始需求,编写一份包含所有功能需求的全面文档。在"claude.ai 克隆版"的案例中,这意味着要列出 200 多个具体功能,例如"用户可以打开一个新的聊天窗口,输入查询,按下回车键,然后看到 AI 的回复"。所有这些功能在初始状态下都会被标记为"未通过 (Failing)",这样后续的编码 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 文件的可能性要低得多。
增量进展 (Incremental progress)
有了这些初始的环境脚手架,接下来就会要求后续的编码 Agent 一次只开发一个功能。事实证明,这种增量式的开发方法对于遏制 Agent "想一次做太多"的冲动至关重要。
一旦确立了增量工作模式,让模型在修改代码后保持环境干净整洁依然是必不可少的。在我们的实验中,要诱发这种良好习惯,最好的方法是:要求模型将其进度连同描述性的提交信息(Commit Messages)一起提交到 Git,并在进度文件中撰写进度摘要。这样一来,如果代码改乱了,模型就可以利用 Git 撤销错误的更改,将代码库恢复到可用的状态。
这些方法同时也提升了效率,因为 Agent 不再需要靠猜测来弄明白之前发生了什么,也不用再浪费时间去尝试修复基础应用使其重新运行了。
测试 (Testing)
我们观察到的最后一个主要失败模式是:Claude 倾向于在没有进行适当测试的情况下就把功能标记为"已完成"。如果不给予明确的提示,Claude 虽然也会修改代码,甚至会使用单元测试或通过 curl 命令对开发服务器进行测试,但它却意识不到该功能在"端到端 (End-to-End)"层面上根本无法正常运作。
在构建 Web 应用的场景下,只要明确提示 Claude 使用浏览器自动化工具,并要求它像人类用户一样进行所有测试,它在端到端验证功能方面的表现就会相当优异。
为 Claude 提供这类测试工具大幅提升了开发质量,因为 Agent 终于能够识别并修复那些光看代码无法察觉的 Bug 了。
当然,一些问题依然存在。例如,Claude 在视觉识别以及浏览器自动化工具上的局限性,导致它很难识别出每一种类型的 Bug。举个例子,Claude 无法通过 Puppeteer MCP 看到浏览器原生的弹窗(Alert Modals),因此那些依赖此类弹窗的功能往往更容易出 Bug。
快速进入状态 (Getting up to speed)
基于上述所有机制,每个编码 Agent 在启动时都会收到提示,要求其执行一系列标准步骤来摸清当前状况(虽然很基础,但非常有效):
-
运行 pwd 命令查看当前所在的工作目录。Agent 只能编辑此目录中的文件。
-
阅读 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 (Initializer Agent) 的行为设置 | 编码 Agent (Coding Agent) 的行为设置 |
|---|---|---|
| Claude 过早宣布整个项目已经完成。 | 设置功能列表文件:根据需求输入,建立一个包含端到端功能描述列表的结构化 JSON 文件。 | 在会话开始时阅读功能列表文件。挑选出单个功能开始开发。 |
| Claude 留下了一个充满 Bug 或未记录进度的烂摊子。 | 编写好初始的 Git 仓库和进度说明文件。 | 会话开始时读取进度说明文件和 Git 提交日志,并在开发服务器上运行基础测试以捕捉任何未记录的 Bug。会话结束时,编写好 Git 提交记录和进度更新。 |
| Claude 过早将功能标记为"已完成"。 | 设置功能列表文件。 | 自我验证所有功能。只有在仔细测试后,才能将功能标记为"已通过 (Passing)"。 |
| Claude 必须花时间去搞清楚如何运行这个应用。 | 编写一个可以直接运行开发服务器的 init.sh 脚本。 | 在会话开始时阅读并执行 init.sh。 |
表:长周期 AI Agent 中四种常见失败模式及解决方案的总结。
未来展望 (Future work)
这项研究展示了在长周期 Agent harness 中,一组能够让模型在多个上下文窗口间取得增量进展的有效解决方案。然而,仍有许多问题有待探索。
最值得关注的是:到底是单一的通用型编码 Agent 在跨语境下表现最好,还是采用多 Agent 架构(Multi-agent Architecture)能实现更高的性能? 这一点目前尚不清楚。不过从逻辑上讲,如果让专门的 Agent(比如测试 Agent、QA 质检 Agent、或是代码清理 Agent)来分别负责软件开发生命周期中的各个子任务,它们可能会表现得更好。
此外,目前的演示主要是针对全栈 Web 应用程序开发进行优化的。未来的一个重要方向是将这些研究成果推广到其他领域。科学研究或金融建模等需要长期运行 Agent 任务的领域,很可能也同样适用这些经验法则的全部或一部分。