最近“skill”这个词在 AI 编程圈里越来越高频。我自己的体感是,Claude Code、Codex、Trae 这类工具都开始把 skill 当作核心能力载体,很多人也在问一个问题:skill 不就是把一段很长很长的提示词存起来吗?为什么我堆了几千字,实际用起来还是不能打?
我前后写了小几十个 skill,从最开始“把提示词换个壳”的自嗨,到后来慢慢摸出一套能稳定复用的创建流程,中间踩过的坑比写过的 skill 还多。这篇文章就是一次完整复盘,重点聊两件事:一是标题里反复强调的“方法抽象”,也就是怎么从一次性的具体求助里,提炼出一套能脱离场景存活的通用方法;二是每次发布前我都会过的 Review 清单,这份清单在很大程度上决定了一个 skill 是“真能用”还是“看起来能用”。如果你正准备把自己的经验沉淀成 skill,或者写过几个 skill 但总觉得不稳,可以照着这套流程走一遍。
1. 先想清楚:skill 不是答案库,是可被执行的方法包
我最早写 skill 的思路非常简单:“把正确答案写进去”。比如做一个代码审查 skill,就把我能想到的 Java 代码规范全部列进去,什么命名、注释、设计模式,能写多全写多全。结果跑起来之后非常尴尬——AI 确实能记住一堆规则,但遇到真实 diff 的时候,它不知道先看什么、后看什么,也不知道什么情况下该升级为严重警告。
这个教训让我意识到一个核心区别:skill 不是“答案库”,而是“方法包”。
不要以为 skill 是给 AI 一本百科全书,真正的 skill 应该是一份可以照着执行的操作手册,里面包含触发条件、执行步骤、判断分支、输出格式,以及必要的边界约束。就像厨房里的菜谱,如果菜谱只写“盐少许、酱油适量、大火收汁”,新手做出来跟老厨师完全不同;如果菜谱写到“热锅冷油放入姜片,翻炒 10 秒后下主料,加生抽 15ml,中火煮 3 分钟再转大火收汁”,那基本上谁做都能复现个七七八八。Skill 要的是后者,是把“怎么做”这件事拆成可执行动作。
1.1 skill、prompt 和 agent,到底差在哪里
很多新手会把三样东西混为一谈:prompt、skill、agent。我先用一个表格把这几个概念放一起对比,再展开说。
| 概念 | 本质 | 生命周期 | 能否复用 | 典型形态 |
|---|---|---|---|---|
| prompt | 一次性沟通文本 | 用完即走 | 差,靠批改粘贴 | 对话框里的指令 |
| skill | 可复用的方法资产 | 长期维护、版本迭代 | 强,可被多个场景调用 | 目录 + SKILL.md + 资源文件 |
| agent | 有自主决策能力的执行体 | 持续运行、自主行动 | 看任务而定 | 感知 → 规划 → 调用工具 → 行动 |
一句话总结:prompt 是你跟 AI 说的一句话,skill 是你沉淀下来的方法包,agent 是拿着方法包去干活的执行者。一个 agent 可以挂载多个 skill,遇到不同类型的任务就调用对应的 skill。你要是把技能写成了 prompt,那么它就是一次性输入;写成真正的 skill,它就是一个可被检索、可被重复调用的独立模块。
这个概念澄清非常关键,因为后面要讲的“方法抽象”,本质上就是让你把写 prompt 时的“怎么嘱咐 AI”,升级成“怎么设计一个方法模块”。你不再需要每次对话都夹带一堆背景信息和操作规范,只需要告诉 AI“用哪个 skill”就够了。
1.2 方法抽象到底在抽什么
“方法抽象”这四个字听上去很玄,其实拆开看就三件事:
- 任务类型:这个 skill 解决哪一类问题?不是哪一次具体问题。
- 处理流程:遇到这类问题时,应该按照什么顺序执行哪些动作?
- 决策规则:流程走到分岔路口时,根据什么信号做判断?什么情况下该停下来向用户要更多信息?
举个例子。你发现最近一个月,连续有同事问你“这段 Java 接口的异常处理规范吗”“这个 PR 有没有安全问题”“前端这次改动对性能有没有影响”。这三个问题看起来风马牛不相及,但它们背后共用同一条流程:拿到变更范围 → 列出审查项 → 逐项核对 → 输出分级结论。
如果你要写一个“代码审查 skill”,正确的抽象方向不是去背 Java 规范,而是把这条公共流程提炼出来,再把具体语言、具体业务规则作为“引用参数”放进 references 目录里。这样你写出来的 skill 可以审 Java、审前端、审接口文档,因为你在抽象层面抓住的是“代码变更审查”这个任务类型,而不是“某个系统的某次改动”。
这也是判断抽象是否到位的标准:把一个具体任务里的所有名词都抽掉之后,剩下的流程还能不能指导操作?能,就是抽象完成了;不能,说明你还在写答案,而不是在写方法。
2. 三步方法抽象:从 5 次答疑到一套通用处理流程
很多朋友问我“怎么才能高效创建 skill”,我都会反问一句:你是不是已经遇到过至少三次同类问题了?如果没有,那你其实不需要写 skill,直接对话解决就行。如果有,那你的素材库已经足够了,接下来只差一套把素材提炼成方法的手段。
我形成了一套固定的三步抽象流程,每一步都有明确产出,不需要靠灵感。
2.1 第一步:建一个“候补池”,专门收集被问了三次以上的问题
我的习惯是准备一个专门的地方记录“人类经验碎片”,不一定用多复杂的工具,一个支持表格的云文档就够了。每次有人问我问题,或者我自己在代码评审里反复纠正同类错误,我都会花 30 秒登记一行:
- 原始问题是什么
- 我当时是怎么解决的
- 解决过程中踩了哪些坑
- 有哪些信息是必须前置知道的
为什么要以“三次”为门槛?一次是偶发,两次可能是巧合,三次就是规律。当同一个问题出现第三次时,就意味着它不值得你每次重复回答一遍,应该让 skill 来回答。
而且这个候补池本身就是最真实的“需求文档”。你在里面记下来的每一个“坑”,都是未来 skill 里必须写进约束条件的素材,比你自己拍脑袋想出来的边界条件可靠得多。
2.2 第二步:把答疑记录摊开,只留下动作序列
当你积累了 5 条同类答疑记录之后,把它们全部摊开,去掉人物、项目名、具体技术栈,只看你在每轮答疑中的动作,你会发现它们的骨架惊人地相似。
以代码评审为例。假设候补池里有三条记录:
- 同事 A 问:这个 Java 接口异常处理规范吗?
- 同事 B 问:新写的订单服务会不会有安全漏洞?
- 同事 C 问:这个 Vue 组件改动对性能有没有影响?
如果停留在“答案”层面,这三条是完全独立的知识点。但你把解决过程抽象成动作,抽出来的流程是一致的:
- 获取变更范围,确认到底改了哪些文件、哪些函数;
- 按变更类型匹配不同的审查点;
- 逐项检查,给每个问题打严重度标签;
- 汇总输出,按照 P0/P1/P2 分级反馈修改建议。
抽完骨架之后,你再去填肉:Java 要重点看异常是否被吞掉、NPE 风险;前端要看是否有大列表无分页、循环内发请求;接口看是否鉴权缺失、是否信任外部输入。这些具体的检查点不是方法层,是资源层,所以放进 references/checklist-java.md、checklist-frontend.md,而不是全部塞进 SKILL.md 的主流程。
这一步做完,一个通用的“代码审查 skill”其实已经成型了。后面所有语言、框架相关的差异,都只是不同配置下的参数而已。
2.3 第三步:明确边界,能力再强也不能越界
方法抽象最容易翻车的地方不是“没内容”,而是“什么都想管”。一个 skill 如果既想做代码审查,又想管需求评审,还想兼职做代码生成,那它大概率什么都做不精。
在编写任何 skill 之前,先把两个列表写出来:
- In-scope:这个 skill 在什么场景下生效。例如“只审查变更内容,不审查历史存量代码”。
- Out-of-scope:遇到什么情况应该主动拒绝或转由人工处理。例如“不替用户直接修改代码;发现敏感信息泄露时必须中断并提醒”。
边界还有一个作用:防止 AI 在信息不足时“硬答”。我在 Review 清单里专门有一条,要求 skill 必须定义“信息缺失”的处理方式——当用户没提供完整的 diff 或者没说明变更意图时,skill 的第一步不是开始审查,而是向用户索要清单里缺的信息。
这一步不会让 skill 看起来更“能干”,但会让它更“可信”。真实工程里,一个知道什么时候该停下来问人的技能,比一个永远自信满满给结论的技能可靠得多。
3. 创建 skill 的完整实操流:目录、主文件、脚本、测试
抽象做完,接下来是落地的部分。我见过很多开发者拿到了很好用的流程,但最后败在实现细节上——目录结构乱、SKILL.md 里全是空话、测试用例就一个 happy path。下面是我现在创建 skill 的固定动作,每一步都可以直接照抄。
3.1 先搭目录骨架,一个文件干一件事
我推荐的 skill 目录结构长这样:
review-skill/ ├── SKILL.md ├── references/ │ ├── checklist-java.md │ ├── checklist-security.md │ └── output-template.md ├── scripts/ │ └── parse_diff.py ├── tests/ │ ├── case-001-standard.json │ ├── case-002-boundary.json │ └── case-003-missing-info.json └── CHANGELOG.md每个部分的分工很清晰:
- SKILL.md:整个 skill 的入口,也是 AI 最先读取的文件。里面只写触发条件、主流程、决策规则和输出格式。
- references/:按需加载的参考资料。SKILL.md 主文件不需要把所有规范一次读完,AI 可以根据任务类型决定就读哪份文档,避免一次性把上下文塞满。
- scripts/:如果 skill 依赖脚本处理数据或调用工具,放这里。脚本应该保持最小化,不要做“全能处理”。
- tests/:测试用例,是 skill 迭代的地基,后面会细说。
- CHANGELOG.md:记录每个版本的改动,尤其是因为什么 bug 做了调整。
很多新手以为 skill 只要有一份 SKILL.md 就行。有当然也能跑,但当技能的知识量变大之后,单文件模式会让 AI 必须一次性读入巨大上下文,效果会断崖式下降。分离目录的最大好处是给 AI 一个“按需取用”的路径:主文件负责带路,参考资料负责补充知识,彼此互不干扰。
3.2 编写 SKILL.md:先写触发条件,再写流程,最后写约束
我写 SKILL.md 通常会按下面模板来:
--- name: code-review description: 当用户要求审查代码变更、PR、diff 或代码质量时使用。 version: 1.0.0 tags: [review, code-quality] --- ## When to Use - 用户提交了一段 diff,希望评估代码质量。 - 用户提交了 PR/MR,希望判断是否可以合并。 - 用户希望从异常处理、安全性、性能等维度审查代码。 ## Workflow 1. 读取用户提供的变更内容或 diff,确认变更范围。 2. 识别变更类型(新增功能、修复 bug、重构、配置调整)。 3. 根据类型从 references/ 中选择对应的检查清单。 4. 逐项检查,每个问题标记严重度:P0(必须修复)、P1(建议修复)、P2(可选改进)。 5. 按 references/output-template.md 输出结论。 ## Constraints - 只审查变更内容,不对存量代码开具长期改进清单。 - 如果 diff 信息不完整,先列明缺少信息,不进入审查流程。 - 不直接修改代码,只提供修改建议。 - 发现敏感信息(密钥、内网地址、个人信息)时,中断审查并提醒用户。有几条是我反复强调的:
第一,description 里必须写满触发场景,别写“这个 skill 很强大”之类的废话。AI 工具在自动匹配 skill 时,靠的就是 description 和当前任务的语义相似度,触发条件写得越具体,匹配准确率越高。
第二,Workflow 里的步骤全部用动词祈使句开头。你写“读取”“识别”“选择”“逐项检查”,AI 就知道每一步该做什么;你写“确保代码质量优秀”,AI 就只能在原地打转。
第三,Constraints 要覆盖“之前真实犯过的错”。那些让你在使用 skill 时不满意的细节,全是 Constraints 的素材来源。比如我发现 code-review skill 在信息缺失时会硬着头皮瞎审,所以专门加了一条“信息不完整先列缺失信息”的约束,效果立竿见影。
3.3 三连测:标准场景、边界场景、错误场景各一次
写完之后别急着发布,你的 skill 至少要过一次“三连测”。这是我把大量不合格 skill 挡在发布门外的关键步骤。
- 测试一(标准场景):挑一个最典型的用例,走通完整流程,确认核心输出质量达标。
- 测试二(边界场景):故意制造极端输入,比如超长的 diff、一行代码的改动、混合多种语言的改动,看 skill 会不会崩、会不会丢失关键信息。
- 测试三(错误场景):故意不提供完整信息,看 skill 是否会主动索要缺失内容,还是会乱给结论。
每跑完一个测试,我都会把实际输出存档到 tests/ 目录下,并在 CHANGELOG 里记录失败原因和修复方式。这里必须说一句大实话:一套流程在标准场景跑通只能说明“功能可用”,连边界和错误场景也稳得住,才说明“方法可靠”。
3.4 Skill 也要做版本管理
很多开发者的代码仓库做 git 管理,但 skill 目录反而是裸奔的,很多人改了之后没记录,下次想回溯只能靠记忆。Skill 本身也是一种代码资产,依赖它运行的 AI 模型也会升级,模型升级之后同一个 skill 的行为可能会变,这时候没有版本管理,连排查问题都无从下手。
我的做法是每个 skill 独立成一个 git 仓库或者独立目录,SKILL.md 头部标注版本号,CHANGELOG 记录最近三次改动背后的问题。不要小看这个动作,因为你写 skill 时做的每个决策大概率都源于一次真实的失败,这些记录就是最珍贵的经验库。
4. 写 skill 最容易翻车的五个隐蔽问题
下面这几个坑,我在审核过的很多 skill 里反复见到,有些自己也踩过。每一个都导致过实际使用体验的严重下滑,值得拿出来单独说。
4.1 把“目标”当成了“步骤”
最常见的失败模式,是在 Workflow 里写“检查代码质量”“确保安全性”“优化性能”这种话。这些是目标,不是步骤。
建议拆解成动作:检查是否有未捕获的空指针异常;检查 SQL 语句是否使用拼接;检查循环体内是否发起了外部请求;检查是否有未关闭的资源连接。只有动作可以被 AI 稳定执行,目标只会让输出质量充满随机性。
怎么判断自己写的是目标还是步骤?把这句话前头加上“执行”两个字,如果能读通,就是步骤;读不通,说明你还是给了一个目标。
4.2 上下文塞得太满,AI 反而抓不住重点
我最早写“日志异常分析” skill 时,把所有命令解释、正则写法、告警规则全部贴进 SKILL.md,结果 AI 在处理长文本时经常逻辑错乱,输出一段没头没尾的结论。后来我把主文件精简成“识别日志格式 → 统计状态码 → 按严重度聚合 → 调用参考正则解析关键行 → 输出报告”,把 90% 的细节移入 references/,效果立刻回来了。
原因是当前 AI 模型的注意力是有限的,一次读入的 token 越多,对每段内容的敏感度就会降低。SKILL.md 的作用是带路,不是装下整个世界。越厚的 skill,越需要在入口处做好指引,让 AI 知道什么时候去翻参考资料,而不是一口气全部吞进去。
4.3 环境假设不清,换个机器就废
Skill 里如果写“用 python3 执行 parse_diff.py”,必须先确认运行环境。不同的 AI 工具运行环境有差异,有的能直接执行命令,有的需要配置白名单,还有的根本没有 Python 环境。
我的经验是把环境信息写进 references/environment.md,内容包括:依赖了哪些外部命令、是否有需要安装的包、脚本的输入输出格式、禁止执行哪些危险操作。同时在 SKILL.md 里加一条“执行脚本前先确认环境变量是否存在,缺失则告诉用户”。看起来保守,实际换环境时能救回很多失效场景。
4.4 忽略不同模型之间的行为差异
同一个 skill 在 Claude 下执行得很稳,换到另一个模型上可能完全跑偏,这事我遇到过不止一次。原因是一些模型的弱项,有的模型对多级目录结构理解力不足,有的模型在长步骤任务中容易丢掉中间结果,有的对“如果/那么”分支处理不稳定。
解决方案是:尽量使用通用的 markdown 结构和简单的指令语言,不依赖某个模型独有的能力;同时在测试记录里标注“在哪个模型、哪个版本下通过验证”。你的 skill 在某个模型下验证过,不代表在别的模型下也成立,这一点写清楚是对使用者负责。
4.5 不设退出条件,永远硬着头皮给答案
我在前面提到过信息缺失时的处理,这背后其实是一个更大的问题:你的 skill 必须允许 AI 承认“我现在不能继续”。很多 skill 作者为了追求成功率,把流程设计成了一条不归路,AI 一进来就必须走到底,就算输入信息完全不够,它也会自己脑补出一堆假设来填充。
这在工程上是灾难。Skill 里一定要有显式的退出条件,例如:“当进入本流程后发现用户未提供必要条件,停止后续动作,列出缺失信息”;“当任务属于 out-of-scope 范围时,告知用户更换 skill”;“当执行脚本失败超过三次时,停止尝试并上报错误”。退出条件不是能力不足的表现,恰恰是一个成熟技能对自己边界有清晰认知的证明。
5. 附 Review 清单:发布前像审代码一样审 skill
Skill 写完了,测试也跑了,但发布前最后一道关卡是 Review。我自己以前经常跳过这一步,后来吃过发布一个不成熟 skill 的亏,从此坚持每次发布前都按清单逐项自检。
这套清单我按七个维度整理,可以打印出来,也可以在 skill 目录里存一份 markdown,作为提交模板:
| 类别 | 检查项 | 通过标准 |
|---|---|---|
| 定位与边界 | description 是否完整描述触发场景? | 用户扫一眼就知道“当前任务适不适合用这个 skill” |
| 定位与边界 | 是否有明确的 out-of-scope? | AI 遇到范围外任务会拒绝或转交,不会硬答 |
| 命名 | 名字是否直观? | 不使用堆满专业术语看不清用途的名字 |
| 命名 | 名称是否重复? | 在已有技能集中没有同名或高度相似的 skill |
| 步骤质量 | Workflow 里的步骤是否都是动词开头? | 没有“保证”“提升”“优化”这类目标型描述 |
| 步骤质量 | 关键分岔点是否有“如果/那么”分支? | 真实失败场景中的修复点已经写入流程 |
| 步骤质量 | 每个步骤是否定义了明确的产出物? | AI 知道这个步骤完成后要输出什么 |
| 资源与依赖 | references 里引用的文件是否真实存在? | 所有链接和文件路径可访问,不出现 404 |
| 资源与依赖 | 运行环境和依赖是否写清楚? | 换到另一台机器或另一个工具也能复现 |
| 资源与依赖 | scripts 脚本是否有测试过? | 至少跑通一个成功场景和一个失败场景 |
| 测试与验收 | 是否准备至少 3 个测试用例? | 标准、边界、错误三类各一个,结果已存档 |
| 测试与验收 | 是否记录实际执行输出? | 测试记录里有真实输出文本,不只是“看起来没问题” |
| 测试与验收 | 是否标注过测试模型及日期? | 以后模型升级后可回查兼容性 |
| 安全与合规 | 是否禁止了危险操作或需要确认? | 自动执行命令前有明确确认机制 |
| 安全与合规 | 是否不包含敏感信息? | 无密钥、无内部地址、无个人隐私信息 |
| 可维护性 | 是否有版本号和最近更新时间? | version、created、updated 字段齐全 |
| 可维护性 | 是否有 CHANGELOG? | 记录最近三次改动的原因和结果 |
这条清单用下来,最大的价值是倒逼你把“模糊”的东西变“具体”。比如“命名是否直观”这条,会逼你想清楚 skill 到底解决什么问题;而“是否记录实际执行输出”这条,会逼你真的去跑一遍测试,而不是看了一下文档就拍板“没问题”。
我自己的习惯是把这张 Review 清单本身也放进 skill 目录里,这样每次迭代到一半被打断,再回来时不用重新回忆当时的思路,打开清单照着过一遍就行。
最后再说一个朴素但很有用的体会:skill 写的不是结果,是流程;不是替你把某件事做完,而是让 AI 每次遇到同类问题时都能按一套可靠的方式把事情做完。所以创建 skill 的效率,不取决于你打字多快,而取决于你对自己的经验是否做过真正彻底的方法抽象。
我自己现在写 skill 有个习惯,每写完一版都要先当一次使用者,拿真实任务去跑一遍流程,而不是站在创作者视角自我欣赏。很多问题,只要你愿意切换到使用者的角度,多问一句“如果我是刚接触这个任务的 AI,我能看懂这一步吗”,就能在发布前及时拦住一大半翻车现场。
如果你也正在建自己的 skill 库,可以试试把第一个 skill 做成纯方法抽象版——不要收集任何具体业务知识进去,只保留任务类型、流程骨架和边界规则,看看它能不能跑通。跑通了,你就掌握到写 skill 的核心手感了。