AI写代码总翻车?四层工作流让AI生成代码真正可用 我第一次用 AI 写代码的时候直接甩了一句话“帮我写个导出 Excel 的接口。”然后就等着看奇迹。结果代码确实出来了但填完参数一跑导出文件打不开字段跟数据库对不上异常处理是空的还把我的原逻辑改得亲妈都不认识。那一下午我基本是在删代码、重写、再让它生成、再删的循环里度过的。后来我才意识到问题不在 AI在我。我把它当成了一个“知道所有答案的老程序员”但它实际更像一个“非常聪明但刚进组的新人”——能力很强但你不给它背景、约束和验收标准它就只能靠猜。猜对了是运气猜不对是常态。所以那之后我把自己跟 AI 协作的方式拆成了一套固定的工作流需求描述、上下文打包、小步验证、代码审查。这套流程救过我好几次项目今天就把完整细节摊开讲包括每一步我踩过的坑和现在真正在用的做法。适合那些想用 AI 写代码但试了几次觉得“生成的东西不敢用”的开发者。这篇不是理论是我实测过、被项目验证过的操作方案。1. 一次失败的“甩指令”实践AI 不是不行是我没把话说清楚先复盘最开始那次翻车。我给 AI 的完整指令就一句话帮我写一个导出 Excel 的接口后端用 Java。它给我返回了大概 20 多行的代码用了 Apache POI接口路径也写好了。乍一看有模有样但实际用起来问题全露出来了它假设我传的是ListMapString, Object但我这边业务返回的是已经封装好的 DTO字段是驼峰命名。它把导出的列名硬编码成了英文表头而产品要求的中文表头一个都没对上。异常处理只留了一个Logger.error的占位空指针都没考虑。更坑的是它默认我项目里已经存在一个叫ExcelUtil的工具类但实际上没有它也没跟我说自己要新增依赖。我起初以为这是“AI 能力不行”后来换了好几个模型试发现表现大同小异。真正开始好转是在我把需求描述从一句话变成一段完整“背景说明”之后。那个转折让我明白了一件很基础的事AI 写代码这事真正考验的不是模型的水平而是你“交代需求”的水平。我干过多年开发正常带新人也知道要讲背景、讲边界、讲验收标准。但面对 AI 的时候我会下意识地以为它懂很多于是省略掉大量“常识”和“隐性约定”——这些恰恰是生成可用代码的关键。那之后我开始观察那些用 AI 用得好的同行都在做什么。发现他们有个共同点几乎没有人真的只用一句指令就完事。有的是先把需求背景写进一个固定的文档模板再丢给模型有的是先让 AI 反问自己一轮问题再开始写码有的是把任务拆成小步调动多个 Agent 协作。本质上大家都摸索出了一套“AI 协作工作流”。所以这篇文章的核心我认为可以浓缩成一个判断你不需要更好的模型你需要一套更好的交互流程。接下来的内容我按我自己实际在用的四层工作流展开——需求、上下文、验证、审查——每一层都对应着不同类型的失败方式。2. 一套四层工作流的全貌需求、上下文、验证、审查各自解决什么问题我现在的 AI 写代码工作流不是一次性输出而是分四层走完一个完整循环。先看整体架构后面每层我单独展开讲。第一层是需求层。这一层要把产品语境的“模糊想法”翻译成技术语境里“可执行的任务描述”。比如“用户想批量导出数据”这句话在需求层会变成“提供一个 REST 接口支持按筛选条件分页查询后导出为 XLSX 格式列名按产品导出的模板顺序排列”。第二层是上下文层。这一层要给 AI 提供项目的局部事实接口风格是什么样的、项目里有没有现成的工具类、数据库字段命名规则、日志怎么打、异常统一处理机制在哪个类里。这些 AI 不知道它只能靠猜所以要主动喂给它。第三层是验证层。AI 给出代码之后不是直接收工。要让 AI 自己列出它写了哪些假设它认为的验收标准是什么。然后我拿着它的清单跟真实需求逐条对把模型看不到的业务规则再补进去形成一份真正的验收清单。第四层是审查层。AI 生成的代码必须经过“怀疑式阅读”重点是检查边界条件、异常分支、性能隐患和隐藏的依赖关系。有条件就换一个不同的模型来审——这一步经常能挑出任谁都没注意的毛病。这四层各有各的作用缺一不可。缺了需求层AI 会自由发挥缺了上下文层AI 会用通用方案替代你的项目方案缺了验证层你不知道它埋了什么假设缺了审查层代码能跑但不敢上线。把这四层串起来跟我最开始“一句指令直接开写”的差别非常大几乎是从“让 AI 替你写代码”变成了“你带 AI 一起做需求分析”。我自己的体验是改用这套工作流之后AI 生成代码的返工率降了至少一半。下面每一层怎么实操我逐个讲。3. 需求层怎么做把“一句话”拆成一个能直接消化的规则卡片需求层的目标只有一个让 AI 在动笔之前对“做什么”“不做什么”“做到什么程度算好”这三件事有明确共识。我实测下来最实用的做法是维护一张“项目规则卡片”。它不是固定模板而是针对当前项目、当前任务填好的一组结构化描述。每次开始一个新任务我会花 5-10 分钟把规则卡片写出来然后一次性发给 AI。跟那种对话里挤牙膏式补需求相比AI 给出的代码稳定程度差别特别大。我常用的规则卡片长这样你直接可以抄过去用角色 你是一名熟悉 Java 17 和 Spring Boot 3 的资深后端工程师熟悉阿里巴巴编码规范。 任务 为订单管理模块提供一个分页导出 Excel 的接口。 - 入参分页参数 page/pageSize筛选参数 orderStatus可空、startTime可空、endTime可空 - 出参接口返回一个文件流导出列名和顺序必须严格按照以下模板 [“订单号”,订单状态,客户名称,下单时间,实付金额] - 数据来源调用 orderService.queryPage() 查询不要绕过 service 层直接使用 mapper 约束 - 不要修改订单模块已有的 Service、Controller 代码 - 不要新增任何全局工具类使用项目中已存在的 poi 依赖 - 文件名生成规则orders_yyyyMMddHHmmss.xlsx - 异常时返回统一的 Result 包装对象错误码用 50001 验收标准 1. 导出的 xlsx 文件能正常用 WPS/Excel 打开 2. 筛选条件为空时不做条件拼接 3. 单次导出最大支持 5 万行超过时抛出业务异常 4. 代码注释用中文这个卡片有几个关键点不是随便写的。首先是“角色”字段。给 AI 设定一个具体的身份会让它在做技术选型、写注释、处理异常时更贴近预期。你不说它默认的可能是通用程序员风格注释英文变量名也英文你说了“阿里巴巴规范”它写出来的东西明显更符合国内团队习惯。然后是“约束”字段。这里要尽量写得具体一点尤其是“不要动哪些代码”。模型有一个很要命的倾向——为了把功能跑通它会顺手改掉它觉得“碍事”的现有代码这就容易引起回归问题。所以我会明确圈定禁区。最后是“验收标准”。我很长一段时间没用这个后来发现加上去效果提升非常明显。模型会自己检查输出是否符合验收标准减少了不少低级疏漏。比如那次它把列名顺序搞错就是因为我在验收标准里有一段“列名和顺序必须严格按模板来”它就会在生成时注意顺序而不是自由发挥。还有一个细节规则卡片不要一次性塞几十条约束AI 会“注意不到”。我试过最多的情况是同时给 15 条约束结果生成的代码只遵守了前 7 条左右。后来我把约束精简到 5 条以内优先级最高的放最前面效果好了很多。这跟人是一样的——要求太多的时候就只剩表面满足了。4. 上下文层的隐藏价值让 AI 先问你问题而不是直接写码写完规则卡片后如果直接命令 AI “按卡片写代码”还是有可能跑偏。因为卡片描述的是“项目里应该有的事”至于你们项目里发生了什么AI 是完全不知情的。举个真实例子。有次我写卡片说“使用项目中已存在的 poi 依赖”但实际项目里的 POI 版本比较老不支持 SXSSFWorkbook 这种流式写法。AI 按它记忆里的最新 API 生成了代码一编译就报ClassNotFoundException。这不是模型笨是我没给它“依赖版本”这个上下文。所以我在需求层和代码生成之间加了一个“上下文确认”步骤。具体操作是这样的第一让我先把规则卡片发给 AI然后明确要求它先提问题而不是立刻写代码。我会在后面补一句在动手之前如果发现以下信息缺失请逐个向我提问 1. 项目技术栈的关键版本Spring Boot 版本、MyBatis/JPA、构建工具 2. 项目里现有的工具类或公共类比如 Result 包装类、PageResult、ExcelUtils 3. 调用链路上的其他接口签名 4. 任何你认为会影响实现方式的团队约定 如果你认为信息不足不要猜直接问。这个方法对我的项目帮助很大因为 AI 一旦开始问问题就说明它在试图理解你的项目而不是套模板。有几次它问到的东西我差点都忘了——比如“项目的分页返回对象是自定义 PageResult 还是直接用 IPage”——这种细节如果它不问我直接开写后面改起来非常痛苦。第二把项目里的真实文件“贴”给它片段而不是让它凭空想象。比如你项目里的 Result 类长什么样Controller 层统一的返回格式是什么直接复制片段给它。我做过对比给文档片段后生成的代码比只给“你可以参考 Result 类”这种模糊提示的代码更容易一遍通过编译。具体来说我会用代码块把这几样东西单独包出来发给 AI// 项目统一返回结构控制器层所有接口都返回这个 public class ResultT { private int code; private String message; private T data; }// 订单查询的 Service 方法签名 PageResultOrderDTO queryPage(OrderQuery query);第三还有一种很隐蔽的上下文来源——报错信息。如果 AI 生成的代码一跑就报错别急着吐槽直接把完整的堆栈信息贴回去让它根据报错调整。这一步的效果经常好到出乎意料因为报错本身包含了项目当前状态的准确信息是最高密度的上下文。以前我会自己看日志然后回去改代码现在很多时候先让 AI 看一遍报错它有可能会直接指出问题。这一层的最重要心法其实就一句话AI 的上下文是你给的你没给它就全靠猜猜出来的八成不是你想要的。花在整理项目信息上的这点时间比后期让 AI 反复改要划算得多。5. 验证层与“人工验收清单”AI 的假设不会自己浮出水面等 AI 把代码写出来很多人的下一步是“复制粘贴跑一下”。跑不通再让它改。这个循环看起来没问题但里面藏着一个大坑AI 可能在代码里埋了它自己的假设而这些假设跟真实业务不一定一致。我遇到过一个典型案子。AI 写了一个定时任务用来扫描超时订单并自动取消。代码能跑日志也正常。但运行了几天后业务反馈说“有些不应该被取消的订单被取消了”。查了半天发现 AI 在代码里默认“下单时间超过 30 分钟未支付就算超时”但实际的业务规则是“只有订单状态为待支付、且超过 30 分钟未支付才算超时”还有几个特殊的订单渠道要跳过。AI 在生成时自己定了个默认规则而我没在需求里写清楚它就按自己的常识来了。从那以后我把验证层改成了强制流程。AI 每次给完代码后我会让它做两件事第一用自己的话复述一遍“它认为的业务规则”尤其是那些从代码里看不懂直接推断的业务假设。第二列一个自测清单讲清楚它验证过哪些场景、没验证哪些场景。我一般会在对话里追加一句代码生成后请用一段简短的说明回答 1. 你在这段实现里做了哪些业务假设 2. 哪些场景你已经考虑到了哪些场景你没有考虑需要我来确认 3. 如果要为这段代码写测试用例你会列哪三个关键用例这一步看起来多了一轮对话但它逼着 AI 把自己的隐藏决策暴露出来。很多问题在这一步就暴露了根本不用跑到线上才发现。然后我会在它的自测清单边上再加上一份“项目专属验收单”。这是因为 AI 不知道很多项目特有的隐性要求比如说“导出文件的金额列必须保留两位小数”“订单状态字段在数据库里存的是数字 0/1/2不是字符串”。这些规则只能来自我AI 再聪明也不知道。我的验收单长这样每次任务我都会往里填这个功能牵扯到的表、状态、枚举有哪些有没有特殊权限控制比如某些角色不能导出全部数据。有没有性能基线比如导出 5 万行时内存不能炸。有没有报表模板或历史接口风格需要遵守上线后有没有需要兼容的老数据、老接口把这些逐条过一遍比让 AI 自我检查靠谱得多。因为它不知道你们的表结构、历史包袱和产品偏好只有你知道。6. 审查层的一个关键建议让另一个 AI 去审 AI 写的代码代码能跑、逻辑也对离上线还差一步——审查。我自己最喜欢的办法是换个模型做“代码评审”。具体操作非常简单把 AI 生成的代码原封不动地粘给另一个模型让它以资深 Reviewer 的视角找出问题。这一步的效果经常比我自己逐行盯代码还好。原因很简单写代码的那个模型对自己的输出有“路径依赖”它不容易发现自己埋的坑。而另一个模型手里没有这段代码的生成过程反而更容易用旁观者视角去发现问题。我实际遇到过的案例是写代码的 AI 用了一个HashMap来存放分页结果然后在多线程并发下做更新。写代码时它没觉得有问题。换了一个模型做审查时对方直接指出在多线程下 HashMap 扩容可能导致死循环并建议改成 ConcurrentHashMap。这种问题我自己一眼很难看出来但独立评审模型却可以因为它是按“寻找问题”的思路来阅读代码的。你可以用这段提示词来做审查你是一名经验丰富的 Java 代码审查者。请以严格的视角审查下面的代码 重点检查以下几类问题 1. 并发安全与线程安全性 2. 资源泄漏IO、连接、流 3. 异常处理的合理性 4. 边界情况与空值处理 5. 潜在性能隐患 6. 与项目常见规范的一致性 请按严重程度从高到低列出发现的问题并给出修改建议。 如果某类问题不存在直接说明“未发现明显问题”不要编造。 code另外把“写代码的模型”“审代码的模型”分开还有一个额外的好处让它们形成互检关系。写代码的模型知道“可能会被其他模型审阅”时输出质量的自我约束会高一些。这个经验是我在团队协作里验证过的团队里如果有两个模型协作最终合入代码的质量比单个模型连续迭代强不少。除了换模型我在审查层还会关注一些固定检查项有没有直接 new 了不必要的对象导致资源损耗异常是否真的被吞掉了有时候 AI 写了一个 catch 块里面只有一行日志其他什么都不做那处理了等于没处理。有没有引入新的外部依赖或者版本冲突风险有没有冗余代码AI 偶尔会生成重复的工具方法或者注释掉不用的逻辑。命名是否符合项目整体规范如果项目里用xxxServiceAI 写成xxxHandler就得统一。审查层真正要解决的问题不是“代码能不能跑”而是“代码能不能上线”。能不能跑编译过了就行能不能上线还牵扯到并发、异常、性能、生态一致性。这一步建议不要省。7. 工具链实测同一个工作流在不同工具上表现差别比我预期大得多前面讲的都是方法论但具体落地在什么工具上体验差别还挺大的。我自己用过三类通用大模型直接网页对话、IDE 插件型工具、原生 Agent 编程工具。分别说下我的真实感受。通用大模型直接对话最大的优点是不挑环境你随时开个网页就能用。配合工作流是最顺滑的因为对话上下文可以一直保持。缺点是代码没法直接跑到 IDE 里来回粘贴比较费事而且对项目本地代码的感知为零。所以通用对话适合需求分析、代码审查、写法咨询、拆解概念这些偏“动脑”的环节不适合完整的大型业务开发。IDE 插件类工具常见的有 Continue、GitHub Copilot 这类。它们的好处是能直接读取当前项目的上下文你选的类、打开的文件、当前光标位置它都能看到。这让“上下文层”变得非常轻松——你不太需要手把手贴文件给它它自己读。但这类工具的对话能力通常比网页版弱一些复杂的规则卡片它偶尔理解不完整。所以我的建议是小改动用插件直接改大任务还是回网页版把规则卡片发一遍。Agent 编程工具这两年也很火比如 Cursor 这类偏向 Agent 的用法以及 Codex 之类的命令行 Agent。它们的特点是能替你跨文件改代码、跑命令、读文档。用好了省力非常多坏处是容错率低——它会按照自己的理解去动你项目里的几个文件如果不加约束可能会改到不该改的位置。所以用 Agent 工具时我的工作流会再强调一下约束字段并且生成之后马上用 diff 工具看它到底改了哪些文件。我的实践结论用表格总结一下方便你按场景选型工具类型优势短板最适合的工作流环节通用大模型网页/API 对话上下文保持好理解复杂需求能力强无法直接读写本地项目需求层拆解、规则卡片起草、代码审查IDE 插件型工具Continue/Copilot能感知当前项目代码结构长对话易丢失规则生成质量波动上下文层、验证层、小步改动Agent 型编程工具Cursor/Codex 类能自动跨文件修改执行命令风险高容易改错文件验证层之后的增量修改、重构有一点我得强调工具选型没有绝对最优优先级永远是“核心难题匹配度”。比如你的需求本身就是“改一个文件里的一个方法”那 IDE 插件直接改最快不用开网页版。反过来如果是“实现一个全新模块、涉及多个文件和边界规则”那我还是推荐通用大模型加规则卡片先把逻辑理清楚再落到代码。8. 实战踩坑记录依赖陷阱、文件覆盖、上下文漂移、过度重写工具和工作流都不万能实际用下来还是有一批高频坑。我把它们列出来每个都附上我现在用的处理策略希望能帮你少走点弯路。第一类坑AI 默认引入依赖或使用工具类结果项目根本没有。这个我前面提过一次是出现频率最高的踩坑点。处理方式是每次生成前在上下文层明确“项目中已有的依赖清单”并且加一条约束“只能使用上述依赖”。如果遗漏了编译报错后不要直接粘贴报错让它改而是主动告诉它项目的依赖情况。第二类坑AI 覆盖了你不想让它改的文件。Agent 型工具特别容易出现这种情况AI 为了解决问题会顺手改掉 Controller、Service甚至在几个文件之间来回折腾。我现在的处理策略是每次用 Agent 工具时先手动备份涉及的源文件大概率用不到但真被改了就有退路。此外我还会在 Agent 启动指令里明确“只允许修改列表中的文件”从根源上约束。第三类坑上下文漂移。长对话里AI 可能会把早几轮确定的规则忘掉越到后面越自由发挥。比如一开始说“列名顺序按模板”聊了几轮之后它可能重新排了顺序。我现在的方法是关键需求在规则卡片里重复出现不要指望 AI 一直记住。每次提出新要求时我会强调“这是在原规则基础上的修改”如果规则卡片本身变了我干脆把整段卡片重新发一次而不是指望它从对话里提炼。第四类坑AI 喜欢“重写”而不是“小步修改”。面对一个简单的加字段需求它可能直接给你生成一个全新的类旧类里的其他逻辑被替代掉了。这个问题我用两种方式规避一是明确写“只修改指定方法保留其余逻辑不变”二是生成后立即用 diff 工具查看改动范围一旦发现改动超出预期立刻回滚。第五类坑模型训练数据带来的“过时 API”。我前面提过那个 POI 版本问题本质上就是模型记得的是新 API。但这不止发生在 POI 上比如 Spring Boot 3 的javax到jakarta包名变更或者一些框架的推荐用法迭代。应对方法是在上下文层加入“技术栈版本信息”尤其是 Spring Boot、JDK、核心库这些AI 的输出会回归到跟你项目一致的范围。这些坑不是一次踩完才攒出来的总结就是真实项目里反复出现的模式。每踩一次我的工作流就补一个环节到现在这套框架基本稳定了。9. 如何让 AI 写出来的代码真正融入项目测试、命名与技术债最后聊一个很容易被忽略的环节——AI 写完代码之后怎么让它被项目的工程化体系接纳。毕竟很多时候能跑的代码不等于能被合入主干、能长久维护的代码。我自己在让 AI 代码进入项目之前会额外过这几关面向测试写代码而不是面向“跑通”写代码。AI 生成的代码往往只顾着主流程通不通很少考虑可测试性。比如直接把数据库连接写在方法里或者把外部接口调用写在私有方法内部。这些写法导致单测特别难写。所以我在需求层的规则卡片中会加一条“请考虑可测试性核心逻辑尽量拆成可以独立测试的方法。”这个提示虽然简单但能让 AI 主动调整方法结构后续补测试的工作量会少很多。命名规范和代码风格在需求层就定好。我见过很多 AI 生成的代码变量名全是temp、data1、result2这种。放到团队里别人看代码会骂人的。所以我会在项目上下文里直接附上团队的命名规范示例比如“查询方法统一用query前缀修改用update删除用delete”并且加一条约束“禁止使用含义不明的缩写变量名”。代码一旦生成后面要花大力气才能把命名全部纠正掉不如一开始就设置好。新技术栈引入要谨慎且要记录为技术债。AI 特别喜欢“顺手”引入一个处理问题的新方式比如Stream、Optional、var之类的语法亮点。如果项目本来还是 Java 8 的风格这种混搭会让代码整体风格混乱。我会把它当成技术债记录到项目文档里并在后续迭代中统一处理而不是让两种风格在代码库里并行生长。让 AI 参与 Code Review 的全过程。我们团队现在的做法是AI 写完主要逻辑后先让另一个模型做初轮审查再把审查结果和代码一起交给一位有经验的工程师做最终决策。这样既保证了效率也保留了人的最终判断权。我不建议完全“无人化”直接把 AI 代码合入主干尤其是核心业务模块至少要在关键分支上有一个人拍板。这个环节的本质是AI 能帮你写代码但项目的长期健康还是要你自己负责。把 AI 当作一个“高效的贡献者”而不是“替代整个开发流程的机器”然后所有质量保障机制仍然要保持运转。最后分享一个我自己的小习惯每次用 AI 完成一个任务后我会顺手把这次比较顺的规则卡片存下来下次做类似功能直接改一改装进去。几次迭代下来我的卡片池已经覆盖了导出、导入、定时任务、消息推送这些常见模块。现在面对新需求我经常只需要花几分钟改几个参数AI 就能产出符合骨架的代码我的精力反而能放到更复杂的业务分析和系统设计上。这就是我现在跟 AI 协作写代码的完整方式希望这套朴素的流程也能帮你少踩点坑。