AI帮忙写代码这件事,很多人用成了“高级搜索引擎”:在对话框里反复描述需求,生成一段代码粘过来,改了又改。真正用得溜的开发者已经在做另一件事——把某一类代码生成的整套经验打包成一个 Agent Skill,让 AI 一次性按照你想要的方式产出结果。围绕若依框架(RuoYi)后台管理系统的自动代码生成,就是一个非常典型的场景。本文我会把 Agent Skill 的黄金三层结构掰开揉碎讲清楚,再用五步法带你从零打造一个专门生成若依框架业务模块代码的 Skill,整个过程全部是实操过的经验,不是概念空转。
1. 先搞懂:为什么要给 AI “配技能”,而不是反复“教对话”
1.1 多轮对话生成若依代码的三大痛点
若依框架的特点是约定非常强:Controller 要返回统一响应、Service 要拆分接口与实现、实体类要加数据库映射注解、权限控制要打上@RequiresPermissions、分页查询要调用startPage()……这些约定对于老手来说是“肌肉记忆”,但对于 AI 来也一样,如果每次都是零散对话,它会频繁出错。
我试过在没有 Skill 的情况下让 AI 生成一个“班级管理”模块,结果代码看起来像若依,实际上哪都不对:Controller 里直接返回了自定义对象(应该用AjaxResult或TableDataInfo),Mapper 层没用 MyBatis 注解也没写 XML,实体字段也没有和数据库列做映射,最要命的是菜单权限 SQL 完全不符合框架要求,插入sys_menu表后菜单根本显示不出来。
这类问题的本质在于:每轮对话,AI 都在“猜测”你的框架约定,而不是根据自己的经验进行输出。如果你花了半小时把约定全部写在提示词里,下一轮对话又要重写一遍。而 Agent Skill 解决的就是这个问题:把框架约定固化成 AI 的长期记忆,让它一上来就按标准执行。
1.2 Skill 的本质:把经验固化成资产
理解 Agent Skill 最好的方式是把它类比成一个“入职培训包”。新员工刚进公司,你需要让他读规范文档、看老代码、学命名规则,培养一阵子才能上手。而 Skill 就是把这个“培养过程”压缩成三块结构化的资料,让 AI 读完就上岗。
- 描述层:告诉 AI 这个 Skill 的身份、用途、适用边界,相当于岗位说明书。
- 规则层:列出生成代码时必须遵守的硬性约束,相当于开发规范。
- 示例层:给出符合所有约定的代码样例,相当于老员工写的“标准答案”。
三层结构互为支撑,缺了哪一层效果都会打折扣。只给描述层,AI 知道该干什么但不知道怎么做;只给规则层,AI 知道约束但缺少具体形态;只给示例层,AI 能模仿样子但把握不了深层逻辑。这就是为什么叫“黄金三层”——结构稳定,可复用。
2. Agent Skill 黄金三层结构拆解:每一层该怎么填,为什么这么填
2.1 描述层:让 AI 清楚自己的“身份卡”
描述层是整个 Skill 最容易被轻视的一层,很多人随手写一段话就完事了,这是大忌。\ 描述层的写法直接决定了系统会不会在正确的时候加载这个 Skill、会不会跟其他 Skill 混淆。
我在实际使用中总结出来,描述层至少包含这四块:
- 名称(Name):Skill 的唯一标识,建议用“若依-业务模块代码生成”这种格式,简洁、可读。
- 触发场景(When to Use):说明在什么条件下应该使用这个 Skill。比如 NLP 提示词中一旦出现若依、RuoYi、后台管理系统、CRUD 模块等关键词,就自动触发。
- 职责边界(What It Does / What It Doesn't):明确当前 Skill 负责什么、不负责什么。这里建议写得非常清楚。比如“负责生成后端代码与前端页面,不负责部署配置、不改动已有业务逻辑、不解释框架原理”。很多人省掉这一块,结果在调用时 AI 会“自作主张”做一些超出 Skill 范围的操作,比如主动推荐注册中心、扯到微服务改造,反而把你带偏。
- 输出风格(Output Style):说明返回内容的组织方式,包括是否给出代码块、是否需要逐文件输出、是否要附带简要说明。若依项目里我一般要求“每个文件一个独立代码块,文件名作为代码块标注”,这样方便批量建文件。
提示:描述层的文字要像写需求文档一样精确,避免“等等”“可能”“也可以”这类模棱两可的词。AI 的风格是照字面执行的,模糊描述等于把选择权还给了它。
2.2 规则层:框架约定要变成“硬约束”
规则层是黄金三层里最体现功力的一层。若依框架的约定非常多,但真正影响代码能否跑起来的其实也就十来条。规则不是抄源码,而是要提炼成可执行的条目。我可以分享一份若依项目常用的规则清单,你可以直接抄到自己的 Skill 里:
- 后端包结构:
com.xxx.system.controller、com.xxx.system.service、com.xxx.system.service.impl、com.xxx.system.mapper、com.xxx.system.domain,不允许随意添加新包。 - Controller 统一继承
BaseController,返回类型是AjaxResult或TableDataInfo,分页列表接口使用startPage()+getDataTable()组合。 - Service 接口定义业务方法,ServiceImpl 实现接口并继承
ServiceImpl<Mapper, Entity>(领域服务基类),事务注解写在实现类上。 - Mapper 接口继承
BaseMapper<Entity>,复杂查询写在 XML 中,简单 CRUD 不写 XML。 - 实体类统一加上
@TableName注解,字段对应数据库列时使用@TableField映射驼峰与下划线。 - 权限控制:每个 Controller 方法都要标注
@RequiresPermissions("system:模块:功能"),如system:class:list。 - 操作日志:写操作(增删改、导入导出)要在方法上加
@Log(title="班级管理", businessType=BusinessType.INSERT)。 - 校验:入参对象使用
@Validated+@NotBlank等校验注解,不写手写校验逻辑。 - 前端页面放在
src/views/对应模块/下,统一使用若依封装好的组件,列表页必须有搜索区、表格区、操作列。 - 菜单与权限 SQL:插入
sys_menu表时,需包含目录、菜单、按钮三级节点,并配置perms标识,与后端@RequiresPermissions对应。
规则不宜过多。我一开始把几十条全部塞进去,结果 Skill 文件巨大,AI 检索时反而抓不住重点。后来精简到核心 12 条左右,效果反而更稳定,因为 AI 的上下文窗口看待一堆规则跟看待十几条规则,筛选能力是不一样。
2.3 示例层:用“标准答案”调教输出口径
示例层的价值怎么强调都不过分。规则写得再细,AI 生成的代码还是会存在细节偏差,因为语言模型是根据概率来生成内容的,它需要看到具体的“正确答案”来锚定输出风格。
示例层不需要把整个项目源码都放进去,而是精选几个有代表性的完整文件。以若依系统为例,我建议准备这六类示例:
- 一个实体类示例:涵盖
@TableName、@TableField、时间字段的@JsonFormat、逻辑删除标记。 - 一个 Controller 示例:涵盖分页列表、详情、新增、修改、删除、权限注解、日志注解。
- 一个 Service 接口与实现类示例:展示接口与实现分离、事务注解、调用 Mapper 的写法。
- 一个 Mapper 接口示例:展示
BaseMapper继承、XML 的写法边界。 - 一个前端列表页示例:展示搜索表单、表格、操作按钮、分页组件的使用。
- 一个菜单 SQL 示例:展示目录、菜单、按钮三级的 insert 语句。
每个示例文件都不需要太长,关键是结构完整、风格统一。AI 在生成新模块时,会以这些示例为模板进行相似度匹配,示例的质量直接决定生成结果的质量。我在实际使用中感觉,示例代码中的注释风格、方法命名、参数顺序,都会被模型模仿得很到位,因此,示例代码要像你希望 AI 产出的最终代码一样高标准。
注意:示例层不是让你贴大段源码就完了。建议给每个示例加一小段“示例说明”,指出这段代码体现了哪些规则。这样 AI 才能把示例和规则关联起来,而不是单纯死抄示例。
3. 五步法实操:从若依源码到可复用的 Agent Skill
3.1 第一步:找标准——从哪几类资料里抽取约定
五步法的起点不是写文档,而是收集资料。若依框架的约定分散在多个地方,你需要按下面的清单去“挖”:
- 框架源码里自带的后端示例模块(比如系统管理模块的代码),这是最权威的样本。
- 前端
views目录下的页面代码,观察列表页、表单页的写法。 - 数据库初始化脚本(如
.sql文件),看sys_menu表的数据结构,理解菜单权限的层级关系。 - 一套完整的业务模块(比如某公司基于若依做过的实际项目),看真实项目中额外的约定。
我建议把收集到的资料分门别类放进五个文件夹:controller示例、service示例、mapper示例、前端页面示例、sql示例。注意不要全塞进 Skill 里,这些文件更多是你提炼规则和编写示例的素材,如果全量塞入会导致文件过于庞大、检索困难。
收集完成后,通读一遍,把你自己平时写若依代码时的“下意识动作”记录下来。这些动作往往是约定最核心的部分,不会被写在框架文档里,但直接影响代码是否能通过编译、能否跑到上线。
3.2 第二步:定边界——明确 Skill 负责什么、不碰什么
这一步是我踩过最大的坑。最开始我做的 Skill 什么都能干,既能生成后端代码,又能做数据库设计,还能帮忙处理服务器部署,结果在实际运行中,AI 经常把需求理解得很奇怪,然后走向了一些奇怪的方向——本来是让它生成一个班级模块,它却开始指导我修改配置文件、调整组件版本。
后来我下决心把边界做了严格划分:
- 负责:生成某个业务模块的后端 Java 代码(Controller、Service、ServiceImpl、Mapper、实体类、DTO)、前端 Vue 页面、菜单 SQL。
- 不负责:修改既有模块的代码、设计数据库表结构(只基于已有表设计)、解释框架原理、排查运行报错、处理部署配置。
边界一旦清晰,AI 的工作方式反而高效很多——它知道自己是“代码生成工具”,而不是“全能助手”。这看起来约束了 AI 的能力,实际上是解放了输出质量。\ 另外,边界里还应该写明“输入要求”:调用者必须提供什么信息才能开始生成,比如“请提供业务模块的中文名称、表名、字段列表、所属权限前缀(如 system 或 monitor)”。否则 AI 连字段都没有,就只能凭感觉硬编,生成的结果当然没法用。
3.3 第三步:建素材——整理一份“框架弹药库”
有了素材和边界,接下来就是把素材“加工”成 Skill 能用的弹药。这一步具体做三件事:
第一,提炼规则清单。把第一步收集的素材里反复出现的行为模式汇总成 10~15 条硬性规则。规则要写成祈使句,尽量简短,让 AI 一眼看明白执行要点。比如“Controller 必须继承 BaseController”就比“Controller 继承 BaseController 以获得分页等公共能力”更直接有效。
第二,编写精简示例。从素材中挑选 6~8 个代表性文件,适当删减非核心代码,保留关键结构和风格特征。每个示例文件用“文件名 + 代码 + 注意点”三个部分组织。注意点是提炼的规则在使用中的体现,这样示例就不只是一个代码粘贴,而是一个带讲解的教学材料。
第三,设计调用模板。也就是写清楚 Skill 被调用时的输入输出格式。我在自己的 Skill 里设计了一个简单的交互模板:要求调用者按固定格式给出“模块名称、数据表名、业务字段列表、权限标识前缀”。这种模板化的方式能让后续输出非常稳定,因为 AI 一旦收到结构化输入,它会十分稳定地按这套路径来组织输出。
3.4 第四步:写 Skill——三层结构组装细节
素材准备好后,进入真正写 Skill 的环节。这里我以最通用的 Agent Skill Markdown 文件格式为例,展示黄金三层结构如何落进文件里:
--- name: 若依-业务模块代码生成 description: 当用户需要基于若依框架生成业务模块的后端Java代码、前端Vue页面或菜单权限SQL时使用。触发词:若依、RuoYi、后台管理系统、CRUD模块、代码生成。 ---这一整段只是元信息部分,真正的结构要从正文开始。我的经验是,在正文中第一段先写身份定位(描述层),接着写规则清单(规则层),最后是示例文件块(示例层)。三个部分用醒目的分隔线隔开,让 AI 在加载时能非常清楚地识别结构。
这里要特别提醒:Skill 不是越长越好。一个合格的若依代码生成 Skill,我建议控制在 8000 到 12000 字左右。内容太少覆盖不全,内容太多则检索和加载都会变慢,而且在 AI 面对长 Skill 时容易出现“前面规则写得很好,后面示例根本没用上”的情况。解决方案是把最重要的规则放前面,示例按“后端代码优先、前端与SQL其次”排列。
3.5 第五步:验效果——用三层测试用例检验 Skill
Skill 写完不是终点,要用测试用例来验证。我一般设计三类测试:
第一类叫“冒烟测试”:给一个最简单的模块(比如“字典类型管理”或者“公告管理”),要求生成完整的后端 CRUD 代码。目标是验证代码能不能跑通基本流程,有没有致命的结构错误。这类测试应该在 Skill 开发过程中反复执行,每次修改规则或示例后都要重新跑一遍。
第二类叫“边界测试”:故意给一个特殊场景,例如“数据表的字段特别多(30+)”、“需要同时生成父子表结构”、“需要导入导出功能”。目的是检验 Skill 在复杂场景下的鲁棒性,是不是一复杂就崩、就胡乱输出。
第三类叫“回归测试”:拿一个你已经手动开发过的模块,让 AI 用 Skill 重新生成一遍,交叉对比代码风格和实现逻辑。这能发现 Skill 是不是把某些自定义习惯带偏了,导致生成的代码和你团队风格不一致。
我在实际验证中发现一个特别管用的小技巧:先在 AI 对话界面里单独加载 Skill,然后用测试用例去触发;不要跳过多轮对话直接让 Skill 生成。用多轮对话去执行会更符合实际使用方式,因为 Skill 往往在对话中需要与用户交互确认信息。\ 每一轮测试后,把 AI 的产出逐行对照规则清单检查,把不符合项记录下来,反向去修改规则或补充示例。通常需要迭代 3~5 轮,Skill 的输出质量才会明显稳定。
4. 实战演练:让 Skill 生成一个“班级管理”模块
4.1 一个可直接抄作业的 Skill 文件结构
为了让你看得更明白,我直接贴一个精简但完整的若依 Skill 文件框架。这个文件我用在一套基于若依框架的教务管理系统模拟项目里,效果相当稳定。
--- name: 若依-业务模块代码生成 description: 若依框架业务模块后端与前端代码生成。触发词:若依/RuoYi/后台管理系统/业务模块 ---身份定位: 你是一名资深 Java 开发工程师,长期使用若依框架(Spring Boot + Vue + MyBatis),熟悉若依框架的所有代码规范和约定。你的职责是基于用户提供的业务信息,生成符合若依框架规范的完整业务模块代码。
严格遵守以下规则:
- Controller 统一放在 controller 包,继承 BaseController,返回 AjaxResult 或 TableDataInfo。
- Service 接口与实现类分离,ServiceImpl 继承 ServiceImpl,并添加 @Service 注解。
- 所有 Controller 中写操作接口必须添加 @Log 注解和 @RequiresPermissions 注解。
- 实体类使用 @TableName 注解映射表,字段使用 @TableField 映射列,时间字段添加 @JsonFormat。
- 分页列表接口调用 startPage(),返回 getDataTable(list)。
- 前端页面放在 src/views/目录对应模块下,使用 el-form 与 el-table,分页使用若依封装的 Pagination 组件。
- 提供插入 sys_menu 表的 SQL,包含目录、菜单、按钮三级,按钮的 perms 标识与后端注解对应。
- 输入信息不完整时,先列出所需字段信息并等待用户补充,不自行臆造。
示例文件:实体类示例 [示例1实体类代码]
示例文件:Controller 示例 [示例2Controller代码]
示例文件:ServiceImpl 示例 [示例3ServiceImpl代码]
示例文件:Mapper 接口与 XML 示例 [示例4Mapper代码]
示例文件:前端列表页示例 [示例5Vue代码]
示例文件:菜单 SQL 示例 [示例6SQL代码]
这个结构你可以直接用。需要注意,中间的人工提示语气全部用“你”来称呼 AI,保持命令式。实际运行中要记得把 `[示例1实体类代码]` 等占位符换成真实的示例代码,你手上如果有某个做完的若依项目,直接把这些模块代码摘出来作为示例就好。 ### 4.2 完整跑一遍:从输入到四个文件一次生成 我以“班级管理”模块为例,实际跑一遍这个 Skill。给 AI 输入以下信息:模块名称:班级管理 表名:tb_class 业务字段:class_name(班级名称)、grade_name(年级)、head_teacher(班主任)、student_count(学生人数)、create_time(创建时间) 权限标识前缀:system:class
Skill 被触发后,AI 会进行多维度的审视判断,注意看它的处理步骤。我观察到 AI 先在内部逻辑里分析表字段和后端实体类的映射关系,然后按“实体类 → Mapper → Service → Controller → 前端页面 → SQL”的结构逐个文件生成。中途不会有多余的提问,因为输入信息已经齐了,它会直接执行。 以下是几个关键文件的生成效果,我摘一段最重要的 Controller 代码: ```java @RestController @RequestMapping("/system/class") public class ClassController extends BaseController { @Autowired private IClassService classService; @RequiresPermissions("system:class:list") @GetMapping("/list") public TableDataInfo list(ClassQuery query) { startPage(); List<Class> list = classService.selectClassList(query); return getDataTable(list); } @Log(title = "班级管理", businessType = BusinessType.INSERT) @RequiresPermissions("system:class:add") @PostMapping public AjaxResult add(@Validated @RequestBody Class clazz) { return toAjax(classService.insertClass(clazz)); } @Log(title = "班级管理", businessType = BusinessType.UPDATE) @RequiresPermissions("system:class:edit") @PutMapping public AjaxResult edit(@Validated @RequestBody Class clazz) { return toAjax(classService.updateClass(clazz)); } @Log(title = "班级管理", businessType = BusinessType.DELETE) @RequiresPermissions("system:class:remove") @DeleteMapping("/{ids}") public AjaxResult remove(@PathVariable Long[] ids) { return toAjax(classService.deleteClassByIds(ids)); } }可以看到,权限注解、日志注解、统一返回结构、校验注解都齐了,格式与若依日常代码保持一致。这个结果靠纯对话很难一次做到,而 Skill 加持后基本是每次稳定输出这个水平。
实体类示例则按规则把@TableName("tb_class")写到类上,@TableField处理了驼峰和下划线的映射,时间字段加上@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")。Mapper 层查询接口使用了@Param注解,XML 路径和命名空间配置也准确。前端页面生成的则是若依常见的搜索区加表格区结构。
4.3 Skill 化前后的效果对比:到底差在哪
我把同一需求分别在“无 Skill 对话”和“有 Skill 输出”两种场景下跑了一遍,差异非常明显。无 Skill 时生成一个完整模块平均需要 4~6 轮对话,且至少会出现 2 到 3 处约定性错误,比如权限注解漏写、返回类型不对、菜单 SQL 缺少按钮层级。有 Skill 时基本上一次生成、小幅修订即可交付,代码风格更统一,集成时间减少一半以上。
差异的根源不是“聪明程度”不同,而是 AI 在无 Skill 时需要从长距离上下文里自己拼凑约定,容易丢失关键约束;在有 Skill 时,规则与示例直接注入上下文,相当于 AI 有了“记忆锚点”。这也是为什么我强烈建议团队里凡是基于若依开发的人都配一个这样的 Skill——它能消除大量低级错误,让团队把精力花在真正的业务逻辑上。
5. 常见问题与排查经验:Skill 不好用?大概率是这几件事没做对
5.1 三个最容易踩的坑
第一个坑是“规则与示例冲突”。我在某次迭代中调整了规则,要求 Controller 列表方法返回TreeDataInfo(因为一个模块需要树表),但示例层还是老的分页结构。结果 AI 生成时一会儿用新规则一会儿照旧示例,代码里两种风格并存,根本没有整体逻辑。解决办法是:每次改规则,必须同步检查所有示例,确保两者指向同一个标准。
第二个坑是“示例太特殊化”。从前端示例中有一处使用了自定义组件来处理级联选择,这个组件只在我那套系统里存在。Skill 生成其他模块时,AI 也依样画葫芦写了个不存在的组件导入,前端运行直接报错。示例一定要选择“通识部分”,把个性化逻辑剔除干净,或者明确标注“以下为个性化代码,不通用”。
第三个坑是“Skill 的容错不足”。用户提供的信息不完整时,Skill 如果没有写清“等待补充”的规则,AI 就会自己编造表名、编造字段。比如你只说了“生成学生模块”,没给表名,AI 可能生成一套基于student表的代码,实际库里的表叫tb_student_info,这样直接不能用。所以规则层必须有这一条:输入不完整时要停下来索要信息,而不是硬着头皮生成。
提示:如果你发现 Skill 生成一个模块要五轮以上对话反复修改才能用,不是你的建模思路有问题,而是 Skill 的规则/示例明细不够。建议先输出一次结果,把 AI 犯的每类错误记录成表,再回头看规则层和示例层缺了什么。
5.2 排查口诀与效率提升技巧
我用了很长一段时间,总结出四个字的口诀:看、查、改、验。
看,是看他生成的代码结构整体是否连贯,有没有文件缺失。查,是把生成代码的注解、返回类型、导入路径等项目逐条对照检查。改,是一旦发现某类问题反复出现,回到 Skill 修改对应规则或示例。验,是用回归测试确认修改有效、且没影响其他模块的生成效果。
效率上还有一个很实用的技巧是“给 Skill 配备配套输入模板”。我在 Skill 描述层中设置了标准输入格式,每次使用时,直接把表结构导出信息粘过来,AI 就能自动完成“表字段 → 实体类字段 → 表单字段 → SQL 菜单”的映射。这会减少海量的来回确认时间。
5.3 后续迭代方向:从单模块生成到全模块规划
这个 Skill 的初级形态是“单模块 CRUD 生成”,实际用顺手之后,完全可以迭代成多版本的“全套后台管理系统生成”。比如,你可以给 Skill 增加“支持树表结构”“支持主子表结构”“支持导入导出功能”“支持定时任务代码生成”等扩展模块,每次新增一个扩展能力,就找一份对应的真实案例塞进示例层。
我最近在往这个方向推进,给 Skill 增加了一套“项目级初始化”规则,让 AI 可以根据需求描述一次性生成多张表、多个模块的后端代码和前端菜单,甚至输出完整的菜单初始化 SQL 脚本。虽然还做不到完美,但已经能让我在搭建模拟项目原型时省下一天的重复劳动。
6. 最后分享一点我个人的实操体会
做 Agent Skill 这件事,技术含量不在于会写 Markdown、会写规则,而在于你能不能把自己脑子里那些“不成文的经验”摊开来,变成 AI 能执行的条目。我先后迭代过不少版本,最开始的规则清单写得又全又细,反而不好用,因为 AI 被太多约束困住,输出变得很僵硬。后来我学会了“少即是多”,只保留关键约束,把判断空间留给模型,效果反而提升。
另外有个习惯值得培养:每次让 AI 生成一段若依代码之后,不管代码是不是直接能跑,我都会花两分钟对照检查一遍。不是不信任 AI,而是这个检查过程本身就是打磨 Skill 的素材——你把发现的问题记下来,回到规则层补一句,下次生成就会少一类问题。这样反复迭代,你的 Skill 会越用越顺手,越用越“懂你”。
如果你所在的团队也在用若依这类强约定框架,我建议你下一周就动手做一个专属 Skill。不用追求一步到位,先从最常写的 CRUD 模块开始,跑顺手了再逐步加功能。这套“黄金三层结构 + 五步法”不止适用于若依,任何有固定代码模式的框架场景——比如生成报表模板、写特定风格的接口文档——都可以用同样的套路去沉淀和复用。