Skill 编写教程
夜莺 v9 Skill 编写完整教程:从 frontmatter 字段速查、正文结构模板、辅助文件用法,到打包上传、调试方法、一个端到端实战案例(写一份《MySQL 慢查询排障 Runbook》Skill)。
这篇文档讲什么
Skill 管理 介绍了 Skill 的概念和操作流程,内置 Skill 一览 列了 19 个开箱即用的 Skill。这篇文档是实操指南:
- frontmatter 每个字段什么时候用、踩坑点在哪;
- 正文怎么结构化写,照搬内置 Skill 的成熟模板;
- 怎么用辅助文件(脚本、参考数据、子文档)让 Skill 更强大;
- 端到端写一个《MySQL 慢查询排障 Runbook》Skill,从空白到上线。
前置条件:先在 LLM 管理 里配一条默认 LLM,否则写完 Skill 也没法测试。
一、Skill 的基本形态
一个 Skill 就是一份带 YAML frontmatter 的 Markdown 文件,文件名固定为 SKILL.md。最简形态:
---
name: my-first-skill
description: 当用户问到 XXX 时使用,覆盖 YYY 场景
---
# 这里是正文
你的领域知识 / 操作指引 / 模板 / 示例……
加上辅助文件就是一个 Skill 包:
my-first-skill/
├── SKILL.md # 主文件(必须)
├── runbooks/
│ ├── disk-full.md
│ └── oom.md
└── scripts/
└── collect-context.sh
打包成 .zip 或 .tar.gz 上传即可。
二、Frontmatter 字段速查
下面这些字段都是可选的,只有 name 和 description 是必填。
核心字段
| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | 必填。Skill 的唯一标识。建议 kebab-case 英文,如 mysql-slow-query-runbook、payment-incident-sop。不能与 19 个内置 Skill 同名(同名会被内置版本盖住),但你可以故意同名来"覆盖"内置 Skill——夜莺规则是「用户 Skill 优先于内置」。 |
description |
string | 必填,最重要的一个字段。AI 根据这段描述决定要不要加载你的 Skill。写得越具体、关键词越多越好。后面有专门一节讲怎么写。最长 4096 字符。 |
触发与匹配增强字段
| 字段 | 类型 | 用途 |
|---|---|---|
tags |
string 数组 | 关键词标签,给 A2A AgentCard 发现层用。SKILL.md 不写也行,发现端会兜默认值。 |
examples |
string 数组 | 典型 prompt 例子。在 A2A AgentCard 里会展示给调用方看,提示"这个 Skill 应该怎么用"。 |
运行行为字段(高级)
| 字段 | 类型 | 用途 |
|---|---|---|
builtin_tools |
string 数组 | 声明这个 Skill 需要哪些内置工具。Agent 在加载这个 Skill 时会自动把这些工具挂上去。例:[list_metrics, get_metric_labels]。 |
recommended_tools |
string 数组 | 推荐工具列表(软建议)。和 builtin_tools 区别:前者是"我要用这些",后者是"建议有更好"。 |
max_iterations |
int | 覆盖 Agent 的默认 ReAct 迭代上限(默认 10)。多步 Skill(创建仪表盘 = 7-10 步起)要调高到 20-25,否则会被默认上限截断。 |
元数据 / 合规字段
| 字段 | 类型 | 用途 |
|---|---|---|
license |
string | 许可证。例 MIT / Apache-2.0。Skill 分享出去时让使用者明白合规边界。 |
compatibility |
string | 环境依赖描述。例 "需要 git、docker" / "需要联网"。AI 在没有相应能力时会跳过本 Skill。 |
allowed-tools |
string | 空格分隔的预授权工具白名单。例 "Bash(git:*) Bash(docker:*) Read"。只有列在这里的工具调用才不会再二次跟用户确认,否则 Agent 每用一次工具都会让用户点同意。 |
metadata |
map | 自定义 key-value。给 Skill 打标签 / 写版本号 / 关联 owner 等。例 {owner: sre-team, version: 1.0}。 |
完整示例:内置 n9e-create-alert-rule 的 frontmatter
---
name: n9e-create-alert-rule
description: 在夜莺(n9e)平台上创建告警规则。支持 Prometheus/Loki/ES/MySQL/TDengine/ClickHouse/Doris/Host 等所有数据源类型。
max_iterations: 20
builtin_tools:
- create_alert_rule
- list_busi_groups
- list_datasources
- list_metrics
- list_notify_rules
- list_files
- read_file
- list_databases
- list_tables
- describe_table
---
注意到三个关键点:
- description 一句话点题 + 枚举范围——先讲清主场景(创建告警规则),再列出支持的数据源类型,让 AI 在不该用的时候不会误触发;
max_iterations: 20——创建告警规则是多步骤动作(选业务组 → 选数据源 → 找指标 → 看标签 → 读模板 → 拼 payload → 创建),默认 10 步不够;builtin_tools区分"动作工具"和"探索工具"——create_alert_rule是最终落地的写操作工具;其它list_*/read_file/describe_table等是辅助 AI 拿元数据的只读工具。写 Skill 时这两类都要列全,否则 Agent 拿不到工具就只能瞎猜。
三、写好 description:让 AI 准确命中你的 Skill
如果一句话只能记住一个建议:description 字段决定一切。
为什么这么重要
夜莺 AI 是这样决定要不要用你的 Skill 的:
- 用户输入 → 提取关键词;
- 把关键词 + 所有启用 Skill 的
description喂给 LLM; - LLM 选出最匹配的 1-2 个 Skill 加载到上下文。
如果你 description 写"故障处理",LLM 看到用户说"我这台机器为什么慢"时,匹配置信度极低,你的 Skill 不会被加载。
4 个 description 写法范式
范式 1:动词驱动 + 多语言关键词
description: 帮用户判断一台机器到底是 真宕机 / agent 假死 / 网络抖动 / 维护中。
当用户问"为什么这台机器失联"、"host 失联告警是不是误报"、"categraf 卡住了吗"、
"心跳停了为啥还能 ping 通"等触发本技能。
要点:动词在前(判断 / 失联 / 卡住)、典型用户原话直接抄进来(用户问什么就匹配什么)。
范式 2:场景列表 + 排他声明
description: 在夜莺平台上创建告警规则。支持 Prometheus/Loki/ES/MySQL/TDengine/ClickHouse/
Doris/Host 等所有数据源类型。
要点:先一句话讲清主场景 + 枚举覆盖范围,避免 AI 在不该用的时候用上。
范式 3:英文动词 + 中文动词全覆盖
description: This skill should be used when the user asks to "troubleshoot",
"diagnose", "debug alert", "investigate incident", "故障定位", "告警排查",
"问题诊断", "排障", "查告警", "分析告警", "根因分析", or discusses
monitoring/alerting/observability issues...
要点:英文/中文都要写,团队里可能两种说法都有人用。
范式 4:核心立场 + 适用边界
description: 帮助用户生成、修改或排障夜莺告警自愈脚本。当用户要求"写一个磁盘清理/重启服务/
清理日志/dump 进程/reload nginx"等自愈脚本,或问"自愈脚本怎么拿告警传过来的参数"、"stdin
是什么格式"、"timeout 应该填多少"等时使用。**本技能专注脚本正文层**——若用户要改告警规则、
接收人或通知模板,引导到对应 skill。
要点:写明边界(“专注 XX 层”、“不涉及 YY”)能避免 AI 在不该用的场景误触发。
Description 不要这么写
❌ description: 故障处理
❌ description: 这是一个有用的 skill
❌ description: 帮助运维人员
❌ description: SOP for ops team
这种宽泛、抽象、没有任何具体关键词的描述,AI 几乎不会命中。
四、正文结构模板:抄就行
看了 19 个内置 Skill,几乎所有"重型"Skill 都按这套模板写。照搬就能写出高质量 Skill。
---
name: <你的 skill 名>
description: <按前面四个范式写好>
builtin_tools:
- <你要用的工具>
---
# Skill: <这个 Skill 的中文标题>
## 适用范围
**进本 skill**:
- 用户原话场景 1
- 用户原话场景 2
- 用户原话场景 3
**不进本 skill**:
- 容易混淆但不该走本 skill 的场景 1 → 转 `xxx-skill`
- 容易混淆但不该走本 skill 的场景 2 → 转 `yyy-skill`
## 一句话原则
<一句最重要的立场,比如"只看一层证据下结论几乎都是错的"。模型读了会先入为主,
后面所有步骤都会围绕这个原则展开。>
## 工作流程
### 第 1 步:<动作名>
<具体怎么做、调什么工具、看什么字段、怎么判断>
### 第 2 步:<动作名>
<具体怎么做……>
### 第 3 步:<动作名>
<具体怎么做……>
## 输出格式
<明确告诉模型 Final Answer 长什么样,最好给一份 Markdown 骨架>
## 注意事项 / 红线
1. **<不要做什么>**:原因是 ……
2. **<必须做什么>**:原因是 ……
## 示例
### 用户输入
<一句真实的用户原话>
### 工作流程
1. <一步一步做了什么>
2. <调用了什么工具,拿到什么结果>
### 输出
<最终回答的样子>
五个写法心法
- 开头一句话点题——用最简洁的语言说清楚这个 Skill 是干啥的、什么时候该用。
- 结构化——用
## 子任务把大任务拆开,每个子任务下再用列表/代码块写步骤。Markdown 结构越清晰,模型越容易稳定执行。 - 少用"我建议"、多用祈使句——模型会模仿你的语气。写"请运行
top -c并截图前 10 行"比"建议你可以试试 top"更确定。 - 明确边界——写清楚"不要做什么"。例如"不要主动修改生产环境配置,只输出建议命令"。
- 配示例——给一个具体的"输入 → 输出"例子,比千言万语都管用。
五、辅助文件:让 Skill 更强大
Skill 包不只是一份 SKILL.md。根目录下可以放任意辅助文件,正文里通过相对路径引用,AI 会用 read_file / list_files / grep_files 工具按需读取。
用法 1:分场景模板
内置 n9e-create-alert-rule Skill 就是个好例子:
n9e-create-alert-rule/
├── SKILL.md
└── datasources/
├── clickhouse.md
├── doris.md
├── elasticsearch.md
├── host.md
├── loki.md
├── mysql.md
├── pgsql.md
├── prometheus.md
├── tdengine.md
└── victorialogs.md
SKILL.md 里写:
通用路径——传 `cate` + `rule_config_json`,`rule_config_json` 的结构
**先通过 `read_file` 读取 `datasources/<cate>.md` 获取模板**,再填充实际值
这样 SKILL.md 本身就不用塞 11 种数据源的模板细节,Agent 按需读对应的子文档。SKILL.md 上限 64KB,单文件上限 16MB——大而全的内容用辅助文件承载。
用法 2:脚本片段
如果你的 Skill 是"写自愈脚本"类,把常用脚本片段单独存成文件:
disk-cleanup-skill/
├── SKILL.md
└── scripts/
├── clean-logs.sh
├── clean-docker.sh
└── clean-yum-cache.sh
SKILL.md 引导:「按用户场景,先 read_file 读 scripts/<场景>.sh 作为骨架,再按需修改」。
用法 3:参考数据 / Cheat Sheet
promql-skill/
├── SKILL.md
└── cheatsheet/
├── common-queries.md # 常用 PromQL 模板
└── label-conventions.md # 公司内部标签命名规范
打包限制
- 单个归档最多 100 个文件
- 解压后总大小 ≤ 50MB
- 单文件 ≤ 16MB
- SKILL.md 本身 ≤ 64KB
- 不允许:符号链接、绝对路径、
..路径穿越 - 自动过滤:
.DS_Store、._*、__MACOSX/等系统噪声
六、上传打包
方式 1:在线创建(简单 Skill)
适用:只有一份 SKILL.md、没有辅助文件、内容简短的场景。
操作流程:
- 进入 AI 配置 → Skill 管理,点
+→ 在线创建 Skill; - 填表:名称、描述、提示词指令(SKILL.md 的正文),高级设置里可填许可证/兼容性/预授权工具/元数据;
- 保存。
详见 Skill 管理 → 在线创建。
方式 2:本地上传(推荐)
适用:带辅助文件、有版本管理需求、要在团队/实例间分发的场景。
操作流程:
-
本地按上面"基本形态"组织好目录结构:
my-skill/ ├── SKILL.md └── (其它辅助文件) -
打包成
.zip或.tar.gz:# zip cd my-skill && zip -r ../my-skill.zip . -x "*.DS_Store" "__MACOSX/*" # 或 tar.gz tar czf my-skill.tar.gz -C parent_dir my-skill可以带顶层目录(如
my-skill/SKILL.md),也可以直接把 SKILL.md 放包根。两种都能解。 -
进入 AI 配置 → Skill 管理,点
+→ 本地上传 Skill,选文件上传。 -
上传成功后,Skill 出现在列表里,默认启用。
替换 / 下载 / 删除
- 替换:详情页三点菜单选「替换」上传新归档,完全覆盖当前 Skill(包括所有辅助文件)。
- 下载:把当前 Skill 导出成压缩包。这是团队内分发、版本备份的标准动作——一份 Skill 在一个实例打磨好,下载下来上传到其它实例。
- 删除:二次确认后删除,所有关联文件级联删除,无法恢复。建议先「下载」做一份备份再删。
七、调试 Skill:怎么知道它工作了?
写完一个 Skill,最常见的尴尬是**“我启用了,但 AI 好像没用上”**。下面是排查流程:
第 1 步:description 命中检查
问一句应该命中你 Skill 的话,看 AI 回答的开头是否引用了你的领域知识 / 用了你定义的术语 / 走了你写的流程。
- 没引用、答案泛泛 → description 没命中,回去把 description 改具体;
- 引用了但没按你的方法答 → 正文不够明确,把工作流程写得更祈使句;
- 完全在答别的事情 → 用户输入和 description 偏差太大,可能是 description 关键词错配。
第 2 步:手动指定 Skill 验证
在对话框里直接说"用 <你的 skill 名> 这个 skill 帮我处理 XXX"。如果手动指定后效果好,但自动不命中——问题在 description,不在正文。
第 3 步:看其它 Skill 抢了你的活
如果用户的问题被别的 Skill 接走了(看 AI 答案的措辞像哪个内置 Skill 的风格),说明那个 Skill 的 description 比你写得更具体。两条出路:
- 写明边界:在你 Skill 的 description 里加一句"不涉及 XX",把容易混淆的场景甩出去;
- 改名字 + 关掉冲突 Skill:极端情况下把你 Skill 命名得和那个内置 Skill 同名,让用户版盖掉内置版。
第 4 步:max_iterations 不够
如果 AI 中途停了,没给完整答案,看是不是工具调用次数被截断了。把 max_iterations 调高(20-25)。
第 5 步:builtin_tools 缺漏
AI 答"我没法查这个"——大概率是 builtin_tools 没列对应工具。回 frontmatter 加上。
八、端到端实战:写一份《MySQL 慢查询排障 Runbook》Skill
下面把一个真实的 Skill 从空白到上线走一遍。
场景
你的团队每周都收到 MySQL 慢查询告警。资深 DBA 排查动作是固定的:拉慢日志 Top 10 → 看 EXPLAIN → 看 SHOW PROCESSLIST 有没有锁 → 看缓冲池命中率。但新人接到告警只会一句"重启 mysql 试试"。
把 DBA 的排障动作写成 Skill。
第 1 步:建目录
mkdir -p mysql-slow-query-runbook/queries
cd mysql-slow-query-runbook
第 2 步:写 SKILL.md
---
name: mysql-slow-query-runbook
description: MySQL 慢查询告警排障 Runbook。当用户问"MySQL 慢了 / 慢查询告警怎么处理 / DB 响应慢 /
qps 上升延迟变高 / lock 等待 / 缓冲池命中率"等时使用。覆盖:慢日志 Top 10、EXPLAIN 解读、
ProcessList 锁分析、innodb_buffer_pool 命中率检查。**不涉及**:MySQL 部署/初始化(转
`agent_deploy_guide`)、写新告警规则(转 `n9e-create-alert-rule`)。
max_iterations: 20
builtin_tools:
- list_databases
- list_tables
- describe_table
- query_log
- search_active_alerts
- get_alert_event_detail
- read_file
metadata:
owner: dba-team
version: 1.0
---
# MySQL 慢查询排障 Runbook
## 适用范围
**进本 skill**:
- 用户告警标签里有 `service=mysql` 或 `category=db` 的慢查询/延迟告警
- 用户原话:"MySQL 慢了"、"DB 响应变慢"、"慢查询变多"、"锁等待"、"qps 高但延迟也高"
**不进本 skill**:
- MySQL 安装 / 初始化 → 转 `agent_deploy_guide`
- 想新加一条告警规则 → 转 `n9e-create-alert-rule`
- 非 MySQL 数据库(PostgreSQL / TDengine 等)→ 直接答用户当前 DB 类型不在本 Runbook 范围
## 一句话原则
**先看现象,再看症状,最后才看代码层 SQL。** 不要一上来就让用户 EXPLAIN——80% 的"慢"是池子和锁。
## 排障四步法
### 第 1 步:拿现象 —— 用 `query_log` 拉慢日志 Top 10
读 `queries/top10_slow_queries.sql` 作为骨架,按用户事件的时间窗口替换 `WHERE` 子句。
聚焦 `query_time > 1s` 的 query,按 `count * avg_query_time` 排序拿 Top 10。
如果 Top 10 集中在同一张表 → 大概率是该表索引/锁问题;
分散在多表 → 偏向资源瓶颈(IO / CPU / 池子)。
### 第 2 步:看池子 —— `innodb_buffer_pool` 命中率
读 `queries/buffer_pool_hit_rate.sql`,关注:
- `Innodb_buffer_pool_read_requests` / `Innodb_buffer_pool_reads` 比值
- 比值 < 99% → 池子配置过小或冷数据访问占比高
- 比值 > 99% 但慢查询仍多 → 走第 3 步
### 第 3 步:看锁 —— `SHOW PROCESSLIST`
读 `queries/processlist.sql`,重点看:
- `State` 列含 "Waiting for table metadata lock" / "Waiting for row lock" → DDL 或长事务卡住
- `Time` 列超过 30s 的 `Sleep` 状态连接 → 应用层连接池泄漏
### 第 4 步:到这里仍未定位 —— 才让用户 EXPLAIN
对第 1 步拿到的 Top 1 慢 query 执行 `EXPLAIN`,看:
- `type=ALL` → 全表扫,缺索引;
- `type=index` 但 `rows` 很大 → 索引选择性差,需要复合索引;
- `Extra=Using filesort/temporary` → ORDER BY / GROUP BY 无法走索引。
## 输出格式
最终回答用 Markdown,结构:
## 结论
<一句话定位是哪一类问题:池子小 / 锁等待 / 缺索引 / 全表扫 / 其他>
## 关键证据
- 慢日志 Top 10:……
- 池子命中率:……
- 锁/长事务:……
- EXPLAIN 关键字段:……
## 建议动作
1-3 条具体可执行项,每条注明影响范围与回滚方式
## 误报风险
说明这个结论可能在什么情况下不准
## 注意事项 / 红线
1. **不要主动修改生产 my.cnf**——只能输出建议改动 + 备份命令,让用户自己执行。
2. **不要建议直接 `kill <thread_id>`**——必须先解释这个连接在做什么,让用户判断。
3. **慎用 `OPTIMIZE TABLE`**——大表会锁表,要先评估是否在低峰期。
## 示例
### 用户输入
"刚才收到 MySQL 慢查询告警,order_db 上 P99 延迟从 20ms 涨到 800ms"
### 工作流程
1. 第 1 步:`query_log` 拉 order_db 最近 10 分钟慢日志 Top 10
2. 发现 Top 1 是 `SELECT * FROM orders WHERE user_id=?` 跑了 9000 次,avg 600ms
3. 第 2 步:池子命中率 99.7%,排除池子问题
4. 第 4 步:`EXPLAIN` 看到 `type=ALL`,`rows=12000000`,缺 `user_id` 索引
5. 给出结论 + 加索引的 DDL + 在线 DDL 风险评估
第 3 步:写辅助 SQL 文件
queries/top10_slow_queries.sql:
SELECT
DIGEST_TEXT AS query,
COUNT_STAR AS exec_count,
AVG_TIMER_WAIT/1e9 AS avg_ms,
SUM_TIMER_WAIT/1e9 AS total_ms
FROM performance_schema.events_statements_summary_by_digest
WHERE LAST_SEEN > NOW() - INTERVAL 10 MINUTE
ORDER BY total_ms DESC
LIMIT 10;
queries/buffer_pool_hit_rate.sql:
SHOW STATUS WHERE Variable_name IN (
'Innodb_buffer_pool_read_requests',
'Innodb_buffer_pool_reads',
'Innodb_buffer_pool_pages_total',
'Innodb_buffer_pool_pages_free'
);
queries/processlist.sql:
SELECT id, user, host, db, command, time, state, info
FROM information_schema.processlist
WHERE time > 30
AND command != 'Sleep'
ORDER BY time DESC;
第 4 步:打包
cd mysql-slow-query-runbook
zip -r ../mysql-slow-query-runbook.zip . -x "*.DS_Store"
或:
tar czf mysql-slow-query-runbook.tar.gz mysql-slow-query-runbook
第 5 步:上传 + 测试
-
进入 AI 配置 → Skill 管理,点
+→ 本地上传 Skill,选mysql-slow-query-runbook.zip; -
上传后 Skill 自动启用;
-
打开右上角 Nightingale AI,问一句应该命中的话:
刚才收到一条 MySQL 慢查询告警,order_db 延迟变高了,帮我看下 -
AI 应该按 Runbook 4 步法走,先拉慢日志、看池子、看锁,最后才让你 EXPLAIN。
如果它没按 Runbook 走,回头看「七、调试 Skill」一节排查。
第 6 步:分发到团队
打磨满意后,从 Skill 详情页下载导出压缩包,提交到团队 Git 仓库的 nightingale-skills/ 目录,作为团队 Runbook 的数字资产。其它夜莺实例直接上传同一份包就能用。
九、Skill 来源:除了自己写还能从哪拿
夜莺的 Skill 包格式与 Anthropic Agent Skills 规范 完全兼容——根目录的 SKILL.md + YAML frontmatter 一致。这意味着:
- 直接用社区 Skill 库——anthropics/skills 仓库里很多开源 Skill 可以直接打包上传。
- 复用 Claude / Cursor 等 AI 客户端的 Skill——只要是 Anthropic Skills 格式,夜莺都能识别。
- 跨实例迁移——开发实例打磨完下载导出,生产实例直接上传。
十、常见问题
Q1:Skill 太多会怎样?
模型会从启用列表里选 1-2 个最相关的加载到上下文。Skill 数量本身没硬上限,但每条都要让模型读 description 做匹配判断——一般 30 条以内不会有明显感知开销。超过这个数建议:
- 同主题的 Skill 合并成一个,用
## 子章节分隔; - 用
compatibility字段写明先决条件,让 AI 在条件不满足时跳过; - 关掉长期不用的 Skill(启用开关)。
Q2:能不能让某个 Skill「永远」被加载?
可以——在 Agent 配置里用 SkillConfig.SkillNames 显式指定。但不推荐,会让上下文变重影响所有问答。正确做法仍然是写好 description,让 AI 在该用的时候自动用。
Q3:辅助文件能调用网络/执行脚本吗?
不能。辅助文件就是被 AI read_file 读出来当上下文的素材,没有执行权。如果你要让 Skill 真的"动手做事",靠 builtin_tools 里挂的工具(这些是夜莺受控的内置工具)。
Q4:能不能在 Skill 里加密敏感信息(如 DB 密码)?
不要。Skill 全文会进模型上下文,等于上传给你接的 LLM。所有密钥/密码/Token 都要从工具层注入(夜莺的工具本身用当前用户的会话凭证),SKILL.md 里只写参数名占位。
Q5:写 Skill 用什么 IDE 体验最好?
任何能编辑 Markdown + YAML 的编辑器都行。推荐 VSCode + YAML 插件,能在 frontmatter 阶段校验语法。
关联文档
- Skill 管理——基础概念与产品操作
- 内置 Skill 一览——19 个内置 Skill 是最好的写法参考
- LLM 管理——Skill 跑起来需要的底层模型
- 夜莺 AI 整体介绍——从产品视角理解 Skill 在整套 AI 能力里的位置
- Anthropic Agent Skills 规范——Skill 包格式参考
- anthropics/skills——社区 Skill 仓库