2026/10/17 15:07:15

用Harness设计构建AI自主开发闭环:从代码生成到真实验证

用Harness设计构建AI自主开发闭环:从代码生成到真实验证 你有没有遇到过这种场景让AI帮着写一个完整的App前后端、页面、逻辑它一口气全给你列出来了代码结构看着也挺完整你心里已经开始盘算“下午就能收工”。结果把项目跑起来启动就报错修完启动报错登录又崩登录解决了保存数据那一步又丢东西。反复折腾几轮之后你开始怀疑到底是AI不行还是我喂的提示词有问题我自己在多个项目里折腾AI自主开发时也狠狠卡过这个阶段。直到最近在AI开发圈子里反复看到“Harness设计”这个思路才算是把这个问题从根上想明白了。它解决的不是“怎么让AI写出更好看的代码”而是“怎么让AI在真实执行环境里自己发现问题、自己改、自己验证”让代码从“看着行”真正变成“用着不崩”。这篇不说空话我把Harness设计的核心逻辑、落地步骤、踩坑经验以及我照着思路把一个打卡App从零跑到通的过程完整拆给你。1. 先聊聊那个尴尬现场AI写完一运行就崩1.1 “看着行”到底行在哪儿先别急着怪AI我们得先搞清楚一个事实AI生成的代码“看着行”是真的行还是只是局部行大部分时候AI的能力强在局部。你让它写一个注册接口它能很规范地给出参数校验、返回格式、异常处理甚至能顺手补上几个工具函数。你让它写前端页面组件拆分合理、状态管理清晰、样式代码也像模像样。这些局部代码单拎出来质量完全在线。但一个完整App不是几段独立代码的堆叠它是一个“系统状态”。这个请求的返回结构要和下一个接口的解析逻辑对得上前端路由的路径要和后端控制器的URL精确匹配数据库里的字段命名要和ORM模型里的大小写完全一致第三方服务的SDK版本要和当前Node环境兼容。AI的局部推理能力再强如果它看不见整个项目的真实状态就只能靠“猜”和“估计”去补全这些连接点。猜对了项目跑得通猜错了就是启动报错、接口404、数据对不上。而且这类错误往往不是单一的是连环的第一个错误掩盖了第二个错误第二个错误又连锁引发第三个。你看到“一用就崩”其实背后是一串没有被验证过的假设在同时崩塌。1.2 崩的往往不是单点代码而是项目状态我举一个很典型的例子。之前我帮朋友救过一个用AI生成的内部工具前端是React后端是Node数据库用了MongoDB。AI生成的时候一切都挺顺利代码量不小目录结构也完整。但一跑起来后端启动时直接报“Schema未定义”。排查到最后发现问题出在Mongoose版本上。AI在生成ORM代码时默认走的是旧版本的连接方式而项目里安装的却是新版本包新版已经把某些API改了。单看那段代码毫无问题换在旧版本里它就是对的。可项目不是一个单文件项目的状态是由几十个依赖包、配置文件和运行环境共同决定的。AI写代码时看不到这些状态所以它给出的“正确答案”放在你的项目里就成了废代码。这就是“看着行、一用就崩”的真相AI能在局部维度给出优秀答案但在系统维度上缺乏验证手段。它不跑、不试、不看结果自然会在无数个需要“真实环境反馈”的细节上翻车。2. Harness设计到底改变了什么开发逻辑2.1 从生成器到代理闭不闭环是分水岭传统的AI辅助开发流程本质上是“人机接力”AI负责生成人负责验证。AI把代码写出来人类开发者负责运行、观察、纠错然后再把错误信息喂给AI让AI重新生成。这个流程不是不能用但它有两个致命问题。第一个问题是反馈延迟。你人工发现问题、截图、整理错误日志、重新提问这个周期至少是几分钟。一次修复需要几分钟十个问题就是一个多小时效率立刻被拖垮。第二个问题是上下文丢失。每次你把错误信息重新喂给AI时AI并不能完整记住自己之前到底写了什么、基于什么假设写了那些代码。它在局部上修复了一个错误很可能又引入了一个新的不一致甚至会把之前本来没问题的代码改坏。你以为你在让AI“迭代开发”实际上你是在让它“盲人摸象式补丁”。Harness设计解决的就是这个问题。它的核心动作是把“运行—观察—反馈—修正”这个循环从人类手上移交到AI手上并且把跑出来的真实结果、错误日志、测试报告自动塞回AI的上下文里。AI不再是写完代码就结束使命的生成器而是一个能自己执行、自己看结果、自己迭代的代理。我最早看到这个思路时第一反应是“这不就是加个自动化测试吗”。深入用下来才发现区别比想象中大得多。测试解决的是“已知问题的回归验证”Harness解决的是“未知问题的动态发现”。它不是让你预先写一堆用例去套AI而是让AI在真实运行环境里自由探索遇到问题自己修修完自己再验证形成一条完整的闭环。2.2 Harness设计的四个核心组件拆开来看一个完整的Harness设计至少包含四块东西。第一可执行环境。AI生成的代码必须能立刻被运行容器、沙箱、本地环境都行但必须保证AI能真实启动项目、真实发起请求、真实操作数据而不是待在纯文本世界里“脑内运行”。第二反馈通道。这一步最关键。AI执行完代码之后终端输出、错误堆栈、测试报告、接口返回体这些信息要能结构化地回到AI的上下文中。它不是一个人类复制粘贴过去的而是系统自动汇总、自动注入的。第三分段校验点。把整个开发任务切成多个有明确验收标准的阶段每个阶段必须通过校验才能进入下一步。比如“后端能启动”是一个校验点“三个核心接口都能返回200”是一个校验点“前端能成功调用后端接口”是下一个校验点。没有通过AI就不允许往下写新代码必须先修复当前问题。第四状态记忆。每次迭代之后系统对当前项目状态的总结——哪里改过了、哪些测试通过了、哪些问题还没解决——要被保存下来作为下一次AI操作的前提条件。没有这一步AI会在每次循环里“失忆”反复犯同一个错。这四个组件一起才构造成一个真正意义上的“自主开发回路”。如果只取其中一两个比如只有可执行环境、没有反馈通道AI还是瞎子只有校验点、没有状态记忆AI还是永远在原地打转。3. 照抄思路做一个可复用的AI自主开发回路3.1 先把执行环境搭好沙箱、命令、反馈通道Harness设计的落地不需要什么神秘的黑科技核心就是一个“能让AI跑代码、看结果、改代码”的工作台。我实践的配置大概是这样的。我的固定方案是一个独立的容器化环境里面装好项目所有依赖。为什么要用容器而不是直接把项目放在本机跑因为AI自主迭代的过程会频繁安装依赖、修改配置、执行命令稍微出点差错就可能把本机环境搞脏。容器隔离之后不管里面怎么折腾外面都是干净的最多把容器删了重建。另一个重点是必须给AI一个“标准操作入口”。我通常会在项目根目录放一个脚本把启动项目、跑测试、检查依赖这三件事封装成统一命令。AI的指令空间被限定在这个入口里它不能自由执行任何shell指令只能调用这几个预设命令。这样既限制了危险操作也让反馈通道更稳定——AI每次运行脚本后返回给它的结果格式是统一的脚本执行失败还是成功看一眼返回值就知道。3.2 把任务拆成可验证的单元这个环节容易被人忽略但它是整个回路能不能跑通的前提。如果你上来就给AI一个大任务“开发一个完整的打卡App”AI会像人类接到一个过于宏大的需求一样不知道从哪下手只能凭记忆发挥一次性输出大量代码。这些代码没有经过任何阶段性的验证堆在一起出错时你根本分不清是哪一块的问题。正确做法是把它拆成颗粒度适中的单元每个单元都要有独立的验收标准。比如单元一初始化项目骨架后端能启动前端能启动。单元二实现数据模型和两个核心接口接口通过冒烟测试。单元三实现前端页面骨架页面能渲染路由能跳转。单元四打通前后端联调能跑通“创建打卡记录”这个主流程。单元五补齐异常场景比如网络中断、参数不合法、重复提交。每个单元运行一次完整的“Harness回路”AI写代码 → 自动执行项目 → 自动跑校验脚本 → 结果反馈给AI → 如果没通过就修复 → 通过后进入下一个单元。3.3 让AI自己跑“计划—写码—执行—修复”循环搭好环境、切好任务后真正驱动这套东西运转的是循环设计。我通常不再用“你给我实现XX功能”这种一次性指令而是给AI一个明确的四步循环第一步计划。AI先简要说明它打算怎么实现这个单元要建什么文件、改什么配置、用什么方式验证。第二步执行。AI按计划生成代码然后立刻调用我已经封装好的执行脚本把项目真正跑起来。第三步观察。AI读取执行后的输出和结果。这个环节我特别强调只允许把它自己跑出来的真实结果而不是推测性的结果作为下一步的依据。如果返回报错就盯着报错改如果返回成功才能继续走。第四步修正与回归。如果是失败状态AI必须针对错误信息修改代码然后再次执行直到校验通过。每一次修正都要重新跑前面已经通过的测试确保没有把老功能改坏。你会发现这个循环的本质是把成熟开发流程中的“编码—测试—调试”动作移植到了AI自己的操作空间里。它不再是“写一手漂亮代码的助手”而是“为自己的代码质量负责的开发者”。4. 实例讲解用Harness回路把一个打卡App从零跑到通理论讲得再多不如直接上手一遍。下面我把最近一次用这套方法开发一个“团队任务打卡App”的过程完整复盘给你看。项目不算复杂但足够覆盖大部分常见的“代码看着行、一用就崩”的场景。4.1 需求梳理与任务切分这个App的需求很简单用户能注册登录登录后能创建每日打卡任务能对任务进行完成打卡能查看最近7天的打卡记录。技术栈是前端React、后端Node.js、数据库用SQLite存本地文件。我没有让AI直接开写而是先把需求拆成了前面说的那几个单元。我特别看重第一个单元项目骨架能不能启动。这个单元如果过不了后面所有单元都是空中楼阁。我给AI的初始提示大概是这样 “这是一个团队任务打卡App。技术栈为前端React、后端Node.js、数据库SQLite。请先初始化项目骨架保持前后端分离目录后端使用Express前端使用Vite。初始化完成后分别运行前端启动脚本和后端启动脚本确认两个服务都能正常启动。把启动后的控制台输出作为校验依据。”注意这个指令里包含了执行动作——“分别运行启动脚本”——目的是让AI从一开始就进入跑-看-改的节奏而不是交付一段“理论上能跑”的代码。4.2 第一轮结构生成与启动验证AI按结构生成了文件后问题马上出现了。前端Vite启动没有问题后端Express启动时报错依赖的某个中间件包版本不兼容。这个错误如果你只在生成模式里看代码根本发现不了——代码里的导入语句完全正确但服务器实际启动时就是会被底层依赖的API冲突卡住。这正是Harness设计发挥作用的地方。AI看到了真实的报错信息没有继续写任何新代码而是先处理启动失败。它尝试更新依赖版本再跑启动脚本又出现新报错再修复直到后端控制台成功输出“listening on port 3000”。如果你是在传统模式下提示AI“帮我写一个后端服务”AI大概率会把这段代码写得很漂亮但绝不会告诉你“你的Node版本需要大于18这个包只支持CommonJS模块规范”。只有让AI真实地跑一遍它才能真正掌握项目环境的全部约束。4.3 第二轮接口联调与数据流设计骨架跑通之后第二个单元是核心数据接口。这里踩到的坑很有代表性。AI实现了用户注册、创建任务、打卡三个接口并自己调用了后端冒烟测试脚本。测试结果注册接口通过创建任务也通过但“打卡”接口返回数据异常。错误是数据库查询语句里字段名不一致AI在创建任务时字段叫task_id在打卡时查询的却是taskId。这就是典型的“生成式一致性问题”——它在不同代码段之间保持风格输出的能力很强但如果两段代码是分多次生成的中间又没有统一的上下文约束这种一致性就会出漏洞。解决这个问题的关键不是让AI记住约定而是让AI在反馈循环里自己发现。Harness回路里每一次运行结果的反馈都会让AI意识到“创建任务用task_id打卡时也要用task_id”。它在修复这个问题后会重新跑一遍全部三个接口的测试确认没有破坏前面已经通过的功能。这种“发现—修复—回归”的闭环人工来做烦琐且容易漏交给AI反而更彻底。4.4 第三轮用户路径与异常输入骨架通了接口通了第三轮开始打通前端页面和用户路径。这里我又加了一个人工不会每一次都做的校验异常输入测试。正常的开发流程里我们验证的是“注册→登录→创建任务→打卡→看记录”这条快乐路径。但真正让App“一用就崩”的往往是异常路径用户提交了空表单、两次点击了打卡按钮、输入了超长文本。在这个环节我明确给AI下达指令“前端页面必须对空输入进行拦截重复打卡请求必须做幂等处理返回上一次打卡结果而不是报错。写完后启动前端页面模拟这些异常操作把控制台报错情况记录下来。”AI最终做得比我预期要好。它在模拟重复打卡时发现后端接口虽然返回了成功但前端却因为响应结构体里的字段不一致把成功响应当成了失败。这个问题又是典型的局部代码正常、系统联动出错。它修正前端解析逻辑后又重新跑了一遍完整流程确认没有引入新问题。到这一轮结束时这个App已经基本能真正用起来了启动不崩、数据能存取、异常操作不至于让页面白屏。从“AI写的代码堆在项目里”到“运行稳定、交互可用”差别就是有没有那一套真实执行与反馈的回路。5. 实操中的坑、工具与建议配置5.1 迭代数量多就乱了先检查反馈的“原子性”用Harness设计跑项目时最容易翻的车不是AI能力不够而是反馈信息“不原子”。我解释一下什么叫“原子性”——就是每次执行返回给AI的结果必须干净、直接、结论明确。如果你让AI自己跑项目结果控制台里既有正常日志又有警告信息还有一堆第三方库的调试输出AI很容易陷入信息过载。它分不清到底哪个是致命错误哪个只是无关痛痒的告警于是开始胡乱修改越改越乱。解决办法是封装脚本。在项目里写好一个run-check.sh之类的脚本让它执行完项目后只输出三样东西是否启动成功、测试用例通过数量、错误摘要。AI拿到的是精简过的结论而不是原始日志的汪洋大海。每条反馈都要保证“结论可判断”——通过就是通过失败就给出失败原因。这样循环才不会被杂音干扰。5.2 上下文窗口与记忆管理AI自主开发的次数一多另一个问题立刻浮现上下文不够用。项目文件几十个执行结果十几轮日志越来越大很快AI就忘了自己最开始是怎么设计数据结构的。这时候你会发现它开始“失智”——本来已经解决的依赖问题换了个单元又遇到又从头折腾一遍。我目前的应对策略是把“项目状态总结”固定成每一轮循环的必选动作。在AI完成一个单元后强制要求它输出一段精简的状态文档当前项目结构是什么、哪些接口已实现、哪些测试已通过、有哪些待办事项。这个状态文档单独保存在下一轮开始时注入新的上下文中。这样做等于给AI配了一个“外部记忆插座”。虽然模型本身的上下文窗口有限但只要关键状态能持续被带进带出它就能表现得像一个记住全程的开发者而不是每次见面都重新认识项目的陌生人。5.3 安全与成本控制把AI放进一个能自由执行命令的环境里安全问题必须提上日程。我的配置原则是“最小权限”项目容器里不安装任何与项目无关的软件不挂载生产环境的敏感目录数据库只用本地临时文件。AI的能力被限定在项目内部就算它执行了危险操作最多也就是把沙箱搞坏重建一个就恢复。成本方面Harness回路比普通“问答式生成”的调用次数多出不少因为每一轮迭代都要反复执行、观察、再执行。我的建议是不要毫无节制地让AI自由循环而是给每个单元的迭代次数设上限比如5轮。如果没有达到验收标准就停下来由人来介入检查多半是任务切分不合理或反馈信息有歧义调整之后重新跑效率反而更高。6. 遇到这些情况先别怪AI可能流程设计错了6.1 常见问题速查表现象真正的原因调整方向AI反复修同一个错误修不好反馈信息不完整AI看不到真实报错检查执行脚本把完整错误堆栈注入上下文代码越改越乱老功能被改坏缺少回归测试环节在每轮循环里强制要求AI重跑所有已通过的测试AI答非所问忽略核心需求任务切分颗粒度过大把任务拆到更小单元每个单元只解决一个可验证目标AI一开始很顺利越往后越笨上下文窗口耗尽记忆丢失使用项目状态文档每轮前后做状态摘要并持久化项目能启动但真实操作时卡顿AI没做异常路径验证在验收标准中增加异常输入和重复操作场景AI执行了不该执行的命令环境权限没限制用容器隔离预设安全命令白名单6.2 Harness设计解决的是流程不是替代你对产品的理解用了Harness设计之后开发效率确实提升了一大截但有一点我必须提醒这套流程解决的是代码质量验证问题它不会替你想清楚产品要什么。我见过一些朋友把需求文档直接丢给AI期待AI“自主开发”出一个能直接上线的App。Harness设计确实能让它跑通可跑通之后的产品逻辑是否合理、交互是否顺畅、数据模型是不是为将来扩展留了空间这些仍然需要人的判断。打个比方Harness像是一条质检流水线——AI是工人自动化执行是机床测试脚本是质检仪。流水线的存在保证了每一件产品在出厂前都能通电测试不会交付一堆漏检的残次品。但产品设计的灵魂、用户需求的洞察还得设计师自己操心。流水线只是让你不用再一遍遍靠肉眼检查螺丝有没有拧紧而已。我在实际项目中的体会是这套思路最大的价值是把AI从一个“口头承诺派”变成了“交付验证派”。代码好不好不再由它的排版和注释来证明而是用启动时是否报错、测试是否通过来证明。这种转变才是AI自主开发真正能落地的关键。最后再分享一个小技巧。如果你也想尝试不用一上来就把完整App丢给AI跑先拿一个已经存在的小项目做试点搭好沙箱封装好执行脚本让AI自己跑一遍启动和核心接口测试。你会发现它改起问题来比你出手还勤快。等这套回路稳定了再去挑战新的App开发那种“代码看着行、实际一用就崩”的尴尬会少很多。