← 返回 AI Agent 课程

【中文精读】Effective Harnesses for Long-Running Agents(长时运行智能体的有效挽具)

原文:https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents · 本文为中文精读版(忠实转述+关键段落翻译),非逐句全译 · 生成于 2026-07-03 · 精读整理:
导读:这是 Anthropic 工程博客 2025 年 11 月发表的实战笔记(作者 Justin Young),在 agent 开发知识体系里的位置非常明确——它是「挽具/线束工程(harness engineering)」这个分支下,专门解决跨上下文窗口连续性问题的第一手官方经验。当任务长到一个上下文窗口装不下时,模型再强也会「翻车」:半途而废、遗忘状态、过早宣布胜利。本文给出的 initializer/coding agent 双阶段模式、JSON 功能清单、progress 文件 + git 交接协议,已经成为长时程 agent 设计的事实标准套路,后来 Addy Osmani 的《Agent Harness Engineering》直接把它列为「关于长时运行挽具设计最好的公开分析」。配套的可运行代码在 GitHub 的 claude-quickstarts 仓库 autonomous-coding 目录。读它之前建议先理解「agent = 模型 + 挽具(harness)」这个基本框架;读完你应该能徒手复述整套机制并在自己的 agent 里复刻。

一、问题:长时运行智能体为什么会失败

随着模型能力提升,开发者开始让 agent 承担需要数小时甚至数天的复杂任务(文中的实验载体是「从零构建一个 claude.ai 的克隆」这样的全栈 Web 应用)。核心矛盾在于:上下文窗口(context window)是有限的,长任务必然被切分为多个离散会话(session),而每个新会话开始时,agent 对之前的工作毫无记忆

文章用了一个精准的类比:这就像一个软件项目由「轮班工程师」接力完成,而每位新工程师上岗时,完全不知道上一班发生了什么。

值得注意的是,Claude Agent SDK 本身已经具备压缩(compaction)等上下文管理能力,理论上可以让 agent「无限期」工作。但作者明确指出:仅靠压缩不够。即使是 Opus 4.5 这样的前沿模型,如果只给一句高层提示(「构建一个 claude.ai 的克隆」),然后让它跨多个上下文窗口循环运行,也产不出生产级的 Web 应用。压缩产生的摘要不总能给下一个会话传递清晰的行动指令——它是「被动记忆」,而长任务需要的是「主动交接」。

两种典型失败模式

作者把问题拆解为两个子问题:(1)如何建立一个为全部需求功能打好地基的初始环境,让 agent 可以逐个功能地推进;(2)如何让每个会话都做增量进展(incremental progress),并在结束时把环境留在「干净状态」——即「可以合并进主分支的代码」:没有重大 bug、代码有序、文档完善,下一位「工程师」可以直接开新功能,不用先收拾烂摊子。

二、解法总览:initializer agent + coding agent 双阶段模式

解决方案由两种 agent 组成(这是全文最核心的机制,务必记住细节):

一个容易误解的点,原文用脚注专门澄清:所谓「两个 agent」,区别仅在于初始用户提示不同;系统提示、工具集和整体挽具完全相同。也就是说这不是多智能体架构,而是同一个挽具在「第一班」和「后续班次」用不同的开工指令。

整套设计的关键洞察是:让 agent 在新上下文窗口启动时,能快速理解工作状态——通过 claude-progress.txt 加 git 历史实现。灵感直接来自优秀人类软件工程师的日常实践(commit 记录、交接文档、README)。

三、环境管理(Environment management)

本节对应 Claude 4 提示指南中「多上下文窗口工作流」的最佳实践:为第一个上下文窗口使用不同提示的框架结构,由 initializer 一次性把环境铺好。

3.1 功能清单(Feature list):对付「一次做完」和「过早宣布完成」的双药方

initializer agent 被要求把用户的初始提示扩写成一份全面的功能需求文件。在 claude.ai 克隆的例子中,这意味着超过 200 个功能条目——比如「用户可以打开新聊天、输入查询、按回车并看到 AI 回复」。所有功能初始一律标记为 failing(未通过),让后续 coding agent 对「完整的成品长什么样」有清晰的靶子。

原文给出了功能条目的 JSON 结构示例,要点如下:

两条配套的硬约束:

3.2 增量进展(Incremental progress)

coding agent 被明确要求每次会话只做一个功能——这是治「一次做太多」的关键处方。保持环境干净的最佳做法是:要求模型把进展用描述性 commit message 提交进 git,并在进度文件里写摘要。git 在这里不只是备份:它让模型可以回滚坏的改动、恢复到可工作状态。这些做法同时提升了效率——agent 不用再猜「之前发生了什么」,也不用花时间摸索怎么把应用跑起来。

3.3 测试(Testing):端到端验证是硬要求

另一大失败模式:Claude 倾向于在没有充分测试的情况下把功能标记为完成。没有明确提示时,Claude 会改代码,甚至会跑单元测试、对开发服务器发 curl 请求——但这仍不足以发现「功能端到端不可用」的问题。

对策:对 Web 应用,明确提示 agent 使用浏览器自动化工具(文中用 Puppeteer MCP 服务器),像人类用户一样完整走一遍。一旦这样提示,Claude 基本能做好端到端验证。原文配了一张图:Claude 在测试 claude.ai 克隆时通过 Puppeteer MCP 截取的浏览器截图——图表结论是:agent 确实在「亲眼看」自己做的界面,并借此发现了只看代码根本看不出来的 bug。

但也有诚实的局限声明:Claude 的视觉能力和浏览器自动化工具本身有限制,某些 bug 仍难以发现。原文举例:Claude 无法通过 Puppeteer MCP 看到浏览器原生的 alert 弹窗,因此依赖这类弹窗的功能更容易残留 bug。

四、快速进入状态(Getting up to speed):每个会话的标准开工流程

每个 coding agent 会话开头,都被提示执行一套固定的「上岗步骤」:

这套流程每个会话都在省 token:agent 不必重新摸索「这项目怎么跑、怎么测」。initializer 写好的 init.sh 负责启动开发服务器;coding agent 在实现新功能之前,先跑一遍基本的端到端测试(smoke test)。在 claude.ai 克隆案例中,agent 总是先启动本地开发服务器,再用 Puppeteer MCP 开一个新聊天、发一条消息、收到回复——确保能立刻识别应用是否处于损坏状态。如果应用已经坏了,先修,再做新功能;否则直接叠加新功能只会让问题恶化。

原文附了一段典型会话开场的消息记录,流程是:助手说要先了解项目当前状态 → 依次调用 pwd、读 claude-progress.txtfeature_list.json → 查看 git log --oneline -20 → 检查 init.sh 并重启服务器 → 导航到应用验证基本功能 → 确认核心聊天、主题切换、会话加载和错误处理都正常 → 这才开始审阅测试文件、决定实现哪个新功能。

五、失败模式与解决方案对照表

原文用一张表总结了四种失败模式在两类 agent 上的对策,这张表可以视为整篇文章的「速查卡」:

问题initializer agent 的行为coding agent 的行为
过早宣布整个项目胜利基于输入规格建立结构化 JSON 功能清单会话开始时读功能清单,选一个功能开工
留下有 bug 或未记录进展的环境建立初始 git 仓库和进度笔记文件开始时读进度文件和 git 日志、跑基本测试;结束时提交 git 并更新进度
过早把单个功能标记为完成建立功能清单文件(含验证步骤)自我验证所有步骤,仅在仔细测试后才标记为 passing
花时间摸索如何运行应用编写能启动开发服务器的 init.sh会话开始时读取并运行 init.sh

注意这张表的结构:每一行都是「一次真实观察到的失败 → initializer 铺设的基础设施 → coding agent 的行为契约」。这正是后来 Osmani 总结的「棘轮机制」——每个失败都固化为一条挽具规则——在 Anthropic 内部的原型形态。

六、未来工作(Future work)

文末致谢部分提到,这项工作体现了 Anthropic 多个团队(尤其是 code RL 和 Claude Code 团队)的集体努力——这也侧面印证了 Osmani 文中提到的「模型—挽具联合训练循环」:挽具里验证有效的原语,会回流进下一代模型的训练。

七、机制复述卡(便于自测)

读完后你应能不看原文复述以下链条:

对开发者的启示