给 Java 后端写 Prompt,不是玄学
摘要同样的需求给同一个 AI不同 Prompt 写出来的代码质量可能差一个数量级。本文不讲通用的 Prompt 技巧讲 Java 后端四个高频场景下具体怎么写——生成 CRUD、生成 MyBatis 映射、Debug 定位、单元测试——每场景给差的写法和好的写法附带可直接改项目名使用的模板。上周同事找我问了一个很实际的问题。“你们用 AI 写代码怎么就能直接跑我每次跟 AI 说’写一个用户管理的 CRUD 接口’它给我的代码 Controller 里全是HashMap没有 Service 层没有参数校验返回裸的ListMap。我跟他说这儿不对、那儿不对来回七八轮改完的代码还不如我自己写得快。有这功夫我早写完了。”我看了他的 Prompt“写一个用户管理的 CRUD 接口用 Spring Boot。”然后我让他把 Prompt 改成这样——“项目用 Spring Boot 3.2 MyBatis-Plus包结构 com.xxx.controller/service/mapper/entity。表结构如下贴了 DDL。统一返回体 Resultcode/message/data。Controller 只做路由和参数校验业务逻辑全放 Service。禁止 Controller 直接操作 Mapper。”他重新发了一遍。AI 生成的代码Controller、Service、ServiceImpl、Mapper、Entity 全齐参数用Valid校验异常抛BusinessException返回体套了ResultT。改个包名直接跑。同事愣了几秒“就这么简单”就是这么简单。同一个需求、同一个 AI。差别不在于你会不会跟 AI 说话在于你给了 AI 多少它能用的上下文。好的 Prompt 不是技巧是上下文打包很多人把 Prompt 工程当成一套咒语——用对词 AI 就听话用错词 AI 就乱来。实际情况是AI 不是不听你的是你给的信息不够它判断这个项目的代码应该长什么样。让它写 Java 代码它能写出能编译的、语法正确的 Java。但它不知道你的项目用 Spring Boot 2.7 还是 3.2、用 MyBatis-Plus 还是 JPA、异常是抛RuntimeException还是BusinessException、返回到前端的是Result还是ApiResponse。这些东西你不写进 promptAI 就只能猜。猜错怎么办代码重写。我总结了一个 Java 后端 Prompt 的六要素模板每次写 prompt 套一遍1. 角色 → 你是一个资深 Java 后端工程师 2. 技术栈 → Spring Boot 3.2 MyBatis-Plus 3.5 MySQL 8.0 3. 业务需求 → 做什么、规则是什么、边界条件是什么 4. 项目规范 → 包结构、分层规则、统一返回体、异常处理方式 5. 输出要求 → 要哪些文件、要不要注释、要不要请求示例 6. 禁止项 → 不要硬编码、不要编造不存在的类、不要省略判空其中第 4 项项目规范和第 6 项禁止项是绝大多数人漏掉的也是 AI 写出不合群代码的主要原因。下面用四个最常用的 Java 场景演示这套模板怎么落地。场景一生成 CRUD 接口最频繁的场景。大部分人第一反应是写一个 XX 管理接口然后抱怨 AI 写的 Controller 里塞了 SQL。❌ 差的写法写一个用户管理接口包含增删改查。AI 会给你一坨 Controller 里直接拼 HashMap 的代码。不是 AI 不行是你没告诉它这个项目不允许这样写。✅ 好的写法你是一个资深 Java 后端工程师。 技术栈Spring Boot 3.2 MyBatis-Plus 3.5 MySQL 8.0。 业务需求实现系统用户的 CRUD 接口。 - 新增用户名/手机号/邮箱必填用户名唯一、手机号唯一 - 查询支持按用户名模糊搜索 分页 - 更新不允许改用户名只能改手机号/邮箱 - 删除软删除改 is_deleted 字段不允许物理删除 项目规范 - 包结构com.xxx.controller / service / service.impl / mapper / entity - Controller 只做路由和 Valid 参数校验业务逻辑全部放 Service - 统一返回体 ResultT(code, message, data) - 业务异常统一抛 BusinessException由全局异常处理器兜底 - 分页参数封装在 PageQuery 基类中 输出要求 - Entity、Mapper接口 XML、Service、ServiceImpl、Controller - 关键逻辑加中文注释 禁止项 - 禁止 Controller 里写任何业务逻辑 - 禁止直接操作 Mapper必须通过 Service - 禁止硬编码常量统一放 Constants 类 - 禁止编造不存在的工具类贴完这段AI 生成的代码基本改个包名就能跑。关键差异不在有没有说需求而是有没有说这个项目不允许做什么。场景二生成 MyBatis 映射AI 写简单 SQL 还不错但一到多表关联就翻车——不是写了 N1 查询就是用了不存在的字段名。❌ 差的写法写一个查询企业工单列表的接口关联工单表、处理人表、客户表。AI 大概率给你一个 MP 的LambdaQueryWrapper嵌套三层或者一个 JOIN 写错表别名的 SQL。✅ 好的写法项目用 MyBatis-Plus但多表关联查询必须写 XML Mapper禁止用 Wrapper 拼接 JOIN。 请生成一个工单列表查询 - 关联表t_ticket t LEFT JOIN t_user u ON t.handler_id u.id LEFT JOIN t_customer c ON t.customer_id c.id - 支持按工单状态、创建时间范围筛选 - 分页返回每页默认 20 条 - 结果包含工单号、处理人姓名、客户名称、优先级、状态、创建时间 已有 Mapper 写法参考贴一个项目中已有的 UserMapper.xml 片段 select idselectUserPage resultType... SELECT u.id, u.username, u.email FROM t_user u WHERE u.is_deleted 0 if testquery.keyword ! null and query.keyword ! AND u.username LIKE CONCAT(%, #{query.keyword}, %) /if ORDER BY u.create_time DESC /select 请参照以上写法生成 OrderMapper.xml 的对应查询。给 AI 看一个已有的正确 Mapper效果比描述 100 个字都好。AI 会模仿你的 XML 风格——if的写法、表别名的习惯、参数命名方式——这些靠口头描述永远说不清楚。场景三Debug——贴报错定位AI 的 Debug 能力被严重低估——不是因为 AI 不会是因为大部分人贴的报错信息根本不够。❌ 差的写法代码报错了帮我看看。或者只贴了一行NullPointerException然后把几百行的业务代码全粘过来。✅ 好的写法Spring Boot 3.2 MyBatis-Plus 项目数据库 MySQL 8.0。 报错信息完整堆栈 java.lang.NullPointerException: Cannot invoke com.xxx.entity.User.getId() because user is null at com.xxx.service.impl.TicketServiceImpl.assignHandler(TicketServiceImpl.java:47) at com.xxx.controller.TicketController.assign(TicketController.java:32) ... 相关代码TicketServiceImpl.java 第 40-55 行 User user userMapper.selectByPhone(ticketDTO.getPhone()); ticket.setHandlerId(user.getId()); // ← 第 47 行这里炸了 ... 预期通过手机号查用户关联到用户所在部门 实际手机号对应的用户不存在时直接 NPEAI 拿到三样东西完整堆栈、炸的那几行代码、你的预期 vs 实际。它不需要猜你在干什么可以直接定位selectByPhone没做空判断需要加if (user null)并抛业务异常。堆栈贴多少贴到最底层你自己的业务代码行号就可以了Spring/MyBatis 框架层的不需要。场景四单元测试生成AI 写测试最容易踩的坑——它只测 happy path。你在 prompt 里不写要测什么场景它就只给你正常流程的测试。❌ 差的写法给这段代码写单元测试。结果一个正常流程的测试方法assert 了返回值。没了。空输入、异常、并发——全没测。✅ 好的写法用 JUnit 5 Mockito 给以下 Service 方法写单元测试。 需要覆盖的场景每个场景一个测试方法 1. 正常流程所有参数合法返回预期结果 2. 参数为 nullusername 为 null抛 BusinessException(用户名不能为空) 3. 依赖异常userMapper.insert() 抛出 DataAccessException返回失败 4. 边界条件username 长度等于 50上限应正常入库 5. 并发两个线程同时插入相同 username第二个应抛 BusinessException(用户名已存在) 禁止项 - 不要用 PowerMock项目不支持 - 不要 mock static 方法除非必须 - 每个测试方法名用 should_xxx_when_xxx 格式列出要测的场景远比写单元测试五个字有效。AI 需要知道你对这个方法的哪些边界有预期——你不说它就只测它觉得最可能的那个。四个可复用的模板把上面的写法抽象成填空模板。下次写 prompt改项目名和技术栈就行。CRUD 模板你是一个资深 Java 后端工程师。 技术栈[框架 版本] 业务需求[功能描述 校验规则 权限规则] 项目规范[包结构 / 分层约束 / 统一返回体格式 / 异常处理方式] 输出要求[要哪些文件 / 要不要注释] 禁止项[不要做的事 1 / 不要做的事 2 / 不要做的事 3]MyBatis 模板多表关联必须写 XML禁止 Wrapper JOIN。 [贴一个项目中已有的正确 Mapper 片段] 请参照以上写法生成 [表名] 的对应查询。 查询条件[字段筛选规则] 分页[每页条数]Debug 模板[项目技术栈] [完整堆栈信息] [出错代码片段 行号标注] 预期[应该怎样] 实际[实际怎样]单元测试模板用 [测试框架] 给以下方法写单测。 覆盖场景 1. 正常流程[预期行为] 2. [边界 1] 3. [边界 2] 禁止项[不用的框架 / 不用的写法]三个常见的反模式1. 上下文过载。有人觉得给越多信息越好把一个 200 个文件的项目全贴进去。AI 的注意力是有限的——上下文越长对关键信息的权重越低。只贴跟当前任务相关的 2-3 个文件。2. 一次性要太多。“给我生成整个工单模块”——AI 会给你一段看起来完整但每个文件都差一点的代码。拆开先要 Entity Mapper确认字段对了再要 Service最后要 Controller。三步比一步质量高得多。3. 不贴规则以为 AI 会自动读。你在项目里配了.cursor/rules、.codebuddy/rules不代表 prompt 里不用再提。AI 不会每次都去翻你的规则文件——prompt 里把关键的 2-3 条禁止项再写一遍是性价比最高的保险。Prompt 好不好不是你语言表达能力的问题是你给 AI 看的上下文够不够它判断这个项目应该怎么写的的问题。每次写完 prompt问自己一个问题AI 有没有足够的信息知道别人在这个项目里是怎么写代码的如果答案是不确定——把 DDL 贴上去、把已有 Mapper 贴上去、把分层规则写清楚、把禁止项列出来。这四件事比任何Prompt 咒语都管用。作者唐悦玮 | 从后端出发用 AI 拓展到全栈的工程师。