agent 改完先别合并:vibe 项目的回归验证基线六层法
agent 改完代码就合并,等于把验证外包给了用户。本篇给 vibe 项目立一条合并门禁:静态门禁、契约测试、黄金路径、数据迁移、视觉抽查、性能冒烟六层,跑不完不合并,跑不过不解释,并给出轻量版十条起步方案。

Agent 改完代码,你第一反应是什么?如果答案是“先合并,跑起来再看”,那你已经把验证这件事外包给了用户。Vibe 项目的开发速度越快,这个习惯的代价越大:一次改动同时动了三处,登录页修好了、结算页悄悄坏了、移动端布局在某个宽度下塌了,而你直到用户截图才知道。解决办法不是“更认真地人工点一遍”,而是给项目立一条回归验证基线:每次 agent 改动合并前,必须跑完的一组固定检查,跑不完不合并,跑不过不解释,直接修。

基线不是测试套件:先分清三样东西
回归验证基线、单元测试套件、人工验收,是三样不同的东西,混在一起就会互相推诿。单元测试回答“这个函数算对了吗”;人工验收回答“这个功能用起来顺吗”;回归基线回答的是第三个问题:“这次改动有没有把以前已经对的东西改坏”。基线的检查对象不是新功能,而是旧功能:登录、注册、结算、搜索、导出、通知——那些用户每天都在用、你早就以为没问题的部分。
这个区分决定了基线的规模:它不需要覆盖所有代码路径,只需要覆盖“坏了会立刻被用户发现”的路径。一个只有 5 个核心流程的小项目,基线可能就是 20 条检查;一个有 10 个模块的产品,基线可能是 60 条。规模不是目标,稳定性才是:一组每次都能跑出同样结论的检查,胜过一百组时灵时不灵的检查。
基线的六层:从快到慢,从廉价到昂贵
第一层,静态门禁:类型检查、Lint、格式化,全部通过才能进入下一层。这一层跑得最快,也最没有争议,agent 自己就能在本地跑完。把静态门禁放进合并请求的自动检查里,不通过的合并请求连人工评审都不必开始。
第二层,单元与契约测试:核心函数的单元测试,加上模块之间接口的契约测试。契约测试专门防一种 vibe 项目高发病:agent 改了 A 模块返回的数据结构,B 模块还在按旧结构解析,单元测试各自通过,合起来却坏了。契约测试不需要多,关键接口各一条即可。
第三层,黄金路径端到端:用自动化脚本(或固定的人工步骤清单)走通每条核心业务流程——注册、登录、创建、支付(沙箱)、导出、通知到达。黄金路径的数量等于核心流程的数量,不多不少。每条路径都要有明确的“完成标志”,例如订单状态变为已支付、导出文件能正常打开,而不是笼统的“页面能打开”。
第四层,数据与迁移验证:改动涉及数据库时,基线必须包含迁移演练——在测试库上从旧版本升到新版本、回滚、再升级,数据不丢、旧数据可读。还要有一条“脏数据”检查:用一批贴近真实的脏数据(超长标题、空字段、特殊字符、时区边界)跑一遍核心流程,因为 agent 写的代码最常在干净的测试数据上通过、在真实数据上失败。
第五层,视觉与布局抽查:对关键页面做截图对比,覆盖桌面与移动端各一个宽度。这一层不需要全站截图,只需要“用户第一眼看到的那几屏”:首页、核心操作页、结算页。视觉回归的阈值要设得宽松一些,防的是布局塌掉、元素重叠、按钮消失,不是像素级抖动。
第六层,性能冒烟:核心接口的响应时间上限、首页加载时间的上限、单次操作触发的数据库查询数量上限。agent 很容易在“修好功能”的同时写出 N+1 查询,性能冒烟的作用就是在合并前抓住这类退化,而不是等用户抱怨变慢。
基线的运行规则:四条铁律
第一条,基线是合并门禁,不是建议清单。跑不完的合并请求不合并,这个规则对人对 agent 一律适用;一旦开一次“这次先合,下次再补”的口子,基线就死了。
第二条,基线失败时先修基线还是先修代码,要分得清。如果基线本身写错了(例如期望值过期),修基线并注明原因;如果代码改坏了旧功能,修代码。最忌讳的是为了让基线变绿而悄悄放宽基线——放宽基线必须走单独的评审,说明为什么旧期望不再成立。
第三条,偶发失败(flaky)要有名有姓。某条检查偶尔失败,必须在当天登记:失败现象、重跑结果、疑似原因、处理人。没有登记的偶发失败,下次出现时会被当作“又是那个老问题”而忽略,而它可能恰好是真问题。
第四条,基线要随产品长大,但一次只加一条。新核心流程上线时,同步加一条黄金路径;旧流程下线时,同步删一条。基线文件本身也要版本化,改动基线与改动代码走同一个评审流程。
给 agent 的验证任务书:不要只说“跑一下测试”
让 agent 执行基线时,任务书要写得像检查单,而不是口号。合格的任务书包含:跑哪些命令(原文)、每条命令的通过标准、失败时先做什么(贴出失败日志原文、定位到具体文件与行号、判断是代码问题还是基线问题)、修完后重新跑哪几层(至少重跑失败层与直接相关的上一层)。还要规定一条:agent 不许为了通过而修改基线的期望值,改基线需要人类单独批准。
一个实用的技巧是“基线报告模板”:每次改动附一张表,六层各一行,写通过、失败或不适用,失败行附日志摘要。评审者先看这张表,再看代码 diff。没有这张表的合并请求,评审者只能凭感觉猜“这次改动影响大不大”,而感觉在 vibe 开发的速度下是最不可靠的评审工具。
与站内已有指南的划界
本篇与四篇邻近指南分工明确。Agent 改坏代码后的抢救篇(cycle102)讲的是改坏之后怎么冻结、分级、逐段抢救,那是事后;本篇讲的是合并之前怎么拦住改坏,那是事前,两者一前一后成对出现,不重复。视觉回归篇讲的是截图对比的技术实现,本篇把视觉抽查只当作六层中的一层,不展开工具选型。AI 评估篇讲的是用测试衡量模型输出本身的质量,本篇衡量的是改动对已有功能的破坏,对象不同。错误监控篇讲的是上线后如何发现与定位错误,本篇讲的是上线前如何不把错误放出去。把四篇混成一篇“质量保障大全”,每篇的检查单都会变模糊;分开写,合并前的基线才能被原样执行。
本周落地:从 20 条检查开始
- 第一步(1 小时):列出你的核心流程(通常 3–6 条),为每条写一条黄金路径检查,先用人工步骤清单跑通,再逐步自动化。
- 第二步(下一次合并时):把静态门禁与单元测试接进合并请求的自动检查,不通过不评审。
- 第三步(本月内):补齐契约测试、迁移演练、视觉抽查与性能冒烟四层,每层先各做一条,不要贪多。
- 第四步(持续):基线失败登记偶发失败,基线放宽走单独评审,基线报告模板随每个合并请求附上。
一个虚构但真实的回归故事:三次改动,三次教训
假设一个小团队在做一款记账应用。第一次,agent 给导出功能加了个新格式,单元测试全绿,合并后用户发现旧格式的导出文件打不开了——因为导出逻辑被重构时,旧格式的分支被顺手删了,而基线里没有“旧格式导出仍可打开”这一条。教训:黄金路径必须覆盖旧功能,不能只测新功能。第二次,agent 优化了列表查询速度,页面变快了,但分页总数算错了,最后一页的数据永远翻不到——因为性能优化改了查询条件,而基线里没有“总数与实际条数一致”这一条。教训:性能冒烟不能只测速度,还要测正确性。第三次,agent 升级了一个依赖,构建通过、测试通过,上线后发现某个旧浏览器的布局全乱了——因为新依赖改了样式生成方式,而基线里没有“关键页面在目标浏览器下的截图对比”这一条。教训:基线的每一层都是用一次真实事故换来的,事故发生后第一件事就是把对应的检查补进基线,而不是只修代码。
这个故事是虚构的,但每一幕都对应 vibe 项目里反复出现的真实模式:新功能掩盖旧功能损坏、性能优化掩盖正确性损坏、依赖升级掩盖环境损坏。基线的价值不在于它多全面,而在于它把“上次吃过的亏”变成“下次自动检查的项”。一个团队的基线文件,读起来应该像一部事故史:每一条检查背后都应该能讲出一次教训。如果某条检查讲不出教训,要么它是多余的,要么它的教训已经被遗忘了——两种情况都值得在评审时问一句。
轻量版基线:一个人、一小时、二十条检查
对独立开发者来说,六层全套可能显得太重,但“太重”不能成为“没有”的理由。轻量版基线的做法是:每层只留一条最关键的检查,加起来就是六条起步,核心流程有多少条就再加多少条黄金路径。一个典型的轻量版是这样:静态层留类型检查,契约层留最关键的一个接口契约,黄金路径留注册、登录、核心操作、导出四条,数据层留一次迁移演练,视觉层留首页与核心页两张截图对比,性能层留首页加载时间上限。总共十条左右,一小时能搭起来,十分钟能跑完。跑完这十条再合并,已经比“凭感觉合并”可靠一个数量级。等项目长大,再按“一次加一条”的规则慢慢扩充,不要一开始就追求六十条的完整版。
轻量版还有一个关键设计:基线报告可以是一张纸。每次改动附一张表,六层各一行,写通过、失败或不适用,失败行贴日志摘要。评审者——哪怕评审者就是你自己换个时间再看——先看表再看代码。这张表的作用是强迫你把“验证过了”从感觉变成记录。感觉会骗人,记录不会。很多回归事故的复盘结论最后都是同一句:当时觉得没问题,但没有记录证明跑过哪几项。
基线与速度的关系:慢在合并前,快在整体上
最常见的反对意见是基线拖慢速度。这个意见只算了合并前的十分钟,没有算合并后的救火时间。一次回归事故的完整成本是:用户反馈、复现、定位、修复、再验证、道歉与信任损失,加起来往往是几小时甚至几天;而基线每次的成本是十分钟。把账算到项目全周期,基线不是慢,而是快——它把“事后救火的不确定时间”换成了“事前验证的确定时间”。对 vibe 项目来说,这个交换尤其划算,因为 agent 的改动速度越快,事后救火的频率就越高,基线的收益也就越大。速度的正确定义不是“合并得多快”,而是“从改动到用户稳定用上新功能有多快”,而回归事故恰恰是这个链条上最长的拖延项。
常见问题:四问四答
问:基线跑一遍要多久才合理?答:没有统一数字,只有两个约束:合并前的验证必须在可接受的等待时间内完成,轻量版十分钟左右是合理的;如果基线跑到一小时以上,说明它已经臃肿到需要拆分——把慢而重的层移到定时任务,把快而关键的层留在合并门禁里。
问:基线失败了,能不能先合并、后补修?答:不能开这个口子。基线失败只有两种合法处理:修代码,或者走单独评审修基线。“先合后补”一旦成为惯例,基线就从门禁降格为建议,而建议在赶工期时永远会被跳过。
问:自动化基线要花多少成本?答:起步成本很低:静态门禁与单元测试本来就该有,黄金路径可以先从人工步骤清单开始,逐步自动化。不要一开始就追求全自动化、全覆盖;先让基线跑起来、成为习惯,再按“一次加一条”的规则扩充。
问:偶发失败的检查应该直接删掉吗?答:不应该。删掉偶发失败等于删掉一个报警器,正确做法是登记、定位、修复或隔离:给它单独的重试策略与负责人,修不好就先标记为“已知不稳定、需人工复核”,而不是悄悄删掉让基线永远变绿。
基线与持续集成的分工:门禁与巡逻
基线与持续集成里的定时任务要分工清楚,不能互相替代。合并门禁里的基线是“放行检查”,跑得快、判得严,决定这次改动能不能进主线;定时任务里的全量测试是“巡逻检查”,跑得全、判得宽,负责发现那些合并时没暴露的慢变量问题,比如依赖升级带来的漂移、第三方服务行为变化、数据量增长导致的性能退化。两者配合起来才是完整的防线:门禁拦住已知的回归,巡逻发现未知的漂移。只留门禁不留巡逻,慢变量问题会在无人注意时积累;只留巡逻不留门禁,每次合并都是一次赌博。把基线文件同时挂进合并检查与每日定时任务,让同一套检查在两个节奏下各尽其用,是成本最低的完整方案。
还有一个容易被忽视的分工是“基线负责人”。基线不能是集体所有、等于无人所有,每个模块的基线检查都应该有一个明确的负责人:谁写、谁评审、谁在失败时第一时间看。负责人不是永久职位,可以轮换,但任何时候都不能空缺。没有负责人的基线,失败时会陷入“大家都看到了、没人去修”的状态,而这种状态持续两周,基线就会被团队默默绕过。把负责人名字写进基线文件头部,与检查项放在一起,让责任与检查本身一样可见。
一句话总结:vibe 开发的速度优势,不应该建立在“用户帮你发现回归”的基础上。立一条合并前必须跑完的基线,让 agent 的每一次改动都先证明“旧功能还活着”,再谈新功能有多好。
评论 (0)
相关文章

换个会话、换个模型,agent 就像失忆一样重新问一遍项目是干什么的。解决办法不是讲得更耐心,而是给仓库立一份交接包:一页纸、架构地图、决策记录、禁区清单、验证命令、任务队列与交接仪式,十分钟读完就能干活。

agent 一次改了 23 个文件、测试挂了 4 个时,最糟的反应是立刻让它再修一遍。本篇给现场急救流程:5 分钟冻结留证、按改动而非文件分级、工作树隔离区抢救、文件级/代码块级/分支级三段回滚,以及重新进场的三条约束。

提醒邮件是早上才看到的,钱是半夜就花完的。本篇给 vibe 项目装硬上限:软上限与硬上限的定义、三层上限(任务级/日级/月级)、调用前 pre-flight 执行、熔断器三态与半开恢复、团队分账,以及一周落地计划——从盘点入口到一次熔断演习。