1. 从“skills”这个热词说起:它到底在解决什么问题
最近半年,不管是在技术社区还是开发者群聊里,“skills”这个词出现的频率高得离谱。你随便翻翻热搜词列表就能看到:skills、claude code、codex、plugin、agents、find skills、skills推荐、codex skills、claude agent skills……这些词扎堆出现,说明一件事:围绕 AI 编程助手的能力扩展机制,正在成为一线开发者最关心的实操话题。
我最早接触这个概念是在折腾 Claude Code 的时候。当时我的诉求很简单:让 AI 助手不只是“聊天写代码”,而是能真正接入我的项目环境、执行具体任务、调用外部工具、按我的规范干活。后来发现,不管是 Claude Code 的 skills、Codex 的 plugin 体系,还是各类 agent 框架里的工具注册机制,本质上都在做同一件事——把“通用大模型”变成“懂你项目、能动手干活的专业助手”。
这篇文章我想聊的“skills”,不是某个单一产品的功能说明,而是一整套围绕 AI 编程助手能力扩展的实操方法论。具体包括:skills 的核心设计思路是什么、为什么各家产品都在做类似的事、怎么从零开始写一个能用的 skill、安装配置过程中会遇到哪些坑、以及我踩过的那些“文档里不会写”的经验。适合正在用 Claude Code、Codex、Cursor 或者任何 AI 编程工具的开发者,也适合想自己动手做 agent 能力扩展的技术人。
提示:本文提到的所有工具、配置、命令,都是基于公开可获取的通用技术方案,不涉及任何特定网络环境或特殊访问方式。所有操作均可在标准开发环境下复现。
2. skills 的核心设计逻辑:为什么不是简单的“插件”
2.1 从 plugin 到 skills:能力扩展的两种思路
很多人第一次听到 skills 会下意识觉得“这不就是插件吗”。我一开始也这么想,但实际用下来发现,skills 和传统 plugin 在设计哲学上有本质区别。
传统 plugin 的思路是“注册一个功能入口”。比如你在 IDE 里装个插件,它给你加个菜单项、加个按钮、加个命令。你点一下,它执行一个预定义好的动作。这种模式的问题是:功能是死的,调用方式是固定的。你得记住哪个插件对应哪个功能,得知道什么时候该点哪个按钮。
skills 的思路完全不同。它更像是“给 AI 助手一本操作手册”。你写一个 skill,本质上是告诉 AI:“当你遇到这类任务时,应该按这个流程、用这些工具、遵循这些规范来做。”AI 会根据当前上下文自己判断什么时候该调用哪个 skill,不需要你手动指定。
举个例子。假设你要让 AI 帮你处理一个前端项目的构建问题。传统 plugin 模式下,你得先找到构建相关的插件,点进去,选对应的功能。skills 模式下,你只需要描述问题:“这个 React 项目构建报错了,帮我看看。”AI 会自动识别这属于前端构建类任务,然后调用你预先写好的frontend-build-debugskill,按照里面定义的排查步骤一步步来。
这个区别听起来不大,但实际用起来体验差很多。skills 把“选择工具”的决策权交给了 AI,你只需要定义“工具怎么用”。
2.2 skills 的底层结构:一个 skill 里到底有什么
我拆过好几个不同平台的 skill 定义文件,虽然格式略有差异,但核心结构基本一致。一个完整的 skill 通常包含这几个部分:
- 触发条件:什么情况下 AI 应该考虑使用这个 skill。可以是一组关键词、一类任务描述、或者特定的文件类型。
- 执行步骤:具体要做什么,分几步,每步的输入输出是什么。
- 工具依赖:这个 skill 需要调用哪些外部工具或命令。比如 shell 命令、API 调用、文件操作。
- 参数定义:skill 执行时需要哪些输入参数,每个参数的类型、是否必填、默认值。
- 输出规范:执行完之后返回什么格式的结果,是纯文本、结构化数据、还是文件变更。
- 约束条件:什么情况下不应该使用这个 skill,或者执行过程中有哪些禁忌。
我用一个实际例子来说明。之前我写过一个codex-project-initskill,用来快速初始化一个新项目。它的结构大概是这样的:
name: codex-project-init description: 初始化一个新的代码项目,包含目录结构、依赖配置和基础模板 triggers: - "新建项目" - "初始化项目" - "create new project" steps: - action: detect_project_type description: 根据用户描述判断项目类型(前端/后端/全栈) - action: create_directory_structure description: 按项目类型创建标准目录结构 - action: generate_config_files description: 生成 package.json、tsconfig.json 等配置文件 - action: install_dependencies description: 安装基础依赖 constraints: - 目标目录必须为空或不存在 - 需要用户确认项目类型这个 skill 写完之后,我在 Claude Code 里直接说“帮我新建一个 TypeScript 前端项目”,它就会自动走这套流程。不需要我记住任何命令,也不需要手动创建目录。
2.3 为什么 skills 突然火了:三个关键推手
skills 这个概念其实不新,但最近集中爆发,我觉得有三个原因。
第一,AI 编程助手从“能写代码”进入“能干活”阶段。早期大家用 AI 写代码,主要是让它生成代码片段,然后自己复制粘贴。现在大家期望的是:AI 直接在你的项目里改文件、跑命令、提交代码。这就要求 AI 必须理解你的项目规范、知道你的工具链、遵循你的工作流程。skills 就是把这些“隐性知识”显性化的载体。
第二,多 agent 协作成为常态。现在一个稍微复杂点的任务,往往需要多个 agent 配合。比如一个 agent 负责写代码,一个负责测试,一个负责部署。每个 agent 需要不同的能力集。skills 让能力定义和 agent 解耦,你可以给不同 agent 挂载不同的 skill 组合,灵活度很高。
第三,社区生态开始形成。我注意到最近出现了find skills、skills推荐、skills官方市场这类搜索词,说明大家不再满足于自己写 skill,而是希望找到别人写好的、经过验证的 skill 直接复用。这跟当年 npm 生态起来的时候很像——先有人写包,然后有人找包,最后形成市场。
3. 动手写第一个 skill:从需求到可运行
3.1 先想清楚:什么样的任务值得做成 skill
不是所有事情都值得写成 skill。我刚开始的时候热情很高,恨不得把每个操作都做成 skill,结果写了一堆没人用、自己也记不住的“僵尸 skill”。后来总结出一个判断标准:如果一个任务你每周至少重复三次,而且每次的流程基本固定,那就值得做成 skill。
具体来说,符合这几个特征的任务适合做成 skill:
- 流程固定:步骤明确,不需要每次临时决策。比如“新建组件文件并注册路由”这种。
- 容易出错:手动做的时候经常漏步骤、写错配置。比如“配置 TypeScript 路径别名”这种。
- 依赖上下文:需要读取项目里的其他文件才能正确执行。比如“根据现有 API 定义生成前端请求函数”这种。
- 有明确规范:团队里有统一的代码风格、目录结构、命名规则。比如“按团队规范创建新的 service 文件”这种。
反过来,那些一次性的、需要大量人工判断的、或者流程经常变的任务,就不适合做成 skill。硬做的话,维护成本比收益还高。
3.2 写 skill 的实操步骤:以“前端组件生成”为例
我拿一个实际写过的 skill 来演示完整流程。需求是:在 React 项目里新建一个组件,自动创建组件文件、样式文件、测试文件,并在 index 文件里导出。
第一步:定义触发条件。我希望 AI 在用户说“新建组件”“创建组件”“add component”这类话时触发这个 skill。同时限定只在 React 项目里生效,通过检测package.json里是否有react依赖来判断。
第二步:拆解执行步骤。这个任务可以拆成五步:
- 确认组件名称和存放路径
- 创建组件目录
- 生成组件文件(
.tsx) - 生成样式文件(
.module.css) - 生成测试文件(
.test.tsx) - 更新 index 导出文件
第三步:定义参数。需要两个参数:组件名称(必填)、存放路径(可选,默认src/components)。
第四步:写约束条件。比如:组件名称必须是大驼峰格式、目标目录不能已存在同名组件、如果项目用的是 JavaScript 而不是 TypeScript 则生成.jsx文件。
第五步:写具体的执行逻辑。这部分是 skill 的核心。我用的是类似这样的结构:
## 执行步骤 1. 读取 package.json,确认项目使用 React 和 TypeScript 2. 检查 src/components 目录下是否已存在同名组件 3. 创建组件目录:src/components/{ComponentName} 4. 生成 {ComponentName}.tsx,内容包含基础函数组件模板 5. 生成 {ComponentName}.module.css,内容为空样式文件 6. 生成 {ComponentName}.test.tsx,内容包含基础渲染测试 7. 更新 src/components/index.ts,添加导出语句第六步:测试和迭代。写完不代表能用。我一般会拿三到五个不同的组件名测试,看生成的文件是否正确、导出语句格式是否一致、边界情况(比如组件名已存在)是否处理了。
3.3 写 skill 时最容易踩的三个坑
坑一:步骤写得太粗。我第一版 skill 里写的是“生成组件文件”,结果 AI 每次生成的模板都不一样。后来改成“生成包含以下内容的 .tsx 文件:import React、函数组件定义、Props 接口、默认导出”,输出就稳定了。skill 里的每一步都要具体到 AI 不需要做任何猜测的程度。
坑二:忘了处理异常情况。比如目标目录已存在、组件名不符合规范、项目不是 React 项目。这些情况如果不处理,AI 可能会做出奇怪的操作。我的做法是在 skill 里显式写出“如果 X 则 Y”的分支逻辑。
坑三:参数没有默认值。如果每个参数都要求用户提供,用起来会很累。能设默认值的就设默认值,比如存放路径默认src/components,样式方案默认 CSS Modules。用户不指定就用默认的,指定了就覆盖。
注意:skill 写完之后一定要在真实项目里跑几遍。我见过太多 skill 在测试环境没问题,一到真实项目就因为目录结构不同、配置文件差异而失败。
4. 安装与配置:不同平台的 skills 接入方式
4.1 Claude Code 的 skills 安装与使用
Claude Code 是我用得最多的环境,它的 skills 机制相对成熟。安装方式分两种:手动放置和通过市场安装。
手动放置的话,skill 文件一般放在项目的.claude/skills目录下,或者用户级的~/.claude/skills目录下。项目级的 skill 只对当前项目生效,用户级的对所有项目生效。我一般把通用性强的 skill 放用户级,项目特有的放项目级。
配置的时候需要注意几个点:
- skill 文件的命名要规范,建议用
kebab-case,比如frontend-component-gen.md - 文件头部要有明确的元信息,包括名称、描述、触发条件
- 如果 skill 依赖外部命令,要确保这些命令在 PATH 里可用
我实测下来,Claude Code 对 skill 的识别挺智能的。你不需要显式调用,只要描述的任务匹配触发条件,它就会自动加载对应的 skill。但有个前提:skill 的描述要写清楚。如果描述太模糊,AI 可能识别不到。
4.2 Codex 的 plugin 与 skills 配置
Codex 这边的概念稍微不同,它更多用 plugin 这个词。但底层逻辑是一样的:定义能力、注册能力、按需调用。
Codex 的配置一般通过配置文件来管理。我用的方式是在项目根目录放一个codex.config.json,里面定义 plugin 列表和各自的参数。比如:
{ "plugins": [ { "name": "project-init", "path": "./skills/project-init.md", "enabled": true }, { "name": "component-gen", "path": "./skills/component-gen.md", "enabled": true, "config": { "styleFormat": "css-modules", "testFramework": "vitest" } } ] }这种配置方式的好处是灵活。你可以给同一个 skill 在不同项目里配不同的参数。比如组件生成 skill,在 A 项目里用 CSS Modules,在 B 项目里用 Tailwind,只需要改配置就行,不用改 skill 本身。
Codex 安装过程中我遇到过几个问题。一个是codex无法加载组织设置,这个通常是因为配置文件路径不对或者权限问题。另一个是cc switch local proxy failed while handling codex endpoint,这个一般是本地服务端口冲突,换个端口就好。
4.3 跨平台使用的注意事项
如果你同时在用 Claude Code、Codex、Cursor 等多个工具,skill 的跨平台复用是个现实问题。不同平台的 skill 格式有差异,不能直接复制粘贴。
我的做法是:把 skill 的核心逻辑和平台相关的配置分开。核心逻辑用通用的 Markdown 写,平台相关的部分(比如触发条件的写法、参数定义的格式)单独维护。这样迁移的时候只需要改平台相关的那一层。
另外,不同平台对 skill 的执行环境要求也不同。有的平台 skill 运行在沙箱里,有的直接在你的 shell 里跑。这直接影响 skill 能做什么、不能做什么。比如需要访问本地文件系统的 skill,在沙箱环境里可能就跑不了。
| 平台 | skill 存放位置 | 触发方式 | 执行环境 |
|---|---|---|---|
| Claude Code | .claude/skills/或~/.claude/skills/ | 自动匹配触发条件 | 本地 shell |
| Codex | 项目配置指定路径 | 配置文件注册 | 本地 shell |
| Cursor | .cursor/skills/ | 自动匹配 + 手动调用 | 沙箱 + 本地 |
提示:跨平台使用 skill 时,建议先在单个平台验证通过,再迁移到其他平台。直接迁移很容易因为格式差异导致 skill 不生效。
5. 常见问题与排查技巧实录
5.1 skill 不触发怎么办
这是最常见的问题。你写了一个 skill,描述任务的时候 AI 却不用它。排查思路是这样的:
先检查触发条件是否匹配。很多 skill 不触发是因为触发词写得太窄。比如你只写了“新建组件”,但用户说的是“创建一个 React 组件”,那就匹配不上。我的经验是触发条件要写宽一点,把常见的同义表达都列上。
再检查 skill 是否被正确加载。不同平台加载 skill 的机制不同。有的需要重启会话,有的需要显式刷新。我一般会在 skill 里加一个简单的测试触发词,比如test-skill-xxx,用来验证 skill 是否被加载。
最后检查优先级冲突。如果你有多个 skill 的触发条件重叠,AI 可能选了另一个。这时候需要调整触发条件的特异性,让每个 skill 的适用范围更明确。
5.2 skill 执行结果不稳定怎么处理
同一个 skill,有时候执行结果对,有时候不对。这种问题最让人头疼。我总结下来,原因通常有三个:
一是步骤描述有歧义。AI 对步骤的理解每次可能略有不同。解决办法是把步骤写得足够具体,具体到“打开哪个文件、修改哪一行、改成什么内容”这种程度。
二是依赖的外部状态不一致。比如 skill 依赖某个命令的输出,但那个命令在不同环境下输出格式不同。解决办法是在 skill 里加一个“环境检查”步骤,先确认环境符合预期再执行。
三是参数没有校验。用户传了一个奇怪的参数值,skill 没有处理就直接用了。解决办法是在 skill 开头加参数校验逻辑,不符合规范的直接报错退出。
5.3 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方式 |
|---|---|---|---|
| skill 完全不触发 | 触发条件不匹配 | 检查触发词是否覆盖用户表达 | 放宽触发条件,增加同义词 |
| skill 触发但执行失败 | 依赖命令不存在 | 手动执行 skill 里的命令 | 安装缺失依赖或改用替代命令 |
| 执行结果每次不同 | 步骤描述有歧义 | 对比多次执行的中间输出 | 细化步骤描述,减少自由度 |
| skill 加载报错 | 文件格式错误 | 检查 skill 文件语法 | 按平台规范修正格式 |
| 多个 skill 冲突 | 触发条件重叠 | 查看哪个 skill 被实际调用 | 调整触发条件特异性 |
| 参数传递失败 | 参数定义不清晰 | 检查参数名和类型 | 补充参数说明和默认值 |
5.4 我踩过的几个“文档里不会写”的坑
坑一:skill 文件编码问题。有一次我写了一个包含中文注释的 skill,在某个平台上死活加载不了。后来发现是文件编码不是 UTF-8。改成 UTF-8 之后就好了。这个坑很隐蔽,因为文件在编辑器里看起来完全正常。
坑二:skill 里的路径用了绝对路径。我在本地测试的时候用了绝对路径,跑得好好的。换到同事机器上就挂了。后来全部改成相对路径,问题解决。skill 里永远不要写绝对路径,这是铁律。
坑三:skill 依赖了特定版本的命令。我写过一个 skill 依赖某个 CLI 工具的特定参数,结果那个工具升级后参数变了,skill 就失效了。后来我在 skill 里加了版本检查,版本不对就提示用户。
坑四:忘了处理空目录情况。有个 skill 需要读取目录下的文件列表,但如果目录是空的,skill 就卡住了。后来加了空目录判断,返回一个友好的提示信息。
6. 进阶玩法:让 skills 真正融入日常工作流
6.1 skill 组合:把多个 skill 串成流水线
单个 skill 解决单个问题,但实际工作中往往需要多个 skill 配合。比如“新建一个功能模块”这个任务,可能涉及:创建目录结构、生成组件文件、生成 API 请求函数、生成测试文件、更新路由配置。每个步骤都可以是一个独立的 skill。
我的做法是定义一个“组合 skill”,它不直接执行具体操作,而是按顺序调用其他 skill。这样既保持了每个 skill 的独立性,又能完成复杂任务。
组合 skill 的关键是定义好 skill 之间的输入输出契约。比如组件生成 skill 输出组件文件路径,API 生成 skill 需要这个路径作为输入。把这个契约写清楚,组合起来就很顺畅。
6.2 skill 的版本管理与团队协作
当团队里多个人都在写 skill 的时候,版本管理就很重要了。我的做法是:
- 每个 skill 文件头部加版本号和修改记录
- 用 Git 管理 skill 目录,跟代码一起提交
- 重要的 skill 加变更审查,避免有人改坏了影响所有人
- 定期清理不再使用的 skill,保持目录干净
团队协作还有一个问题:不同人的 skill 风格不一致。有的人喜欢把步骤写得很细,有的人喜欢写得很粗。我的建议是团队内部定一个 skill 编写规范,至少统一文件结构、命名规则、参数定义方式这几个关键点。
6.3 从“自己写”到“找现成的”:skill 市场使用心得
最近find skills、skills推荐、skills官方市场这类需求明显增多,说明大家开始意识到:不是每个 skill 都需要自己从零写。社区里已经有很多经过验证的 skill,直接拿来用效率更高。
我用社区 skill 的经验是:先看描述,再看步骤,最后看约束条件。描述决定它能不能解决你的问题,步骤决定它靠不靠谱,约束条件决定它会不会在你环境里出问题。三个都符合预期,再拿来用。
另外,社区 skill 不要直接复制到项目里就用。我一般会先在一个测试项目里跑一遍,确认没问题再放到正式项目。因为社区 skill 的作者环境跟你的环境很可能不一样,直接用的风险不小。
提示:使用社区 skill 时,注意检查它依赖的外部命令和工具是否在你的环境里可用。很多 skill 失效都是因为依赖缺失。
6.4 skill 的调试技巧:怎么快速定位问题
调试 skill 跟调试代码思路类似,但有一些特殊技巧。
第一,加日志输出。在 skill 的关键步骤里加日志,记录每一步的输入输出。这样出问题的时候能快速定位是哪一步不对。
第二,分步执行。如果 skill 执行失败,不要一次性跑完。把 skill 拆成几个部分,逐个执行,看哪部分出问题。
第三,对比执行。同一个 skill 跑两次,对比中间输出。如果某一步的输出不一致,说明那一步的描述有歧义。
第四,最小化复现。把 skill 简化到最小可运行版本,去掉所有非必要步骤,看问题是否还存在。如果不存在了,再逐步加回步骤,定位到具体是哪一步引入的问题。
7. 我对 skills 这套机制的个人体会
折腾了这么久,我最大的感受是:skills 的价值不在于“让 AI 多会一个功能”,而在于“把人的经验固化下来”。你写一个 skill,本质上是在告诉 AI:“这件事我以前是这么做的,你以后也这么做。”这个过程本身就是在做知识沉淀。
我刚开始写 skill 的时候,总想着写“大而全”的,一个 skill 解决所有问题。后来发现,小而专的 skill 才好用。一个 skill 只做一件事,做精做透,比一个什么都想做的 skill 强得多。
另外,skill 不是写完就完了。项目在变、工具在变、需求在变,skill 也需要持续维护。我现在的习惯是每个月花半小时过一遍自己写的 skill,看看有没有过时的、有没有需要补充的。这个投入很值得,能避免很多“skill 突然不好用了”的尴尬。
最后分享一个小技巧:写 skill 的时候,把自己当成在给一个新同事写操作手册。新同事不了解你的项目、不知道你的习惯、不会做任何猜测。你写的每一步都要让他能照着做出来。按这个标准写出来的 skill,AI 用起来基本不会出问题。