1. 从“skills”这个词说起:它到底在解决什么问题
第一次看到“skills”这个标题,很多人会以为是某个泛泛的能力清单,或者招聘网站上的技能标签。但如果你最近在折腾 Claude Code、Codex、Cursor 这类 AI 编程工具,就会发现“skills”已经变成了一个非常具体的工程概念——它指的是给 AI Agent 挂载的一套可复用、可组合、可版本管理的任务能力包。
我最早接触这个概念是在给团队搭内部 AI 编码助手的时候。当时遇到一个很典型的问题:每次让 Agent 做代码审查,它都要重新理解一遍我们的规范;每次让它生成数据库迁移脚本,它都要重新问一遍表结构约定。上下文窗口就那么大,反复解释规则既浪费 token,又容易在长对话里“忘掉”前面的约束。skills 这套机制本质上就是把这些重复的“领域知识 + 操作流程 + 工具调用”固化下来,让 Agent 在需要的时候按需加载,而不是每次都从零开始。
它适合谁?如果你只是偶尔用 AI 写个脚本,可能感受不深。但只要你开始把 AI 编程工具接入真实项目——尤其是多人协作、有明确代码规范、涉及多步骤操作(比如“改代码 → 跑测试 → 更新文档 → 提交”)的场景——skills 的价值就会立刻显现。它解决的核心问题是:如何让 AI Agent 的行为从“每次即兴发挥”变成“按既定规程执行”。
这篇文章我会从设计思路、核心机制、实操落地、踩坑排查四个层面,把 skills 这套东西讲透。不管你是刚装好 Claude Code 的新手,还是已经在用 Codex 接入自定义模型的老手,都能找到可以直接抄作业的部分。
2. skills 的整体设计与核心思路拆解
2.1 为什么是“技能包”而不是“更长的提示词”
很多人第一反应是:我直接把规范写进系统提示词不就行了?我试过,短期可行,长期会崩。原因有三个。
第一,上下文是稀缺资源。一个项目的编码规范、API 约定、目录结构说明,全部塞进系统提示词,轻松吃掉几千 token。这些 token 在每一轮对话里都要重新计费、重新占用窗口,而 Agent 真正需要用来“思考”的空间被压缩了。skills 的做法是按需加载:平时不占地方,触发相关任务时才把对应技能注入上下文。
第二,提示词无法版本管理。你把规范写在配置里,改一次要动整个配置文件,团队里谁改了什么很难追溯。skills 通常以独立文件或目录的形式存在,可以进 Git,可以 review,可以回滚。这跟代码本身的管理逻辑是一致的。
第三,提示词是“说”,skills 是“说 + 做”。一个 skill 不只是描述“你应该怎么做”,它还可以绑定具体的工具调用、脚本执行、模板文件。比如一个“生成数据库迁移”的 skill,可以包含迁移文件的命名规则、模板、以及调用某个 CLI 命令的步骤。这是纯提示词做不到的。
提示:如果你现在的做法是把所有规则堆在一个巨大的系统提示里,并且已经开始感觉到 Agent“记不住”或者响应变慢,那就是该拆成 skills 的信号了。
2.2 skills 的组成结构:一个技能包里到底有什么
不同工具对 skill 的定义略有差异,但核心结构高度一致。我把它拆成四个部分来理解。
- 元信息(metadata):技能的名称、描述、触发条件。这部分决定了 Agent 什么时候会“想起”这个技能。描述写得越精准,触发越可靠。
- 指令正文(instructions):具体要做什么、按什么顺序做、有哪些约束。这是技能的主体,通常用自然语言写,但结构要清晰。
- 资源文件(resources):模板、示例、参考文档、schema 定义等。Agent 在执行时可以读取这些文件作为依据。
- 可执行部分(scripts / tools):需要实际运行的脚本或命令。有些工具支持在 skill 里直接声明可执行脚本,有些则需要通过工具调用间接完成。
这个结构和我们写一个函数很像:函数名和注释是元信息,函数体是指令,依赖的库是资源,内部调用的子函数是可执行部分。理解了这一点,你就能明白为什么 skills 可以被组合、复用、测试——它本来就是按软件工程的思路设计的。
2.3 触发机制:Agent 怎么知道该用哪个 skill
这是整个体系里最容易被低估的环节。我见过太多人写了一个很棒的 skill,结果 Agent 从来不触发它,最后得出结论“skills 没用”。问题几乎都出在触发描述上。
触发机制通常有两种模式。一种是显式调用,你在对话里直接说“用 XX skill 来做这件事”,Agent 就会加载对应技能。这种方式可靠但不够智能。另一种是语义匹配,Agent 根据当前任务和 skill 的描述做匹配,自动决定加载哪个。这种方式体验好,但对描述质量要求极高。
我的经验是:描述里要包含“什么时候用”而不只是“这是什么”。比如“代码审查技能”这种描述就很弱,改成“当用户要求审查代码、检查代码质量、或提交 PR 前需要自查时使用”就强很多。前者只说了是什么,后者明确了触发场景。
2.4 和 plugin、agents 的关系:别把它们混为一谈
热词里同时出现了 skills、plugin、agents,这三个概念经常被混用,但职责不同。
| 概念 | 职责 | 类比 |
|---|---|---|
| Agent | 执行任务的主体,负责决策和调度 | 一个员工 |
| Skill | 可复用的能力包,告诉 Agent 怎么做某类事 | 员工掌握的某项技能 |
| Plugin | 扩展工具能力的插件,通常提供新的工具接口 | 给员工配的新设备 |
一个 Agent 可以挂载多个 skills,也可以安装多个 plugins。skills 偏“知识和流程”,plugins 偏“工具和能力”。理解这个分层,你在设计自己的 AI 工作流时就不会把东西放错地方。比如“如何写单元测试”是 skill,“运行测试的命令行工具”是 plugin。
3. 核心细节解析与实操要点
3.1 一个合格 skill 的目录长什么样
虽然不同平台的目录约定不完全一样,但主流做法是把每个 skill 放在独立目录下,用文件名区分不同部分。下面是我在实际项目里常用的结构,你可以直接参考:
skills/ code-review/ SKILL.md # 元信息 + 指令正文 checklist.md # 审查清单,作为资源被引用 examples/ good.md # 正面示例 bad.md # 反面示例 db-migration/ SKILL.md template.sql # 迁移文件模板 schema.md # 表结构约定SKILL.md是入口文件,通常包含 YAML 格式的元信息头(frontmatter)和 Markdown 正文。元信息头里写 name 和 description,正文写具体指令。这种设计的好处是:人可以直接读,Agent 也可以直接解析,不需要额外的编译步骤。
注意:目录名和元信息里的 name 尽量保持一致,并且用短横线连接的小写英文。我踩过的坑是用中文目录名,在某些环境下会出现路径编码问题,排查起来很费时间。
3.2 描述字段怎么写才能被稳定触发
前面提到触发靠描述,这里给一个可以直接套用的写法模板:
--- name: code-review description: 当用户要求审查代码、检查代码质量、在提交前自查、或提到 review/审查/检查 等关键词时使用。适用于 Python 和 TypeScript 项目。 ---拆解一下这个描述的结构:触发场景 + 关键词 + 适用范围。触发场景告诉 Agent 什么时候该想起它,关键词覆盖用户可能用的不同说法,适用范围避免在不相关的项目里误触发。
我实测下来,加上“关键词”这一层之后,自动触发的准确率明显提升。因为用户不会每次都精确地说“审查代码”,可能说“帮我看看这段有没有问题”“检查一下”“review 一下”,把这些变体列进去,匹配就稳很多。
3.3 指令正文的写法:结构化但不死板
指令正文最忌讳两种极端:一种是写成一大段散文,Agent 抓不住重点;另一种是写成死板的编号列表,遇到稍微不同的情况就不知道变通。
我的做法是用“目标 + 步骤 + 约束 + 输出格式”四段式。目标说清楚这个技能要达成什么,步骤给出推荐流程,约束列出不能碰的红线,输出格式规定结果长什么样。举个例子:
## 目标 对指定代码进行审查,找出潜在问题并给出修改建议。 ## 步骤 1. 先通读代码,理解整体意图 2. 对照 checklist.md 逐项检查 3. 按严重程度排序问题 4. 给出具体修改建议 ## 约束 - 不要直接修改代码,只给建议 - 不要评论代码风格以外的个人偏好 - 遇到不确定的问题标注“待确认”而非直接下结论 ## 输出格式 按严重程度分三档:阻塞、建议、可选。每条包含位置、问题、建议。这种写法的好处是既有结构又不僵化。Agent 知道大方向,但在具体执行时有判断空间。我对比过纯列表式的写法,四段式在复杂任务上的表现明显更稳。
3.4 资源文件的引用方式
资源文件不是自动加载的,需要在指令正文里显式引用。常见做法是写相对路径,让 Agent 在执行时去读。比如:
## 步骤 2. 对照 `checklist.md` 逐项检查这里有个细节:引用路径要相对于 skill 目录,而不是相对于当前工作目录。不同工具对路径解析的规则不一样,我建议在写完之后实际触发一次,确认 Agent 能正确读到文件。如果读不到,通常是路径基准搞错了。
另外,资源文件不要太大。我见过有人把整个项目的 API 文档塞进 skill 资源里,结果每次触发都要读几千行,token 消耗爆炸。正确做法是只放“执行这个技能必需的最小信息”,大文档应该放在项目里,让 Agent 按需检索。
3.5 版本管理与团队协作
skills 进 Git 之后,团队协作就有了基础。但有几个约定需要提前定好。
- 命名规范:统一用
领域-动作的格式,比如db-migration、api-review、doc-generate。避免my-skill、test1这种名字。 - 变更记录:在 SKILL.md 顶部维护一个简单的变更说明,写清楚谁在什么时候改了什么。不需要复杂的 changelog 工具,几行文字就够。
- 评审机制:skill 的改动应该像代码一样走 review。因为一个写错的 skill 会影响所有使用它的人,而且问题往往很隐蔽。
提示:如果团队里有人频繁改 skill 但不通知其他人,很快就会出现“为什么 Agent 今天的行为和昨天不一样”这类问题。把 skill 当代码管,这个坑就能避开。
4. 实操过程与核心环节实现
4.1 环境准备:把工具装起来
不管你用的是 Claude Code 还是 Codex,第一步都是把 CLI 工具装好。以 Claude Code 为例,常见的安装方式是通过包管理器:
# 以 npm 全局安装为例 npm install -g @anthropic-ai/claude-code # 验证安装 claude --versionCodex 的安装类似,具体包名以官方文档为准。装完之后需要配置 API 凭证,这一步不同工具差异较大,但核心都是设置环境变量或写入配置文件。
# 环境变量方式(示例,具体变量名以工具文档为准) export ANTHROPIC_API_KEY="your-key-here"注意:API 凭证不要写进 skill 文件,也不要提交到 Git。用环境变量或本地的、已被 gitignore 的配置文件管理。我见过有人把 key 写进 skill 示例里然后推到了公开仓库,后果很麻烦。
如果你在国内网络环境下遇到安装或连接问题,优先检查包管理器的镜像源配置,以及工具本身的网络设置。这部分各工具文档都有说明,按官方指引操作即可。
4.2 创建第一个 skill:从零到能跑
假设我们要做一个“生成数据库迁移脚本”的 skill。步骤如下。
第一步,建目录:
mkdir -p skills/db-migration cd skills/db-migration第二步,写 SKILL.md:
--- name: db-migration description: 当用户要求创建数据库迁移、修改表结构、添加字段或索引时使用。适用于使用 SQL 迁移文件的项目。 --- ## 目标 根据用户描述的表结构变更,生成符合项目规范的迁移脚本。 ## 步骤 1. 读取 `schema.md` 了解现有表结构约定 2. 读取 `template.sql` 作为文件模板 3. 根据用户描述生成迁移 SQL 4. 按 `YYYYMMDDHHMMSS_description.sql` 格式命名文件 ## 约束 - 迁移必须可回滚,每个迁移都要有对应的 down 脚本 - 不要删除已有字段,只做新增或修改 - 索引命名遵循 `idx_表名_字段名` 格式 ## 输出格式 输出完整的迁移文件内容,并在开头用注释说明变更目的。第三步,写资源文件template.sql:
-- Migration: {{description}} -- Created: {{timestamp}} -- UP {{up_sql}} -- DOWN {{down_sql}}第四步,写schema.md记录表结构约定,比如主键统一用id、时间戳字段用created_at和updated_at等。
第五步,实际触发测试。在对话里说“帮我加一个用户表,包含邮箱和昵称字段”,看 Agent 是否自动加载了这个 skill,生成的迁移是否符合规范。
4.3 参数与格式的选择过程
上面例子里有几个参数是刻意设计的,说一下背后的考量。
文件命名用时间戳前缀,而不是自增序号。原因是多人协作时自增序号容易冲突,时间戳天然有序且不会撞车。格式YYYYMMDDHHMMSS精确到秒,实际项目中同一秒创建两个迁移的概率极低。
UP 和 DOWN 都要有。很多团队只写 UP,结果出问题要回滚时抓瞎。把可回滚作为硬约束写进 skill,能从流程上保证这一点。
索引命名规范写进约束。数据库索引命名不统一是后期维护的噩梦,趁早用 skill 固化下来,比事后治理成本低得多。
这些选择都不是拍脑袋定的,而是从实际项目里踩坑总结出来的。你在设计自己的 skill 时,也应该把团队历史上出过问题的地方写成约束。
4.4 把 skill 接入工作流
skill 写好之后,要让它真正被用起来。有两种接入方式。
一种是手动触发,在对话里明确说“用 db-migration 技能”。适合刚开始验证阶段,确认 skill 本身没问题。
另一种是自动触发,靠描述匹配。这需要你在日常对话里观察触发情况,如果发现该触发没触发,就回去改描述,补充关键词和场景。
我的做法是:新 skill 先手动触发跑通,确认输出符合预期后,再观察自动触发的情况,根据实际对话逐步优化描述。这个过程通常要迭代两三轮才能稳定。
4.5 多 skill 组合的实战场景
单个 skill 能解决的问题有限,真正的威力在于组合。举个我实际用过的场景:一个完整的“功能开发”流程,涉及三个 skill。
api-review:审查接口设计是否符合规范db-migration:生成数据库变更脚本doc-generate:根据代码变更生成文档
当用户说“帮我加一个用户注册接口”时,Agent 可以依次触发这三个 skill,先设计接口、再生成迁移、最后更新文档。整个过程不需要用户手动切换,体验上就像有一个懂全套流程的助手。
要实现这种组合,关键是每个 skill 的边界要清晰,不能互相重叠。如果api-review里也包含了数据库变更的内容,组合时就会冲突。设计 skill 时多问一句“这件事该不该由这个 skill 负责”,能避免很多后期的混乱。
5. 常见问题与排查技巧实录
5.1 skill 不触发怎么办
这是最高频的问题。排查顺序如下。
先确认 skill 文件位置对不对。不同工具对 skill 目录的约定不同,有的要求放在项目根目录的特定文件夹,有的要求放在用户主目录。位置错了,Agent 根本扫不到。
再确认元信息格式对不对。YAML frontmatter 对缩进和符号很敏感,一个多余的空格都可能导致解析失败。用工具自带的校验命令(如果有)检查一下。
最后看描述质量。如果前两项都没问题,那就是描述没覆盖到用户的实际说法。把最近几次没触发的对话翻出来,看看用户是怎么表达的,把这些表达补进描述里。
5.2 触发了但输出不符合预期
这种情况通常是指令正文的问题。常见原因有三个。
一是约束写得太模糊。比如写“代码要规范”,Agent 不知道你说的规范是什么。改成“函数名用 snake_case,类名用 PascalCase”就明确了。
二是步骤有歧义。比如“先检查再修改”,Agent 可能理解为先检查所有文件再统一修改,也可能理解为逐个文件检查并修改。把顺序和粒度写清楚。
三是资源文件没读到。前面提过路径问题,这里再强调一次:确认引用路径的基准,必要时用绝对路径测试。
5.3 多个 skill 冲突
当两个 skill 的触发条件重叠时,Agent 可能加载错误的那个,或者两个都加载导致指令打架。解决办法是在描述里明确排除条件。比如api-review的描述里加一句“不适用于数据库 schema 变更”,把边界划清楚。
如果冲突频繁发生,说明这两个 skill 的职责划分有问题,应该考虑合并或重新拆分。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| skill 完全不触发 | 目录位置错误 / 元信息格式错误 | 检查路径约定和 YAML 语法 |
| 偶尔触发偶尔不触发 | 描述覆盖不全 | 补充关键词和触发场景 |
| 触发后输出跑偏 | 指令有歧义 / 约束模糊 | 细化步骤和约束条件 |
| 资源文件读不到 | 路径基准错误 | 确认相对路径的参照点 |
| 多 skill 打架 | 触发条件重叠 | 在描述里加排除条件 |
| token 消耗异常高 | 资源文件过大 | 精简资源,大文档外置 |
5.5 几个我踩过的坑
坑一:把 skill 写成了万能模板。一开始我想做一个“什么都能干”的 skill,结果指令又长又泛,Agent 执行时经常抓不住重点。后来拆成多个小 skill,每个只干一件事,效果反而好很多。skill 的粒度应该像函数一样,单一职责。
坑二:忽略了对输出格式的约束。早期我没写输出格式,Agent 每次返回的结构都不一样,有时是列表有时是段落,后续处理很麻烦。加上输出格式约束后,结果变得可预测,也方便做自动化处理。
坑三:skill 改了不通知团队。有一次我优化了一个 skill 的约束条件,结果同事那边因为缓存或者没同步,行为不一致,排查了半天。后来我们约定 skill 变更要在群里说一声,并且定期同步。
坑四:在 skill 里硬编码环境相关的路径。比如写死了某个绝对路径,换台机器就失效。正确做法是用相对路径或者环境变量,让 skill 在不同环境下都能跑。
5.6 性能与成本优化
skills 用多了之后,token 成本会上升。几个优化方向。
一是精简资源文件。只保留执行必需的信息,大文档放到项目里按需检索。
二是控制触发范围。描述写得太宽会导致频繁触发,写得太窄会漏触发,需要在实践中找平衡。
三是定期清理。项目里不再使用的 skill 及时删掉,避免 Agent 在匹配时被干扰。
四是合并相似 skill。如果两个 skill 有大量重复内容,考虑抽出一个公共部分,用引用或继承的方式复用。
6. 进阶:把 skills 做成团队资产
6.1 从个人使用到团队共享
个人用 skill 和团队用 skill 是两回事。个人用可以随意,团队用必须规范。我总结了几条团队落地的经验。
统一存放位置。所有 skill 放在项目仓库的固定目录下,比如.skills/或skills/,不要散落在各人本地。
统一命名和结构。前面提过的命名规范,团队里要达成一致。新成员加入时,看目录结构就能明白有哪些能力可用。
建立评审流程。skill 的改动走 PR,至少一个人 review。review 的重点是触发描述是否清晰、约束是否完整、有没有引入冲突。
维护一份索引。在 skills 目录下放一个 README,列出所有 skill 的名称、用途、负责人。新人上手时先看这个。
6.2 skill 的测试思路
skill 也需要测试,但测试方式和代码不同。我的做法是准备一组典型输入,每次改完 skill 就跑一遍,看输出是否符合预期。
典型输入要覆盖:正常情况、边界情况、容易误触发的情况。比如db-migration的测试输入可以包括“加一个字段”“加一个表”“加一个索引”“修改字段类型”,以及一个不该触发的输入比如“帮我写个查询语句”。
这套测试不需要自动化工具,手动跑一遍也就几分钟,但能挡住大部分低级错误。
6.3 和其他工具的配合
skills 不是孤立的,它要和版本控制、CI、文档系统配合。几个实际的做法。
把 skill 的变更纳入 CI 检查,比如校验 YAML 格式、检查命名规范。这样能避免格式错误混进主分支。
把 skill 和项目文档关联起来。比如api-reviewskill 里引用的规范文档,就是项目 API 文档的一部分,改一处两边同步。
把 skill 的使用情况记录下来。哪些 skill 用得多、哪些从没触发过,这些数据能指导你优化 skill 库。
6.4 后续可以扩展的方向
skills 这套机制还在快速演进,几个值得关注的方向。
一是skill 的自动生成。从现有的代码规范、文档、历史对话里自动提取出 skill 草稿,人工审核后入库。这能大幅降低维护成本。
二是skill 的效果度量。记录每次触发的输出质量,用数据驱动优化。比如某个 skill 的输出经常被人工修改,说明指令需要调整。
三是跨项目的 skill 复用。把通用性强的 skill 抽出来做成共享库,不同项目按需引入。这需要一套依赖管理机制,目前还在探索阶段。
我个人在实际操作中的体会是:skills 的价值不在于数量,而在于质量。一个写得精准、触发稳定、输出可靠的 skill,胜过十个模棱两可的。与其追求覆盖所有场景,不如先把最高频、最痛的那几个场景做扎实。等团队习惯了这套工作方式,再逐步扩展,节奏会顺很多。