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 字段速查

下面这些字段都是可选的,只有 namedescription 是必填

核心字段

字段 类型 说明
name string 必填。Skill 的唯一标识。建议 kebab-case 英文,如 mysql-slow-query-runbookpayment-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
---

注意到三个关键点:

  1. description 一句话点题 + 枚举范围——先讲清主场景(创建告警规则),再列出支持的数据源类型,让 AI 在不该用的时候不会误触发;
  2. max_iterations: 20——创建告警规则是多步骤动作(选业务组 → 选数据源 → 找指标 → 看标签 → 读模板 → 拼 payload → 创建),默认 10 步不够;
  3. builtin_tools 区分"动作工具"和"探索工具"——create_alert_rule 是最终落地的写操作工具;其它 list_* / read_file / describe_table 等是辅助 AI 拿元数据的只读工具。写 Skill 时这两类都要列全,否则 Agent 拿不到工具就只能瞎猜。

三、写好 description:让 AI 准确命中你的 Skill

如果一句话只能记住一个建议:description 字段决定一切。

为什么这么重要

夜莺 AI 是这样决定要不要用你的 Skill 的:

  1. 用户输入 → 提取关键词;
  2. 把关键词 + 所有启用 Skill 的 description 喂给 LLM;
  3. 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. <调用了什么工具,拿到什么结果>

### 输出
<最终回答的样子>

五个写法心法

  1. 开头一句话点题——用最简洁的语言说清楚这个 Skill 是干啥的、什么时候该用。
  2. 结构化——用 ## 子任务 把大任务拆开,每个子任务下再用列表/代码块写步骤。Markdown 结构越清晰,模型越容易稳定执行。
  3. 少用"我建议"、多用祈使句——模型会模仿你的语气。写"请运行 top -c 并截图前 10 行"比"建议你可以试试 top"更确定。
  4. 明确边界——写清楚"不要做什么"。例如"不要主动修改生产环境配置,只输出建议命令"。
  5. 配示例——给一个具体的"输入 → 输出"例子,比千言万语都管用。

五、辅助文件:让 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_filescripts/<场景>.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、没有辅助文件、内容简短的场景。

操作流程:

  1. 进入 AI 配置 → Skill 管理,点 +在线创建 Skill
  2. 填表:名称、描述、提示词指令(SKILL.md 的正文),高级设置里可填许可证/兼容性/预授权工具/元数据;
  3. 保存。

详见 Skill 管理 → 在线创建

方式 2:本地上传(推荐)

适用:带辅助文件、有版本管理需求、要在团队/实例间分发的场景。

操作流程:

  1. 本地按上面"基本形态"组织好目录结构:

    my-skill/
    ├── SKILL.md
    └── (其它辅助文件)
    
  2. 打包成 .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 放包根。两种都能解。

  3. 进入 AI 配置 → Skill 管理,点 +本地上传 Skill,选文件上传。

  4. 上传成功后,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 步:上传 + 测试

  1. 进入 AI 配置 → Skill 管理,点 +本地上传 Skill,选 mysql-slow-query-runbook.zip

  2. 上传后 Skill 自动启用;

  3. 打开右上角 Nightingale AI,问一句应该命中的话:

    刚才收到一条 MySQL 慢查询告警,order_db 延迟变高了,帮我看下
    
  4. 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 阶段校验语法。

关联文档

更新时间 2026-05-22

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云