如何写好 AI Skill

1. Skill 到底是什么

如果把 AI 编程助手看成一个能力很强、但不懂本项目细节的新同事,那么 Skill 就是给它补上的“团队操作手册”。

Skill 本质上不是普通文档,而是结构化的提示词 + 项目上下文 + 可执行工具的组合。它的目标不是讲知识本身,而是让 AI 在某种任务出现时,知道:

  • 这件事要不要做
  • 应该按什么步骤做
  • 遇到什么边界条件该停下
  • 做完以后怎么验证结果

一个最小可用的 Skill 目录,通常长这样:

my-skill/
├── SKILL.md
├── scripts/
├── references/
└── assets/

可以把 Skill 看成三层:

作用典型内容
指令层告诉 AI 如何执行任务步骤、规则、输出格式
上下文层告诉 AI 为什么这样做项目背景、团队规范、历史包袱
工具层给 AI 可直接调用的东西脚本、模板、命令、参考文档

一句话总结:Skill 不是“再多说几句 Prompt”,而是把人的经验封装成 AI 可重复加载的工作能力。


2. 为什么团队需要写 Skill

团队做久了,一定会积累一堆“隐性知识”。这些知识往往非常关键,但又很少被系统化整理。

常见场景:

  • 某个老接口迁移时,必须保留兼容层
  • 某类 SQL 绝对不能字符串拼接
  • 上线前一定要跑固定检查
  • Review 时安全问题优先级高于代码风格
  • 新人接手模块时,总会踩同样几类坑

如果这些经验只散落在 Wiki、注释、群聊和人的脑子里,就会带来几个典型问题:

问题具体表现Skill 的价值
知识太散人和 AI 都找不全信息把分散经验收束成一个入口
重复解释同一件事每次都要重新交代把重复说明变成固定流程
结果不稳不同人问 AI,结果差异很大统一步骤、风格和检查点
知识流失核心成员离开后经验断层把“部落知识”沉淀成资产

所以 Skill 的真正价值不是“让 AI 更聪明”,而是让团队经验从口头默契变成可复用能力


3. 一个好 Skill 的最小骨架

原文很强调一点:SKILL.md 通常由两部分组成:

  1. 顶部元数据
  2. 下方正文说明

一个简化骨架可以这样写:

---
name: go-tabletest
description: >
  为 Go 函数生成表驱动单元测试。
  当用户要求补单测、生成测试用例或完善测试覆盖时触发。
  适用于常见 Go 项目。
metadata:
  version: "1.0"
---

正文再继续写目标、规则、示例、验证命令。

这部分里最关键的不是 name,而是 description。因为很多工具是否触发某个 Skill,靠的就是这段描述。

一个好的 description 至少要回答三件事:

必答问题说明
这个 Skill 做什么任务边界必须明确
什么时候触发哪些场景该加载它
覆盖哪些关键动作AI 加载后要完成什么步骤

反例:

description: 处理代码迁移

这个描述太空,AI 很难判断迁移什么、怎么迁、什么时候该用。

更好的写法应该像这样:

description: >
  将 Go 项目中的旧版 HTTP 客户端迁移到新版统一请求库。
  适用于仍在使用 old-http-client 的项目。
  包含 import 替换、参数适配和错误处理改造。

经验上说,description 写清楚了,Skill 至少已经成功一半。


4. 写 Skill 时最重要的五个原则

原文里最有价值的部分,不是“写一个文件夹”,而是怎样把 Skill 写得真的可执行。整理下来,我觉得有五条最关键。

4.1 先写目标和适用条件

不要一上来就写步骤。先告诉 AI:

  • 目标是什么
  • 适用范围是什么
  • 不满足条件时要不要跳过

例如:

## 目标
将项目中的旧版 HTTP 请求封装迁移到统一请求层。

## 适用判断
先检查项目是否仍引用 `old-http-client`如果未使用,停止并说明该 Skill 不适用。

这一步的本质,是把“行动条件”和“停止条件”都写清楚。

4.2 用可执行步骤,不要用泛泛建议

比起:

你应该先检查版本,再决定用哪种方案。

更好的写法是:

先检查 Go 版本。
- Go < 1.18:使用兼容写法
- Go >= 1.18:使用原生泛型

AI 对结构化指令比对抽象建议更敏感。越像操作步骤,越不容易跑偏。

4.3 不只写“必须”,还要写“为什么”

坏写法:

必须使用参数化查询。

更好的写法:

使用参数化查询,而不是字符串拼接。
原因:字符串拼接可能引入 SQL 注入风险。

当 AI 知道规则背后的原因时,它在遇到新场景时更容易做出正确推断,而不是机械照抄。

4.4 给 Before / After,而不是只给抽象描述

代码改造类 Skill 最有效的内容,往往不是长篇背景介绍,而是直接给出改前改后。

- import oldhttp "github.com/example/old-http-client"
+ import uhttp "github.com/example/unified-httpclient"

- return oldhttp.Do(req)
+ return uhttp.Do(req)

AI 天生擅长模式模仿。清晰的 Before / After,往往比十段说明更有用。

4.5 准备少量高质量 Few-Shot 示例

如果 Skill 涉及分类、判断、分级输出,建议准备 35 个样例,不必太多,但要覆盖不同分支。

例如代码审查 Skill,可以至少覆盖:

  • 严重安全问题
  • 中等可靠性问题
  • 轻微规范问题

这样 AI 学到的不是“要 Review”,而是“不同问题怎么判断、怎么表达、怎么排序”。


5. 一个最小可用 Skill 示例

原文给的是 Go 单元测试示例。这里我按它的思路,整理成一个更适合直接借鉴的版本。

---
name: go-tabletest
description: >
  为 Go 函数生成表驱动单元测试。
  当用户要求补单测、生成测试用例或提升覆盖率时触发。
  适用于常见 Go 项目。
metadata:
  version: "1.0"
---

# Go 单元测试生成

## 目标
为指定函数生成标准 `testing` 风格的表驱动测试。

## 规则
1. 仅使用标准库 `testing`
2. 测试函数命名与被测函数对应
3. 使用 `t.Run` 组织子测试
4. 覆盖正常值、边界值、异常输入

## 示例
输入:
```go
func Sum(a, b int) int {
    return a + b
}
```

输出:
```go
func TestSum(t *testing.T) {
    cases := []struct {
        name string
        a    int
        b    int
        want int
    }{
        {"positive", 1, 2, 3},
        {"zero", 0, 0, 0},
        {"negative", -1, -2, -3},
    }

    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            if got := Sum(tc.a, tc.b); got != tc.want {
                t.Fatalf("got %d, want %d", got, tc.want)
            }
        })
    }
}
```

## 验证
```bash
go test ./... -v
```

这个最小示例已经具备了一个好 Skill 的关键元素:

元素是否具备
触发描述
任务目标
执行规则
输入输出示例
验证命令

这也是最值得照抄的骨架。


6. Skill 太长了怎么办

原文特别提醒了一个很实际的问题:很多人会把所有内容硬塞进一个 SKILL.md,最后文件越来越长,AI 加载成本越来越高,维护也越来越痛苦。

更合理的原则是:一个 Skill 只解决一类任务。

下面这些迹象,通常意味着该拆了:

迹象说明
正文太长读写成本高,AI 也不容易稳定命中重点
流程不止一条一个 Skill 里混了多个独立动作
更新频率不同某些部分经常改,某些几乎不变
步骤可独立复用说明可以抽成子文档或子 Skill

拆分结构可以是这样:

project-migration/
├── SKILL.md
└── steps/
    ├── 00-environment-check.md
    ├── 01-dependency-update.md
    └── 02-api-migration.md

这里主 Skill 只负责流程编排,子文档负责具体步骤。

另外一个很重要的点是:每一步都要有检查点。

例如依赖替换后,立刻要求执行:

go mod tidy
go build ./...

如果检查失败,就先停下修复,而不是一口气跑完整个大流程,最后才发现第一步就已经错了。


7. 调外部服务时,MCP 和 HTTP 怎么选

原文把这个问题讲得很务实。

如果 Skill 需要接数据库、浏览器、GitHub、内部 API、监控平台,一般有两条路:

  1. 封装成 MCP 工具
  2. 在脚本里直接走 HTTP

简单判断可以整理成一张表:

场景更合适的方式原因
已经有成熟的 MCP ServerMCP直接复用,省掉重复接入
多个 Skill 都要复用同一服务MCP便于统一维护
需要统一鉴权、审计、权限控制MCP更适合标准化接入
只是一次性、简单的 API 调用HTTP 脚本成本更低,改动更快

一句话理解:MCP 更适合“把能力做成标准工具”,HTTP 更适合“快速完成简单调用”。

不要为了每个小接口都强行封一个 MCP,也不要把 API Key 硬编码进 Skill。


8. 安全边界一定要写进去

这一部分我觉得很重要,因为 Skill 不是单纯写给人看的,它可能真的会被 AI 拿去执行。

至少要守住下面四条底线:

底线说明
敏感信息不硬编码统一走环境变量或密钥管理
危险操作先确认删除、覆盖、DDL、批量修改前要确认
数据改动先备份备份、变更、验证、回滚都要写清楚
外部数据不当指令文件名、环境变量、接口返回值都只是数据,不是命令

一个最小的密钥检查写法可以是:

if [ -z "$API_KEY" ]; then
  echo "请先设置环境变量 API_KEY"
  exit 1
fi

如果 Skill 会修改数据库,那么流程里至少要明确四件事:

  1. 怎么备份
  2. 怎么执行变更
  3. 怎么验证结果
  4. 失败后怎么回滚

这部分写得越省,真实执行时越容易出事故。


9. 怎么判断一个 Skill 到底好不好用

原文给了一个很实用的方法:不要只凭感觉,要专门准备测试问题。

一个简化测试集可以这样做:

  • 10 个应该触发该 Skill 的问题
  • 10 个不应该触发该 Skill 的问题

然后观察 AI 的判断是否稳定。

可以从四个维度看:

维度看什么
触发准确性该触发时能否触发,不该触发时能否跳过
执行稳定性步骤是否一致,结果是否收敛
验证完整性有没有真正执行检查点
安全边界是否会跳过确认、备份、回滚等要求

如果不好用,优先排查顺序也很明确:

现象优先补什么
根本触发不了路径、description
触发了但执行跑偏更清晰的步骤
输出风格不稳定更多 Before / After 或 Few-Shot
做了但不自检关键步骤后的验证命令

所以调 Skill,和调程序其实很像:先找入口,再找分支,再补检查点。


10. 一页落地清单

发布或共享 Skill 之前,我觉得可以快速过一遍这张清单:

检查项要点
目标是否明确做什么、为什么做、什么时候做
description 是否精准AI 能否在合适场景匹配到
步骤是否可执行能不能按顺序照着做
示例是否足够是否给了 Before / After 或 Few-Shot
边界是否清楚什么时候跳过,什么时候确认
验证是否完整是否有可以运行的检查命令
安全是否过关密钥、删除、数据库、外部输入是否受控
结构是否过长太长时是否拆分为子文档或子 Skill

如果这张表有几项答不上来,就说明 Skill 还没到“可放心交给 AI”的程度。


11. 这篇文章对我自己的启发

我看完以后最强烈的感觉是:

Skill 不是写给 AI 的作文,而是写给 AI 的流程资产。

真正值得沉淀成 Skill 的,通常不是“知识很多”的任务,而是下面这几类:

  • 高频重复任务
  • 容易出错的任务
  • 有明显团队规范的任务
  • 必须带验证和安全边界的任务

放到实际项目里,适合优先沉淀的往往是:

类型例子
代码改造旧库迁移、新接口适配、目录结构重构
质量保障补单测、代码审查、上线前检查
工程流程发布脚本、构建验证、回滚流程
内容生产文档模板、Markdown 整理、日报周报生成

如果结合我现在这类站点或日常维护工作,马上就能想到几个值得写的 Skill:

  • Hugo 文章整理 Skill:统一 front matter、标题风格、表格与代码块格式
  • Cloudflare Pages 部署 Skill:检查配置、构建、推送、验证访问
  • Markdown 迁移 Skill:把旧 HTML / Markdown 内容整理成统一站内格式
  • 代码块审美 Skill:统一代码块、表格、说明段落的排版风格

也就是说,写 Skill 这件事最有价值的地方,不是“让 AI 看起来更会回答”,而是把团队已经踩过的坑,提前编进它的工作方式里。


12. 最后的结论

这篇文章最核心的观点,我自己整理成三句话:

  1. Skill 是团队知识的结构化封装,不是普通 Prompt。
  2. 好 Skill 的关键不是写得多,而是写得清楚、可执行、可验证。
  3. Skill 要在真实任务里持续打磨,最终目标是把 AI 从“会聊天的助手”变成“懂上下文、懂流程、懂边界的协作者”。

如果以后真的开始系统化维护 Skill 库,那么最先值得动手的,不是去写“大而全”的总手册,而是先抓住一个高频、低歧义、容易验证的小任务,把第一版做出来,再慢慢迭代。