我先说一个真实感受:用提示词生成代码,最大的风险不是“生成的代码跑不通”,而是“跑通了,但你觉得它没问题”。
我见过很多次这样的场景——开发者把需求丢给大模型,拿到一段看似完整、甚至带注释的函数,直接粘进项目里。表面上功能正常,几天后线上出现诡异的性能波动,排查到最后,问题出在当初那行“看起来完全没有问题”的循环上。
这个清单是我自己在日常开发里踩过坑之后沉淀下来的,也是我带团队做代码评审时反复强调的十五条底线。它不是给“会用提示词的人”看的,而是给“把提示词输出的代码当生产代码对待的人”看的。如果你正在用大模型辅助写业务代码、写脚本、写自动化测试,这篇文章能帮你少走很多弯路。
1. 为什么要盯紧“代码质量”这条线
1.1 提示工程代码质量与传统代码质量有什么不同
传统代码质量关注的是:可读性、可维护性、性能、边界条件、测试覆盖。提示工程生成的代码,除了这些,还要多问一句——这段代码和你的原始意图之间,有没有出现语义偏移?
所谓语义偏移,就是模型“听懂”了你的字面描述,但没有“理解”你的真实约束。比如你说“把用户列表按时间排序”,模型可能默认按创建时间升序排,而你的业务期望是最近更新的排在前面。代码本身没有语法错误,但它满足的是它以为的需求,不是你的需求。
所以,提示工程里的代码质量,本质上是一场“需求传递的保真度”问题。你写下的每一个词,都可能被放大成一段实现逻辑。这也是为什么单纯给出功能描述远远不够,必须把约束、边界、验收标准全部写进提示词里。
1.2 这份清单是给谁用的,它解决什么问题
如果你是架构师或者技术负责人,这份清单能帮你建立一套评审大模型生成代码的检查标准。如果你是普通开发者,这份清单能帮你避免把“运行时才暴露的问题”带到生产环境。
我整理这15项时,给自己定了一个原则:每一项都必须对应一个具体的踩坑场景,而不是笼统的“注意质量”。比如第3项“版本约束缺失”,它对应的场景是——模型默认生成了较新的语法,而你们项目还跑在旧版本运行环境上,结果测试环境一切正常,生产环境直接编译失败。
所以这份清单的定位是:一份可以在写提示词之前、拿到代码之后、合入分支之前反复比对的检查表。
2. 15个关键项全景:一张表看懂全局
2.1 清单全景与分类
先把15个关键项完整列出来。我自己把它们分成三组:需求与上下文、约束与规范、输出与验证。
| 分组 | 序号 | 关键项 | 核心问题 |
|---|---|---|---|
| 需求与上下文 | 1 | 功能需求描述过于简略 | 模型靠猜测补齐业务逻辑 |
| 需求与上下文 | 2 | 缺少项目背景与既有代码结构 | 生成代码与现有架构脱节 |
| 需求与上下文 | 3 | 未指定语言版本与依赖版本 | 语法/API与目标环境不兼容 |
| 需求与上下文 | 4 | 期望一次提示生成完整系统 | 复杂逻辑超出单轮上下文容量 |
| 需求与上下文 | 5 | 忽略业务规则和异常场景说明 | 只覆盖了正常路径 |
| 约束与规范 | 6 | 未声明代码风格与命名规范 | 输出风格与团队标准冲突 |
| 约束与规范 | 7 | 缺少性能与复杂度要求 | 生成低效算法或冗余查询 |
| 约束与规范 | 8 | 未要求输入校验与安全防护 | 留下注入或越权风险 |
| 约束与规范 | 9 | 没有明确模块边界与接口契约 | 函数职责混乱、耦合度高 |
| 约束与规范 | 10 | 缺少日志、错误处理与可观测性要求 | 线上问题无法定位 |
| 输出与验证 | 11 | 未约束输出格式与代码组织方式 | 解析困难、人工整理成本高 |
| 输出与验证 | 12 | 没有要求配套测试用例 | 回归验证完全靠人肉 |
| 输出与验证 | 13 | 拿到代码不审查直接合入 | 模型幻觉被当成正确答案 |
| 输出与验证 | 14 | 缺少构建验证与静态检查环节 | 编译问题拖到集成阶段才发现 |
| 输出与验证 | 15 | 不做复盘,同类问题反复踩 | 没有形成组织级经验沉淀 |
这张表我打印了一份贴在显示器边上。每次写完提示词,我会先扫一遍前10项;每次拿到生成结果,我会再扫一遍后5项。这两次扫描加起来不到两分钟,但能省掉后面好几个小时的调试时间。
2.2 关键项之间的依赖关系
这15项不是孤立的。第1项和第5项经常同时出现——功能描述太简单,自然就漏掉了异常场景。第6项如果一开始不约束,后面第13项审查时就会非常痛苦,因为你的注意力全被风格差异带走了,反而忽略了更严重的逻辑错误。
真正的检查顺序应该是:先确认需求与上下文(第1-5项),再补上约束与规范(第6-10项),最后盯住输出与验证(第11-15项)。这和前面表格的分组一致,也是我在实际项目中验证过最顺的流程。
3. 逐项拆解:15个关键项的实际把关方式
3.1 第一组:需求与上下文(第1-5项)
第1项,功能需求描述过于简略。这是最普遍的问题。我经常看到有人写“写一个函数,解析配置文件并返回配置项”,然后模型确实生成了一个函数,但它既没有处理文件不存在的情况,也没有考虑配置格式错误。我现在的习惯是,在提示词里把“正常流程、边界场景、失败场景”三个段落都写清楚,哪怕只是一句话,模型的输出质量都会明显改善。
第2项,缺少项目背景与既有代码结构。这个是隐性成本最高的坑。模型不知道你的项目里已经有了一套配置加载机制,它会自己造一套新的;它不知道你的团队用的是依赖注入容器,它会生成静态工厂方法。结果就是,单看生成代码,逻辑是合理的;放进项目里,架构上就是两个世界。我的做法是,在提示词里附上一小段现有代码的骨架,或者明确说“本项目采用XX模式,新代码必须遵循”。
第3项,语言版本与依赖版本约束。有个项目因为生成的代码里用了某个新版语法特性,而目标环境的编译器版本不支持,导致发布窗口被硬生生推迟了一天。从那以后,我的提示词末尾固定会加一句“仅使用目标运行环境支持的语法特性,不使用新版本专属特性”。如果项目有固定的依赖版本,直接写进上下文。
第4项,期望一次提示生成完整系统。你要做一个导入导出功能,包括文件解析、数据校验、错误报告、进度通知,这不是一条提示词能搞定的。与其给一个巨大的需求然后得到一堆拼接感很强的代码,不如拆成多次生成,每次聚焦一个职责,生成完立刻检查,再进入下一步。这看起来多花了几次调用,但调试和返工的时间省下来了。
第5项,忽略业务规则与异常场景说明。这条我体会最深的是“数据导入”类任务。如果你只说“导入用户数据”,模型生成的代码很可能只处理“每行格式正确”的情况。但真实场景里,一定有重复用户名、缺失邮箱、格式错误的日期。把这些异常分支在提示词里明明白白列出来,代码质量会提升一个档次,因为模型被逼着走完了异常流。
3.2 第二组:约束与规范(第6-10项)
第6项,代码风格与命名规范。别默认模型会遵守ESLint或者内置风格。你需要在提示词里指定“使用typescript strict模式、函数命名采用动词开头、错误处理统一走错误码枚举”。如果不指定,你大概率会拿到一份“混合风格”的代码——一会儿构造函数、一会儿函数式,一会儿常量、一会儿魔法数。
第7项,性能与复杂度要求。模型默认倾向于选择实现难度最低的方案,而实现难度最低往往意味着时间复杂度更高,或者在大数据量下会产生显著的内存开销。比如处理一个列表去重,如果数据量只有几百条,随便写没问题;如果是百万级,就必须提醒模型“时间复杂度必须控制在O(n)以内,禁止嵌套循环”。把数据规模预估写进提示词里,这个动作本身就能筛掉很多低质量的实现。
第8项,输入校验与安全防护。我承认,这个领域模型已经进步了很多,但它仍然倾向于“信任输入”。在生成涉及外部输入、文件上传、数据库查询、命令拼接的代码时,务必显式声明安全要求:“所有外部输入必须经过校验之后才能参与业务逻辑,SQL查询必须使用参数化方式”。如果不写,你拿到的可能就是一段裸拼接的SQL,跑起来没毛病,但安全评审一定不过。
第9项,模块边界与接口契约。这个和架构密切相关。如果项目里有明确的分层,你需要在提示词中描述清楚当前要生成的代码属于哪一层、调用方是谁、被谁调用。我通常会给出接口签名,然后要求“实现该接口,但不要在内部依赖底层存储细节”。这样生成出来的代码,边界感会强很多。
第10项,日志、错误处理与可观测性。没有日志提示词,模型倾向于只用return null或者抛一个笼统的异常。加上日志要求之后,代码的可观测性会立刻提升。我的固定写法是“每个分支入口和异常出口必须有结构化日志,日志字段包含requestId和操作标识”。
3.3 第三组:输出、验证与迭代(第11-15项)
第11项,输出格式与代码组织方式。如果你拿到代码后还要复制到编辑器里手动调整,说明提示词里的输出约束没到位。我一般会写清楚“输出一个包含完整实现的TypeScript文件,类和方法之间不要输出额外说明性文字”。这听起来是很小的事,但当你要连续生成多个文件的时候,输出规整带来的效率提升非常明显。
第12项,配套测试用例。没有测试的生成代码,就像没有验收标准的交付,你不知道它什么时候会坏。我在提示词里会加一句“请为该函数补充一组单元测试,覆盖正常路径、边界输入和异常分支”。模型在这方面其实很适合——它生成的测试代码,往往比业务代码更规整。
第13项,拿到代码不审查直接合入。这是所有关键项里代价最大的一条。模型生成的代码不是同事提交的代码,你不能默认它有基本的质量保障。一定要带着前面那些约束去逐行读,尤其是循环条件、索引边界、资源释放、事务提交这些位置。我自己的做法是:模型生成的代码,没有经过一次正式代码评审之前,绝不合并。
第14项,构建验证与静态检查。代码审查通过后,还需要让工具说话。拉取代码后立刻运行编译/静态检查/测试套件,这一步能抓住很多肉眼容易忽略的兼容性问题。不要相信“看起来没问题”,要相信“跑完整条流水线的结果没问题”。
第15项,不做复盘、同类问题反复踩。这一项是最容易被忽视的。模型生成的代码出了兼容性问题,你修完就完了,下次还是会踩同样的坑。我会在每次出了问题之后,把导致问题的提示词片段和处理方式记到一个共享文档里,慢慢就形成了一份团队自己的提示词经验库。这份库比任何外部教程都管用,因为它记录的都是你真实项目里的常见病。
4. 实操过程:从模糊需求到一个可合入的提交
4.1 构建一份合格的提示词
拿一个实际场景举例:我需要生成一个“批量导入用户”的接口实现。使用这套清单之前,我的提示词是“写一个批量导入用户的接口”,生成结果可想而知——只有正常路径,没有重复检查,没有格式校验,更不用说事务和日志了。
按清单重写的提示词大致是:
项目背景:在XX管理系统中,新增一个用户批量导入接口。 技术栈:Java 17,Spring Boot 2.7,MyBatis,数据库MySQL(已有user表)。 需求: 1. 接收一个包含用户信息的CSV文件,第一行为表头; 2. 校验字段合法性:username非空且唯一,email格式合法; 3. 对合法记录批量插入数据库,单批不超过500条; 4. 对非法记录收集错误原因,全部处理完后统一返回错误清单; 5. 整个导入过程必须在一个事务中,任一失败则整体回滚。 约束: - username、email字段在插入前必须参数化校验,禁止拼接SQL; - 使用项目已定义的日志组件,在每个分支出口打印结构化日志; - 不引入额外依赖,使用项目现有的工具类; - 代码风格与现有Controller/Service层保持一致。 输出要求: - 输出一个完整的Service实现类和一个资源文件解析工具类; - 等待确认后再补充对应单元测试。这样写出来的代码,虽然也未必百分百完美,但它从一开始就具备正确的边界感、异常分支和可观测性,你后续要做的,只是细节修正,而不是推倒重来。
4.2 一次典型的迭代调优过程
第一次生成往往不是最优解。我拿到生成结果之后,会重点看几个位置:事务注解是不是加在public方法上(如果是同类内部调用,事务会失效);批量插入是不是真的用batch方式(有些模型为了简单,会生成循环逐条插入);错误清单是否真的收集完整了。
如果发现循环逐条插入的问题,我不会直接手改,而是把当前实现和问题一起再发给模型,让它基于“当前实现”做一次优化。这样做的好处是,模型能结合上下文做针对性调整,而不是重新生成一份全新的代码。
迭代两次之后,通常就能得到一份结构合理的实现。到这一步再进行人工微调,成本已经非常低了。
4.3 把质量检查点嵌入工作流
如果你只有一个人写代码,靠自觉就够了。但如果是在团队里推广这套方法,就必须把检查点嵌入到工作流里。我的建议是四个固定节点:提示词写完后自检一次,对照第1-10项;代码生成后审查一次,对照第11-13项;准备合入前跑一次构建,对应第14项;每次线上问题复盘时,把根因对应到第15项。
四个节点加起来的额外工作量不大,但能把“大模型辅助开发”这个过程从“碰运气”变成“可管理”。
5. 常见问题与排查技巧实录
5.1 高频问题速查表
| 现象 | 根因 | 排查方向 | 对应关键项 |
|---|---|---|---|
| 生成的代码风格与项目差异明显 | 提示词里没有给出本地规范 | 检查提示词是否声明了代码风格 | 第6项 |
| 跑通但输入一奇怪就崩 | 未补齐异常分支 | 检查提示词里有没有列出边界场景 | 第5项 |
| 生产环境编译失败 | 用了新版本语法或API | 核对运行环境版本并显式声明 | 第3项 |
| 接口返回慢,数据量稍大就超时 | 默认实现是嵌套循环或逐条查询 | 审查循环结构、确认复杂度和批量操作 | 第7项 |
| 线上日志完全无法定位问题 | 没有结构化日志 | 在提示词中加入日志要求 | 第10项 |
| 多次生成的代码质量忽高忽低 | 提示词本身不完整,随机依赖模型发挥 | 把关键约束固定成模板片段 | 第15项 |
5.2 排查思路与独家避坑经验
排查顺序,我总结三个原则:
第一,先确认不是自己的问题,再去看模型的问题。绝大多数“模型生成错误代码”的情况,追根溯源都发现是提示词里漏了关键约束。所以先回读提示词,比反复重新生成更有效。
第二,遇到生成的代码逻辑跑不通,不要直接修改,而是把报错信息和当前实现塞回提示词里,要求模型基于报错修正。这比让它重新生成一份要可靠得多,因为重新生成的实现很可能引入新的不一致。
第三,团队使用提示工程时,一定要有个统一的提示词模板库。我见过太多次“同一个需求,不同人写出来的提示词水平差距巨大”的情况。把我在第4节展示的那种结构固定成模板,团队每个人都用同一套骨架去填内容,下限一下子就被拉高了。
另外说一个我自己试了很久才总结出来的技巧:在提示词里故意加一句“不要假设输入一定合法”,效果比单独说“请处理异常情况”好很多。因为“处理异常”是一个模糊指令,模型不知道该处理哪些异常;而“不假设输入合法”会把模型的注意力引导到验证路径上,生成结果会自动带上防御式检查。
清单第13项“拿到代码不审查直接合入”最终给人的教训是:模型没有责任心,只有你有。它不知道代码会跑在什么环境里,不知道线上数据长什么样,也不知道维护你代码的同事有什么习惯。这些信息,只有通过提示词才能传递过去。
我个人现在的体会就是一句话:把写提示词当成写需求文档,把审代码当成审外包交付。如果都能做到这个心态,大模型生成的代码,是可以成为团队生产力的。怕就怕把它当成一个“能自动写对的工具人”,那踩坑只是时间问题。
最后分享一个每次发布前都会做的动作:把关键文件里由模型生成的代码段,统一过一遍“变量命名是否贴切、分支逻辑是否冗余、异常信息是否可读”。这个过程十分钟都不用,但做完之后,那份代码和你亲手写的质量已经没有多少区别了。这份清单我强烈建议你也保留一份,按自己的项目情况增删,慢慢它就会成为团队的代码质量护城河。