1. 从"skills"这个模糊词说起:它到底指什么
第一次看到"skills"这个标题,很多人会懵。它太泛了,泛到像是一个占位符。但结合热搜词里反复出现的 Claude Code、Codex、agents、plugin 这些词,方向其实很明确——这里说的 skills,指的是 AI 编程助手生态里的技能扩展机制,也就是给 Claude Code、Codex 这类命令行 AI 代理挂载可复用的能力模块。
我最早接触这个概念是在折腾 Claude Code 的时候。当时我的理解很朴素:不就是给 AI 加几个自定义命令吗?后来用久了才发现,skills 的设计思路和传统的插件、prompt 模板完全不是一回事。它更像是给 AI 代理装了一套"操作手册加工具箱",让它在特定场景下知道该调用什么、按什么顺序调、输出成什么格式。
为什么这个概念值得单独拿出来讲?因为大多数人用 Claude Code 或 Codex,停留在"对话式写代码"的阶段——你问它答,它给你一段代码你复制粘贴。但 skills 把这个交互模式改了:你定义好一个技能,AI 在遇到匹配场景时自动触发,按预设流程执行,产出结构化结果。这中间的差别,类似于"每次手动敲命令"和"写好脚本一键执行"。
热搜词里还有几个信号值得注意:claude agent skills: a first principles deep dive、agent skills测试、skills开发、codex skills。这说明已经有一批人在认真研究 skills 的底层机制,而不只是停留在"怎么安装"的层面。我写这篇东西,就是想把这几个月的实操经验、踩过的坑、以及一些别人不太会讲的细节整理出来,给正在摸索这条路的人一个参考。
适合谁看?如果你已经在用 Claude Code 或 Codex,想从"能用"进阶到"好用",这篇对你有用。如果你还没装过,也没关系,我会从环境准备讲起,但重点会放在 skills 的设计逻辑和实战技巧上,而不是保姆级安装教程——那种内容网上已经很多了。
2. skills 的运行机制:为什么它不是简单的插件
2.1 从一次误触发说起
有一次我给项目配了一个"自动生成单元测试"的 skill,结果在改一个纯配置文件的时候它也被触发了,生成了十几行毫无意义的测试代码。当时我以为是配置写错了,排查了半天才发现问题出在触发条件的粒度上。
这个经历让我意识到,skills 的核心不是"功能",而是"触发逻辑加执行逻辑"的组合。传统插件是你主动调用它才工作,skills 是 AI 根据上下文判断该不该用。这个判断过程依赖的是 skill 的描述信息、触发关键词、以及当前对话的上下文语义。理解这一点,后面所有的设计决策就都说得通了。
2.2 skills 的三层结构
我把一个完整的 skill 拆成三层来看:
| 层级 | 作用 | 常见问题 |
|---|---|---|
| 元信息层 | 名称、描述、触发条件 | 描述太模糊导致误触发或漏触发 |
| 指令层 | 告诉 AI 做什么、按什么步骤 | 步骤太笼统,AI 自由发挥跑偏 |
| 资源层 | 附带的脚本、模板、参考文件 | 路径写死,换环境就失效 |
元信息层是最容易被忽视的。很多人写 skill 的时候,描述就写一句"用于处理数据",结果 AI 根本不知道什么时候该用它。我现在的习惯是,描述里必须包含场景词、动作词、排除词三类信息。比如"当用户要求生成 API 文档时使用,不适用于前端组件文档"——这样 AI 的判断准确率会高很多。
指令层的关键是步骤要具体到可执行。我见过有人写"分析代码质量并给出建议",这种指令 AI 只能泛泛而谈。改成"第一步检查是否有未处理的异常,第二步检查函数长度是否超过 50 行,第三步按严重程度排序输出"——效果完全不一样。
资源层最典型的坑就是路径问题。我早期写的 skill 里引用了绝对路径,换台机器就报错。后来统一改成相对路径,并且在 skill 开头加一段"先确认当前工作目录"的指令,稳定多了。
2.3 和 prompt 模板的本质区别
有人会问:这不就是高级一点的 prompt 模板吗?我的理解是,区别在于状态管理和工具调用。
prompt 模板是无状态的,你每次都要把上下文重新喂进去。skills 可以携带自己的资源文件、可以调用外部脚本、可以在多轮对话中保持自己的执行状态。举个例子,一个"代码审查"的 skill 可以在第一轮读取文件,第二轮调用 lint 工具,第三轮汇总结果——这个流程是 skill 自己维护的,不需要你每轮都提醒它。
这也是为什么热搜里会出现claude agent skills: a first principles deep dive这种词——真正用好 skills 的人,都在研究它的状态机模型和工具调用协议,而不是停留在写 prompt 的层面。
3. 环境准备:安装 Claude Code 和 Codex 时最容易忽略的细节
3.1 安装本身不难,难的是环境隔离
claude code安装、codex安装教程、codex安装 csdn这些词搜索量很高,说明大量人卡在安装这一步。但根据我的观察,真正的问题往往不是安装命令本身,而是环境隔离没做好。
我建议的做法是:给 AI 编程工具单独建一个工作目录,不要和日常开发的项目混在一起。原因有两个。第一,skills 的配置文件、缓存、日志都会堆在工具目录下,混在一起时间长了很难清理。第二,不同项目对 AI 工具的行为要求不一样,隔离之后可以给每个项目配独立的 skill 集合,互不干扰。
具体操作上,我会在用户目录下建一个ai-workspace文件夹,里面按项目分子目录,每个子目录里放该项目的 skill 配置。这样切换项目的时候,AI 工具加载的 skill 集合是干净的。
3.2 Node 版本和包管理器的选择
Claude Code 和 Codex 都依赖 Node 环境。我踩过的坑是:系统里装了多个 Node 版本,全局安装的工具用了 A 版本,项目里用的是 B 版本,结果 skill 里调用的脚本行为不一致。
解决方案是用版本管理工具锁定一个版本,并且在 skill 的文档里注明依赖的 Node 版本范围。我现在统一用 LTS 版本,并且在 skill 的元信息里加一行requires: node >= 18,这样换环境的时候一眼就能看出问题。
包管理器方面,npm、pnpm、yarn 都能用,但如果你要在 skill 里调用安装命令,建议统一成一种。我遇到过 skill 里写的是npm install,但项目用的是 pnpm,结果装出来的依赖树和预期不符,排查了很久。
3.3 配置文件的位置和优先级
这是最容易出问题的地方。Claude Code 和 Codex 都会读取多个位置的配置:全局配置、项目配置、用户配置。优先级搞错了,skill 不生效或者被覆盖,你会以为是 skill 写错了。
我的经验是:全局配置只放通用的、和项目无关的 skill,项目配置放该项目专属的 skill。如果同一个 skill 在两个地方都定义了,项目配置优先。这个规则听起来简单,但实际排查问题的时候,很多人会忘记检查全局配置里是不是有个同名的旧版本。
提示:改完配置后,一定要重启工具或者执行一次重载命令。我至少有三次以为是 skill 写错了,折腾半天才发现是配置没重新加载。
4. 写一个能用的 skill:从需求拆解到落地
4.1 先想清楚"什么时候不该触发"
大多数人写 skill 的第一反应是"我要让它做什么"。我的建议反过来:先想清楚什么情况下不该触发。
拿一个"自动生成 commit message"的 skill 举例。你希望它在git diff有变更的时候触发,但你不希望它在以下情况触发:变更只涉及格式化、变更涉及敏感配置文件、当前分支是主分支。把这些排除条件写进 skill 的描述里,比事后调参有效得多。
我现在的模板是这样的:
name: generate-commit-message description: 当用户要求生成提交信息时使用。不适用于:仅格式化变更、涉及 .env 或密钥文件的变更、主分支上的提交。 trigger: - 用户明确要求生成 commit message - git diff 有实质性代码变更 exclude: - 变更仅涉及空格或换行 - 变更文件匹配 *.env, *.key, secrets.*这个结构看起来啰嗦,但它把"该不该用"的判断逻辑显式化了,AI 执行起来准确率高很多。
4.2 指令要写成"可验证的步骤"
什么叫可验证?就是每一步都有明确的输入和输出,AI 执行完能自己判断对不对。
反面例子:"检查代码是否有问题。"——AI 不知道什么叫"问题",只能泛泛而谈。
正面例子:"第一步,读取目标文件,统计函数数量。第二步,对每个函数检查是否超过 50 行。第三步,输出超过 50 行的函数名和行数,格式为函数名: 行数。"
正面例子里,每一步都有明确的动作和产出,AI 执行完能对照检查。如果第三步的输出格式不对,你一眼就能看出是哪一步出了问题。
4.3 资源文件的组织方式
skill 目录下通常会有这几类文件:
SKILL.md:主指令文件scripts/:可执行脚本templates/:输出模板references/:参考资料
我的组织习惯是,脚本按功能命名,模板按输出类型命名,参考资料按来源命名。比如scripts/check-length.js、templates/report.md、references/style-guide.md。这样过几个月回来看,还能快速找到需要的文件。
一个容易忽略的点是:脚本要有独立的测试入口。我写过一个 skill,脚本在 AI 调用的时候正常,但我手动执行就报错,因为脚本依赖了 AI 传入的环境变量。后来我养成了习惯,每个脚本都加一个if (require.main === module)的测试入口,手动跑一遍确认没问题再挂到 skill 上。
5. 调试 skills 的完整排查链路
5.1 症状:skill 不触发
这是最常见的问题。排查顺序我总结成四步:
- 确认配置加载了没有。执行工具的重载命令,看日志里有没有加载该 skill 的记录。
- 确认触发条件匹配了没有。把当前对话的上下文和 skill 的 trigger 条件逐条对照,看是不是某个 exclude 条件被命中了。
- 确认描述信息够不够具体。如果描述太泛,AI 可能判断"这个场景不需要用 skill"。
- 确认有没有同名 skill 冲突。全局配置和项目配置里如果有同名 skill,可能加载了错误的那个。
我遇到过一次,排查了两小时,最后发现是全局配置里有个半年前写的同名 skill,描述更宽泛,把新的覆盖了。删掉旧的就好了。
5.2 症状:skill 触发了但执行结果不对
这种问题通常出在指令层。排查方法是把 skill 的指令拆成单步,手动执行一遍。
比如一个 skill 有三步,你就手动执行第一步,看输出对不对;再执行第二步,看输出对不对。哪一步不对,问题就在哪一步。这个方法听起来笨,但比盯着指令文件猜有效得多。
另一个常见原因是资源文件路径不对。skill 里引用的脚本或模板,路径是相对于 skill 目录还是相对于工作目录,不同工具的行为可能不一样。我的做法是统一用相对于 skill 目录的路径,并且在指令开头加一句"先切换到 skill 所在目录"。
5.3 症状:skill 执行到一半中断
这种问题最头疼,因为往往没有明确的报错。我的经验是,八成是超时或者资源限制。
skill 里如果有耗时的操作(比如遍历大目录、调用外部 API),可能会触发工具的超时机制。解决方案是把耗时操作拆成多个小步骤,每步之间让 AI 输出一次进度,这样既避免了超时,也方便定位问题。
还有一种可能是脚本抛了异常但被吞掉了。我现在的习惯是,脚本里所有try-catch都要把错误信息输出到 stderr,这样即使 AI 不显示,我也能从日志里看到。
5.4 一个真实的排查案例
上个月我写了一个"自动生成 API 测试用例"的 skill,测试的时候发现它有时候生成 3 个用例,有时候生成 8 个,数量不稳定。
排查过程是这样的:先看 skill 指令,发现写的是"根据接口复杂度生成适量用例"——问题就在"适量"这个词上,AI 每次理解不一样。改成"每个接口至少生成 3 个用例:正常路径、边界值、异常输入"之后,数量就稳定了。
这个案例的教训是:指令里不要出现模糊的形容词。"适量"、"合理"、"适当"这些词,对人来说有共识,对 AI 来说就是随机数。
6. skills 开发中的经验与避坑
6.1 不要试图用一个 skill 解决所有问题
我早期有个坏习惯,喜欢写"大而全"的 skill,一个 skill 里塞了十几个功能。结果就是触发条件很难写清楚,AI 经常在不该用的时候用,该用的时候又判断不出来。
后来我改成"一个 skill 只做一件事",比如"生成 commit message"和"审查 commit message"分成两个 skill。虽然文件多了,但每个 skill 的触发条件都很清晰,维护起来也容易。
6.2 版本管理要跟上
skills 是会迭代的。我现在的做法是,每个 skill 目录下放一个CHANGELOG.md,记录每次改了什么、为什么改。这个习惯帮我省了很多事——有一次一个 skill 突然不工作了,我翻 changelog 发现是三天前改了一个触发条件,改回去就好了。
如果团队协作,建议把 skills 目录纳入 git 管理。这样谁改了什么、什么时候改的,一目了然。
6.3 测试要覆盖"边界场景"
agent skills测试这个词说明已经有人在做系统化测试了。我的测试清单包括:
- 正常场景:skill 该触发的时候触发了吗
- 排除场景:skill 不该触发的时候触发了吗
- 异常输入:输入为空、输入超长、输入包含特殊字符时会怎样
- 并发场景:多个 skill 同时匹配时会怎样
最后一项特别容易被忽略。我有一次配了两个 skill,触发条件有重叠,结果 AI 同时执行了两个,输出混在一起。后来在描述里加了优先级标记才解决。
6.4 文档是给未来的自己看的
写 skill 的时候,你觉得自己的设计思路很清晰,三个月后回来看,大概率会懵。所以文档要写清楚三件事:这个 skill 解决什么问题、为什么这么设计、有哪些已知限制。
我现在每个 skill 的SKILL.md开头都有一段"设计说明",用大白话写清楚上面三件事。虽然写的时候觉得多余,但每次回头改 skill 的时候都觉得值。
7. 几个值得参考的 skill 方向
7.1 代码审查类
这是最实用的方向之一。一个设计良好的代码审查 skill,可以在提交前自动检查命名规范、函数长度、异常处理、注释覆盖率等。关键是把检查项拆细,每项有明确的通过标准。
7.2 文档生成类
根据代码自动生成 API 文档、README、变更日志。这类 skill 的难点在于输出格式的稳定性,建议用模板文件约束输出结构。
7.3 环境检查类
在开始开发前检查环境依赖是否齐全、版本是否匹配。这类 skill 特别适合团队协作场景,新人入职跑一遍就能发现环境问题。
7.4 数据处理类
处理日志、清洗数据、生成报表。这类 skill 要注意的是输入数据的格式多样性,建议在指令里先做格式检测,再走对应的处理分支。
8. 关于 skills 生态的一些个人观察
用了一段时间之后,我最大的感受是:skills 的价值不在于"让 AI 多做事",而在于"让 AI 做事的方式可预期"。
没有 skills 的时候,你每次都要重新描述需求,AI 每次的理解都可能不一样。有了 skills,你把最佳实践固化下来,AI 每次执行都走同一条路径。这个从"随机"到"确定"的转变,才是 skills 真正解决的问题。
热搜里还有superpower skills、find skills、skills推荐这些词,说明社区里已经有人在整理和分享 skill 集合了。我的建议是,先别急着装一堆别人的 skill,而是从自己最常重复的操作开始,写两三个自己用的 skill。用顺了,再去看别人的怎么写的,取长补短。
另外,codex接入deepseek、claude code 调用lmstudio的本地模型这类词也值得关注。skills 的机制和底层用哪个模型关系不大,但不同模型对指令的理解能力有差异。同一个 skill,在能力强的模型上可能一步到位,在能力弱的模型上可能需要拆得更细。这一点在选型和调试的时候要有心理预期。
最后说一个我自己的习惯:每次写完一个 skill,我会故意用模糊的、不完整的指令去触发它,看它能不能正确理解。如果能,说明这个 skill 的鲁棒性够了;如果不能,说明描述或指令还需要打磨。这个方法帮我提前发现了很多问题,比等到实际使用的时候再排查要省事得多。