1. 从“skills”这个热词说起它到底在解决什么问题最近半年不管是在技术社区还是开发者群聊里“skills”这个词出现的频率高得离谱。你如果只看字面意思可能会以为它说的是“技能”这个泛泛的概念但放到当下的开发语境里它其实指向一个非常具体的东西给 AI 编程助手比如 Claude Code、Codex 这类工具安装可复用的能力模块。你可以把它理解成给一个刚入职的实习生发了一本《岗位操作手册》手册里写清楚了遇到什么情况该怎么做、用什么工具、遵循什么规范。没有这本手册实习生也能干活但干出来的东西可能五花八门有了手册输出质量就稳定得多。我最初接触这个概念的时候也走过弯路。当时我以为 skills 就是普通的提示词模板复制粘贴一段文字丢给 AI 就完事了。后来实际用下来才发现真正的 skills 是一套有结构、有触发条件、有执行逻辑的工程化配置。它通常包含几个核心部分触发描述告诉 AI 什么时候该用这个 skill、执行指令具体怎么做、依赖声明需要哪些工具或插件、以及输出规范结果应该长什么样。这四样东西缺一个skill 的可用性就会打折扣。那为什么现在大家都在聊这个因为 AI 编程助手已经从“能写代码”进化到了“能按规范写代码”的阶段。早期的工具你问它一句它答一句现在你可以给它装上一整套 skills让它在你打开项目的时候自动识别技术栈、自动加载对应的编码规范、自动跑测试、自动生成符合团队要求的提交信息。这个变化带来的效率提升是实打实的我自己的项目里光是代码审查这一块的返工率就降了将近四成。这篇文章适合谁看如果你是刚接触 Claude Code 或 Codex 的新手想搞清楚 skills 到底怎么装、怎么用、怎么自己写那接下来的内容会给你一条完整的路径。如果你已经在用这些工具但总觉得输出不够稳定那问题很可能就出在 skills 的配置上。我会从整体设计思路讲到具体实操再到踩过的坑和排查方法尽量把每个环节都说透。2. 整体设计思路为什么 skills 要这样组织2.1 核心思路把“隐性知识”变成“显性指令”任何一个团队里老员工和新员工的差距往往不在硬技能上而在那些“没人明说但大家都知道”的隐性规则上。比如提交代码前要跑哪几个检查、日志格式要遵循什么约定、遇到特定报错该查哪个文档。这些知识散落在每个人的脑子里新人只能靠试错来积累。skills 的核心价值就是把这些隐性知识抽出来写成 AI 能读懂的显性指令。我见过不少团队的做法是写一份很长的 README把所有规范都塞进去然后指望 AI 每次都能记住。实际用下来效果很差因为 AI 的上下文窗口是有限的你把一堆不相关的内容塞进去反而会稀释真正重要的指令。skills 的设计思路正好相反按需加载精准触发。每个 skill 只负责一个具体的场景AI 在遇到这个场景时才去读取对应的指令这样既节省了上下文又提高了执行的准确率。这个思路背后其实有一个很朴素的工程原则关注点分离。你把“什么时候做”和“怎么做”分开把“通用规范”和“特定场景规范”分开整个系统就变得可维护了。我自己的项目里skills 目录下分了四层基础层放编码风格和提交规范框架层放 React、Vue 这些技术栈的特定约定工具层放测试、构建、部署相关的操作业务层放跟具体产品逻辑相关的规则。每一层都可以独立更新互不影响。2.2 方案选型为什么是 Markdown 加 YAML 的组合你如果去看 Claude Code 或 Codex 的 skills 目录结构会发现一个很明显的特征指令主体用 Markdown 写元信息用 YAML 写。这个组合不是随便选的。Markdown 的优势在于它对自然语言友好你可以用标题、列表、代码块来组织复杂的操作步骤AI 读起来也顺畅。YAML 的优势在于它结构化程度高适合放那些需要被程序解析的字段比如触发关键词、依赖的工具名、版本号这些。我试过纯 Markdown 的方案把触发条件也写在正文里结果 AI 经常忽略掉那些条件在不该用的时候也用了。后来改成 YAML front matter 来声明触发条件准确率明显上来了。因为 YAML 部分在解析时会被单独提取出来AI 在判断是否触发时只看这部分不会被正文的长篇描述干扰。还有一个细节值得说skill 的命名。我见过有人用skill-001、skill-002这种编号也见过用中文命名的。实测下来用英文小写加连字符的命名方式最稳比如react-component-style、api-error-handling。原因是这些名字会出现在文件路径和引用里中文或特殊字符在某些环境下容易出问题。而且英文命名在 AI 解析时歧义更少它不需要去猜这个词的边界在哪里。2.3 避免什么问题不要试图用一个 skill 解决所有事新手最容易犯的错误就是写一个“万能 skill”把能想到的规范全塞进去。我早期就这么干过写了一个叫coding-standards的 skill里面从变量命名到数据库设计全都有洋洋洒洒两千多字。结果呢AI 在执行具体任务时经常只记住了开头几条后面的内容像是没看见一样。而且这个 skill 的触发条件很难写因为它的适用范围太广了几乎每个任务都能触发反而失去了“精准触发”的意义。后来我把它拆成了六个小 skill每个只负责一个维度比如naming-convention只管命名、error-handling只管异常处理。拆完之后每个 skill 的正文控制在三百字以内触发条件也清晰了AI 的执行准确率肉眼可见地提升。这个经验告诉我skill 的粒度应该跟“一个具体的决策点”对齐而不是跟“一个大的知识领域”对齐。另外要避免的是过度依赖 skill 而忽略基础提示。skills 是补充不是替代。你仍然需要在跟 AI 对话时把当前任务的目标说清楚skill 只是帮你在执行细节上保持一致。我见过有人装了一堆 skills 之后跟 AI 说话就变得很简略结果 AI 虽然按 skill 的规范执行了但方向跑偏了。这个锅不能让 skills 来背。3. 核心细节解析一个 skill 文件里到底该写什么3.1 触发条件怎么写才准触发条件是 skill 的入口写不好就会出现两种问题要么该触发的时候不触发要么不该触发的时候乱触发。我总结了一个比较稳的写法用“场景描述 关键词列表”的组合。场景描述用一句话说清楚这个 skill 适用于什么情况关键词列表放那些在用户输入里可能出现的词。举个例子我写了一个处理 API 错误的 skill触发部分是这样的--- name: api-error-handling description: 当需要处理 HTTP 请求错误、设计错误响应格式、或编写重试逻辑时使用 triggers: - API 错误 - 请求失败 - 错误响应 - 重试 - error handling ---这里有个细节关键词要覆盖中英文两种表达。因为你在跟 AI 对话时可能一会儿用中文一会儿用英文如果只写中文关键词英文提问时就触发不了。另外关键词不要写得太泛比如“错误”这个词太常见了几乎每个任务都可能提到写进去反而会导致误触发。我一般会选那些跟 skill 主题强相关的复合词而不是单个的通用词。还有一个经验触发条件里不要写否定句。比如“当不涉及数据库操作时使用”这种写法 AI 很难判断因为它需要先确认“不涉及数据库”这个条件而这个确认过程本身就容易出错。正确的做法是正面描述适用场景让 AI 做正向匹配。3.2 执行指令的层次结构执行指令是 skill 的主体也是最容易写乱的部分。我的建议是采用三层结构原则层、步骤层、示例层。原则层用一两句话说明这个 skill 的核心目标是什么步骤层用有序列表列出具体的操作流程示例层给出一两个正例和反例。原则层看起来有点虚但它其实很重要。因为 AI 在执行步骤时如果遇到步骤里没覆盖到的情况它会回退到原则层去推断该怎么做。如果你只写步骤不写原则AI 遇到边界情况就容易瞎猜。比如我在api-error-handling的原则层写的是“错误处理的目标是让调用方能够明确知道发生了什么并且能够决定是否重试。”这句话在遇到步骤里没提到的错误类型时就能引导 AI 往“提供足够信息”的方向去处理。步骤层我一般控制在五到七步太多了 AI 记不住太少了又不够具体。每一步都用动词开头比如“检查响应状态码”、“提取错误信息”、“判断是否可重试”。这样 AI 解析时能直接映射到动作不需要额外推理。示例层是很多人会忽略的部分但它的效果非常好。我给每个 skill 都配了一组对比示例一个符合规范的写法一个不符合的写法然后用一句话说明为什么。AI 通过对比来学习规范比单纯看规则要准确得多。这个技巧我是从测试驱动开发里借鉴过来的效果立竿见影。3.3 依赖声明和输出规范依赖声明这部分很多人觉得可有可无但我实际用下来发现它挺关键的。如果你的 skill 需要调用某个外部工具比如需要读取项目里的package.json来判断依赖版本那你就应该在依赖声明里写清楚。这样 AI 在执行前会先确认这个文件是否存在不存在的话它会提示你而不是执行到一半报错。输出规范则是告诉 AI 结果应该以什么形式呈现。比如你是希望它直接修改文件还是只给出建议是希望输出一段代码还是输出一个 diff这些如果不写清楚AI 每次的表现可能都不一样。我一般会在输出规范里写明格式要求和确认机制。格式要求比如“输出 Markdown 表格”确认机制比如“在修改文件前先展示将要修改的内容并等待确认”。后者在涉及重要文件时特别有用能避免 AI 直接改坏东西。4. 实操过程从零开始配置一套可用的 skills4.1 环境准备与目录结构不管你用的是 Claude Code 还是 Codexskills 的存放位置基本遵循一个约定项目根目录下的.skills文件夹或者用户主目录下的全局 skills 文件夹。我建议优先放在项目目录下因为不同项目的规范可能不一样放在项目里可以跟着代码一起做版本管理。目录结构我一般这样组织.skills/ ├── base/ │ ├── naming-convention.md │ ├── commit-message.md │ └── code-review.md ├── framework/ │ ├── react-component.md │ └── vue-composition.md ├── tooling/ │ ├── test-runner.md │ └── build-check.md └── business/ └── order-flow.md分层的逻辑前面说过了这里补充一点层与层之间可以有依赖关系但不要有循环依赖。比如business层的 skill 可以引用base层的规范但base层不应该反过来引用business层。这个约束能保证基础规范在任何项目里都能独立使用。创建文件的时候我习惯先用一个模板把骨架搭好然后再填内容。模板长这样--- name: your-skill-name description: 一句话说明这个 skill 的用途 triggers: - 关键词1 - 关键词2 dependencies: - 需要读取的文件或工具 --- ## 原则 这里写核心目标。 ## 步骤 1. 第一步 2. 第二步 3. 第三步 ## 示例 **正确做法** ... **错误做法** ...这个模板我用了大半年基本上覆盖了大部分场景。你可以根据自己的需求调整字段但name、description、triggers这三个是必须的缺了任何一个都会影响 skill 的正常工作。4.2 编写第一个 skill以提交信息规范为例拿一个最常用的场景来演示规范 Git 提交信息。这个 skill 的目标是让 AI 在帮你生成提交信息时遵循统一的格式。先写触发条件。提交信息相关的关键词包括“提交”、“commit”、“提交信息”、“commit message”。description 写“当需要生成或检查 Git 提交信息时使用”。然后是原则层。我写的是“提交信息应该让阅读者在不看代码的情况下就能理解这次变更的目的和范围。”这句话定下了基调重点是“目的”和“范围”而不是罗列改了哪些文件。步骤层我列了五步查看暂存区的变更内容识别变更类型新增功能、修复缺陷、重构、文档更新等确定影响范围是单个模块还是跨模块按照“类型: 简述”的格式生成标题行标题不超过 50 个字符如果变更较复杂在标题下方空一行后补充详细说明说明变更原因和影响检查是否有关联的任务编号如果有在末尾追加示例层给了一组对比正确做法feat: 增加订单导出功能 支持按时间范围筛选订单并导出为 CSV 格式 导出任务在后台异步执行完成后通过站内信通知。 关联任务: ORD-1234错误做法更新了一些文件错误做法的说明我写的是“没有说明变更类型和目的阅读者无法判断这次提交的影响范围。”写完这个 skill 之后我实测了大概二十次提交AI 生成的提交信息基本都能直接使用偶尔需要微调但不会偏离格式。这个投入产出比是很划算的因为写这个 skill 只花了不到半小时。4.3 参数选择与调试过程skill 写完之后不是就完事了还需要调试。调试的核心是观察触发时机和执行结果然后针对性地调整。我一般会准备一组测试用例覆盖三种情况应该触发的场景、不应该触发的场景、边界场景。比如对于提交信息 skill应该触发的是“帮我写个提交信息”不应该触发的是“帮我写个函数”边界场景是“帮我看看这次提交有没有问题”——这个场景既涉及提交又涉及检查需要判断 skill 是否适用。调试过程中最常见的问题是触发过于敏感。我写过一个处理数据库迁移的 skill触发词里放了“迁移”两个字结果每次提到“数据迁移”、“代码迁移”甚至“迁移到新服务器”时都会触发但后面这些场景跟数据库迁移完全没关系。后来我把触发词改成了“数据库迁移”、“schema 变更”、“migration 文件”这些更具体的组合误触发就少了很多。另一个常见问题是执行结果不稳定。同样的输入有时候 AI 按 skill 执行了有时候没有。排查下来发现是 skill 的正文太长AI 在上下文里读到一半就跳过了。解决办法是把正文精简到三百字以内把详细说明移到单独的参考文档里skill 正文只保留核心步骤和原则。4.4 多工具环境下的同步策略如果你同时用 Claude Code 和 Codex可能会遇到一个问题两个工具的 skills 格式不完全一样。Claude Code 的 skill 文件用 YAML front matterCodex 可能用 JSON 配置。这时候你有两个选择要么维护两套 skills要么写一个转换脚本。我选的是后者。写了一个简单的 Node.js 脚本读取.skills目录下的 Markdown 文件解析 YAML front matter然后生成 Codex 需要的 JSON 配置。脚本核心逻辑大概三十行const fs require(fs); const path require(path); const yaml require(js-yaml); const skillsDir path.join(__dirname, .skills); const output []; function walk(dir) { const entries fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath path.join(dir, entry.name); if (entry.isDirectory()) { walk(fullPath); } else if (entry.name.endsWith(.md)) { const content fs.readFileSync(fullPath, utf-8); const match content.match(/^---\n([\s\S]*?)\n---/); if (match) { const meta yaml.load(match[1]); output.push({ name: meta.name, description: meta.description, triggers: meta.triggers || [], path: fullPath }); } } } } walk(skillsDir); fs.writeFileSync(codex-skills.json, JSON.stringify(output, null, 2));这个脚本我放在项目的scripts目录下每次更新 skills 之后跑一次就行。如果你用的工具更多可以在这个基础上扩展核心思路是一样的以 Markdown 为单一数据源其他格式通过转换生成。这样你只需要维护一套内容不用操心同步问题。5. 常见问题与排查技巧实录5.1 触发失败为什么我的 skill 没生效这是被问得最多的问题。skill 没生效通常有三个原因。第一个是文件位置不对。不同工具对 skills 目录的位置要求不一样有的要求放在项目根目录有的要求放在用户主目录。你先确认一下你用的工具默认读哪个位置然后把文件放对地方。第二个原因是YAML 格式错误。YAML 对缩进很敏感多一个空格少一个空格都可能导致解析失败。我建议你写完 front matter 之后用一个在线的 YAML 校验工具过一遍确认没有语法问题。常见的错误包括冒号后面没加空格、列表项缩进不一致、特殊字符没加引号。第三个原因是触发词不匹配。你写的触发词是“API 错误”但用户输入的是“接口报错”这两个词虽然意思相近但字面上不匹配AI 就不会触发。解决办法是在触发词列表里多放几个同义词覆盖不同的表达习惯。我一般会放三到五个同义词太少覆盖不够太多又容易误触发。排查的时候你可以先手动在对话里输入触发词看 AI 有没有加载对应的 skill。如果加载了但执行不对那是正文的问题如果根本没加载那就是触发条件或文件位置的问题。这个二分法能帮你快速定位问题所在。5.2 执行偏差AI 没有按 skill 的要求做有时候 skill 触发了但 AI 的执行结果跟你的预期有偏差。这种情况我遇到过的原因主要有两个。一个是指令有歧义。比如你写“输出简洁的代码”这个“简洁”就很主观AI 的理解可能跟你不一致。改成“函数不超过 20 行嵌套不超过 3 层”就明确多了。写 skill 的时候要尽量用可量化、可验证的描述避免主观形容词。另一个原因是skill 之间有冲突。如果你装了两个 skill一个说“错误信息要详细”另一个说“错误信息要简洁”AI 就不知道该听谁的。解决办法是给 skill 设定优先级或者在冲突的 skill 里明确说明适用范围。比如详细错误信息用于开发环境简洁错误信息用于生产环境这样就不冲突了。还有一个比较隐蔽的原因AI 的上下文里已经有其他指令覆盖了 skill。比如你在对话开头说了一句“尽量用简短的代码”这句话可能比 skill 里的规范优先级更高。遇到这种情况你需要在对话里明确说“按照 skill 的规范来”把优先级拉回来。5.3 性能问题skills 太多导致响应变慢skills 装多了之后你可能会发现 AI 的响应速度变慢了。这是因为每次对话时AI 都需要扫描一遍所有的 skill 来判断是否触发。如果你的 skills 目录下有几十个文件这个扫描过程就会消耗不少时间。我的做法是按项目启用 skill。不是所有项目都需要所有 skill你可以在项目配置里指定只加载哪些 skill。比如一个纯前端项目就不需要数据库迁移的 skill把它排除掉能省不少时间。大部分工具都支持这种配置你查一下对应工具的文档就能找到。另一个优化点是合并相似 skill。如果你有五个 skill 都是关于代码风格的可以考虑合并成一个用不同的章节来区分。这样扫描时只需要读一个文件而不是五个。合并的时候注意保持每个章节的独立性不要让它们互相干扰。5.4 常见问题速查表问题现象可能原因排查方法解决方式skill 完全不触发文件位置错误确认工具默认读取路径移动到正确目录skill 完全不触发YAML 语法错误用校验工具检查 front matter修正缩进和格式skill 偶尔触发触发词覆盖不足检查用户输入与触发词的匹配度增加同义词执行结果不稳定正文过长统计 skill 正文字数精简到 300 字以内执行结果偏差指令有歧义检查是否使用了主观描述改为可量化描述多个 skill 冲突规范互相矛盾检查 skill 之间的规则设定优先级或适用范围响应变慢skill 数量过多统计 skills 目录文件数按项目启用或合并5.5 几个我踩过的坑第一个坑是在 skill 里写死版本号。我早期写了一个 React 相关的 skill里面写了“使用 React 18 的 API”。后来项目升级到 React 19这个 skill 就过时了但 AI 还是会按旧版本的建议来。后来我改成从package.json里动态读取版本号skill 里只写“根据项目实际使用的 React 版本选择 API”。这样 skill 就不用跟着版本升级而频繁修改了。第二个坑是skill 的触发词跟其他工具的关键词撞车。我写了一个处理“构建”的 skill触发词里有“build”。结果每次我提到“build 一个函数”时也会触发但这里的 build 跟项目构建完全没关系。后来我把触发词改成“项目构建”、“构建配置”、“build script”这些更具体的组合问题就解决了。第三个坑是忘了给 skill 写版本记录。skills 是会迭代的你今天写的规范可能下个月就调整了。如果没有版本记录你很难追溯某个规范是什么时候改的、为什么改。我现在每个 skill 文件末尾都会加一个简单的变更记录格式就是日期加一句话说明。这个习惯帮我省了很多回溯的时间。6. 进阶玩法让 skills 真正融入工作流6.1 用 skills 串联多个工具skills 不只能给单个 AI 助手用你还可以用它来串联多个工具。比如我现在的流程是用 Claude Code 写代码用 Codex 做代码审查用另一个工具跑测试。这三个环节各自有对应的 skill但它们共享同一套基础规范。这样不管在哪个环节输出的代码风格和错误处理方式都是一致的。实现方式是在基础 skill 里定义通用规范然后在各个工具的配置里引用这些基础 skill。大部分工具都支持引用外部 skill 文件你只需要在配置里写上路径就行。这样你更新基础规范时所有工具都会同步生效不用一个个去改。6.2 根据项目类型动态加载不同类型的项目需要不同的 skill 组合。Web 项目需要前端相关的 skillCLI 工具需要命令行参数处理的 skill库项目需要 API 设计规范的 skill。你可以写一个简单的加载脚本根据项目里的特征文件来判断项目类型然后自动加载对应的 skill。判断逻辑可以很简单有package.json且依赖里有react或vue就加载前端 skill有Cargo.toml就加载 Rust 相关的 skill有go.mod就加载 Go 相关的 skill。这个脚本我放在项目的scripts目录下配合 Git hooks 在切换分支时自动执行。6.3 团队协作中的 skills 管理如果你在团队里推广 skills有几个点需要注意。首先是命名规范要统一不然每个人起的名字不一样引用的时候容易乱。我们团队的做法是统一用领域-具体场景的格式比如frontend-component、backend-api、devops-deploy。其次是变更要走评审。skills 是团队共享的规范改动了会影响所有人。我们现在的做法是 skills 的修改也走 Pull Request至少一个人 review 之后才能合并。这样能避免有人不小心改错了规范导致大家的输出都出问题。最后是定期清理。团队用久了之后skills 目录下会积累很多不再使用的文件。我们每个季度会做一次清理把过时的、重复的、没人用的 skill 删掉。清理的标准很简单如果过去三个月没有任何项目引用过这个 skill就标记为待删除公示一周后没人反对就删掉。6.4 从 skills 到自动化工作流skills 的终极形态是跟自动化工作流结合。比如你可以配置成每次提交代码时自动触发代码审查 skill检查提交信息是否符合规范、代码风格是否一致、有没有遗漏的测试。如果检查不通过就阻止提交并给出修改建议。这个配置需要结合 Git hooks 和 CI 流程来实现。Git hooks 负责本地检查CI 负责远程检查。两边的 skill 是同一套保证标准一致。我现在的项目里本地提交时会有三个 skill 自动运行提交信息检查、代码风格检查、敏感信息扫描。这三个检查加起来大概两秒钟但能拦住大部分低级错误。7. 一些个人体会写了这么多最后说几句实在的。skills 这个东西刚上手的时候会觉得有点繁琐要写 YAML、要组织 Markdown、要调试触发条件。但一旦跑通了它带来的收益是持续的。我自己的项目里AI 生成的代码从“需要大改”变成了“小修即可”这个变化节省的时间远远超过写 skill 的时间。另外不要追求一次写完美。我最早的几个 skill 现在回头看写得很粗糙但正是从那些粗糙的版本开始我慢慢摸清楚了什么样的指令 AI 能准确执行、什么样的触发条件不会误触发。这个过程没有捷径就是写、用、改、再写。你如果刚开始接触建议先从一两个最常用的场景入手比如提交信息规范或者代码风格检查跑通之后再逐步扩展。还有一个小心得skill 的正文里多放示例少放规则。规则是抽象的示例是具体的。AI 从示例里学到的模式比从规则里推导出来的更准确。我现在的每个 skill 至少配两组对比示例效果比单纯列规则好很多。这个技巧你可以直接拿去用不用谢。