从氛围编程失控到工程纪律闭环:用TDD和Superpowers给AI代码上护栏
最近半年我身边好几个团队都在用AI写业务代码速度是真的快但代码库崩起来也是真的吓人。最典型的一个场景有同事把一个“内部订单小工具”改了一行字段类型结果测试红了一片他让AI自己修AI修一次多两个bug修到后来谁也不敢碰那个模块。这就是典型的“氛围编程”失控——大家沉浸在“描述需求、AI生成、点击接受”的顺畅感里完全忽略了代码库正在悄悄失去秩序。等雪崩来临不是某一个函数坏了而是整个项目进入“改哪哪炸、没人能重建心智模型”的瘫痪状态。这篇文章想聊的就是怎么从这种失控里走出来。我会拆解三个东西一是“氛围编程”为什么会引发代码雪崩失控的过程到底分几个阶段二是Superpowers技能框架是怎么让LLM从“自由发挥”变成“按流程执行”的三是TDD契约驱动和AI工程纪律闭环如何配合把测试、契约、回滚这些传统工程手段变成AI时代的新护栏。适合正在用AI辅助开发、但又觉得“代码越写越不可控”的工程师和团队技术负责人参考。1. 雪崩不是突然发生的氛围编程失控的四个阶段1.1 生成期的红利为什么头几周特别爽“氛围编程”刚上手的时候体验确实无可挑剔。你只需要用自然语言描述需求AI就把函数、组件、接口一次性生成出来甚至还能帮你顺手写好注释。对一个“不算复杂”的业务系统来说前两到三周通常是产能爆发期——每天下班都有新功能交付测试也跑得通代码虽然谈不上优雅但至少“看起来在正常工作”。这段红利期的本质是LLM在替你完成“从需求文本到代码实现”的这一跳。它跳得快但跳得是否稳固取决于它当时的上下文窗口里有多少真实约束。问题是大多数人在这段时间并不会检查约束也不会给AI立任何规矩。代码风格不统一没关系能跑就行。错误处理逻辑各搞一套先放着后面再统一。数据流边界模糊AI迟早会处理。这些信号在红利期全被“交付速度”掩盖了。这段时期的另一个隐患是团队开始形成对AI的“盲目信任惯性”。人不再去读AI生成的代码只关心结果是否符合预期。于是从第一条“自己看不懂的代码”被合入主干开始代码库的整体心智模型就从团队大脑中剥离出去了。你以为代码是团队的资产实际上它已经变成了LLM上下文窗口里的一堆拼接文本。1.2 从堆叠到修补局部正确掩盖全局失序到了第四周左右第一个功能需求出现了“轻微修改”。改一个按钮文案AI发散了顺手改了三处不相关的地方改一个接口参数名AI没把握住影响面直接把调用方的行为也改了。这时候你会发现每一次AI都“理解”了你的要求但它每次理解的只是你这句话本身而不是这句话在整个系统里的上下文。这个阶段我称之为“堆叠期”。新功能还在往上加但每加一层代码库内部的风格分裂就更严重——同一个业务概念在这个文件里叫orderStatus在另一个文件里叫state同一个查询逻辑在这个模块里用ORM在那个模块里裸写SQL。LLM其实很擅长模仿你提供的最近代码风格但它只会模仿当前上下文里的局部风格所以你代码库里到底有几套风格取决于你有多少个“上下文窗口”。紧接着进入“修补期”。一旦bug开始出现团队习惯性把报错信息丢给AI让AI自己修。这是最危险的动作。因为AI修复bug的方式通常是“找到最近的相似逻辑做局部打补丁”。它不会站在全局数据流的角度去判断这个补丁会不会影响其他路径。如果这个bug的根因在A模块AI大概率会在B模块加一个if判断来绕过因为这样最省事、最容易被测试通过。结果就是bug看起来修好了系统的逻辑混乱却加深了一层。1.3 掩埋期的代码雪崩现场复盘当修补持续到一定阈值代码库就进入了“掩埋期”。这个阶段的显著特征是所有常规手段都开始失效。让AI加一个新功能它会先花大量时间探路因为代码库太大了它的上下文放不下全景让它修一个bug它改完一个又冒出一个同时跑全部测试也变得越来越慢因为中间层早就杂草丛生。我复盘过一个典型例子。某个模拟项目里开发者用AI写了一个“数据分析模块”前两版很顺利但从第三版开始每次改动都要连带调整四到五个文件。到第六版AI已经无法在没有人为引导的情况下完成任何独立改动。第七版团队决定“重写”。重写其实就是宣告这段代码已经失去了被维护的可能——它没有架构边界、没有契约约束、没有测试兜底也没有人能说清楚它内部的数据流。这就是氛围编程的终极代价。它不是“多了几个bug”的问题而是代码库丧失了所有工程上的可维护性。整个团队被拖进了“AI修代码、AI写代码、人审不动”的失控循环。我们常说“技术债”但氛围编程积累的不是债是地雷——你不知道它埋在哪、什么时候爆但你知道继续在这个库上加代码迟早会碰到它。2. Superpowers技能框架把LLM从“自由发挥”改成“按流程执行”2.1 技能框架的本质给LLM发一本操作手册面对“AI自由发挥不可控”的问题一个相当有效的思路是别再让LLM在每一次对话里现场发挥而是给LLM定义一整套可复用的“技能”。这套做法在圈子里有个名字叫Superpowers翻译过来就是“技能超集”。它的核心不是某个特定的工具或插件而是一种组织AI能力的方式把那些“有经验的人在遇到某类问题时是怎么处理的”沉淀成结构化文档让AI在执行任务时先加载这些文档再按里面的流程走。你可以把Superpowers理解成给LLM发的一本操作手册。普通提示词工程是“做一道菜之前口头告诉厨师这菜大概是什么味”技能框架是“把这道菜的完整做法、用料标准、出锅判据都写进厨房手册厨师做菜前先翻手册”。区别在于口头描述会因为厨师的理解不同而跑偏手册则把“正确做法”固定下来了。技能框架最关键的改变是让AI的思考过程从“生成式”变成“检索式步骤式”。传统方式下AI接到任务后直接在语言模型里“猜”最可能的答案技能框架下AI首先要判断“这属于哪类任务”然后去技能库里检索对应的处理流程再在流程的约束下生成结果。这样它就不会再靠“灵感”做事而是靠“规程”。2.2 技能包的三个组成环境感知、执行步骤、自我验证一个合格的技能包通常包含三大部分。第一是“环境感知”明确告诉AI在执行前需要收集什么信息。比如做代码重构时先用什么命令扫描依赖关系、检查哪些文件会被影响、输出什么样的依赖树。这一步的目的是让AI在执行前先建立“当前上下文”的足够认知而不是闭眼就写。第二是“执行步骤”这一步是把任务拆成有序的动作序列。比如“先读接口定义再写测试用例再实现业务逻辑最后跑测试”。每一步都要有明确的入口和退出条件。最重要的是每个步骤之间要有“检查点”AI每走一步都要输出中间结果而不是一次性吐完一大段代码。很多氛围编程翻车就是因为AI总喜欢“一口气梭哈”等它输出完了错误早就深埋在几千行里了。第三是“自我验证”在执行完成后AI必须按技能包里的验证清单逐项检查自己的产出。这个清单要具体有没有跑测试、有没有做静态检查、有没有把新代码注入到变更日志里、有没有补充文档。没有自我验证的AI产出本质上就是“没有经过验收的交付物”——这也是氛围编程里最缺的一环。一个技能包在磁盘上的形态可以是一份Markdown文档里面用固定的结构描述触发条件、执行步骤、验收标准。当AI收到任务时它先根据任务类型找到对应的技能包读取并执行。这样每一次AI的行为就不会是“随机游走”而是“按图索骥”。随着团队踩坑经验积累技能包本身也被持续修订——今天这个AI在某个任务上栽了跟头明天就把教训写进技能包里让以后的执行不再犯同样的错。2.3 技能框架与传统提示词工程的对比对比维度传统提示词工程Superpowers技能框架知识存在位置分散在人物设定里每次对话重新灌输集中沉淀在技能包文档里按需加载复用执行方式即时生成一次性输出按步骤推进逐步验证错误纠正靠人发现后重新描述技能包里预置自检清单AI自查团队经验沉淀基本无法沉淀每次踩坑都能更新技能包可预测性低同一需求两次结果差异大高同一技能包下行为趋于稳定从这张表能看出技能框架真正解决的问题不是“让AI更聪明”而是“让AI的行为更可预测”。工程领域最怕的不是能力不足而是不确定性——你不知道这次它会做成什么样。Superpowers通过把执行流程标准化把不确定性压缩到了可接受的范围。氛围编程的雪崩本质上就是不确定性累积到无法控制的结果技能框架等于在代码还没开始写之前先给AI定好“怎么写的规则”。3. TDD契约驱动让测试成为AI与需求之间的硬边界3.1 什么是契约驱动先定义行为再让AI实现“契约驱动”这个词听起来抽象其实落地起来非常朴素在让AI写任何业务代码之前人先定义好“这段代码必须遵守的行为契约”然后用可执行的测试把这套契约固化下来。AI要做的不是“理解需求然后自由发挥”而是“在满足所有测试的前提下实现最直接的逻辑”。很多人觉得TDD在AI时代已经过时了理由是“AI生成代码那么快为什么还要先写测试浪费时间”。这恰恰是本末倒置。AI生成代码快但生成的代码质量不稳定而测试正是唯一能稳定衡量“代码是否符合预期”的标准。没有测试你只能靠肉眼review几万行代码有测试你可以让机器在毫秒级告诉你“这次生成的代码到底有没有兑现契约”。契约驱动包含两个层次。第一层是接口契约函数签名、数据结构、字段类型、错误类型这些都要在编码前由人确定。第二层是行为契约输入什么、输出什么、遇到边界情况怎么处理这些用测试用例表达。接口契约保证“形状”正确行为契约保证“逻辑”正确。两层加在一起AI就没有多少“自由发挥”的余地了——它越自由偏离契约的风险就越大。3.2 一次完整的“红绿循环”实操我来演示一个完整流程用的是“运费计算”这个很简单的业务。假设需求是包裹按重量计费基础运费5元超出3公斤的部分每公斤加1元偏远地区运费翻倍重量不合法要抛异常。和氛围编程不同我们不是在对话里把这堆需求丢给AI而是先生成一个测试文件里面把这些规则全部写成断言describe(calculateShippingFee, () { it(3公斤以内收取5元基础运费, () { expect(calculateShippingFee(2.5)).toBe(5); }); it(超过3公斤后超出部分每公斤加1元, () { expect(calculateShippingFee(5)).toBe(7); }); it(偏远地区运费翻倍, () { expect(calculateShippingFee(2.5, { remote: true })).toBe(10); }); it(重量小于等于0时抛出异常, () { expect(() calculateShippingFee(0)).toThrow(invalid weight); }); });然后让AI先运行一下测试确认这些测试全部失败红灯。这一步很重要它让AI“看见”需求的全貌也知道自己的起点是“还没开始实现”。接下来才让它写出一个能通过全部测试的实现。等测试全部变绿再让AI做代码审查性检查函数是否正确导出、是否有明显类型问题、是否保持简洁。这个流程和TDD在人类团队里并无二致但放到AI协作场景里有一个额外好处人的review聚焦点变了。以前review AI代码时你要逐行看逻辑对不对非常累而且容易被表面正常的代码骗过去。现在有了测试你只需要看“测试是否如实反映了需求”。这是一次“审理需求”而非“审理代码”的过程工作量小得多正确率反而高得多。3.3 为什么说测试是防雪崩的安全绳雪崩之所以发生是因为改动的影响范围在缺乏测试的代码库里是完全未知的。你改了一个函数鬼知道它被几个模块调用鬼知道调用方对它的行为有什么隐性假设。但如果你有一个覆盖主干逻辑的测试网每次改动之后一跑测试哪些依赖受影响立刻无所遁形。在AI协作里测试网还有一个额外价值——它是AI的“记忆锚点”。LLM没有长期记忆它每次出代码都只能依赖当前上下文。代码库一膨胀它根本不可能把全部依赖关系装进窗口。但测试网不需要装进窗口AI只需要“跑一下测试看结果”就知道自己刚才的修改是否有副作用。这等于给AI装了一个外部记忆系统测试红绿灯就是它的记忆。很多氛围编程翻车的案例里团队连一个像样的测试都没有。AI改完代码人只能靠“点一下功能看有没有报错”来验收这连手工测试都算不上。而契约驱动等于把工程质量的第一道闸门前置到“AI动手之前”了——不是写完再测而是“没写就已经测了”。这听起来违背直觉但实际执行过就知道它的成本远低于事后再修因为AI不用在错误方向上跑太远。4. 纪律闭环的设计从需求拆解到知识沉淀不只是流程4.1 闭环的五个环节与流转规则把前面讲的三件事连起来看就构成了一个完整的AI工程纪律闭环需求拆解、契约定义、技能执行、验证反馈、知识沉淀。这五个环节不是孤立存在的它们形成了一条“从想法到可维护代码”的流水线。需求拆解这一步是把笼统的产品描述拆成足够小的任务卡。任务卡里必须包含明确的验收标准越小越好。一张合格任务卡的标准是一个中等水平的工程师或AI拿到它之后不需要再去找产品经理确认细节就能开工。契约定义紧随其后把任务卡里的验收标准转换成接口签名和测试用例。这两步是人的主要工作也是整个闭环里AI无法代劳的部分——因为AI无法替人决定“系统到底该长什么样”。技能执行阶段AI根据技能包和任务卡生成实现代码。验证反馈阶段要跑测试、做code review还要把验证结果记录回任务卡。最后一环知识沉淀最容易被忽略把这次任务里AI踩的坑、人做的修正、测试覆盖的盲区回写到技能包里。这样下一次AI做同类任务时起点就比上一次更高了。4.2 反直觉的三个事实纪律反而提速很多团队拒绝TDD和纪律核心原因就一条——“太慢了”。但等我把这套闭环跑熟之后拿到了三个反直觉的结果。第一多花30%时间在写测试上总工期反而缩短。原因很简单AI写的代码在测试约束下首次通过率很高省掉了大量“已经让AI跑路了但方向不对”的来回扯皮。氛围编程的时间大头根本不是写是“让AI从错误方案里掉头”。第二限制AI自由发挥产出质量反而更高。这个现象起初我完全不理解后来想明白了AI在自由发挥模式下经常在两个极端之间游走——有时过度设计把简单功能写成“工厂模式全家桶”有时偷工减料把边界条件和错误处理全都省略。契约和技能包把这两个极端都堵死了反而让AI的输出稳定在一个“够用且正确”的水平上。第三把AI当“执行者”比当“协作伙伴”更高效。氛围编程倡导“和AI讨论、让AI给建议、一起探索方案”听起来很酷但实际经验是AI在探索性对话里能给的建议大多平庸因为它并不真正理解你的业务背景。真正高效的模式是人来做架构决策和需求定义AI只管按契约实现。双方边界越清晰协作效率越高。4.3 单人/小团队如何从轻量开始搭建闭环完整闭环听着很重我也没建议所有团队第一天就全套上。最轻量的起步方式是只加一道门禁——AI交付的所有代码必须附一个测试文件。这一步不需要改架构不需要引入新工具只需要在项目里立一条规矩没有测试的任务卡不算完成。就这一条就能把氛围编程最危险的部分——“没有验证的生成”——直接拦住。第二步是建立任务卡模板。每次交给AI的需求都不要再用聊天窗口里的“帮我加一个什么功能”这种话而是填一张卡片需求背景、涉及模块、输入输出示例、边界条件、验收标准。这张卡片本身就是给AI看的同时也是给它立规矩的坐标点。你会发现把需求写清楚这件事对AI有多重要——AI表现的“智商下线”大部分时候不是模型不行而是需求说得太含糊。第三步才是引入技能包。在团队里挑重复度最高的几个任务类型比如“新增API接口”“修复回归bug”“重构某模块”各写一份技能包。一开始可以很粗糙甚至只是几段“先做什么再做什么”的列表。重要的是“用起来”然后根据实际踩坑不断修订。技能包不是文档它是活的工具。哪怕你只写了三份把它跑顺了整个团队的AI协作体验都会立刻上一个大台阶。5. 实战中的坑与兜底技能边界、CLI入口和回滚点5.1 技能框架最容易翻车的三个设计误区技能框架本身也会被用歪。我见过最典型的误区是把技能包写成了“思想理论”。什么“以用户为中心”“追求代码可读性”之类的大词全塞进去AI读完完全不知道第一步该干什么最后还是自由发挥。技能包必须写操作指令写“当……时执行……”不能写抽象价值观。第二个误区是契约覆盖了所有正常路径但边界和异常情况全留白。测试只写了happy pathAI就真的只实现happy path——因为对它来说测试通过就是“做完”。要强制人在定义契约时必须写失败路径测试输入非法值时怎么办、下游接口超时怎么办、数据库返回空值时怎么办。没有这些测试兜底你的表面对覆盖很好实际上代码库里到处都是“没人定义的意外”等待爆发。第三个误区是只建验证门禁不给AI建回滚点。很多团队让AI在一个大分支上连续迭代迭代了三轮发现有一轮的基础就错了却不知道应该退回哪里。正确的做法是给AI的每次执行建立“最近可用点”每完成一个子任务就提交一次每次提交信息里注明“这是在第几轮改动基础上的增量”。这样即使方向跑偏了也能精确回退到最后一个正确位置而不是推倒重来。5.2 CLI入口与“最近可用点”回滚兜底除了技能包和测试还想分享一个自己实践之后很喜欢的技术方案给核心业务逻辑建立CLI入口。也就是说把代码库里那些高价值、高风险的操作比如数据迁移、订单状态流转、报表计算都封装成可以通过命令行调用的脚本或服务AI生成的新代码只负责“编排调用”这些入口而不是重写它们的实现。用“CLI兜底”的思路代码的稳定性立刻上了一个台阶。因为核心逻辑的入口被物理化、可手动复现了AI每次改动产生的影响被限制在“胶水层”。即便AI把胶水层写飞了核心逻辑依然可以从命令行手动执行人永远不会被困在崩溃的界面上。再配合前面的回滚点策略我通常要求AI在动手改任何代码前先帮我做两件事一是查看当前分支的提交记录找最近的稳定提交点二是跑一遍全部测试确认目前是绿的。这两步都是低成本操作却能阻止AI把一次小修小补变成“在未知土地上盖楼”。很多错误其实在第一步就被拦住了——AI会发现它根本不知道当前代码处于什么状态。5.3 一些落地建议最后说点实操层面的体会。如果你现在正处于氛围编程的甜蜜期别急着“全盘纪律化”而是先挑一个“最让人头疼的模块”试点。把它的关键路径用测试网包起来再写一份技能包把它的修改流程固定下来让AI每次碰这个模块都按规矩走。看着它从“每次改动都炸”变成“按部就班交付”你的团队自然会产生推广这套打法的动力。还有一件事也别较真不是所有代码都需要测试和契约。一次性脚本、原型验证、临时的数据分析这些场景里氛围编程无可厚非。工程纪律管的是“要长期维护的代码”不是“用完就扔的草稿”。分清这条界线比盲目追求“所有AI代码都要TDD”更符合现实。我自己的感受是AI不会替我们写代码它只是在替我们把“想法变成代码”的速度加快了几十倍。快如果真的能带来价值唯一的前提是——我们有一张足够清晰的图纸和一个足够可靠的刹车。技能包是图纸TDD是刹车。工程纪律帮我们把这块拼图闭环了。