1. 从"skills"这个热词说起:它到底在解决什么问题
最近一段时间,不管是在开发者社区还是各类技术讨论群里,"skills"这个词出现的频率高得离谱。很多人第一次看到它,会以为是某个新出的编程语言或者框架,其实不是。这里的 skills,指的是围绕 AI 编程助手(比如 Claude Code、Codex 这类工具)构建的一套可插拔的能力扩展机制。你可以把它理解成给 AI 助手装"技能包"——原本它只会通用地回答问题、写写代码,装上 skills 之后,它就能按照你预设的流程、规范和领域知识去干活。
我最初接触这个概念的时候,也走了不少弯路。当时我以为 skills 就是普通的提示词模板,复制粘贴一段 prompt 就完事了。结果实际用下来发现完全不是那么回事。真正的 skills 是一套结构化的东西,它包含触发条件、执行步骤、依赖工具、输出格式,甚至还有错误处理逻辑。这就好比你去餐厅点菜,普通提示词是你跟厨师说"随便炒个菜",而 skills 是你递给厨师一份标准菜谱,上面写清楚了用料、火候、摆盘要求。
为什么这个东西突然火起来?核心原因在于,大家发现通用 AI 助手在实际工作场景里"不够专业"。你让它写个前端组件,它可能给你写出一堆不符合项目规范的代码;你让它处理数据,它可能忽略了你公司特定的字段命名规则。skills 的出现,就是让 AI 助手能够加载特定领域的"操作手册",从而在特定任务上表现得像一个有经验的从业者,而不是一个什么都懂一点但什么都不精的万金油。
这篇文章适合哪些人看?如果你正在使用 Claude Code、Codex 或者类似的 AI 编程工具,并且觉得"它挺好用但总差那么点意思",那这篇内容就是为你准备的。如果你还没开始用这些工具,但想了解 skills 到底能带来什么价值,也可以先看看,心里有个底。我会从 skills 的本质讲起,然后拆解它的核心结构,再给出实际配置和开发的完整思路,最后分享一些我在实操中踩过的坑和总结出来的技巧。
需要提前说明的是,skills 这个概念本身还在快速演进中,不同工具对它的实现方式有差异。Claude Code 的 skills 和 Codex 的 skills 在细节上并不完全一样,但它们背后的设计哲学是相通的。我会尽量把通用的部分讲透,同时指出不同平台之间的差异点,方便你根据自己的工具链做适配。
2. skills 的本质:不是提示词模板,而是能力封装协议
2.1 为什么"复制一段提示词"解决不了问题
很多人对 skills 的第一个误解,就是把它等同于"一段写得很好的提示词"。我一开始也是这么想的。当时我在做一个前端项目,需要 AI 助手按照我们团队的规范生成 React 组件。我的做法是在对话开头粘贴一大段说明:"请使用函数式组件,使用 TypeScript,样式用 CSS Modules,状态管理用 Zustand,不要用 any 类型……"刚开始几次还行,但对话一长,AI 就"忘了"这些要求,又开始给我写 class 组件,或者随手用 any。
这个问题的根源在于,提示词是会话级的,它存在于当前对话的上下文里。一旦上下文被截断、被压缩,或者你开了新对话,这些要求就消失了。而 skills 是持久化的,它作为一个独立的文件或配置存在,每次触发时都会被完整加载。这就像你每次做饭都要重新背一遍菜谱,和把菜谱贴在厨房墙上的区别。
另一个关键差异是,提示词只能"说",而 skills 可以"做"。一个成熟的 skill 不仅能告诉 AI"你应该怎么做",还能携带可执行的脚本、模板文件、参考数据。比如一个代码审查的 skill,它可以包含一套检查规则文件,AI 在执行时会真正去读取这些规则,而不是凭记忆瞎猜。
2.2 skills 的三层结构:触发、执行、验证
拆开来看,一个设计良好的 skill 通常包含三个层次。
第一层是触发层。它定义了"什么时候该用这个 skill"。触发条件可以是关键词匹配,比如用户提到"生成组件"就触发前端组件 skill;也可以是文件类型匹配,比如打开.test.ts文件时触发测试编写 skill;还可以是显式调用,用户直接输入命令来激活某个 skill。触发层设计得好不好,直接决定了 skill 会不会在错误的场景下被激活,或者该激活的时候没反应。
第二层是执行层。这是 skill 的核心,它描述了"具体怎么做"。执行层通常包含步骤化的指令、需要读取的参考文件、需要调用的工具或脚本。比如一个"生成 API 文档"的 skill,执行层会写明:先扫描路由文件,提取接口定义,然后按照指定模板生成 Markdown,最后写入 docs 目录。每一步都要足够具体,不能有歧义。
第三层是验证层。这一层最容易被忽略,但恰恰是区分"能用"和"好用"的关键。验证层定义了"怎么确认做对了"。它可以是一个检查清单,比如"生成的组件必须通过 ESLint 检查";也可以是一个自动化脚本,比如"运行测试用例,确保全部通过"。有了验证层,AI 在执行完 skill 之后会自己检查一遍,发现问题就重试,而不是把半成品丢给你。
2.3 和 agents、plugin 的关系到底是什么
热词里同时出现了 skills、agents、plugin 这几个词,很多人搞不清楚它们之间的关系。我用一个类比来说明:把 AI 助手想象成一台电脑。agents是这台电脑的操作系统,它负责整体的任务规划和调度,决定"先做什么、后做什么"。skills是安装在系统上的应用程序,每个应用解决一类具体问题。plugin则是驱动程序或者扩展卡,它让电脑能够连接外部设备、访问外部服务。
在实际使用中,这三者是配合工作的。你给 agent 下达一个任务,agent 分析后决定调用哪个 skill,skill 在执行过程中可能需要通过 plugin 去访问外部资源(比如读取数据库、调用 API)。理解了这个关系,你就不会纠结"我到底该学哪个"——它们是不同层面的东西,都需要了解,但切入点可以从 skills 开始,因为它最贴近日常的具体工作。
3. 一个 skill 从零到能用的完整搭建过程
3.1 先想清楚:这个 skill 要解决什么重复劳动
动手写 skill 之前,最重要的一步是选对场景。不是所有事情都值得做成 skill。我的判断标准是:如果一件事你每周至少重复做三次,而且每次的流程基本固定,那它就适合做成 skill。反过来,如果一件事你一个月才做一次,或者每次做法都不一样,那做成 skill 的投入产出比就很低。
举个例子。我之前经常需要把后端接口返回的 JSON 数据转换成前端 TypeScript 类型定义。这个活儿每次都要做,流程也固定:拿到 JSON 样本,分析字段类型,处理嵌套结构,生成 interface。这就是一个典型的适合做成 skill 的场景。而像"设计系统架构"这种事,虽然也经常做,但每次的决策因素太多,很难固化成固定流程,就不适合。
选好场景之后,下一步是拆解流程。把你平时手动做这件事的步骤一步步写下来,越细越好。还是以 JSON 转 TypeScript 为例,我的步骤是:第一步,确认 JSON 样本的完整性,检查有没有缺失字段;第二步,识别每个字段的类型,注意区分 number 和 string,注意 null 值的处理;第三步,处理嵌套对象,决定是展开还是引用;第四步,处理数组,确定元素类型;第五步,生成代码并格式化。这五步写下来,skill 的骨架就有了。
3.2 目录结构怎么组织才不乱
一个规范的 skill 目录通常长这样:
my-skill/ SKILL.md # 主文件,定义触发条件和执行指令 references/ # 参考文件目录 rules.md # 规则说明 examples.md # 示例 scripts/ # 可执行脚本 validate.py # 验证脚本 templates/ # 模板文件 output.tpl # 输出模板SKILL.md是入口文件,它的内容质量直接决定 skill 好不好用。我见过很多人把 SKILL.md 写成一篇散文,洋洋洒洒几千字,结果 AI 读完之后抓不住重点。正确的做法是结构化、指令化。用清晰的标题分节,用列表列出步骤,用加粗标出关键约束。AI 读这种结构化的内容,执行准确率会高很多。
references目录放的是"背景知识"。比如你的 skill 需要遵循某个编码规范,就把规范文档放在这里。注意,这些文件不是每次都会被完整读取,AI 会根据需要去查阅。所以文件命名要清晰,内容要分节,方便按需检索。
scripts目录放的是"确定性逻辑"。有些事情用自然语言描述容易有歧义,但用代码写就非常明确。比如"检查生成的代码是否符合命名规范",与其用文字描述规则,不如写一个正则匹配脚本。AI 调用脚本得到明确结果,比它自己判断要可靠得多。
3.3 SKILL.md 里必须写清楚的几件事
SKILL.md 是 skill 的灵魂,我总结了几件必须写清楚的事。
第一,触发条件。明确写出什么情况下应该激活这个 skill。可以用关键词列表,也可以用场景描述。比如:"当用户要求生成 React 组件、或者提到'新建组件'、'创建页面'时,激活本 skill。"
第二,前置检查。执行之前需要确认什么。比如:"确认当前项目根目录存在 package.json,确认已安装 TypeScript。"
第三,执行步骤。这是核心内容,要分步骤写,每步说清楚输入是什么、做什么操作、输出是什么。步骤之间如果有依赖关系,要明确标注。
第四,约束条件。哪些事情绝对不能做。比如:"不要修改现有组件的导出方式"、"不要引入新的第三方依赖"。
第五,验证方式。执行完之后怎么检查。比如:"运行npm run lint,确保无报错"、"检查生成的类型定义是否覆盖了所有字段"。
第六,输出格式。最终产物长什么样。可以给一个模板或者示例。
把这六件事写清楚,一个 skill 基本就能用了。剩下的就是不断迭代优化。
3.4 验证环节:怎么知道 skill 真的生效了
skill 写完不等于能用,必须经过验证。我的验证方法分三步。
第一步是单元验证。找一个最简单的场景,手动触发 skill,看它能不能跑通。比如 JSON 转 TypeScript 的 skill,我就拿一个只有三个字段的简单 JSON 去测。如果这都跑不通,说明基础逻辑有问题。
第二步是边界验证。找一些特殊情况来测。比如 JSON 里有 null 值、有嵌套数组、有特殊字符的字段名。这些情况最容易暴露 skill 的缺陷。
第三步是回归验证。在你真实的项目里用几次,看看会不会和现有流程冲突。我曾经写过一个自动生成测试文件的 skill,单元测试都过了,但放到真实项目里发现它会覆盖已有的测试文件。这就是回归验证才能发现的问题。
提示:验证 skill 的时候,一定要用真实项目的数据,不要只用构造的测试数据。真实数据的"脏"程度往往超出你的想象,而 skill 的价值恰恰体现在处理这些脏数据上。
4. 不同工具链下 skills 的落地差异
4.1 Claude Code 的 skills 机制特点
Claude Code 对 skills 的支持相对成熟,它的 skill 以文件形式存放在特定目录下,启动时会自动加载。我实测下来,它的触发机制比较智能,能够根据对话内容自动判断该不该激活某个 skill,不需要你每次都手动指定。
Claude Code 的 skill 有一个我很喜欢的设计:它支持渐进式加载。也就是说,skill 的完整内容不会一次性全部塞进上下文,而是先加载一个摘要,等真正需要细节的时候再去读取具体文件。这个设计很聪明,因为上下文窗口是有限资源,如果每个 skill 都全文加载,很快就会把窗口撑爆。
不过要注意,Claude Code 的 skill 目录位置和命名规则有特定要求,放错地方就不会被识别。我建议你先用官方提供的最小示例跑通,确认环境没问题,再往里加自己的内容。
4.2 Codex 的 skills 配置思路
Codex 这边的 skills 机制和 Claude Code 有相似之处,但配置方式不太一样。Codex 更强调通过配置文件来管理 skill 的启用和参数。我在配置 Codex 的 skill 时,遇到过一个典型问题:skill 文件写好了,但一直不生效,排查了半天才发现是配置文件里的路径写的是相对路径,而 Codex 的工作目录和我预期的不一样。
Codex 的另一个特点是它对 skill 的执行结果有比较严格的格式要求。如果你的 skill 输出格式不符合预期,它可能会报错或者忽略。所以写 Codex 的 skill 时,输出格式那部分要格外注意,最好给出明确的示例。
4.3 跨工具复用的现实与妥协
很多人希望写一个 skill 就能在 Claude Code 和 Codex 上通用。理想很美好,现实是有难度的。两个工具对 skill 的文件格式、触发语法、执行环境都有差异。我的做法是核心逻辑复用,适配层分开。
具体来说,把 skill 的核心指令、参考文件、脚本这些"内容"部分做成通用的,然后在不同工具下各写一个薄的适配文件,负责处理触发条件和格式转换。这样维护成本可控,又不会因为强行统一而导致两边都用不好。
| 对比项 | Claude Code | Codex |
|---|---|---|
| skill 存放位置 | 特定配置目录 | 配置文件指定路径 |
| 触发方式 | 自动识别为主 | 配置驱动为主 |
| 加载策略 | 渐进式加载 | 按需加载 |
| 输出格式要求 | 相对宽松 | 较严格 |
| 脚本支持 | 支持 | 支持 |
4.4 本地模型接入时的注意事项
有些朋友会把 Claude Code 或 Codex 接到本地运行的模型上,这样做的好处是数据不出本地,隐私性更好。但接入本地模型之后,skills 的表现可能会有变化。主要原因是本地模型的指令遵循能力通常不如云端大模型,对复杂 skill 的执行准确率会下降。
我的建议是,如果要用本地模型跑 skills,skill 的设计要更简单、更明确。步骤不要太多,每步的指令要短,约束条件要反复强调。另外,本地模型的上下文窗口可能更小,skill 的参考文件要精简,避免加载过多内容导致窗口溢出。
5. 实操中踩过的坑和对应的解法
5.1 skill 不触发:从日志里找线索
最常见的问题就是 skill 写好了但不触发。我遇到过好几次,每次原因都不一样。有一次是触发关键词写得太窄,用户换个说法就匹配不上;有一次是 skill 文件编码有问题,工具读取时解析失败;还有一次是 skill 之间的触发条件冲突,两个 skill 抢同一个触发词,结果谁都没触发。
排查这类问题,第一步是看日志。大多数工具都会输出 skill 加载和触发的日志,从日志里能看出 skill 有没有被加载、有没有被匹配。如果日志显示 skill 加载了但没触发,那就是触发条件的问题;如果日志显示 skill 根本没加载,那就是文件位置或格式的问题。
第二步是简化测试。把 skill 内容精简到最少,只保留触发条件和一句执行指令,看能不能触发。能触发就逐步加回内容,定位是哪部分导致的问题。
5.2 执行结果不稳定:约束要写在前面
skill 能触发,但每次执行结果不一样,这也是个高频问题。根本原因通常是 skill 里的指令有歧义,AI 每次理解得不一样。解决办法是把关键约束前置,并且用明确的、无歧义的语言表达。
比如"生成的代码要规范"这种表述就很模糊,什么叫规范?改成"生成的代码必须通过项目根目录下的 ESLint 配置检查,缩进使用 2 个空格,字符串使用单引号",就明确多了。另外,重要的约束可以在 skill 里重复出现,开头提一次,执行步骤里再提一次,强化 AI 的印象。
5.3 上下文被撑爆:参考文件要按需加载
前面提到过,skill 的参考文件如果全部加载,很容易把上下文窗口占满。我踩过这个坑,一个 skill 带了十几个参考文件,结果一触发就把窗口占了八成,后续对话都没法正常进行了。
解法是分层加载。把参考文件分成"必读"和"选读"两类。必读的放在 SKILL.md 里直接引用,选读的放在 references 目录,在 SKILL.md 里说明"需要时查阅某某文件"。这样 AI 只在真正需要的时候才去读取,平时不占窗口。
5.4 和现有工作流冲突:先隔离再合并
skill 和现有工作流冲突,这个坑比较隐蔽。我曾经写过一个自动格式化的 skill,结果它和项目里的 pre-commit hook 打架,每次提交都报错。后来我的做法是,新 skill 先在独立的分支或者独立的项目里验证,确认没问题了再合并到主工作流。
还有一个技巧是给 skill 加一个"干跑"模式。也就是执行 skill 但不实际修改文件,只输出它打算做什么。这样你可以在不破坏现有状态的前提下,观察 skill 的行为是否符合预期。
注意:skill 的调试过程中,一定要做好版本管理。每次修改 skill 之前先提交一次,这样出问题了可以快速回滚。我吃过亏,改了半天发现还不如之前的版本,结果之前的版本已经被覆盖了。
6. 让 skill 真正好用的几个进阶思路
6.1 把"经验"写进 skill,而不是把"知识"写进去
知识和经验的区别在于,知识是"是什么",经验是"什么情况下会出问题"。一个 skill 如果只写知识,那它和搜索引擎没区别。真正有价值的 skill,是把老手才知道的经验写进去。
比如写一个数据库迁移的 skill,知识部分是"用 migration 工具生成迁移文件"。经验部分是"生成之前先检查有没有未提交的更改,因为迁移工具可能会把未提交的更改也纳入迁移范围"、"如果表数据量超过百万行,迁移要分批执行,避免锁表"。这些经验才是 skill 的核心价值。
6.2 用脚本处理确定性逻辑,用自然语言处理判断逻辑
skill 里哪些部分该用脚本,哪些部分该用自然语言,这个边界要划清楚。我的原则是:确定性的、可验证的逻辑用脚本,需要判断和权衡的逻辑用自然语言。
比如"检查文件是否存在"、"统计代码行数"、"运行测试"这些,用脚本,结果明确。而"判断这段代码是否可读"、"决定用哪种设计模式"这些,用自然语言描述判断标准,让 AI 去权衡。
这样划分的好处是,脚本部分稳定可靠,不会因为 AI 的理解偏差而出错;自然语言部分保留了灵活性,能够处理复杂情况。
6.3 给 skill 加"自检"步骤
前面提过验证层的重要性,这里再展开说一下。我现在的习惯是,每个 skill 的最后一步都是自检。自检的内容包括:输出是否符合格式要求、是否违反了约束条件、是否覆盖了所有必要的内容。
自检可以是 AI 自己做的,也可以是脚本做的。AI 自检适合检查内容质量,脚本自检适合检查格式和规则。两者结合,效果最好。
6.4 定期回顾和迭代 skill
skill 不是写完就一劳永逸的。项目在变,规范在变,skill 也要跟着变。我建议每隔一段时间(比如一个月)回顾一下自己在用的 skill,看看有没有过时的内容,有没有可以优化的地方。
回顾的时候重点关注:哪些 skill 经常触发但效果不好,说明需要优化;哪些 skill 几乎不触发,说明触发条件有问题或者场景选错了;哪些 skill 执行时经常需要人工干预,说明自动化程度不够。
7. 关于 skills 的一些个人体会
用了一段时间 skills 之后,我最大的感受是:它改变的不是 AI 的能力上限,而是 AI 的稳定性下限。通用 AI 助手在简单任务上表现很好,但任务一复杂、要求一具体,表现就忽上忽下。skills 的作用是把那些"忽下"的情况兜住,让 AI 在特定任务上的表现稳定在一个可接受的水平。
另一个体会是,写 skill 的过程其实是在梳理自己的工作流程。很多时候我以为自己很清楚某件事怎么做,但真正动手写 skill 的时候才发现,有些步骤我从来没想清楚过。写 skill 逼着我把这些模糊的地方明确下来,这本身就是一种收获。
最后分享一个小技巧:如果你不知道从哪个 skill 开始写,就观察自己一天的工作,找出那个"每次做都要翻文档、每次做都要回忆步骤"的事情,把它做成第一个 skill。这种场景做出来的 skill,价值最直观,也最容易坚持用下去。