1. 从“skills”这个标题说起:它到底在解决什么问题
第一次看到“skills”这个标题,很多人会以为是某个泛泛的能力清单,或者一份简历上的技能标签。但结合热搜词里反复出现的 Claude Code、Codex、plugin、agents 这些词,就能判断出这里说的 skills 不是人力资源语境下的“技能”,而是 AI 编程助手生态里一个非常具体的概念——给 AI Agent 挂载的可复用能力包。
我最早接触这个概念是在折腾 Claude Code 的时候。当时我的诉求很朴素:每次让 AI 帮我写代码,都要重复交代一堆上下文,比如“这个项目用 pnpm 不用 npm”“提交信息要遵循 Conventional Commits”“测试文件放在tests目录下”。说一次两次还行,说一百次就是纯浪费。后来发现 Claude Code 支持一种叫 skills 的机制,可以把这些约定、流程、脚本打包成一个目录,Agent 在需要的时候自动加载。这一下就把我从重复劳动里解放出来了。
所以这篇内容我想聊的,就是围绕 skills 这一整套东西:它是什么、为什么值得投入时间、怎么从零搭一个能用的 skill、踩过哪些坑、以及 Claude Code 和 Codex 这两个主流工具在 skills 支持上的差异。适合两类人看:一类是已经在用 AI 编程助手、但还停留在“聊天式提问”阶段的开发者;另一类是团队里想把 AI 使用规范沉淀下来的技术负责人。哪怕你之前完全没接触过 skills,跟着走一遍也能上手。
需要先说明一点:skills 这个概念目前在不同工具里的实现细节不完全一样,Claude Code 有自己的一套目录约定,Codex 那边又略有不同,社区里还有各种第三方 plugin 市场。我会尽量把通用的部分讲透,工具特有的部分单独标注,避免你照着做的时候发现对不上。
2. skills 的核心设计思路:为什么是“目录 + 描述”而不是“插件”
2.1 从 prompt 堆砌到能力封装,思路的转变在哪
早期用 AI 编程助手,大家的做法基本是往对话里塞 prompt。项目规范写在一个巨大的 system prompt 里,或者每次开新会话手动粘贴一段说明。这种做法在项目小的时候没问题,一旦项目变大、规范变多,就会遇到几个硬伤。
第一个硬伤是上下文窗口的浪费。你把所有规范都塞进去,不管这次任务用不用得上,模型都要读一遍。一个前端项目可能同时有组件规范、样式规范、测试规范、提交规范、部署规范,但这次只是改一个工具函数,读那么多纯属浪费 token。
第二个硬伤是维护困难。规范散落在各个 prompt 模板里,改一处要同步好几处,时间一长就没人记得哪份是最新的。
skills 的设计思路正好针对这两点。它把能力拆成一个个独立的目录,每个目录里有一个描述文件,说明这个 skill 是干什么的、什么时候该用。Agent 启动时只读这些描述(很轻量),真正需要执行某个任务时,才把对应 skill 的完整内容加载进来。这就像图书馆:书架上的索引卡片很薄,你按需去取那本书,而不是把整个图书馆搬回家。
提示:这个“按需加载”的机制是 skills 最核心的价值。理解这一点,后面所有的目录结构、描述写法、拆分粒度,逻辑都能串起来。
2.2 一个 skill 的最小构成:目录、描述、正文
一个能用的 skill,最小构成其实就三样东西。我用 Claude Code 的约定来举例,因为它的结构最清晰,其他工具大同小异。
- 一个独立目录:通常放在项目的
.claude/skills/或者用户级的~/.claude/skills/下,目录名就是 skill 的名字,比如commit-helper、api-test。 - 一个描述文件:一般是
SKILL.md,开头有一段 frontmatter,写明 name 和 description。description 是给 Agent 看的,决定它什么时候会想起这个 skill。 - 正文内容:描述文件的后半部分,写具体的操作步骤、命令、注意事项。这部分只在 skill 被激活时才进入上下文。
这里最关键的是 description 的写法。很多人第一次写 skill,description 写成“这是一个提交辅助工具”,结果 Agent 从来不主动用它。原因很简单:Agent 判断要不要用某个 skill,靠的是把当前任务和 description 做语义匹配。“提交辅助工具”这种描述太抽象,匹配不上“帮我把这次改动提交了”这种具体请求。正确的写法应该把触发场景写进去,比如“当用户要求提交代码、生成 commit message、或整理暂存区改动时使用”。
2.3 为什么不做成传统插件:轻量与可读的取舍
有人会问,既然要封装能力,为什么不直接做成传统意义上的插件,写代码、注册钩子、走一套完整的生命周期?我的理解是,skills 刻意选择了“轻量”这条路。
传统插件功能强,但门槛高。你要懂它的 API、要处理版本兼容、要打包发布。而 skills 本质上就是一堆 Markdown 加脚本,任何人打开目录就能看懂,改一行字就能调整行为,不需要编译、不需要发布流程。这种低门槛带来的好处是,团队里每个人都能贡献自己的 skill,而不是只有少数懂插件开发的人才能参与。
代价当然也有。skills 不适合做复杂的逻辑编排,它更像“给 Agent 的一份操作手册”,而不是“一个独立运行的程序”。如果你需要的是复杂的条件分支、状态管理、外部服务调用,那还是得走插件或者自己写工具。判断标准很简单:如果这件事用一段自然语言说明加几条命令就能讲清楚,就用 skill;如果讲不清楚,才考虑插件。
3. 动手搭第一个 skill:从目录结构到实际生效
3.1 环境准备与目录约定
动手之前先把环境理清楚。以 Claude Code 为例,你需要先确认它已经装好并且能正常跑起来。安装方式各平台不太一样,Windows 桌面版、macOS、Linux 都有对应的包,社区里也有大量安装教程可以参考。装完之后,在终端里能调起claude命令,就说明基础环境没问题。
接下来是目录。skills 一般有两个存放位置,作用范围不同:
| 位置 | 路径示例 | 作用范围 | 适用场景 |
|---|---|---|---|
| 用户级 | ~/.claude/skills/ | 当前用户所有项目 | 个人通用习惯,如提交规范 |
| 项目级 | <项目根>/.claude/skills/ | 仅当前项目 | 项目特有规范,如目录约定 |
我的建议是:个人习惯放用户级,项目约定放项目级。这样换项目的时候,个人习惯跟着走,项目约定不会污染其他项目。如果你在团队里协作,项目级的 skills 可以提交到仓库,所有人共享,这比在群里发一份 Word 文档靠谱得多。
注意:不同工具对目录名的要求不完全一样。Claude Code 认
.claude/skills/,Codex 那边可能是别的路径。写之前先查一下你用的工具当前版本的文档,别照着旧教程硬套。
3.2 写一个能真正被触发的 description
前面强调过 description 的重要性,这里给一个具体的对比。假设我要做一个“生成 commit message”的 skill。
反面写法:
description: 帮助生成提交信息正面写法:
description: 当用户要求提交代码、生成 commit message、整理暂存区改动、或询问如何写提交说明时使用。适用于 Git 仓库中已有 staged 改动的场景。差别在哪?正面写法里包含了动作词(提交、生成、整理)、对象词(代码、commit message、暂存区)、场景限定(已有 staged 改动)。Agent 在做语义匹配时,这些词都能提高命中率。我实测下来,description 里把用户可能说的原话写进去,触发率会明显提升。
还有一个技巧:如果两个 skill 的职责有重叠,description 里要写清楚边界。比如你有一个“提交”skill 和一个“代码审查”skill,提交 skill 的 description 里可以加一句“不负责代码质量检查,那是 review skill 的职责”。这样能减少 Agent 选错 skill 的情况。
3.3 正文写法:把 Agent 当成一个聪明但没上下文的新同事
description 决定“用不用”,正文决定“怎么用”。正文的写法我总结成一句话:把 Agent 当成一个聪明但完全不了解你项目的新同事,你要把操作步骤讲到他能照着做。
具体来说,正文里应该包含这几类信息:
- 前置检查:执行前要确认什么。比如“先运行 git status 确认有 staged 改动,如果没有就提示用户先 add”。
- 操作步骤:一步一步写清楚。命令用代码块标出来,参数写明白。
- 判断逻辑:遇到什么情况怎么处理。比如“如果改动涉及多个不相关的模块,建议拆成多个 commit”。
- 输出格式:最终产物长什么样。给一个示例,Agent 会照着模仿。
- 禁止事项:明确不能做什么。比如“不要自动执行 git push”。
我踩过的一个坑是:正文写得太抽象,全是“根据情况灵活处理”这种话。结果 Agent 每次行为都不一样,有时候靠谱有时候离谱。后来我把能确定的分支都写死,只在真正需要判断的地方留余地,稳定性一下就上来了。能写死的就别留给模型判断,这是用 skills 的一条重要经验。
4. Claude Code 与 Codex 的 skills 差异:别拿一套经验硬套
4.1 加载机制与触发时机的不同
Claude Code 和 Codex 都支持类似 skills 的能力,但加载机制有差异,直接影响到你怎么组织内容。
Claude Code 的 skills 更偏向“描述驱动”。它会在会话开始时读取所有 skill 的 description,建立一个索引,然后在对话过程中根据语义匹配决定加载哪个。这意味着 description 的质量直接决定触发效果,而正文可以写得比较长,因为不触发就不占上下文。
Codex 那边,根据社区反馈和实际使用体验,它对 skills 的处理更偏向“显式引用”。有时候你需要在任务描述里明确提到 skill 的名字,或者通过配置指定加载哪些。这种机制下,description 的重要性相对降低,但你需要更主动地管理哪些 skill 处于激活状态。
这个差异带来的实操建议是:如果你同时用两个工具,skill 的正文可以共用,但 description 要针对各自机制优化。Claude Code 那边把触发词写足,Codex 那边保证 skill 名字好记好引用。
4.2 配置文件的坑:那些报错信息在说什么
热搜词里有一堆报错信息,比如 “cc switch local proxy failed while handling codex endpoint /responses”、“codex 无法加载组织设置”、“the 'gpt-5.6-sol' model is not supported when using codex”。这些看着吓人,其实大部分和 skills 本身没关系,是工具配置和模型接入的问题。
我挑两个和 skills 使用间接相关的说一下。一个是模型不支持的问题,通常是因为你在配置里指定了一个当前环境不认识的模型名,解决方法是检查配置文件里的 model 字段,换成实际可用的。另一个是组织设置加载失败,多半是网络或者认证配置的问题,和 skill 内容无关,但会让人误以为是 skill 写错了。
提示:遇到报错先别急着改 skill。把报错信息里的关键词单独搜一下,确认是工具层问题还是 skill 层问题。我见过太多人把配置错误当成 skill 写错,白白折腾半天。
4.3 跨工具复用的现实做法
如果你团队里有人用 Claude Code,有人用 Codex,怎么让 skills 复用?我的做法是维护一份“源文件”,放在项目里的docs/skills/目录,每个 skill 一个 Markdown。然后用一个简单的脚本,把源文件转换成各工具需要的目录结构和格式。这样改一处,两边同步。
脚本本身不复杂,无非是读文件、解析 frontmatter、写到目标路径。关键是养成“改源文件、跑脚本、不同步手改”的习惯。一旦有人图省事直接改目标目录,两边就会漂移,过段时间就没人搞得清哪份是对的。
5. 常见问题与排查:那些文档里不会写的坑
5.1 skill 不触发怎么办
这是最高频的问题。排查顺序我一般是这样的:
- 确认目录位置对不对。放错目录是最常见的原因,尤其是项目级和用户级搞混。
- 确认 description 有没有触发词。把用户可能说的原话列出来,看 description 里覆盖了几个。
- 确认 skill 名字有没有冲突。两个 skill 名字太像,Agent 可能选错。
- 确认工具版本支持。老版本可能不支持 skills,或者支持的方式不一样。
如果以上都没问题,还有一个偏方:在对话里显式提一下 skill 的名字,比如“用 commit-helper 帮我提交”。如果这样能触发,说明 skill 本身没问题,是 description 的匹配度不够,回去改 description。
5.2 skill 触发了但行为不对
这种情况通常是正文写得不够明确。我遇到过一次,skill 里写“根据改动内容生成合适的提交信息”,结果 Agent 有时候生成中文,有时候生成英文。后来我在正文里明确写“提交信息使用中文,格式为 type(scope): description”,问题就解决了。
另一个常见原因是正文里的命令有环境依赖。比如你写pnpm test,但用户环境里只有 npm。解决办法是在正文里加一句前置检查,或者写成“优先使用项目 lock 文件对应的包管理器”。
5.3 多个 skill 互相干扰
当 skill 数量多起来,互相干扰是必然的。表现是 Agent 在一个任务里加载了不相关的 skill,或者该加载 A 却加载了 B。
我的处理原则是职责单一。一个 skill 只做一件事,description 里写清楚边界。如果两个 skill 确实有重叠,就在各自的 description 里互相引用,说明分工。比如“代码格式化”和“代码审查”两个 skill,格式化 skill 里写“只处理格式,不评价代码质量”,审查 skill 里写“只评价质量,不自动改格式”。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| skill 完全不触发 | 目录位置错误 | 检查.claude/skills/路径 |
| skill 偶尔触发 | description 触发词不足 | 补充用户原话中的动作词 |
| 触发了但输出不稳定 | 正文判断逻辑太模糊 | 把能确定的分支写死 |
| 加载了错误的 skill | 多个 skill 职责重叠 | 拆分或明确边界 |
| 命令执行失败 | 环境依赖不匹配 | 加前置检查或写清依赖 |
| 跨工具行为不一致 | 两套机制差异 | 针对各工具优化 description |
6. 把 skills 用出复利:从个人习惯到团队资产
6.1 从“我自己的 skill”到“团队的 skill”
个人用 skills,解决的是自己的效率问题。但 skills 真正的价值放大,是在团队层面。我经历过一次转变:一开始只有我自己写 skill,后来我把几个通用的 skill 提交到项目仓库,同事拉下来就能用。再后来,团队里每个人都开始贡献自己的 skill,慢慢形成了一套“团队 AI 使用规范”的活文档。
这个过程中最关键的一步是建立 review 机制。skill 也是代码,也会出错,也需要维护。我们现在的做法是,skill 的改动走和代码一样的 PR 流程,有人 review,合并后生效。这样能避免有人写了个有问题的 skill 把大家都带偏。
6.2 版本管理与更新策略
skills 的版本管理有个特殊之处:它不像代码那样有明确的版本号,但行为会随工具版本变化。我的做法是在 skill 目录里放一个CHANGELOG.md,记录每次改动的原因和影响。同时在 description 或正文里标注“适用于 Claude Code x.x 及以上版本”这类信息。
更新策略上,我倾向于小步快跑。发现 skill 行为不对,当天就改,不要攒着。因为 skill 的问题会持续影响每一次使用,拖得越久损失越大。
6.3 什么样的 skill 值得沉淀
不是所有东西都值得做成 skill。我判断的标准是:这件事我重复做过至少三次,且每次步骤基本一致。满足这个条件,做成 skill 才有复利。如果一件事只做一次,或者每次情况都不同,那临时处理就好,别为了 skill 而 skill。
另外,那些“我知道该怎么做但每次都要想一下”的事情,也特别适合做成 skill。比如发布流程、回滚流程、环境初始化流程。这些流程平时不常用,用的时候容易漏步骤,做成 skill 就相当于给自己留了一份不会忘的检查清单。
6.4 我个人的几条经验
最后分享几条我实际用下来觉得最有价值的经验。第一条是先写 description 再写正文,因为 description 决定了 skill 会不会被用,正文写得再好,不触发也是白搭。第二条是skill 要短,一个 skill 超过两屏就该考虑拆了,太长的 skill 加载慢、维护难、还容易让 Agent 抓不住重点。第三条是定期清理,过时的 skill 比没有 skill 更糟,因为它会误导 Agent,我一般每季度过一遍,删掉不再用的。
还有一条偏门但很有用的:给 skill 写测试。不是自动化测试,而是手动测试。写完一个 skill,故意用几种不同的说法去触发它,看行为是否一致。我靠这个习惯发现了不少 description 的盲区。
这套东西说到底,核心就一句话:skills 是把你的经验和规范,变成 Agent 能理解和执行的形式。它不神秘,也不复杂,难的是持续维护和团队协作。但只要开始做,哪怕只有一个 skill,你就能感受到那种“不用重复交代”的轻松。