若依框架代码生成:用Agent Skill黄金三层结构锁定AI输出规范 我最近被一个问题折腾得够呛让AI生成若依框架代码它每次都能给你写出来但写出来的风格总是和团队规范差着那么一口气。权限注解偶尔跑到类上分页方法时用时不用菜单SQL里的权限串和Controller里对不上。你盯着这些代码改吧费时间不改吧上不了分支。后来我把这套规范做成了一个结构化的Agent SkillAI才终于像团队里一个懂规则的同事而不是一个记忆力时好时坏的实习生。这篇文章想分享我总结的黄金三层结构以及用五步法打造一个能自动生成若依框架代码的Agent Skill的全过程。适合正在用AI辅助业务开发的后端同学也适合想把项目规范沉淀成可复用资产的人。文章里不会有虚头巴脑的概念全是能直接落地的结构和做法。1. 先把“散装提示词”升级成Skill黄金三层结构1.1 为什么散装提示词撑不住若依这种规范密集型项目一开始我走的弯路是把所有要求写进一段超长Prompt里什么“你是资深Java工程师”“请严格遵循若依规范”“分页要正确”“权限注解别写错”杂七杂八堆了上千字。问题是AI处理长Prompt时越靠后的指令权重越低上下文一长前面要求的“统一风格”经常被后面的具体任务冲散。更麻烦的是维护。今天发现实体类缺了序列化ID往Prompt里补一句明天发现菜单SQL父级写死又补一句。来回改几次之后这个Prompt变成一坨自己都不想看的东西。同事想复用也复用得提心吊胆因为谁也说不清它现在到底会生成出什么。Agent Skill解决的是这件事它把一段结构化的Markdown文档挂到Agent工作区里AI在遇到相关任务时自主读取。这个文档是静态的不受当前对话上下文漂移影响它是独立文件可以进版本库它可以被反复测试和迭代。换句话说散装Prompt是口头的“你注意点”Skill是白纸黑字的《团队编码规范手册》哪个更可靠不言而喻。我当时做了个实验同一套需求用长Prompt生成一次用Skill生成一次。长Prompt那次的产物有三分之二的地方需要人工修Skill那次的基本能直接进开发分支。差距就是从“碰运气”到“有预期”的变化。1.2 黄金三层结构意图层、知识层、执行层把大量经验塞进一个文件之前得先搞清楚文件里的信息怎么组织。我总结的黄金三层结构是意图层、知识层、执行层。拿生活打个比方。意图层是前台判断来的人是不是找对了窗口知识层是专家手册把这一行的规则、标准、禁忌写得清清楚楚执行层是车间主任告诉工人先干什么后干什么、用什么模板产出什么。三层各管一摊缺一不可。落到SKILL.md文件里结构是这样的--- name: ruoyi-code-generator description: 当用户需要生成符合若依框架规范的模块代码时使用。 覆盖建表SQL、Java后端分层代码、Vue页面、菜单权限SQL。 使用前需要用户提供表名、字段说明或数据库表结构缺少关键信息时主动询问不要自行假设。 仅用于后台管理模块代码生成不处理其他领域的编程问题。 --- # 目标与边界 ... # 若依编码规范 ... # 标准工作流 ... # 参考示例 ...前面的YAML头就是意图层正文里的“若依编码规范”是知识层“标准工作流”和“参考示例”合起来是执行层。实际使用中三层各有各的关键点。意图层的description写得准不准直接决定Skill会不会在错的场合被触发知识层是AI判断“怎么写正确”的依据写得越具体越可验证越好执行层决定了AI是东一榔头西一棒子还是按照依赖顺序稳扎稳打地产出。一层的质量差整个Skill的效果都会大打折扣。1.3 三层各做各的事别混在一起我见过不少失败的Skill失败原因不是内容不够而是内容全混在一起。有人把“什么时候触发”写进知识层有人把具体代码规范塞进描述里还有人把工作流步骤和编码规则揉成一个大段落。这样AI读取时很难分辨哪些信息用于触发、哪些用于生成、哪些用于排序。刻意拆分是有理由的。意图层只回答一个问题这个Skill在什么场景下该被调用。知识层只回答一个问题这个领域里有哪些规则和约束。执行层只回答一个问题接到任务后按什么顺序、用什么模板产出结果。每层职责单一AI解析的难度就低误触发的概率也小。在设计层面还有一个经验把“不做什么”写进意图层比只写“做什么”更管用。比如若依代码生成Skill的描述里明确写“不要处理登录鉴权设计、消息队列集成等跨领域问题”Agent就不会在你问Redis集群方案的时候莫名其妙生成一个后台查表接口。这种边界感越清晰Skill的专业性越强。2. “五步法”从零打造若依代码生成Skill2.1 第一步定义意图边界打造Skill的第一步不是在知识层写代码规范而是先把“这个Skill什么时候出场”定义清楚。很多人上来就写技术细节结果Skill文件写到一半才发现连合适的使用场景都没想明白。我建议把以下三件事写进意图层这个Skill叫什么名字名字要短、唯一、方便识别。什么样的话题会触发它尽量用“当用户需要XX时”句式。它明确不处理什么把边界划出来。以若依代码生成Skill为例我最初的定义是“当用户要求生成若依风格的业务模块、后台管理页面、菜单SQL时使用”。后来加了半句“需要用户提供表名、字段说明或数据库表结构缺少关键信息时主动询问不要凭空假设”触发率一下子准了很多因为AI知道必须先拿到字段数据才会开始干活而不会上来就编一张表。这里面有个容易被忽略的坑description不要写太长长了AI抓不住重点。核心触发条件控制在两三句话之内越精炼越有效。详细的触发判断规则可以放到正文里但YAML头部的summary一定要短平快。2.2 第二步蒸馏团队领域的“硬知识”知识层是整个Skill的地基。若依这种框架之所以适合做成Skill是因为它的规范足够固定表名小写下划线、实体继承BaseEntity、权限注解用指定写法、分页必须先调startPage、导出依赖Excel注解、菜单SQL的perms必须与Controller注解一致。这些规则是可枚举、可验证、可沉淀的。知识层的素材来源是实际项目代码和团队约定不是凭记忆生成的。我会把项目里三五个写得最规范的模块翻出来逐个对照整理出以下内容后端分层结构Controller、Service、ServiceImpl、Mapper、XML的位置与命名风格。实体类规范继承关系、主键策略、审计字段处理、是否需要序列化ID。权限注解格式模块名:业务名:操作名三个段位的命名规则。分页返回协议startPage()的调用时机、TableDataInfo的返回方式。导出规则哪些字段需要加Excel注解、字典转换怎么写。整理成知识条目后放在“若依编码规范”标题下面一条条列清楚。这里有一个重要的取舍不是知识越多越好而是越“可验证”越好。你写一句“代码风格要统一”AI无法判断什么算统一你写一句“所有Controller方法使用PreAuthorize(ss.hasPermi(模块:业务:操作))声明权限”AI就有一把明确的尺子。2.3 第三步把生成过程写成固定工作流知识层告诉AI“什么是正确”执行层告诉AI“按什么顺序干活”。我见过不少Skill在这块栽跟头规则写了一大堆但Agent拿到需求后还是凭感觉出牌东写一块西写一块最后产出的代码支离破碎。我的做法是把若依模块生成拆成固定8步确认输入核对表名、字段说明、模块功能缺信息先问。设计表结构补主键、审计字段、索引和字段注释。生成建表SQL小写下划线表名字段类型与Java类型映射明确。生成实体类按字段映射关系逐一对应。生成Mapper与XML基础CRUD复杂查询按需添加。生成Service与ServiceImpl业务逻辑为空壳也要有标准方法签名。生成Controller权限注解、日志注解、分页接口写完整。生成Vue页面与菜单SQL接口路径与后端保持同源。为什么是这个顺序而不是反过来因为依赖关系决定了先后数据库字段是源头字段错了后面全错后端的Controller依赖ServiceService依赖MapperMapper依赖实体必须自底向上前端接口依赖后端路径所以放在后端之后菜单SQL里的权限串必须和Controller注解对齐放在最后顺手自检最合理。2.4 第四步注入少量优质示例知识层讲规则但AI有时候看不懂抽象规则塞几个示例让它“抄作业”是最有效的补强手段。示例不在于多而在于准。我建议准备2到3个完整示例覆盖不同复杂度的场景。以若依为例单表CRUD最简单覆盖基础增删改查和分页。树表覆盖父子结构、层级查询。主子表覆盖关联表、明细行操作。每个示例不需要把几百行代码全贴出来只需要保留“可复用的骨架”一个Controller的完整写法、一个实体的注解布局、一段菜单SQL的标准结构。这样既控制Skill文件体积又能在关键节点给AI提供参照。这里有一个我踩过的坑示例不能选那种“写得有特色但不符合团队规范”的代码。比如老项目里某个Controller把权限注解写到了类级别虽然能跑但它不是团队标准做法。选示例必须从当前最规范的模块里挑否则AI会把两个风格一起学走反而导致风格分裂。2.5 第五步测试、复盘、迭代Skill是写出来的也是测出来的。不经过几轮真实用例打磨的Skill文件上线后大概率翻车。我的测试方法是准备一个固定用例集每次改完Skill都用同一批用例跑一遍保证改动是可对比的。用例不需要复杂五六个即可测试场景期望输出检查点单表CRUD生成完整模块代码权限注解格式、分页返回树表生成父子结构正确树查询接口、前端树组件主子表生成明细表操作正确子表外键、批量保存缺字段信息时Agent主动询问不自行假设表结构非若依任务Skill不触发描述边界生效跑完之后把失败案例归类。触发错误是指该触发没触发、不该触发乱触发知识错误是指规则写得不够明确导致产物走样输出错误是指工作流步骤缺了某段导致前后不同源。三种错误的修法完全不一样归错类会白改一遍。我第一个版本的Skill前后迭代了四五次才稳定下来。每次迭代只改一个点改完立刻跑全部用例集确认没有引入副作用才提交版本库。这个习惯帮我省掉了大量排队等Agent“随机发挥”的时间。3. 完整实操让Skill自动生成“物资台账”模块3.1 输入设计怎么给Agent描述需求Skill再强也依赖输入质量。用户给Agent的描述越结构化生成结果越稳定。我总结了一套请求模板团队里直接用请生成若依风格的【物资台账】模块。 表名material_record 模块名material 功能物资入库、出库、库存查询 字段 - id bigint 主键 - material_name varchar(128) 物资名称 - category_id bigint 分类ID - stock bigint 库存数量 - status char(1) 状态0正常 1停用 - create_by varchar(64) 创建人 - create_time datetime 创建时间 - remark varchar(500) 备注 需要功能列表查询、新增、编辑、删除、导出。这套模板生效的关键在于把字段清单、功能清单、模块名一次性给全。缺了字段清单Agent要么瞎编要么反复追问浪费你时间。缺了功能清单它会在“列表新增编辑删除”之外自由发挥多生成一堆你不要的接口。如果需求本身不明确Skill会在意图层就发起追问。这比让Agent直接猜要好得多因为后台管理模块的表结构一旦定错后面生成的代码全是废的。3.2 生成建表SQL与EntitySkill拿到输入后第一步产出建表SQLCREATE TABLE material_record ( material_id bigint NOT NULL AUTO_INCREMENT COMMENT 物资ID, material_name varchar(128) NOT NULL COMMENT 物资名称, category_id bigint DEFAULT NULL COMMENT 分类ID, stock bigint DEFAULT 0 COMMENT 库存数量, status char(1) DEFAULT 0 COMMENT 状态0正常 1停用, create_by varchar(64) DEFAULT COMMENT 创建者, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, remark varchar(500) DEFAULT NULL COMMENT 备注, PRIMARY KEY (material_id) ) ENGINEInnoDB COMMENT物资台账;注意几个细节主键用了bigint自增而不是叫id字段名全小写下划线每个字段都有COMMENT时间和审计字段自动补齐。这些动作背后都是知识层里写明的若依规范。紧接着生成实体类TableName(material_record) public class MaterialRecord extends BaseEntity { TableId(value material_id, type IdType.AUTO) private Long materialId; Excel(name 物资名称) private String materialName; Excel(name 分类ID) private Long categoryId; Excel(name 库存数量) private Long stock; Excel(name 状态, dictType material_status) private String status; Excel(name 备注) private String remark; }status字段绑定了字典类型material_status这样导出时自动转成字典文案前端下拉框也能直接复用字典数据。这个细节是知识层里的条目“字典字段必须绑定dictType”的具象化。3.3 Service与Controller生成后端生成的依赖顺序是从底层到上层。这里演示一套常见的接口加实现加XML风格具体代码以你项目实际依赖为准但职责划分是一样的。Service接口public interface IMaterialRecordService { ListMaterialRecord selectMaterialRecordList(MaterialRecord materialRecord); MaterialRecord selectMaterialRecordById(Long materialId); int insertMaterialRecord(MaterialRecord materialRecord); int updateMaterialRecord(MaterialRecord materialRecord); int deleteMaterialRecordByIds(Long[] materialIds); }Controller是权限控制的关键位置RestController RequestMapping(/material/record) public class MaterialRecordController extends BaseController { Autowired private IMaterialRecordService materialRecordService; PreAuthorize(ss.hasPermi(material:record:list)) GetMapping(/list) public TableDataInfo list(MaterialRecord materialRecord) { startPage(); ListMaterialRecord list materialRecordService.selectMaterialRecordList(materialRecord); return getDataTable(list); } PreAuthorize(ss.hasPermi(material:record:add)) Log(title 物资台账, businessType BusinessType.INSERT) PostMapping public AjaxResult add(RequestBody MaterialRecord materialRecord) { return toAjax(materialRecordService.insertMaterialRecord(materialRecord)); } PreAuthorize(ss.hasPermi(material:record:edit)) Log(title 物资台账, businessType BusinessType.UPDATE) PutMapping public AjaxResult edit(RequestBody MaterialRecord materialRecord) { return toAjax(materialRecordService.updateMaterialRecord(materialRecord)); } PreAuthorize(ss.hasPermi(material:record:remove)) Log(title 物资台账, businessType BusinessType.DELETE) DeleteMapping(/{materialIds}) public AjaxResult remove(PathVariable Long[] materialIds) { return toAjax(materialRecordService.deleteMaterialRecordByIds(materialIds)); } }分页方法必须由继承的BaseController提供权限注解格式严格遵守日志注解标注业务类型。这些都是在知识层里写死的规则AI不用思考直接套用即可。3.4 Vue页面与菜单SQL前端页面按若依的常规结构生成列表页包括搜索区、按钮区、表格区。el-form :modelqueryParams refqueryRef :inlinetrue el-form-item label物资名称 propmaterialName el-input v-modelqueryParams.materialName placeholder请输入物资名称 clearable stylewidth: 200px keyup.enterhandleQuery / /el-form-item el-form-item el-button typeprimary iconSearch clickhandleQuery搜索/el-button el-button iconRefresh clickresetQuery重置/el-button /el-form-item /el-form el-table v-loadingloading :datamaterialList el-table-column label物资名称 aligncenter propmaterialName / el-table-column label状态 aligncenter propstatus template #defaultscope dict-tag :optionsmaterial_status :valuescope.row.status/ /template /el-table-column /el-table el-button v-hasPermi[material:record:add] typeprimary iconPlus clickhandleAdd新增/el-button菜单SQL生成时最容易出错因为按钮权限的父ID必须指向菜单ID不能随便写-- 先插入菜单拿到menu_id INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon) VALUES (物资台账, 1, 1, material, material/record/index, 1, 0, C, 0, 0, material:record:list, example); -- 再插入按钮权限parent_id必须用上面的menu_id INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon) VALUES (新增物资, [上一步生成的menu_id], 1, , , 1, 0, F, 0, 0, material:record:add, );Skill工作流里增加了“提示用户确认父菜单ID”的步骤因为Agent无法知道你的菜单树结构。这个设计可以避免AI无脑把parentId写死成0结果插出来的菜单挂在根节点上权限完全错位。3.5 生成后的自检清单Skill的最后一步是自检。我把自检项做成了固定清单Agent生成完代码后会逐项核对检查位置检查内容Controller每个接口是否都有权限注解权限串格式是否为“模块:业务:操作”分页list方法是否先调startPage()返回值是否通过getDataTable包装实体字段注解是否完整主键策略是否正确字典字段是否绑定dictType前端接口路径、请求方法、参数名是否与后端一致菜单SQLperms是否和Controller注解完全一致按钮权限是否挂在对应菜单下建表SQL是否包含主键、字段注释、索引审计字段是否齐全这个自检步骤效果出奇的好。原因很简单AI在“生成模式”下容易犯低级错误但你让它“检查模式”下找自己的错准确性会明显更高。生成和审查两个动作分开比让AI边写边改靠谱得多。4. 实战中踩过的坑与排查技巧实录4.1 常见问题速查表Skill迭代过程中我积累了一份问题排查表。这里整理几个最典型的情况现象可能原因对策生成代码同时出现“XML风格”和“BaseMapper风格”知识层缺少统一风格声明在Skill中写死“本项目Mapper采用XML方式”并贴一个标准片段作为锚点权限注解被写到类级别而非方法级别少样本示例里Controller权限写法不规范替换为规范示例在知识层补一句“权限注解统一写在方法上”分页返回缺少total未调用startPage或返回体用错在工作流自检步骤中加入“检查分页”这一项字段类型乱映射Double替代BigDecimalJava与MySQL类型映射表缺失在知识层补一张完整的类型映射表菜单SQL的parentId写死为0工作流没有菜单上下文确认环节增加“先询问父菜单ID再生成SQL”的步骤Vue接口与后端路径对不上前端与后端分开生成导致路径漂移工作流要求先定RequestMapping再在同一轮生成前端保证同源实体类缺少serialVersionUID知识层没有序列化注意事项在规范清单里加入“实体类必须声明serialVersionUID”Agent拒绝一次生成全部文件输出过长超出模型处理上限在工作流中说明“按文件逐个产出不要尝试一次输出全部代码”这份速查表不是一次性写出来的而是每次踩坑后往里追加迭代了几轮才到现在的完整度。Skill的价值必须靠这种持续积累来体现它不是写完就能一劳永逸的。4.2 写在知识层里的“禁止事项”比规则更管用一个让我印象深刻的经验是正面规则写着“保持风格统一”AI还是会跑偏但你在知识层写一句“不要生成BaseController已经存在的分页方法”AI就真的不碰了。负面清单对AI的约束力比抽象的正向要求强得多。我的Skill里沉淀了这几条禁止事项不要重复生成BaseController、BaseEntity、AjaxResult、TableDataInfo这些公共类。不要修改数据库表结构除非用户明确要求。不要手写与字典表无关的下拉选项一律从字典数据读取。不要生成单元测试除非用户点名要求。不要在Mapper XML里创建已存在的resultMap。这些负面清单的作用机制是给AI划出一道明确的“到此为止”线它能有效减少AI的“自由发挥”。每一次发现AI在某个不该冒进的地方冒进了就把这个行为转译成一条禁止事项补进知识层。这个过程类似给实习生写“千万别做清单”效果立竿见影。4.3 多Skill协作生成器不是万事通实践中我把“生成”和“审查”拆成了两个Skill配合作业。生成器Skill负责从需求到代码的全流程产出审查Skill负责对产物做规范逐项检查。这样分工的收益是审查Skill可以复用多个生成器的产物不只服务于代码生成这一条线。三个Skill的定位如下生成器Skill负责把描述转化成完整模块包含建表SQL、后端、前端、菜单SQL。规范审查Skill只读代码对照项目规范逐项打分输出问题清单。数据库设计Skill负责表结构评审检查字段类型、索引、命名是否合理。生成完成之后让审查Skill过一遍再进开发分支相当于给AI配了一个“自检员”。这个做法最大的好处是生成和审查互相独立不会因为生成过程跑偏被AI自我感觉良好地掩盖掉。团队用下来的体会非常直观引入审查环节后AI生成代码被打回重做的比例降了接近一半。5. 让Skill长期好用的几个心法Skill不是一次写成的而是用出来的。这句话我验证了很多遍。再完善的Skill第一次上真实项目也会露怯关键是你愿不愿意根据失败反馈持续迭代。我的习惯是每次Agent生成的代码被人工修过都会追溯到Skill文件本身——是知识层没覆盖到还是工作流顺序不对还是示例不够典型。修Skill的成本远低于下次继续返工的成本。另一个心法是别贪多。一个Skill只做好一件事比一个Skill想做十件事强得多。你完全可以先做一个只覆盖单表CRUD的最小Skill跑通流程、建立知识层骨架再扩展树表、主子表、复杂查询。一上来就想让Skill生成整个系统级代码文件会臃肿到AI都懒得完整读效果反而更差。最后一个建议是把Skill文件纳入版本库跟随项目代码一起评审。这么做不仅让团队成员都能看到规范的载体还能在评审过程中发现知识层里那些过时、冗余、不准确的条目。Skill不是某个人私有的咒语而是团队公共资产的一部分。让它接受团队Review它才会越来越接近团队真正想要的形态。我自己现在每次更新Skill文件后都会用固定的测试用例集跑一遍再提交确保改动没有破坏其他场景。这套流程跑下来AI生成的若依模块已经从“勉强能看”变成了“可以直接进开发分支”省下来的时间不是一点点。如果你也受够了AI代码风格飘忽不定别急着堆提示词先按这个黄金三层结构用五步法做一个你自己的Skill哪怕只覆盖一个模块试试就知道值不值。