大白话解释:Harness Engineering
大白话解释Harness EngineeringAnthropic 工程师博客揭示的 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网站。结果发现光靠一个高层次的 PromptOpus 4.5连这个任务都搞不定。它会以两种非常典型的方式翻车。第一种一口气冲太猛冲到一半 Context 耗尽留下一个烂摊子模型没有做完功能后续的Session启动的时候完全不知道之前在干嘛就开始猜测浪费大量 Token还可能把之前的进度越弄越乱。第二种Context 快满的时候模型开始主动收尾这个比第一种更隐蔽也更危险。模型不是真的做完了而是感知到自己的“空间”快用完了开始主动包装工作、宣布完成。Anthropic 工程师给这个现象起了个名字叫Context 焦虑Context Anxiety。症状是任务没做完模型却开始说“基本框架已经搭好了”“核心功能已实现剩下的可以继续扩展” 然后停下来。你以为它交棒了其实它是跑了。这两种失控靠写更好的 Prompt 都解决不了。你再怎么叮嘱模型“认真一点”“不要偷懒”也改变不了Context Window有上限这个事实。你再怎么提醒它“记住之前做了什么”它也没有地方真正存下来。这是结构性问题需要结构性的解法。这就是 Harness 存在的原因。二、什么是 HarnessHarness直译的话是“马具”“脚手架”但放在 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.shinit.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 ResetSession结束时完全清空上下文启动一个全新的 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解决虚假完成和自我评估偏差。而且这套方案本身也要随着模型能力的提升不断精简。不是越复杂越好是越合适越好。