首页 › tutorials › 从零构建迁移安全守卫Skill

Claude Code Skills 开发实战:从零构建「数据库迁移安全守卫」

概述

本教程面向已经会用 Claude Code 跑日常编码任务、但还没写过自定义 Skill 的开发者。我们将从一张空白 SKILL.md 开始,完整走通「写描述 → 编写工作流 → 拆分参考文件 → 触发测试 → 评估打磨」的全流程,最终产出一个数据库迁移安全守卫 Skill:它能在你提交 ALTER TABLE、DROP COLUMN、批量回填等高风险 SQL 时自动介入,按破坏性等级给出审查意见与锁表风险评估。学完后你将掌握 Skill 的三层渐进式披露结构、自动触发描述的写法,以及如何用 Evals 闭环验证一个 Skill 是否真的「该出手时才出手」。

前置条件


一、先搞懂:Skill 到底是什么

很多人把 Skill 想得太重。一句话定义:Skill 是一个带 YAML 头的 Markdown 文件(SKILL.md),里面写着「什么时候用我、按什么流程做」,Claude 会按需加载它。

它和另外两个常被混淆的概念的区别:

概念 加载时机 适合放什么
CLAUDE.md 每个会话都全量加载 项目级常驻规则、技术栈约定
Skill(SKILL.md) 需要时才加载(描述命中用户意图) 可复用的专项工作流
Subagent / MCP 显式调用或工具发现 独立上下文 / 外部数据源

关键认知:Skill 的正文不会一直占用上下文。Claude Code 启动时只读取每个 Skill 的 frontmatter(描述部分),只有当判断「这次任务和某个 Skill 相关」时,才会把该 Skill 的完整正文加载进来。这就是官方文档反复强调的 渐进式披露(Progressive Disclosure)。

渐进式披露的三层结构

第一层:frontmatter 的 description      ← 永远在上下文里(要短、要准)
第二层:SKILL.md 正文                   ← 命中后才加载(决策流程、关键规则)
第三层:同目录的参考文件(references/)  ← 用到才读取(完整清单、模板、样例)

理解这三层,是写好 Skill 的全部秘密。下面我们直接动手。


二、动手前:给 Skill 选一个存放位置

Skill 可以放在三个层级,加载优先级从高到低:

  1. 项目级:<项目>/.claude/skills/<skill-name>/SKILL.md——只在当前项目生效
  2. 用户级:~/.claude/skills/<skill-name>/SKILL.md——对你所有项目生效
  3. 插件级:随 Plugin 分发——适合跨团队共享

我们的「迁移安全守卫」和具体项目耦合(要识别项目里的迁移文件),放项目级最合适。

先建好目录骨架:

mkdir -p .claude/skills/migration-guardian/references
cd .claude/skills/migration-guardian

最终的目录结构会是:

.claude/skills/migration-guardian/
├── SKILL.md                      # 第二层:决策流程 + 关键规则
└── references/
    ├── destructive-patterns.md   # 第三层:完整破坏性模式清单
    ├── lock-risk-matrix.md       # 第三层:锁表风险矩阵
    └── rollback-template.md      # 第三层:回滚脚本模板

三、第一层:写好 frontmatter(决定 Skill 能否被触发)

SKILL.md 的开头是 YAML frontmatter,用三连横线包裹。这是整个 Skill 最该反复打磨的部分——因为它是唯一永远在上下文里的内容,写不好 Skill 就永远不被触发(或被错误触发)。

字段说明

字段 必填 作用
name 是 Skill 唯一标识,全小写连字符,同时也是斜杠命令 /migration-guardian
description 是 触发依据。写明「这个 Skill 做什么、什么场景该用它」
allowed-tools(或 allowed_tools) 否 限制该 Skill 可调用的工具白名单,收敛权限
metadata 否 任意键值,便于组织/检索

写 description 的三条铁律

来自社区对 650 次会话的实测:很多 Skill 不触发,根因就是 description 写成了「名词介绍」而非「触发条件」。

  1. 用第三人称、陈述「做什么 + 何时用」,不要写「这是一个用于……的强大工具」
  2. 显式铺开关键词:把用户真实会打的词(迁移、migration、ALTER、DROP、回填、DDL)都融进去
  3. 划清边界:用「不要用于……」明确反面场景,防止误触发

我们的 frontmatter

---
name: migration-guardian
description: Reviews database migration files for destructive or lock-heavy DDL before they are applied. Use when the user edits, stages, or asks about migration files (*.sql, Alembic, Rails migrations, Flyway, Liquibase, Prisma migrate, Knex) — especially operations like DROP TABLE/COLUMN, ALTER TABLE, TRUNCATE, renaming columns, NOT NULL without default, large backfills, or creating indexes without CONCURRENTLY. Do NOT use for seed data, fixture generation, or application-level SQL queries in code.
allowed-tools: Read, Grep, Glob, Bash
---

注意这 30 行字里塞进了多少触发信号:文件后缀(*.sql、Alembic、Rails、Prisma……)、具体危险操作(DROP、ALTER、TRUNCATE……)、边界排除(seed、fixture、应用层查询)。这一段写得越具体,自动触发越准。

常见问题:我的 Skill 写完了但从不自动触发? 排查:90% 是 description 缺少用户会实际输入的词。把你的描述读给同事听,问他「你会这样描述需求吗」。


四、第二层:编写正文(决策流程 + 关键规则)

正文只在 Skill 被触发后加载。这里要给 Claude 一个清晰、可执行的决策流程,而不是泛泛而谈。一个好的 Skill 正文像一份「带判断分支的检查清单」。

正文写作要点

我们的 SKILL.md 正文

# 数据库迁移安全守卫

你是一个数据库迁移审查助手。目标是:在迁移被应用到生产前,识别破坏性操作和高锁表风险,并给出可执行的缓解建议。

## 工作流程

1. **定位迁移文件**
   - 优先审查用户当前正在编辑 / 已 `git add` 的迁移文件。
   - 若用户未指定,用 Glob 找到最近的迁移目录(`db/migrate/`、`alembic/versions/`、`prisma/migrations/`、`migrations/`、`src/main/resources/db/changelog/` 等)。

2. **识别 DDL 类型**(用 Grep 扫描关键字,忽略大小写):
   `DROP`, `TRUNCATE`, `ALTER`, `RENAME`, `MODIFY`, `ADD COLUMN`, `CREATE INDEX`, `NOT NULL`

3. **按破坏性等级分类**,参考 `references/destructive-patterns.md` 获取完整清单:
   - 🟥 **高危**:DROP TABLE/COLUMN、TRUNCATE、重命名列/表、删约束
   - 🟧 **中危**:NOT NULL 无默认值、加唯一索引、改列类型
   - 🟨 **低危但有锁风险**:普通 CREATE INDEX(无 CONCURRENTLY)、大表 ADD COLUMN + 回填

4. **评估锁表风险**
   - 读取 `references/lock-risk-matrix.md`,结合表行数(如能从代码/文档推断)给出 `低/中/高` 评级。

5. **输出审查报告**,格式固定:
   - 风险摘要表(文件、行号、等级、一句话原因)
   - 每个高危/中危项的**缓解建议**(如:先加可空列 → 分批回填 → 后续再设 NOT NULL)
   - 是否需要**停机窗口**的明确结论

6. **回滚预案**:对每个高危变更,参考 `references/rollback-template.md` 生成对应的正向 + 回滚 SQL。

## 关键规则(不可违反)

- **永不自动修改迁移文件**。只读、只建议。`allowed-tools` 已限定为只读工具。
- **不确定时按更严重的等级判定**,并标注「需人工确认」。
- **Postgres / MySQL / SQLite 差异**要识别:例如 `CREATE INDEX CONCURRENTLY` 仅 Postgres 支持,不要给 MySQL 项目提这个建议。
- 若迁移文件用了 ORM DSL(如 Rails 的 `remove_column`、Alembic 的 `op.drop_column`),按等价 DDL 判定。

## 何时停止

- 报告交付后,等待用户决定是否按建议修改。不要主动重写迁移。

到这里,SKILL.md 第二层就完整了。注意我们把完整模式清单和锁表矩阵都外链到了 references/——这就是渐进式披露的精髓:正文只留决策骨架,细节按需加载。

常见问题:正文该写多长? 答:以「能照着执行」为准,社区经验是正文控制在 5000 词以内为佳。超出的部分就该拆到 references。


五、第三层:编写参考文件(按需加载的细节库)

参考文件是普通 Markdown,只有当正文明确引用、且 Claude 判断需要细节时才会被读取。这意味着你可以放心地把长清单、大表格、模板塞进来,而不会污染主上下文。

references/destructive-patterns.md

# 破坏性 DDL 模式完整清单

## 🟥 高危(需停机或灰度)
| 模式 | 原因 | 典型缓解 |
|------|------|---------|
| DROP TABLE | 数据丢失,不可逆 | 先重命名(`_archived`)→ 观察期 → 真删 |
| DROP COLUMN | 旧代码可能仍读该列 | 先停写引用 → 再删 |
| TRUNCATE | 清空数据 | 同 DROP TABLE |
| RENAME COLUMN/TABLE | 旧代码/查询断裂 | 视图别名过渡 / 双写期 |
| 删除索引/约束 | 查询计划突变、写入报错 | 评估查询依赖后再删 |

## 🟧 中危(需灰度或分批)
| 模式 | 原因 | 缓解 |
|------|------|------|
| ADD COLUMN ... NOT NULL 无 default | 锁全表回填 | 先加可空列 → 回填 → 改 NOT NULL |
| ADD UNIQUE INDEX | 大表长锁 + 冲突失败 | 用 `CREATE UNIQUE INDEX CONCURRENTLY`(PG)|
| MODIFY 列类型 | 重写表、长锁 | 新列 + 双写 + 切换 |
| 收紧 CHECK 约束 | 已有数据可能违规 | 先扫描存量数据 |

## 🟨 低危但需注意
| 模式 | 注意点 |
|------|--------|
| CREATE INDEX(无 CONCURRENTLY)| 大表写锁,建议 `CONCURRENTLY` |
| ADD COLUMN(nullable,有 default)| PG 11+ 不重写表,MySQL 视版本而定 |
| ADD 默认值为非常量(如函数)| 部分方言行为不一致 |

references/lock-risk-matrix.md

# 锁表风险矩阵

风险 = f(操作类型, 表行数量级)。结合项目实际行数评级。

| 操作 | < 10万行 | 10万–1千万 | > 1千万 |
|------|---------|-----------|---------|
| DROP TABLE | 低(瞬时元数据锁)| 低 | 低 |
| ALTER ADD COLUMN(PG 11+)| 低 | 低 | 低 |
| ALTER ADD COLUMN w/ default 重写 | 低 | 🟧 中 | 🟥 高 |
| CREATE INDEX 普通 | 低 | 🟧 中 | 🟥 高 |
| CREATE INDEX CONCURRENTLY | 低 | 低 | 低(注意失败遗留 invalid index)|
| ADD UNIQUE INDEX | 🟧 中(冲突检查)| 🟥 高 | 🟥 高 |
| NOT NULL + 回填 | 低 | 🟧 中 | 🟥 高 |
| MODIFY 列类型 | 🟧 中 | 🟥 高 | 🟥 高(重写表)|

> 行数无法确定时:默认按「> 1千万」保守评级,并提示用户确认。

references/rollback-template.md

# 回滚脚本模板

每个迁移应提供 forward(上卷)与 rollback(回滚)两段。

## 加列(安全模式)
```sql
-- forward
ALTER TABLE orders ADD COLUMN status_new VARCHAR(20);

-- rollback
ALTER TABLE orders DROP COLUMN status_new;

改 NOT NULL(分两步,禁止合并)

-- Step 1 forward: 加可空列
ALTER TABLE orders ADD COLUMN email_verified BOOLEAN;
-- Step 1 rollback
ALTER TABLE orders DROP COLUMN email_verified;

-- Step 2 forward: 回填 + 收紧(必须在 Step 1 全量上线后)
UPDATE orders SET email_verified = false WHERE email_verified IS NULL;
ALTER TABLE orders ALTER COLUMN email_verified SET NOT NULL;
-- Step 2 rollback
ALTER TABLE orders ALTER COLUMN email_verified DROP NOT NULL;
到这一步,三层结构全部就位:**frontmatter 永驻、正文按需、references 深挖**。

---

## 六、验证:手动触发与自动触发

### 手动触发(最直接)

在项目里运行 Claude Code,输入:

/migration-guardian

应看到 Claude 开始按正文流程执行:先用 Glob 找迁移文件、再 Grep 关键字、再调取 references 分类。

### 自动触发(才是 Skill 的价值)

新建一个故意带坑的迁移文件 `db/migrate/20260622_drop_users_avatar.sql`:

```sql
-- 删掉头像列,反正没人用了
ALTER TABLE users DROP COLUMN avatar_url;
TRUNCATE TABLE user_avatar_history;
CREATE INDEX idx_users_email ON users(email);  -- 大表无 CONCURRENTLY

然后对 Claude 说一句完全不提 skill 名的自然话术:

我准备把这周的迁移上生产,帮我看一眼有没有问题。

预期结果:Claude 不需要你点名,会自动识别这是「审查迁移文件」场景,加载 migration-guardian,产出类似下面的报告:

🟥 高危
- db/migrate/20260622_drop_users_avatar.sql:3  DROP COLUMN avatar_url
  → 旧代码可能仍在读取,建议先双写/停引用,本轮不要删
- db/migrate/...:4  TRUNCATE user_avatar_history
  → 数据不可逆,建议先 RENAME 为 _archived 观察

🟨 低危但锁风险
- db/migrate/...:5  CREATE INDEX 无 CONCURRENTLY
  → users 为大表时写锁显著,建议改 CREATE INDEX CONCURRENTLY

结论:本批次不建议直接上线,需停机窗口或拆分为多步灰度迁移。
回滚预案见已生成的 forward/rollback 脚本。

常见问题:自动触发没成功? 排查清单: 1. description 里有没有出现用户原话里的关键词?(如「迁移」「上线」「生产」) 2. 是否把 Skill 放对了 .claude/skills/<name>/SKILL.md 路径? 3. 启动时是否重新加载?(改动 frontmatter 后建议重启会话) 4. 是否与另一个 Skill 的 description 重叠导致歧义?给本 Skill 加更尖锐的边界。


七、用 Evals 闭环:验证「该出手才出手」

Skill 写完不算完,要验证两件事:该触发时必触发(召回)、不该触发时不乱入(精确)。Claude Code 的 skill-creator / Evals 能力支持你跑一组带预期结果的用例。

设计两类用例:

# evals 用例示例
should_activate:
  - input: "帮我看看 alembic/versions/ 下新加的迁移安不安全"
    expect: migration-guardian 被加载,输出风险报告
  - input: "prisma migrate 这次的 down 迁移会不会锁库"
    expect: 加载并评估锁表风险

should_not_activate:
  - input: "帮我写一个查最近订单的 SQL 查询"
    expect: 不加载(这是应用层查询,非迁移)
  - input: "生成一批测试用的 seed 数据"
    expect: 不加载(属 seed,已在 description 排除)

跑完看通过率。召回不足就去补 description 关键词;误触发多就去收紧边界词。这是把 Skill 从「能用」打磨到「好用」的标准动作。


八、完整工作流程图

flowchart TD
    A[用户发消息] --> B{Claude 扫描所有 Skill 的 frontmatter}
    B -->|描述命中意图| C[加载该 Skill 正文<br/>第二层]
    B -->|未命中| Z[按普通对话处理]
    C --> D[正文流程引用 references?]
    D -->|是| E[按需读取参考文件<br/>第三层]
    D -->|否| F[直接执行正文步骤]
    E --> F
    F --> G{是否破坏性/锁风险?}
    G -->|有| H[输出分级报告+缓解建议+回滚]
    G -->|无| I[给出低风险确认]
    H --> J[用户决定是否修改]
    I --> J
    J --> K[结束<br/>不自动改文件]

    style B fill:#e8f0fe,stroke:#1a73e8
    style C fill:#fef7e0,stroke:#f9ab00
    style E fill:#e6f4ea,stroke:#34a853

九、实战案例:把它接到 CI 里做提交门禁

Skill 在交互式会话里好用,但「上线前审查」这种事更适合卡在 CI。借助 Claude Code 的无头模式(-p / --print),可以把这个 Skill 变成 PR 检查:

# 在 CI 的迁移文件变更时调用
changed_migrations=$(git diff --name-only origin/main...HEAD -- \
  'db/migrate/*.sql' 'alembic/versions/*.py' 'prisma/migrations/**/migration.sql')

if [ -n "$changed_migrations" ]; then
  claude -p "审查以下迁移变更的安全性与锁表风险,只输出 JSON:{risk: high|medium|low, items:[...], block: bool}:$changed_migrations" \
    --allowed-tools "Read,Grep,Glob"
fi

block: true 时 CI 直接失败,挡住破坏性迁移进主干。这样 Skill 的知识资产就从「个人助手」升级为「团队门禁」,且逻辑只有一处,维护成本极低。


延伸阅读


训练营适用性评估


参考来源

  1. Creating custom skills — Claude 官方文档 — Skill 创建、结构化与测试的权威指南,涵盖 frontmatter 与多文件包
  2. Extend Claude with skills — Claude Code Docs — Claude Code 内 Skill 的管理、共享与自定义命令机制
  3. Chapter 29|Deep Dive into SKILL.md: Progressive Disclosure — AgentUpdate — SKILL.md 模块化分层设计的工程化深度讲解
  4. How Claude Code Automatically Triggers Skills vs Manual Invocation — BSWen — 自动触发 vs 手动 /skill 调用的边界与排查
  5. How to Create Custom Claude Skills: Complete Tutorial (2026) — SkillsMD — 2026 版从零创建 Skill 的完整步骤与渐进式披露三层结构实操

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入