大白话解释:Harness Engineering
大白话解释:Harness Engineering
Anthropic 工程师博客揭示的 Harness 方法论
参考文章:https://www.anthropic.com/engineering/harness-design-long-running-apps
全文 6026 字|阅读需 13 分钟
导读
这篇文章主要回答 5 个问题:
- 为什么 AI 在长任务里经常“做着做着就跑偏”?
Harness到底是什么,为什么它不是“更强的 Prompt”?- Anthropic 总结出的 4 类典型失控模式是什么?
- 他们是怎么用两套机制把问题压住的?
- 为什么 Harness 也必须随着模型能力升级而持续简化?
当用 Claude Code 或者 Cursor 写一个稍微有点复杂的项目时,前半段可能顺风顺水,模型表现得让人觉得,AI 马上就要碾压式地取代我了。
然后,到了某个时间点,它开始犯一些奇怪的错误。
- 忘了之前做过的决定。
- 甚至直接说“已完成”,但功能跑起来完全不对。
于是,人类工程师开始怀疑,是自己 Prompt 写得差,还是模型本来就不够强。
但其实,问题的关键并不在这里。
关键点:这不是单纯的 Prompt 问题,也不是模型“智力不足”的问题,而是一个长任务场景下的结构性问题。
一、根本问题:模型没有记忆,但任务有连续性
打个比方,你雇了一个工程师帮你做项目。
但这个工程师有一个特点:他每隔几个小时就会完全失忆。
醒来之后,他不知道自己做了什么,做到哪里了,之前做了什么决定。他能靠的,只有你在白板上写下的那几条备注,还有现在能看到的代码。
这就是 AI 在长项目里的真实处境。
这不是模型的“智力”问题,这是一个结构性问题。因为所有大语言模型,都有一个叫做 Context Window 的上限,也就是它在一次对话里能“记住”的信息总量。任何稍微复杂一点的项目,都需要跨越多个 Context Window 才能完成。而每次新 Session,模型都是失忆重启。
Anthropic 的工程师在做内部实验的时候,也踩到了这个坑。
他们用最强的编程模型 Opus 4.5,在 Claude Agent SDK 里跑了一个任务:克隆 claude.ai 网站。
结果发现,光靠一个高层次的 Prompt,Opus 4.5 连这个任务都搞不定。它会以两种非常典型的方式翻车。
第一种:一口气冲太猛,冲到一半 Context 耗尽,留下一个烂摊子
模型没有做完功能,后续的 Session 启动的时候,完全不知道之前在干嘛,就开始猜测,浪费大量 Token,还可能把之前的进度越弄越乱。
第二种:Context 快满的时候,模型开始主动收尾
这个比第一种更隐蔽,也更危险。
模型不是真的做完了,而是感知到自己的“空间”快用完了,开始主动包装工作、宣布完成。
Anthropic 工程师给这个现象起了个名字,叫 Context 焦虑(Context Anxiety)。
症状是:任务没做完,模型却开始说“基本框架已经搭好了”“核心功能已实现,剩下的可以继续扩展” 然后停下来。
你以为它交棒了,其实它是跑了。
这两种失控,靠写更好的 Prompt 都解决不了。你再怎么叮嘱模型“认真一点”“不要偷懒”,也改变不了 Context Window 有上限这个事实。你再怎么提醒它“记住之前做了什么”,它也没有地方真正存下来。
这是结构性问题,需要结构性的解法。
这就是 Harness 存在的原因。
二、什么是 Harness
Harness,直译的话是“马具”“脚手架”,但放在 AI 工程领域,我觉得用“工作制度”来理解最合适。
它不是让模型变得更聪明。
它是给模型搭建一套规矩,让模型的工作变得可控、可持续、可验收。
具体来说,Harness 包含四件事:
- 任务怎么拆
- 状态怎么记录
- 完成怎么验收
- 出错怎么回退
而 Harness Engineering,就是专门设计和维护这套“工作制度”的工程学科。
但这里有一个重要的认知:
Harness Engineering 的核心动作,不是“搭建一套最优结构”,而是持续判断,哪些约束现在还需要,哪些已经可以去掉了。
这个点非常非常重要。
可以把 Harness 理解成一套面向 AI Agent 的“工作制度”,而不是一套为了炫技而存在的复杂框架。
三、Harness 解决了哪四个具体问题
Anthropic 工程师在实验里,系统梳理了四个最常见的失控模式。
每一个,程序员们可能都经历过。
先看一个总览:
- 任务失控:一口气冲太猛,做一半上下文耗尽。
- 状态丢失:新 Session 接手时,不知道之前做到哪里。
- 虚假完成:嘴上说完成了,实际功能并没有真正跑通。
- 自我评估偏差:模型对自己的工作天然偏宽容。
失控模式一:任务失控
你跟 Claude Code 说“帮我把整个项目做完”。
它非常积极地开始冲,做了两个小时,Context 用光了。
留下半个功能,代码结构一团糟,下一个 Session 不知道从哪里捡起来。
失控模式二:状态丢失
新的 Session 启动了,模型开始猜,之前做了什么,做到哪里了。
猜错了,就开始在一个错误的假设上继续叠代,越做越偏。
失控模式三:虚假完成
模型做了一些代码上的改动,用 curl 命令跑了一个 API 测试,显示 OK。
然后告诉你,这个功能完成了。
你打开浏览器一看,页面白屏,啥都没有。
失控模式四:自我评估偏差
你让模型评价一下自己的工作成果。
它说,非常棒,逻辑清晰,界面美观,质量优秀,完全符合你的需求。
你对着那个丑到不行的 UI,沉默震耳欲聋。
这四个问题,Anthropic 工程师都在实验里遇到了,然后设计了对应的解法。
四、怎么解决的:两个核心机制
机制一:初始化 + 增量推进
这个机制同时解决任务失控和状态丢失两个问题。
思路是把第一个 Agent 变成一个“项目基础设施搭建者”,而不是让它直接开始写功能。
在 Anthropic 的实验里,第一个 Agent(叫做 Initializer)负责做四件事。
1. 写功能清单(JSON 格式)
不是 Markdown,是 JSON。
所有功能条目,初始全部标记为 "passes": false。
{
"category": "functional",
"description": "新建对话按钮能创建一个新的会话",
"steps": [
"导航到主界面",
"点击「新建对话」按钮",
"验证新会话已创建",
"验证对话区域显示欢迎状态",
"验证对话出现在侧边栏"
],
"passes": false
}
为什么用 JSON 而非 Markdown?
因为实验发现,模型在面对 JSON 的时候,比 Markdown 更不容易自作主张地修改或覆盖内容。特别是对于功能清单这种“不能随便改”的文件,JSON 更安全。
2. 建立进度文件(claude-progress.txt)
每次 Session 结束,模型把自己做了什么写进这个文件。
下一个 Session 启动,第一件事就是读这个文件,知道自己接棒的位置在哪里。
3. 写一键启动脚本(init.sh)
init.sh 负责把开发服务器跑起来。
之后,每个新 Session 启动时,Agent 会主动用 Puppeteer 跑一遍基础端到端测试。比如克隆 claude.ai 的实验里,Agent 会打开页面、发一条消息、确认能收到回复。
为什么要这样设计?
因为每个新 Session 启动的第一件事,是判断“当前状态是不是 OK 的”。
如果上一个 Session 留下了一个隐性的 Bug,新 Session 必须在动手之前就知道。否则,它会在一个已经坏掉的基础上继续叠代,越做越乱。
4. 初始 Git commit
建立版本历史,出了问题随时能回退。
有了这套基础设施,后续每个 Coding Agent 的工作流变成了:
- 启动开发服务器,跑基础测试,确认当前状态 OK。
- 读
git log和进度文件,知道现在在哪里。 - 从功能清单里挑一个还没完成的功能来做。
- 做完,提交 Git,更新进度文件。
一次只做一个功能,是这里最关键的约束。
听起来简单,但它从根本上解决了“冲太猛”的问题。
这套基础设施,也是解决 Context 焦虑的关键。
还记得第一节说的第二种失控:模型快没空间了,开始主动宣布完成?
光靠压缩上下文(Compaction)解决不了这个问题。Compaction 只是把对话历史变短,让同一个 Agent 继续跑,但那种“快没空间了”的焦虑感仍然存在。
真正有效的解法是 Context Reset:Session 结束时完全清空上下文,启动一个全新的 Agent,通过进度文件和 Git 历史把状态交接过来。
新 Agent,干净的白板,没有焦虑。
这也是为什么进度文件和 Git commit 如此关键。它们不只是“方便下一个 Session 了解情况”,而是让 Context Reset 成为可能的基础设施。没有它们,重置之后新 Agent 什么都不知道,交接就断了。
这一机制的核心,不是让模型“一口气做完”,而是先把交接、回退、验收和状态恢复的基础设施搭好。
机制二:Generator + Evaluator 分离
这个机制解决虚假完成和自我评估偏差两个问题。
这里值得先说一下这个设计的灵感来源。
Anthropic 工程师参考了机器学习里一个经典架构 GAN(生成对抗网络)。
GAN 的核心思路是:用两个神经网络互相对抗。一个负责“生成”,一个负责“判别”,判别者不断挑生成者的毛病,生成者不断改进,最终产出越来越高质量的结果。
把这个思路搬到 Agent 设计里,就变成了:
Generator(生成者):负责做功能,写代码。Evaluator(评估者):负责验收,找 Bug。
核心逻辑超级简单:让做事的和评价的,不是同一个人。
两者之间的协作节奏是这样的:Generator 每次做一批功能,做完交给 Evaluator 验收,通过了才继续下一批。
这个节奏单位叫做 Sprint。
把一个大项目切成一段一段可验收的节奏,每一段都有明确的完成标准,Generator 和 Evaluator 就是围绕这个节奏反复交手的。
但这里有个坑需要注意,也是自我评估偏差问题最深的那一层:
仅仅把 Generator 和 Evaluator 分成两个实例,并不够用。
因为 Evaluator 也是 LLM,天然倾向于对 LLM 产出的工作给高分。
Anthropic 工程师在早期实验里就发现了这个问题:Evaluator 会识别出真实的问题,然后自己说服自己“这其实不是大问题”,最后还是给了通过。
所以仅靠“分离”本身,并不能消除这种宽容倾向。
真正有效的第二步,是专门把 Evaluator 调教成一个挑剔的审稿人。
调教过程需要多轮迭代:读 Evaluator 的判断日志,找到它和你的判断出现分歧的地方,更新它的 Prompt,再跑一遍,再对比。
几轮下来,Evaluator 才会开始以一种你觉得“合理”的严苛标准来评审工作。
在前端设计实验里,Anthropic 工程师专门针对 UI 主观质量设计了四个评分维度:
- 设计质量:整体有没有形成一个有统一感的风格?颜色、排版、布局有没有共同撑出一个气质?
- 原创性:有没有自己的创作决策?还是模板默认 + AI 通病,比如清一色的紫色渐变白色卡片?
- 工艺:排版层级、间距一致性、色彩和谐、对比度。这是基本素养检查,做到及格就行,但做不到就是大问题。
- 功能性:用户能不能看懂界面,找到主要操作,不靠猜就能完成任务?
这四个维度里,Anthropic 特别加重了“设计质量”和“原创性”的权重。
因为实验发现,模型在工艺和功能性上,通常已经过关了。但在设计和原创性上,经常产出让人一眼认出来的“AI 风格糊弄货”。
加重权重,就是逼着模型往更有创意的方向去。
到了全栈 App 的验收场景,Evaluator 的评分维度换了一套:
- 产品深度:功能有没有真正实现,还是只是一个看起来像样的壳?
- 功能完整性:用户能不能实际完成核心操作,还是点进去发现是 stub?
- 视觉设计:界面有没有统一的视觉语言,还是一堆默认组件拼在一起?
- 代码质量:代码结构是否清晰,有没有给后续维护留下明显的雷?
每一条都有硬性阈值。任何一条不达标,这个 Sprint 就判定失败,Generator 拿到详细的反馈,重新来过。
还有一个细节值得注意:一开始的 Harness 里,Generator 每次 Sprint 结束后,会先做一次自我评估,然后再把工作交给 Evaluator。
这不是让自评代替 Evaluator,而是作为一道预筛。Generator 自评一遍,把明显的问题先修掉,Evaluator 再进来做更深层的挑剔。
但这个设计是和 Sprint 结构绑定的。
后来 Anthropic 工程师在 Opus 4.6 上把 Sprint 结构整个去掉了,Generator 的自评步骤也随之调整。这是 Harness 随模型能力动态精简的一个具体例子。
然后最关键的一步是:
Evaluator 不是看代码,它是用 Playwright 像真实用户一样点击运行中的 App,截图,研究界面,然后才出评分和批评意见。
这和只跑 unit test,或者只看代码结构,是完全不同的层次。
这一机制的核心,不只是“角色分工”,而是让验收真正独立于实现,并且尽量贴近真实用户视角。
五、Harness 要随模型能力动态调整
Anthropic 工程师做完实验,发现了一件事:
给 Opus 4.5 设计的 Harness,在 Opus 4.6 上用,很多地方变成了多余的累赘。
比如之前给 Opus 4.5 设计的 Sprint 分解结构,把一个大任务拆成一个个小 Sprint,每个 Sprint 结束 Evaluator 来验收,是因为 4.5 存在 Context 焦虑,会在 Context 接近满的时候主动提前收尾,表现失控。
但 4.6 发布之后,这个问题基本消失了。
Opus 4.6 能更长时间保持连贯,能在更大的代码库里可靠运行,还能更好地 catch 自己的错误。
这些,原来都是 Harness 在帮它补的能力。
模型自己能做到,Harness 里对应的约束,就变成了开销:
更慢、更贵、更复杂,却没有对应的收益。
Anthropic 工程师的原话是:
Harness 里的每一个组件,都编码了一个假设:模型在某件事上自己做不到。这些假设值得不断压力测试:一方面它们可能本来就是错的,另一方面随着模型不断迭代,它们很快就会过时。
所以很重要的一个实践建议是:
每次换了新模型,重新跑一次你的任务,看看哪些约束还需要,哪些可以去掉。
越精简的 Harness,越容易维护,越能随模型升级保持活力。
Anthropic 工程师自己的结论是:
Harness 的有趣组合空间,不会随模型提升而收缩,它只会移动。AI 工程师的工作,是不断找到下一个最优组合。
太长不看版
AI 编程工具在关键地方掉链子,根本原因不是 Prompt 写得差,也不是模型不够聪明。
而是没有给它配上一套能让它持续工作的“工作制度”。
Anthropic 工程师用内部实验验证的方案,核心是两个动作:
- 初始化 + 增量推进,解决任务失控和状态丢失。
- Generator + Evaluator 分离(灵感来自 GAN),解决虚假完成和自我评估偏差。
而且,这套方案本身也要随着模型能力的提升不断精简。
不是越复杂越好,是越合适越好。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)