为啥别人的AI Agent一跑几个小时你的却不行,了解下harness工程!
你想让AI Agent帮你从零开始构建一个完整的Web应用,你把需求告诉Agent:"帮我做一个聊天应用,能取代Facebook的那种"。
Agent开始干活了,它读需求、写代码、创建文件,一切看起来很顺利,几个小时后,你打开项目一看——妥妥的豆腐渣工程,到处是写了一半的功能,有些代码逻辑甚至互相矛盾。
恭喜你遇到了一个根本性的问题:Agent会失忆。
失忆的Agent
要理解这个问题,你得先弄清楚Agent是怎么工作的。
Agent有一个"上下文窗口"——你可以把它想象成一块白板。Agent在这块白板上读需求、写代码、做推理。但白板的面积是有限的,当写满了,Agent就得擦掉一些内容才能继续。
更要命的是,当一次会话结束、下一次会话开始时,Agent面前是一块全新的空白板。之前写了什么代码、做了什么决策、遇到了什么都全忘了。
这有点像一个搞轮班制的研发团队,但每个新来的工程师都完全不知道上一班做了什么。新牛马来了之后只能到处翻代码,猜测前一班的意图,然后凭感觉继续干。
除了失忆问题之外你还观察到Agent的两种典型翻车姿势:
第一种:一口吃成胖子。Agent一上来就想把整个应用写完,一口气取代Facebook。结果功能还没完成上下文窗口就用完了,下一个倒霉蛋Agent接手时,看到的是一堆半成品——界面写了一半,后端接了一半,到处是TODO注释。它不知道哪些是写完的、哪些是没写完的,只能硬着头皮猜,花大量时间去修前一班留下的烂摊子。
第二种:自我感觉良好。 到了项目后期,Agent看了看代码,发现已经有不少功能了,于是宣布:"项目完成!"实际上还有一大堆功能压根没做。
你叹了口气,Agent的能力其实不差,问题出在工作方式上。
给白板拍张照
你开始想办法,既然Agent每次会话都是一块空白板,那有没有办法让它在白板擦掉之前,先把关键信息记下来?
Agent运行的环境里有一样东西是持久化的,那就是文件系统。代码文件在那里,配置文件在那里,git记录也在那里,Agent的白板会被擦掉,但文件不会。
你想到了一个办法:让Agent在每次会话结束前,把自己做了什么、做到哪一步了,写到一个文件里。
# progress.txt ## 已完成 - 搭建了项目脚手架(React + Express) - 完成了用户登录功能 - 完成了聊天界面的基础布局 ## 当前状态 - 正在开发消息发送功能,已完成前端部分,后端API待实现 ## 已知问题 - 登录页面在移动端有样式错位 ## 下一步 - 完成消息发送的后端API - 对接WebSocket实现实时推送同时,让Agent把每次改动提交到git,写清楚提交信息。
这样,下一个Agent来了之后,第一件事不是到处翻代码瞎猜,而是:
1. 打开 progress.txt,看上一轮做了什么、做到哪了 2. 看 git log,了解最近的代码变动 3. 搞清楚状况后,从断点继续这就像轮班制里加了一个**交接本,每个人下班前必须写交接记录,下一个人上班前先看记录再干活。
你测试了一下,效果立竿见影,Agent再也不用花大量时间猜测之前发生什么了,它能快速了解项目状态,然后从上次停下的地方继续。
之前Agent接手后到处瞎猜的问题,解决了!
但你很快发现了新问题。
渐进式完成任务
进度文件解决了失忆问题,但没解决贪多问题。
你想了想,问题的根源是什么?Agent不知道"完成"长什么样。你给它一个模糊的大目标——"做一个聊天应用",它只能自己估计需要哪些功能、做到什么程度算完。
因此需要一个明确的、细粒度的功能清单,拆到每一个可验证的小功能点:
{ "description": "用户点击新建聊天按钮,创建一个空白对话", "steps": [ "打开应用主界面", "点击新建聊天按钮", "验证新对话被创建", "验证聊天区域显示欢迎页面", "验证侧边栏出现新对话" ], "passes": false }像这样的功能点,一个完整的聊天应用可能有数百个。每个功能点都有明确的验证步骤,每个都标记着当前状态——passes: false表示还没做。
有了这份清单,你给Agent的指令也变了的更具体了:**"从功能清单里找到优先级最高的、还没通过的功能,只做这一个。"**
Agent一次只做一个功能,做完之后,提交代码、更新进度文件、把功能清单里对应的条目标记为passes: true。然后这轮会话就结束了。
下一轮Agent来了,翻开进度文件看看哪些做了,翻开功能清单找到下一个要做的,继续。
之前Agent贪多求全的问题,解决了!之前Agent提前宣布项目完成的问题也解决了——功能清单里还有一堆passes: false,你想完成也得清单说了算。
必须自测
Agent做完一个功能后,很自信地把清单里的状态改成了passes: true,但你上手一试根本不能用。
你点了按钮,没反应,你输入了内容,提交后页面空白,Agent说它做完了,实际上只是代码写完了,从没真正跑过一遍。
这就像一个程序员跟你说代码写完了,但从来没编译运行过一样。
Agent的问题出在哪?它可能跑了一下单元测试,或者用curl命令调了一下API,但从来没有像真正的用户那样在浏览器里端到端地操作一遍。
你给Agent配上了浏览器自动化工具,让它像真正的用户一样:打开浏览器、访问应用、点击按钮、输入文字、检查页面是否正确渲染。
而且你设了一个规矩:每次开始新功能之前,先跑一遍基础功能的端到端测试。
先测试再开发,发现问题就先修,确保地基稳固后再往上建。
一轮典型的Agent工作流程: 1. 打开进度文件,了解项目当前状态 2. 查看git记录,了解最近的改动 3. 启动开发服务器 4. 用浏览器跑一遍基础功能测试 如果有bug,先修bug 如果一切正常,继续 5. 从功能清单中选择下一个待完成的功能 6. 实现这个功能 7. 用浏览器端到端验证 8. 提交代码,更新进度文件这种指挥AI Agent的外围系统,就是所谓的Agent Harness。
