这两年和AI结对写Vue的时间,比我一个人手写代码的时间都长。你要是也天天被AI生成的Vue代码气到,应该能秒懂这几种痛:组件库导入路径五花八门,上个组件还规规矩矩用<script setup>,下个组件突然冒出整段 Options API;明明项目里封装好了统一的请求层,它非要自己跑去fetch;一个页面组件写下来八百行,样式连scoped都不加。问题真不在模型笨,而在它压根不知道你的项目章程。后来我把Vue项目的编码规范、技术栈基线、反模式清单全部沉淀成一个 Skills(技能包),AI产出的Vue代码才算真正有了“团队味”。这篇文章就聊聊,怎么教 AI 正确写 Vue,以及为了做一个可复用的 Vue Skills,我在项目里实际走完的每一步。
1. 为什么AI写的Vue代码总差口气
1.1 生成式AI写Vue的典型翻车现场
我这几年主要做中后台管理系统,Vue 3 + TypeScript + Ant Design Vue 是主力技术栈。刚把AI编码接入日常开发时,最初的体验确实惊艳——写个表单、画个表格,几分钟就出来一版能跑的东西。但真正开始 review 代码,血压就开始往上走。
翻车现场大概可以分成五类。
第一类是 API 风格混乱。同一个项目里,前一个组件用<script setup>加ref,后一个组件就给你冒出来一个data()返回对象,再下一个又变成defineComponent套 Options API。坦白说,每个单独拎出来都能跑,但代码库的风格完全失控,团队里任何一个人接手都会崩溃。第二类是项目约定被无视。我们项目里所有请求都走src/api目录下的模块,接口统一返回{ code, data, message }结构,AI 经常绕过这套封装直接fetch,也不判断业务码,等于把项目最核心的容错逻辑全部跳过了。第三类是组件库用法跑偏。项目用的是 Ant Design Vue,AI 有时候会生成自己“想象中的原生按钮”,或者把a-table的列定义写成嵌套十几层的对象,看着很酷,维护起来想哭。第四类是样式污染。全局样式、scoped 样式、内联样式混着来,组件不写scoped,改一处样式全站跟着变。第五类是依赖乱加。项目里明明装了dayjs,AI 转头就npm install moment;明明有lodash-es,它非要引入lodash的 CommonJS 版本。
这些问题的根源,其实是同一个:大模型对 Vue 的理解来自海量公开代码,它知道的是“通用 Vue”,而不是“你项目里的 Vue”。模型不知道你们团队约定响应码统一叫code,不知道你们封装的权限指令叫v-permission,更不知道你们已经积累了一整套组合式函数。它只能凭概率猜测“大多数Vue项目大概是什么样子”,然后照着写。
1.2 Skills机制是什么,凭什么能救场
2025年初,Claude Code、Codex、OpenCode 这些主流的AI编码工具,陆陆续续都开始支持一种叫 Skills(技能)的机制。通俗点说,你可以在工程仓库里放一个带规范说明的目录,里面写清楚“这个项目怎么写Vue”,AI 在动手写代码前,会先去读取这份说明,然后照着执行。
这个思路的巧妙之处在于,它不是给模型“补课”,让模型再学一遍Vue语法;而是给模型一份随查随用的项目手册。模型的通用知识早就够了,缺的是你这位架构师脑子里那些项目级的信息——用哪个组件库、路由怎么组织、请求层怎么封装、命名规范是什么。Skills 解决的,就是这份“项目上下文”的缺失问题。
我通常给团队新人打比方说,Skills 就像你入职第一天拿到的那本《项目交接文档》。你不可能靠背熟Vue文档就写出符合团队风格的代码,你得先知道这个项目的套路。AI 也一样。以前我们靠的是在 prompt 里反复强调“用 Composition API”“别用 moment”,但这些话每次都写一遍太累,而且容易漏。Skills 把这件事固化成文件,跟着仓库走,谁用AI谁生效。
1.3 适用场景与不适用场景
我也得先把边界划清楚,免得有人兴冲冲做了一堆技能发现没用。Skills 最适合三类场景:第一,中大型Vue项目,团队有明确技术栈和代码规范,但AI参与度高,产出的代码需要和团队风格对齐;第二,长期维护的模块化项目,AI 经常要生成新的页面组件、状态模块或路由配置,规则沉淀后能持续复用;第三,多人在同一个仓库协作,希望所有开发者手里的AI都遵守同一种约定。
反过来,如果只是写一个几十行的演示Demo,或者几个文件的一次性脚本,不值得为它做技能包。还有一个常见的误解是:简单事情不要仪式化。如果你只是想让AI每次都用script setup,那你直接在对话里说一句就行,不需要建一整套SKILL.md。Skills 的真正优势,在于成体系、可复用、可团队共享的规则沉淀;而单点小规则,用普通指令反而更轻快。这个边界把握好,后面的东西才有意义。
2. Skills文件怎么组织,AI才能看得懂
2.1 先理解工具约定的目录结构
不同工具的细节有差异,但主流方案已经收敛出一个共同模式:在项目根目录下放一个.claude/skills/、.codex/skills/或.opencode/skills/之类名字的目录,每个技能占一个文件夹。一个典型的技能文件夹长这样:
.claude/skills/ └── vue-guidelines/ ├── SKILL.md ├── references/ │ ├── component-patterns.md │ └── api-request-layer.md └── scripts/ └── check-vue-style.mjs每个技能文件夹里必须有一个SKILL.md,这是技能的“说明书”;references目录放辅助文档,供AI按需查阅;scripts放可执行脚本,用于实际校验。我在实际项目里的体会是,别小看这个结构,它保证了一个技能不只是“一段被塞进上下文的提示词”,而是有引用体系、有校验能力的微文档。目录位置和文件名必须严格按工具要求来,不能自己改,否则技能根本不会被加载。
2.2 SKILL.md 的头部与正文规范
SKILL.md本身用 Markdown 写,但最上面有一段 YAML 头部。头部字段不同工具有差异,但核心两个字段是name和description。下面是我在一个项目里用的实战版本:
--- name: vue-guidelines description: 当需要生成或修改Vue组件、Vue页面、Vue路由配置、Pinia状态模块、Vue指令或组合式函数时使用本技能,用于遵循项目的Vue 3技术栈与编码规范。 ---头部最重要的就是description。很多AI工具是靠读取description来判断“要不要启动这个技能”的,它写得宽泛或含糊,AI就经常不触发。我的建议是写清楚“什么时候用”,而不是“这个技能是什么”。比如“当需要生成或修改Vue组件时使用”就比“Vue编码规范”好用得多,因为前者给了AI一个明确的匹配条件。
正文部分是实际的规范内容。不同工具处理方式略有差异,但大多数情况下,AI会把正文当作系统指令的一部分注入上下文。这意味着正文字数不是越多越好,应该控制在合理规模,重点信息尽量前置。我自己的规范正文一般控制在 40 到 60 行以内,再长的细节拆到references里去。
2.3 让AI正确“触发”技能的关键技巧
这大概是整个Skills体系里最容易被忽略、但又最影响成败的一环。工具判定要不要启用技能,主要依据就是description和当前任务语义的匹配度。我在实践里摸索出三个技巧,基本可以解决 90% 的“技能没生效”问题。
第一,把触发词写具体。Vue、组件、模板、路由、Pinia、store、props、emits、slot、computed、watch、指令,这些项目中用得上的关键词都应该出现在description里。模型匹配的时候是按语义算相似度的,触发词越多,命中率越高。第二,用“当……时”句式描述触发条件。description不要写成“Vue 编码规范文档”这种名词短语,而要写成“当需要……时使用本技能”这种任务描述。第三,一个技能只负责一类事。如果你把Vue规范和Node脚本规范塞进同一个技能,AI在写Vue时可能因为混入了无关内容而降低规则权重;拆开以后,每个技能的触发反而更精准。
2.4 references与scripts的用法,为什么我推荐拆开
如果所有规则都堆在SKILL.md里,文件会越来越大,AI一旦全量读取,上下文被占满,处理速度变慢,而且容易“忘”掉后面的指令。更合理的做法是“头部给精简规则,细节放 references,AI按需读取”。
比如,我会在 SKILL.md 正文里只写20条最核心的规则,然后加一行“生成组件前,请先阅读 references/component-patterns.md”。当AI准备写组件时,它会自己去读那份文档,而不是被动地把所有内容都塞进上下文。这种方式在减少无效信息、提升生成质量上效果非常明显。
scripts目录可以放脚本,用来做实际校验。它不是必备项,但能把技能从“约束AI”升级为“可验证”。比如我写了一个脚本去检查新生成的组件是否包含<script setup>、是否出现被禁止的defineComponent和moment关键词。AI写完代码,我跑一遍脚本,不过就让它改。这比靠肉眼 review 高效得多。
3. 亲手写一个Vue Skills的完整过程
3.1 第一步:明确Vue技术栈基线
写规范之前,先把自己项目的技术栈基线写清楚。这一条看似简单,但它决定了后文所有规则的适用性,特别重要。我以自己一个中后台项目为例,基线是这样写的:
- 框架:Vue 3.4 + Vite 5 + TypeScript
- 组件库:Ant Design Vue 4.x
- 状态管理:Pinia,按业务模块拆分 store
- 路由:Vue Router 4,路由按模块拆文件,懒加载统一用
() => import(...) - 请求:统一走
src/api层,调用request封装,不直接使用fetch - 样式:默认
<style scoped lang="scss"> - 日期处理:统一用
dayjs,禁止引入moment
这份基线要写成你们项目真实在用的那套,别写理想态。你要是连“项目里用没用 TypeScript”都含糊,AI 就按最大概率猜,大概率猜错。基线越精确,后续规则越好写。
3.2 第二步:把代码风格规则写成“必须/禁止”
描述性语言害死人。如果你写“组件命名应保持一致性”,AI 会点头,然后继续按自己的想法写。真正有效的表达是命令式的“必须”“禁止”,几乎没有歧义。我摘几条我实际在用的:
- 必须使用
<script setup lang="ts">,禁止使用defineComponent与 Options API。 - 组件文件名必须使用大驼峰,例如
UserProfileModal.vue。 - props 必须用
defineProps<类型>()泛型方式定义,并在类型上标注required。 - 组件内禁止直接写
fetch,统一调用src/api下的方法。 - 模板中禁止出现超过一层嵌套的复杂
v-if表达式,优先拆成计算属性或子组件。
每一条都落在动词上,AI执行起来才干脆。我的经验是,规则写好后,自己默读一遍:如果一条规则还能解释出三种执行方式,那就得继续改,直到它只剩一种正确做法。
3.3 第三步:注入项目专属约定
通用规范网上到处都是,Skills 真正的护城河是项目专属约定。我把这几项作为“隐藏彩蛋”写进了技能里:
- 项目里已经封装好的组合式函数,比如
useTable、useFormDialog、usePagination,AI 必须优先复用,不允许新造轮子。 - 权限判断必须用项目封装的
v-permission指令,禁止在模板里写if (role === 'admin')这类硬编码。 - 接口返回处理必须判断业务码
code === 0,失败统一走message.error并提前return。 - 分页参数统一用
current和pageSize,和组件库保持一致,禁止用page、size这种别名。
这些约定如果不写在技能里,AI 几乎不可能自己猜出来。我第一次把项目里的组合式函数清单放进references/component-patterns.md后,AI 生成的列表页代码直接从“能用”变成了“符合项目规范”,这个提升是肉眼可见的。
3.4 第四步:写一份“反模式清单”
这一步是我做完整套 Skills 后个人收益最大的环节。与其告诉 AI “应该怎么做”,不如先告诉它“不要这么做”。反模式清单要写得像排雷手册,每条都是我在 review 里真实踩过的坑:
- 禁止在
watch中修改被监听的状态,这会造成循环更新,应该用computed或显式事件。 - 禁止在模板里写超过三元表达式的逻辑,复杂逻辑一律抽到
script里的函数或计算属性。 - 禁止用
as any逃避类型检查,接口类型不完善时先补类型。 - 禁止在组件里直接
import { message } from 'ant-design-vue',要用项目中封装好的Message组件方法,否则样式不统一。
写反模式清单有个技巧:每一条最好附带一句“为什么”。AI 虽然不会真正理解,但会把“禁止某做法 + 替代方案”当成强约束,生成时更倾向于走替代路径。比如“禁止as any,接口类型不完善时先补类型”,这比单纯写“不要使用 any”有效得多。
3.5 第五步:配一个辅助校验脚本
如果你用的工具支持脚本调用,可以配一个scripts/check-vue-style.mjs,在 AI 生成完代码后跑一遍基础风格检查。我不用特别复杂的 AST 解析,就做两件事:检查文件扩展名和<script setup>是否存在,检查禁止的关键词(defineComponent、moment、as any、fetch()有没有出现。下面是一个简化版:
// scripts/check-vue-style.mjs import { readFileSync } from 'node:fs'; const args = process.argv.slice(2); const forbidden = ['defineComponent', 'moment', 'as any', 'fetch(']; let failed = false; for (const file of args) { const content = readFileSync(file, 'utf8'); if (!file.endsWith('.vue')) { console.log(`[SKIP] ${file} 不是Vue文件`); continue; } if (!/script setup/.test(content)) { console.log(`[FAIL] ${file} 缺少 <script setup>`); failed = true; } for (const word of forbidden) { if (content.includes(word)) { console.log(`[FAIL] ${file} 包含禁止的关键词: ${word}`); failed = true; } } if (!failed) console.log(`[PASS] ${file}`); } process.exit(failed ? 1 : 0);本质上,这个脚本是个“守门员”。AI 写完代码我跑一遍,不通过就让它改,不用人工一项项盯。实际使用中,脚本帮我拦住的问题比我想象的多,尤其是as any和fetch(这两个高频翻车点。
4. 主流AI编码工具怎么加载,以及我的选型建议
4.1 几种主流工具的Skills机制对比
现在大家用得比较多的 AI 编码工具,主要是 Claude Code、Codex、OpenCode,以及带规则功能的 Cursor。它们的 Skills 机制命名和目录不太一样,但逻辑上是共通的。我整理了一张对比表,方便你快速定位:
| 工具 | 技能/规则目录 | 核心文件 | 特点 |
|---|---|---|---|
| Claude Code | .claude/skills/ | SKILL.md | 结构最完整,支持 references 与 scripts |
| Codex | .codex/skills/或项目指令文件 | SKILL.md/AGENTS.md | 与项目级指令结合紧密 |
| OpenCode | .opencode/skills/ | SKILL.md | 轻量,适合个人项目 |
| Cursor | .cursor/rules/ | .mdc文件 | 规则型,简单直接,适合小团队 |
如果你已经在用 Claude Code 或 Codex,那直接按它们目录规范放SKILL.md就行。如果你用的是 Cursor 这类规则型工具,也可以用同样的思路写规则文件,差别只是目录和加载方式。
4.2 项目级与全局级怎么选
我习惯把 Skills 按作用域分成两类。项目级 Skills 放在仓库内,跟着 git 走,适合约束团队协作,比如组件规范、请求层约定、权限指令用法;全局级 Skills 放在用户目录,对所有项目生效,适合放个人风格、通用命名习惯、代码注释格式这类跨项目沉淀。
实际项目中我更推荐“项目级为主、全局级为辅”。因为项目级技能能跟着仓库走,新成员 clone 下来 AI 配置就齐全了,不用每个人单独折腾。全局级技能我一般只放“这开发者喜欢什么格式”这类个人偏好,不放任何和具体项目强相关的内容,否则换个项目就串味了。
4.3 验证AI是不是真的“学会了”
写完 Skills 之后一定要做验证,否则可能是在自嗨。我的验证方法是准备一组“测试题”,让 AI 在一个空目录里分别完成三件事:生成一个标准列表页组件、修改一个现有组件的 props 定义、写一个路由模块的配置。然后我对照 SKILL.md 里的规则逐条检查,看它有没有踩线。
这组测试我能复用到每次迭代里。如果你改了规范,跑一遍测试题,对比前后效果就知道改动是正向还是负向的。这样做还有个好处:团队里其他成员也能用同一套题验收自己的技能包。实测下来,90% 的“技能写了没用”,问题出在加载没生效或description没匹配上,而不是规则本身写得不好。
5. 常见问题与排查技巧实录
5.1 AI无视Skills规则,怎么排查
我碰到过好多次 SKILL.md 写得清清楚楚,AI 还是按老套路写的情况。这时候先别急着改规则,按照排查顺序来:先确认技能文件夹的位置对不对,文件名是不是SKILL.md,有没有被工具扫描到;再确认description里有没有包含当前任务的关键词,比如生成组件时必须出现“组件”泛称;最后用工具的命令行界面查看已加载的技能列表,很多工具提供了/skills或/help之类的命令。实际经验告诉我,80% 的“不生效”其实是没被加载,而不是规范写得不行。
5.2 规则冲突导致AI“行为异常”
项目里如果同时存在多个技能,比如一个“Vue 规范”和一个“TypeScript 规范”,两者在接口类型、文件命名上如果出现重叠,AI 就会陷入选择困难,或者把两套规则混着执行。我给团队定的办法是“单入口原则”:顶层只保留一个 Vue Skills 作为入口,其他专项规范全部挂在references下被它引用,避免同一时刻多个技能注入互相矛盾的指令。另外要注意技能描述别写得太宽,别让“Vue 规范”去管 Node 脚本的格式,各管一摊才不容易打架。
5.3 技能内容太多,AI上下文被拉爆
早期我差点把所有前端规范都塞进一个 SKILL.md,结果就是 AI 回复变慢,而且后文经常“忘”掉前面的要求。后来我把大文档切碎:SKILL.md 只放核心的 20 条硬规则,其余细节放 references 按需读取。这个策略在我用过的几个工具上都有明显改善。我的经验是,规则数量控制在 50 条以内比较合适,超过这个量级,模型对每条规则的注意力会被稀释,反而不如精简版本效果好。“少即是多”在 Skills 这里特别成立。
5.4 团队协作时的Skills维护
当技能成为团队基础设施,维护方式也得跟上。我把 SKILL.md 放在 git 仓库里,改规则走 Pull Request,任何约定更新都同步更新 references,并且每次改动后在 commit message 里注明影响范围。这样团队里每个人都能看到 AI 规则在演进,而不是某个人偷偷改了没人知道。还有个小技巧:把 3.4 节那组验证测试题也放进仓库,规则更新后跑一遍,保证没有引入新的问题。
5.5 常见问题速查表
| 问题现象 | 排查方向 | 解决办法 |
|---|---|---|
| AI不按规范写 | 技能没有加载或没被触发 | 检查目录位置、文件名、description 触发词 |
| 多技能规则冲突 | 技能职责重叠 | 合并为一个入口技能,其他作为 references |
| 上下文溢出、回复变慢 | 技能体积过大 | 精简 SKILL.md,细节拆到 references |
| 团队行为不一致 | Skills 版本不一致 | 放入 git 仓库,统一发布流程并写清变更记录 |
| 生成代码通不过脚本 | 规则与项目实际不符 | 回归项目基线,修正 SKILL.md 中的硬规则 |
最后分享一个我自己的体会。这套 Vue Skills 从最早的一段 prompt,演进到现在结构化的技能包,最大的变化不是我写代码的速度变快了,而是“团队的 Vue 经验终于有了一个可以沉淀、可以版本化、可以让 AI 和新人一起遵守的地方”。如果你也在为 AI 写出的 Vue 代码头疼,我的建议是别急着骂模型,先花一个下午把踩过的坑写进一个 SKILL.md。这件小事值得所有用 AI 写 Vue 的前端认真做一次。