全栈工程师AI编程五条纪律:从契约到版本控制,避免返工

发布时间:2026/9/30 5:11:30
全栈工程师AI编程五条纪律:从契约到版本控制,避免返工 1. 为什么“让 AI 先写”几乎总是最慢的路径我做了十多年全栈从 jQuery 时代一路写到现在的 AI 辅助开发见过太多团队在引入 AI 编程工具之后第一周效率暴涨、第三周开始返工、第二个月直接把 AI 生成的代码全部推翻重写。问题从来不在模型能力上而在于协作纪律。标题里说的“别急着让 AI 写代码”不是反对用 AI而是反对把 AI 当成一个“你说一句它吐一坨”的黑盒。全栈工程师的战场横跨前端、后端、数据库、部署、调试任何一环的上下文丢失都会让 AI 生成的代码变成技术债的加速器。先把这个结论摆出来AI 写代码的质量取决于你给它的约束质量而不是取决于模型参数有多大。我实测过同一个需求用两种方式让 AI 生成第一种是直接丢一句“帮我写一个用户登录接口”第二种是先写清楚技术栈、目录结构、错误码规范、鉴权方式、返回体格式再让它写。第一种出来的代码能跑但字段命名和项目里其他模块完全对不上错误处理是它自己编的一套第二种出来的代码我基本只改了两三个变量名就合并了。差距不在 AI在于我有没有先做“纪律”这件事。这篇内容适合三类人一是刚把 AI 编程工具接进日常工作的全栈工程师二是带团队、需要制定 AI 协作规范的技术负责人三是还在观望、想知道“别人到底怎么用才不出事”的开发者。我会把五条纪律拆开讲透每一条都配上我踩过的坑和具体的落地做法。关键词里提到的 CLAUDE.md、Claude Code、Codex 这些工具我会在对应纪律里自然带出来讲清楚它们在纪律体系里扮演什么角色而不是单独做工具测评。有一点必须先说清楚纪律不是限制你而是让你少返工。我见过最惨的一次是一个同事让 AI 一口气生成了整个订单模块两千多行跑起来没问题但里面用了三种不同的日期格式、两套日志方案、四个重复的工具函数。后来光是对齐这些花的时间比手写还多。这就是没有纪律的代价。2. 纪律一先立契约再让 AI 动笔2.1 契约到底是什么为什么它比提示词更重要很多人把精力全花在“怎么写出更好的提示词”上却忽略了一个更根本的东西契约。契约不是提示词它是你和 AI 之间关于“这个项目长什么样”的共识文件。提示词是临时的、一次性的契约是持久的、可复用的。在全栈项目里契约至少包含四层技术栈与版本、目录与模块边界、命名与代码风格、接口与数据格式。我现在的习惯是任何新项目在让 AI 写第一行代码之前先花二十分钟写一份契约文件。这份文件不需要多漂亮但必须具体。比如技术栈不能只写“React”要写“React 18 TypeScript 5 Vite状态管理用 Zustand不用 Redux”目录结构不能只写“前后端分离”要写清楚src/api放请求封装、src/features按业务域拆分、server/routes放路由、server/services放业务逻辑。这些细节看起来啰嗦但正是它们决定了 AI 生成代码能不能直接融进项目。这里就要提到 CLAUDE.md 这类文件的价值了。它的本质就是一份放在项目根目录的契约AI 工具在读取项目时会优先加载它。我见过很多人装了 Claude Code 之后第一件事是研究怎么让它跑起来却从来没想过在项目里放一份 CLAUDE.md。结果就是每次对话都要重新解释一遍项目背景AI 每次生成的风格都不一样。把契约写进 CLAUDE.md等于给 AI 装了一个“项目记忆”它每次动手前都会先读这份约束。2.2 契约里必须写死的五类信息我把契约里必须写死的信息归成五类缺一类都会出问题。第一类是技术栈与版本号因为 AI 默认可能用旧版本 API比如它可能给你写 React 类组件而你的项目全是函数组件加 Hooks。第二类是目录与文件职责不写清楚AI 会把工具函数塞进组件文件里。第三类是命名规范比如接口返回字段统一用 camelCase 还是 snake_case数据库字段用不用下划线这些不统一前后端联调就是灾难。第四类是错误处理与日志规范AI 默认的错误处理往往很随意要么直接console.log要么抛一个没有错误码的异常。第五类是依赖白名单明确告诉 AI 哪些库可以用、哪些不许引入否则它会给你装一堆你根本没打算用的包。我举个真实例子。之前做一个后台管理系统契约里写了“所有请求走src/api/request.ts封装禁止在组件里直接调 axios”。结果有个新同事没看契约直接让 AI 写了一个页面AI 果然在组件里直接import axios发请求。代码能跑但绕过了统一的鉴权拦截和错误提示上线后用户 token 过期时页面直接白屏。后来我们把这条规则加粗写进 CLAUDE.md 顶部类似问题再没出现过。这就是契约的作用它把“大家都知道但没人写下来”的隐性规则变成 AI 也能遵守的显性约束。2.3 契约的维护节奏什么时候更新谁来更新契约不是写完就锁死的。项目在演进契约也要跟着更新。我的做法是每次引入新依赖、新增一个业务域、调整一次目录结构就顺手更新契约文件。更新的人就是做这次改动的人不另设“契约管理员”否则一定会滞后。更新的时候有个小技巧在契约文件里用一个“变更记录”小节简单记一行“某月某日新增支付模块引入 xxx 库”这样 AI 读到的时候能感知到项目的最新状态。还有一点契约要短。我见过有人把契约写成了一本手册几千字结果 AI 读取时反而抓不住重点。我的经验是控制在两三百行以内用列表和表格把最关键的约束放前面。真正复杂的业务逻辑不该塞进契约而应该放在代码注释或单独的文档里让 AI 按需读取。契约的定位是“宪法”不是“百科全书”。3. 纪律二把任务切到 AI 能一次吃下的粒度3.1 全栈任务为什么天然容易“喂太大”全栈工程师最容易犯的错就是习惯性地把一整条链路当成一个任务。比如“做一个商品详情页”这句话背后其实包含了前端页面渲染、路由参数解析、接口请求、后端查询、数据库联表、缓存策略、错误兜底。你把这整句话丢给 AI它要么只做前端给你一个假数据页面要么前后端都写但两边对不上。这不是 AI 笨是任务粒度太大了。我做过一个对比实验。同一个“商品详情”需求第一种方式一次性丢给 AI它生成了前端组件、一个 mock 数据文件、一个后端路由但前端请求的字段名和后端返回的字段名对不上图片字段一个叫imageUrl一个叫img_url。第二种方式我拆成四步先让它根据数据库表结构写后端查询接口确认返回体再让它根据返回体写前端类型定义再写请求封装最后写页面组件。四步下来几乎没有返工。差别就在于粒度。3.2 一个可复用的任务切分模板我现在切任务基本遵循一个模板数据层 → 接口层 → 类型层 → 视图层 → 交互层。数据层是数据库查询或数据转换接口层是路由和请求处理类型层是前后端共享的类型定义视图层是页面或组件渲染交互层是事件、状态和副作用。每一步都单独和 AI 对话每一步的产出都作为下一步的输入。这个模板的好处是每一步的产出都是可验证的。数据层写完我可以直接跑一个查询看结果对不对接口层写完我可以用 curl 或 Postman 测一下类型层写完TypeScript 编译能过就说明对上了视图层和交互层写完页面能跑就基本没问题。如果一次性让 AI 写完整条链路中间任何一环错了你都要在两千行代码里找那一行。这里要提一下 Codex 这类工具的使用场景。Codex 在补全和单文件生成上很强但它不适合处理跨文件的大任务。我通常用它来做“类型层”和“视图层”这种边界清晰、上下文集中的活而把“数据层”和“接口层”交给能读取整个项目上下文的工具比如 Claude Code。工具没有绝对好坏关键看任务粒度和它擅长的边界是否匹配。3.3 切分之后怎么给每一步写“验收标准”光切分还不够每一步都要有验收标准否则 AI 交出来的东西你还是不知道对不对。我的做法是在给 AI 下指令的时候顺手把验收标准也写进去。比如让它写后端查询接口我会写“返回体必须是{ code, data, message }结构data 里包含 id、name、price、imageUrl 四个字段price 是数字类型imageUrl 是完整 URL”。这样 AI 生成完我一眼就能对照检查。验收标准还有一个隐藏作用它逼着你在动手前就想清楚需求。很多时候我们觉得“让 AI 写就行了”其实是因为自己也没想清楚要什么。把验收标准写出来的过程就是逼自己把模糊需求变具体的过程。我见过太多返工根源不是 AI 写错了而是人自己没想清楚AI 只是把这种模糊放大了。4. 纪律三让 AI 先读代码再写代码4.1 “凭空生成”是返工的最大来源AI 编程工具最诱人的地方就是它能凭空生成代码。但恰恰是这个“凭空”埋了最大的雷。因为你的项目里已经有了一套约定俗成的写法工具函数放在哪、请求怎么封装、状态怎么管理、组件怎么拆分。AI 不知道这些它只会按它训练数据里最常见的写法来生成。结果就是新代码和旧代码风格割裂维护成本飙升。我踩过最典型的一次坑是让 AI 写一个表单校验。它生成了一套基于yup的校验方案但我们项目里统一用的是zod。代码能跑但项目里从此多了一套校验库打包体积大了团队里两个人维护两套校验逻辑。后来我强制要求任何 AI 生成代码之前必须先让它读一遍项目里已有的同类实现。4.2 怎么让 AI “读代码”三种可操作的方式第一种方式是显式引用文件。在对话里直接告诉 AI“参考src/utils/validate.ts的写法实现一个新的校验函数”。大多数支持项目上下文的工具都能读取指定文件。第二种方式是让它先总结再动手。我会说“先读src/api目录下的所有文件总结出请求封装的模式然后再按这个模式写一个新的接口调用”。这样它输出的总结本身就是一次校验我能看出它有没有理解对。第三种方式是用契约文件兜底。如果项目太大AI 读不完就在 CLAUDE.md 里写清楚“所有请求必须走 request.ts所有校验必须用 zod”让它至少知道边界在哪。这三种方式我通常组合使用。先靠契约兜底再显式引用关键文件最后让它总结确认。三步下来AI 生成的代码基本能无缝融入项目。这里有个细节让 AI 读代码的时候不要一次让它读太多。我试过让它读整个src目录结果它抓不住重点总结得乱七八糟。后来我改成一次只让它读一个模块比如“只读src/features/order下的文件”效果立刻好了很多。4.3 读完之后让它“复述约定”再动手这是一个我强烈推荐的习惯AI 读完代码后不要立刻让它写先让它用几句话复述它理解的约定。比如“我理解这个项目的请求封装是这样的所有请求走 request.ts自动带 token错误统一弹 toast返回体解包后直接给业务层”。如果它复述对了再让它写如果复述错了说明它没读明白这时候纠正比写完再改成本低得多。这个习惯还有一个好处它把 AI 从“生成器”变成了“协作者”。生成器是你给指令它给结果协作者是它先确认理解再动手。后者出错率低得多。我现在带新人也是这个逻辑先让他读代码复述一遍确认理解对了再动手。AI 和人在这件事上没有本质区别。5. 纪律四AI 写的每一行你都要能解释5.1 “能跑就行”是全栈工程师最危险的幻觉我见过太多人AI 生成代码后跑一下页面出来了、接口通了就直接合并。这种“能跑就行”的心态在 AI 时代特别危险。因为 AI 生成的代码往往“看起来对”但里面可能藏着性能问题、安全问题、边界条件缺失。你如果解释不了这行代码为什么这么写那你就没有真正拥有它出了问题你也不知道从哪查。举个我亲历的例子。一个同事让 AI 写了一个分页查询代码跑起来没问题数据也返回了。但上线后数据量一大接口响应从 200ms 涨到 8 秒。后来排查发现AI 写的是先查全量再在内存里分页而不是数据库层面分页。代码“能跑”但完全不能用。如果当时他多问一句“这个分页是在数据库做的还是内存做的”就不会有这个事故。5.2 解释的四个层次从“知道它干嘛”到“知道它为什么这么干”我要求自己对 AI 生成的代码至少能解释四层。第一层是功能层这行代码在做什么。第二层是数据层它操作了哪些数据数据从哪来、到哪去。第三层是边界层空值、超长、并发、异常情况下它会怎样。第四层是取舍层为什么用这个方案而不是另一个比如为什么用Map不用对象为什么用防抖不用节流。这四层里最容易忽略的是边界层和取舍层。功能层和数据层看一眼就懂但边界和取舍往往藏着坑。我现在养成一个习惯AI 生成代码后我会刻意问它“如果输入是空数组会怎样”“如果两个请求同时到达会怎样”。它的回答如果含糊我就自己补测试。这个过程很烦但比上线后半夜被叫起来排查强。5.3 解释不了怎么办三个处理动作如果某段 AI 生成的代码我解释不了我有三个动作。第一让它自己解释问它“这段代码为什么这么写有没有更简单的写法”。第二查文档尤其是涉及新 API 或新库的时候AI 可能用了过时或错误的用法。第三重写如果解释完还是觉得别扭就自己重写一遍哪怕功能一样。重写的过程就是理解的过程而且重写后的代码往往更贴合项目风格。这里要提醒一句不要因为“AI 写的”就降低标准。我见过有人对 AI 生成的代码特别宽容觉得“它能写出来就不错了”。这种心态要不得。AI 是你的工具不是你的背锅侠。代码合并进主干署名是你出了问题也是你负责。所以解释不了就别合并这是底线。6. 纪律五把 AI 的产出纳入版本控制与评审6.1 AI 生成的代码提交信息要写清楚很多人用 AI 写完代码git commit的时候随手写个“update”或者“fix”。这在 AI 协作场景下是灾难。因为三个月后你回头看根本分不清哪些代码是 AI 生成的、当时为什么这么写。我的做法是提交信息里明确标注 AI 参与的部分比如“feat: 订单列表接口AI 生成初稿人工调整分页逻辑”。这样回溯的时候一目了然。更进一步我会在提交信息里写清楚“人工改了什么”。比如“AI 生成的分页是内存分页已改为数据库分页”。这条信息在 code review 的时候特别有用评审的人能直接看到 AI 的原始产出和人工修正的差异从而判断修正是否合理。这比看最终代码更有价值因为最终代码看不出修改痕迹。6.2 评审 AI 代码重点看什么评审 AI 生成的代码和评审人写的代码重点不一样。人写的代码重点看逻辑和边界AI 生成的代码我重点看四样东西。第一是一致性命名、目录、错误处理是否和项目其他部分一致。第二是依赖有没有引入不该引入的库。第三是边界空值、异常、并发有没有处理。第四是冗余有没有重复造轮子项目里已有的工具函数它是不是又写了一遍。这四样里冗余是最隐蔽的。AI 不知道你项目里已经有一个formatDate函数它可能又给你写一个。单个看没问题积累多了项目里就有五六个功能重复的工具函数。我现在的做法是评审时先搜一遍关键函数名看有没有重复实现。这个动作花不了几分钟但能省下大量后期重构的时间。6.3 建立“AI 代码回滚”的预案最后一条也是最少人做的一条给 AI 生成的代码准备回滚预案。AI 生成的代码有时候会引入一些隐蔽的问题上线后才发现。这时候如果没法快速回滚就只能热修复风险更大。我的做法是AI 参与度高的功能单独拆成一个提交或一个分支上线后观察一段时间再合并主干。这样出问题可以直接回滚不影响其他功能。这个做法听起来保守但在 AI 协作场景下特别必要。因为 AI 生成的代码你对它的信任度天然低于自己手写的代码。既然信任度低就要用工程手段兜底。回滚预案不是不信任 AI而是承认 AI 的不确定性用流程来对冲。我实测下来这个习惯让我在两次 AI 代码引发的小故障里都在五分钟内完成了回滚没有影响到用户。7. 我在实际协作中总结的几条补充心得7.1 工具选型别追新追匹配关键词里提到的 Claude Code、Codex 这些工具我都用过。我的体会是工具没有绝对的好坏关键看它和你的任务粒度、项目规模是否匹配。Claude Code 适合读取整个项目上下文、处理跨文件任务Codex 适合单文件补全和边界清晰的生成。我现在的组合是大任务用能读项目的工具小任务用补全工具两者不冲突。还有一点工具装好之后第一件事不是写业务代码而是拿一个已有模块做实验。让它读一遍、复述一遍、改一个小功能看它的输出风格和项目是否匹配。这个实验花半小时但能帮你判断这个工具适不适合当前项目。我见过有人装完工具直接上生产代码结果风格完全不搭返工了一周。7.2 心态AI 是副驾驶不是自动驾驶最后说心态。标题说“别急着让 AI 写代码”核心不是技术是心态。AI 是副驾驶它能帮你导航、帮你观察、帮你处理一些重复操作但方向盘在你手里。你如果把它当自动驾驶闭眼让它开出事是迟早的。全栈工程师的价值不在于写代码的速度而在于对系统的理解和判断。AI 能加速写代码但替代不了理解。我现在的日常是AI 写初稿我改逻辑AI 写重复代码我定架构AI 查文档我做决策。这个分工下我的产出比纯手写快了不少但质量没有下降。关键就在于我没有把判断权交出去。每一条纪律本质上都是在守住这个判断权。契约是判断权的显性化任务切分是判断权的粒度化读代码是判断权的上下文化能解释是判断权的验证化版本控制是判断权的兜底化。五条纪律一个核心你始终是那个负责的人。踩过几次坑之后我越来越觉得AI 协作最难的不是技术是克制。克制住“让它一口气写完”的冲动克制住“能跑就行”的侥幸克制住“追新工具”的焦虑。把这几条纪律坚持下来AI 才真正成为你的助力而不是你的技术债来源。