原文:09-effective-harnesses-for-long-running-agents.md 来源:https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents
长任务 Agent 的有效 Harness
发布于 2025 年 11 月 26 日
Agent 在跨多个上下文窗口工作时仍面临挑战。我们从人类工程师身上寻找灵感,构建更有效的长任务 Harness。
随着 AI Agent 变强,开发者越来越多地让它们承担需要数小时甚至数天工作的复杂任务。然而,让 Agent 跨多个上下文窗口持续推进仍是开放问题。
长任务 Agent 的核心挑战:它们必须在离散会话中工作,每个新会话都从零记忆开始。想象一个软件项目由轮班工程师组成——每个新工程师都不记得上一班发生过什么。因为上下文窗口有限、大多数复杂项目无法在单个窗口内完成,Agent 需要跨编码会话间桥接的方式。
我们开发了一个让 Claude Agent SDK 跨多上下文窗口有效工作的两部分方案:
- 初始化 Agent(Initializer Agent):首次运行时设置环境
- 编码 Agent(Coding Agent):每个会话中做增量推进,并为下一会话留下清晰产物
长任务 Agent 问题
Claude Agent SDK 是强大、通用的 Agent Harness,擅长编码以及其他需要模型用工具收集上下文、规划、执行的任务。它有压缩等上下文管理能力,让 Agent 工作时不耗尽上下文窗口。理论上这套设置可让 Agent 任意长时间持续做有用工作。
但压缩还不够。开箱即用,即使前沿编码模型如 Opus 4.5 在 Claude Agent SDK 上跨多个上下文窗口循环,给一个高层提示如"构建 claude.ai 的克隆",也无法构建生产质量的 Web 应用。
Claude 的失败模式有两种:
1. Agent 倾向一次做太多——基本上想要 one-shot 整个应用。这常导致模型在实现中途用完上下文,下个会话从一个半实现、未文档化的功能开始。Agent 不得不猜测发生了什么,花大量时间试图让基础应用再次工作。即使有压缩也会发生——压缩不总是把完美清晰的指令传给下一个 Agent。
2. 后期失败模式:一些功能已构建后,后续 Agent 实例环顾四周,看到已有进展,宣布工作完成。
这把问题分解为两部分:
- 设置初始环境,为给定提示需要的所有功能奠定基础——让 Agent 一步一步、一个功能一个功能地工作
- 提示每个 Agent 做增量推进,同时会话结束时让环境处于干净状态——指像可以合并到主分支的代码:没有大 bug,代码有序且文档良好,开发者能轻松开始新功能而无需先清理无关混乱
环境管理
功能列表
为解决 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——模型不太可能不当改变或 覆盖 JSON 文件(相比 Markdown 文件)。
增量推进
给定初始环境脚手架,编码 Agent 接下来被要求一次只做一个功能。这种增量方法对解决 Agent 一次做太多的倾向至关重要。
工作中也必须让模型在代码改动后保持环境干净。实验中我们发现引出该行为的最佳方式:要求模型用描述性提交消息将进展提交到 git,并在进度文件中写进展摘要。这让模型可以用 git 回退坏代码改动并恢复代码库的工作状态。
这些方法也提升效率——消除了 Agent 不得不猜测发生过什么、花时间让基础应用再次工作的需要。
测试
观察到的最后一个主要失败模式:Claude 倾向不充分测试就把功能标为完成。没有明确提示,Claude 倾向做代码改动、甚至用单元测试或 curl 命令测试开发服务器,但无法识别功能没有端到端工作。
构建 Web 应用时,一旦明确提示用浏览器自动化工具像人类用户那样测试,Claude 大多能端到端验证功能。提供这些测试工具戏剧性提升了性能——Agent 能识别和修复仅从代码看不明显的 bug。
仍有一些问题——Claude 视觉和浏览器自动化工具的限制让识别每种 bug 困难。例如 Claude 无法通过 Puppeteer MCP 看到浏览器原生 alert 弹窗,依 赖这些弹窗的功能因此倾向更多 bug。
进入状态
有了上述设置,每个编码 Agent 都被提示运行一系列步骤进入状态:
- 运行
pwd看你工作的目录。只能编辑此目录中的文件 - 读取 git logs 和进度文件,了解最近做的工作
- 读取功能列表文件,选择最高优先级未完成的功能
这种方法每个会话给 Claude 节省一些 token——它不必弄清如何测试代码。还有用的:让初始化 Agent 写一个 init.sh 脚本能运行开发服务器,然后在实现新功能前运行基础端到端测试。
claude.ai 克隆中,这意味着 Agent 总是启动本地开发服务器,用 Puppeteer MCP 开始新聊天、发送消息、接收响应。这确保 Claude 能快速识别应用是否被留在坏状态,并立即修复任何现存 bug。否则 Agent 开始实现新功能可能会让问题更糟。
典型会话开始的助手消息:
[Assistant] 我先获取我的方向并理解项目当前状态。
[Tool Use] <bash - pwd>
[Tool Use] <read - claude-progress.txt>
[Tool Use] <read - feature_list.json>
[Assistant] 让我看 git log 看最近工作。
[Tool Use] <bash - git log --oneline -20>
[Assistant] 现在让我看是否有 init.sh 脚本来重启服务器。
<启动开发服务器>
[Assistant] 太棒了!现在让我导航到应用并验证一些基础功能仍然工作。
<测试基础功能>
[Assistant] 基于我的验证测试,我能看到基础功能工作良好。核心聊天功能、主题切换、对话加载、错误处理都正确工作。现在让我更全面审查 tests.json 文件了解下一步需要实现什么。
<开始新功能工作>
Agent 失败模式与解决方案
| 问题 | 初始化 Agent 行为 | 编码 Agent 行为 |
|---|---|---|
| Claude 过早宣布整个项目胜利 | 设置功能列表文件:基于输入规格,设置带端到端功能描述列表的结构化 JSON | 会话开始读功能列表文件,选单个功能开始工作 |
| Claude 留下 bug 或未文档化的环境 | 写初始 git repo 和进度笔记文件 | 会话开始读进度笔记和 git commit logs,对开发服务器跑基础测试。会话结束写 git commit 和进度更新 |
| Claude 过早把功能标为完成 | 设置功能列表文件 | 自我验证所有功能。只在仔细测试后把功能标为"passing" |
| Claude 不得不花时间弄清如何运行应用 | 写能运行开发服务器的 init.sh 脚本 | 会话开始读 init.sh |
未来工作
本研究展示了长任务 Agent Harness 的一种可能解法。仍有开放问题:
最值得注意的是,仍不清楚单个通用编码 Agent 跨上下文表现最佳,还是多 Agent 架构能取得更好性能。看似合理的是专门 Agent——如测试 Agent、QA Agent、 代码清理 Agent——能在软件开发生命周期的子任务上做得更好。
另外,本演示针对全栈 Web 应用开发优化。未来方向是把这些发现泛化到其他领域——可能部分或全部经验可应用到其他长任务 Agent 任务,例如科学研究或金融建模。