但做完之后,我很快意识到:一个 Skill 能跑起来,不等于它已经可用。
第二篇里,我讲了一个慢查询分析前处理 demo。
它做的事情并不复杂:
把 DBA 在慢查询前处理里那些重复动作,先让 AI 接过去一部分。
比如:
• 整理 SQL
• 查看表结构
• 查看索引
• 分析执行计划
• 输出一份初步判断
这个 demo 跑通之后,效果还不错。原来大约 25 分钟的前处理,压到了 2 分钟左右。
但做完之后,我很快意识到另一个问题:
这句话如果只停留在概念上,会显得有点虚。所以这篇我不想继续讲大而全的方法论,而是换一个更具体的问题:
demo 阶段,我们很容易高估它
慢查询分析前处理 demo,通常可以很快做出来。
最简单的形式,可能就是一句话:
再贴一段 SQL:
from orders
where user_id = 10001
order by created_at desc
limit 20;
AI 很可能会给出一组看起来还不错的建议:
• 需要查看执行计划
• 可能缺少联合索引
• 关注扫描行数是否过大
• order by created_at 可能触发排序
• 可以考虑 (user_id, created_at) 这样的索引方向
如果只是做 demo,这已经足够让人兴奋。因为它确实接住了一部分重复分析动作。
但如果站在 DBA 的角度,这个答案其实还不能直接用。
原因很简单:
它不知道表结构。
它不知道现有索引。
它不知道执行计划。
它不知道数据分布。
它不知道这个 SQL 的调用频率。
它也不知道这个表的写入压力。
所以它给出的"建议",更像一个方向。不是一个可以直接进入决策链路的结论。
demo 证明这个方向能跑;可用要求这个结果能被信任。
Skill 不是 SOP:先把粒度说清楚
在继续讲 Skill 工程化之前,我觉得还需要先补一个概念边界。
前面为了方便表达,我一直在说"把慢查询分析做成一个 Skill",但严格来说,这个说法不够准确。
SOP 更像一套处理模板,描述某类问题通常应该怎么处理。它可能包含判断、分支、前置检查、执行步骤、验证步骤和回滚步骤。
而 Action 更像其中某一步允许调用的标准动作。
Skill / Executor 则是这个 Action 背后的具体执行能力。
如果放到一个更完整的系统里,这条链路更应该是:
-> 根因分类
-> SOPTemplate
-> HealingPlan
-> HealingStep
-> Action
-> Skill / Executor
也就是说:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
所以,一个 SOP 不应该简单等于一个 Skill。一个 Skill 也不应该试图包下整个 SOP。
以慢查询分析为例,完整 SOP 里可能包含:
• 收集 SQL 与时间范围
• 查询表结构
• 查询索引
• 获取执行计划
• 提取关键特征
• 生成初步建议
• 人工复核
这些步骤里,有些会映射成 Action,再由对应能力执行;有些只是流程判断,有些必须留给人。
SOP 是剧本,Plan 是本次安排,Step 是分镜头,Action 是标准动作,Skill / Executor 是动作背后的执行能力。
这里需要额外说明一下。很多平台也会把一整个能力目录称为 Skill,比如 OpenClaw 这类工具就经常会说"已经帮你创建了 Skill"。
这个叫法没有问题,它是平台口径下的 Skill。但如果放到数据库工程化场景里,只说"创建了一个 Skill"还不够。
因为我们还要继续追问:
• 这个 Skill 是一个场景能力包?
• 还是某个 Action 背后的执行能力?
• 它包含 SOP 吗?
• 它能不能拆出标准 Action?
• 哪些部分可以自动执行,哪些部分必须人工确认?
|
|
|
|
|
|
|
|
|
|
|
|
这背后的逻辑其实很简单:
如果把整个 SOP 都压成一个 Skill,这个 Skill 很快就会变得过大、过重、难以复用,也难以审计。
这也是为什么我认为,谈 Skill 工程化之前,必须先把它的粒度和边界说清楚。
可用的能力包,首先要有一个"形状"
如果慢查询分析这个场景想从 demo 往前走,我觉得它至少不能只是一段 Prompt。
它应该开始有一个基本的工程形态。
这里我不再把它命名成 slow-query-skill,而是更倾向于把它看成一个场景化能力包。
能力包不是一个更大的 Skill。它更像是把 SOP + Plan 模板 + Action 定义 + Skill 实现 + 样例 + 测试 放在一起的交付形态:
├── sop.yaml # 慢查询分析处理模板
├── plan_template.yaml # 分步计划模板
├── actions/
│ ├── parse_sql.yaml # 标准动作定义
│ ├── read_schema.yaml
│ ├── read_indexes.yaml
│ ├── analyze_explain.yaml
│ └── generate_advice.yaml
├── skills/
│ ├── read_indexes/ # Action 背后的执行实现
│ └── analyze_explain/
├── prompts/
│ └── advice_format.md # 建议输出格式约束
├── examples/
│ ├── input.json # 输入样例
│ └── output.json # 输出样例
└── tests/
└── slow_query_cases.md # 典型慢查询样例
这个目录不复杂。但它传递了一个关键变化:
这里面最关键的不是文件数量,而是这些问题被显式写出来了:
• 这个场景适合处理什么问题?
• 它会走哪套 SOP?
• 本次执行会生成什么 Plan?
• 每一步对应什么 Action?
• 每个 Action 由哪个 Skill / Executor 实现?
• 每个 Skill / Executor 需要哪些输入?
• 每个 Skill / Executor 不能做哪些动作?
• 失败时应该怎么降级?
一旦这些问题没有被写清楚,它就很容易停留在 demo 状态。看起来能用,但每次用出来的结果都不太一样。
如果真要落地,我会从一个最小 Action 开始
如果真要把这件事落地,我不会一上来就做一个完整的"慢查询分析 Skill"。
因为这个粒度太大。它里面有 SOP、有计划、有步骤、有动作、有判断,也有人要参与复核。
更稳的方式,是先选一个最小 Action。
比如:
这个 Action 只做一件事:解析执行计划,提取关键特征,输出初步风险判断。
它的输入可以先定义成:
"db_type": "mysql",
"sql_summary": {
"tables": ["orders"],
"filters": ["user_id = ?"],
"order_by": ["created_at desc"],
"limit": 20
},
"indexes": [
"PRIMARY KEY (id)",
"KEY idx_user_id (user_id)"
],
"explain": {
"type": "ref",
"key": "idx_user_id",
"rows": 120000,
"extra": "Using where; Using filesort"
}
}
输出可以先固定为:
"action": "analyze_explain",
"problem_type": "possible_sort_cost",
"evidence": [
"执行计划 key = idx_user_id",
"执行计划 rows = 120000",
"Extra 包含 Using filesort"
],
"risk_boundary": [
"当前信息不足以直接建议创建索引",
"需要结合数据分布、查询频率和写入压力判断"
],
"confidence": "medium",
"human_review_required": true
}
然后再补四件事:
• 权限:默认只读,不允许 DDL / DML
• 样例:准备成功样例、信息缺失样例、证据冲突样例、超时样例
• 失败策略:拿不到执行计划时,不生成确定结论
• 挂回流程:让慢查询 SOP 的某个 Step 调用这个 Action
这样做的好处是,它不需要一开始就把整个慢查询分析流程做完。
先把一个最小 Action 做稳,再逐步补 parse_sql、read_schema、read_indexes、generate_advice。
多个 Action 稳了之后,再回到 SOP 和 Plan 层做编排。
Skill / Executor 的四条基本法
一个 Skill / Executor 要从 demo 走向可用,第一层要补的不是 Prompt 技巧,而是工程化底盘。
我现在会先看四条。

第一条,不是简单地说"所有 Skill 都只能只读"。
更准确的说法是:
比如慢查询分析里的这些原子能力:
• parse_sql
• read_schema
• read_indexes
• analyze_explain
• generate_advice
它们本质上都属于分析型或采集型能力。
它们可以:
• 解析 SQL
• 查询表结构
• 读取现有索引
• 分析执行计划
• 输出初步建议
但它们不应该默认:
• 修改数据
• 执行 DDL
• 创建索引
• 修改数据库参数
• 自动创建或修改其他 Skill
未来如果进入 DB Agent、自愈或者变更执行类场景,确实可能会出现"写权限"或"操作权限"。但那已经不是普通分析型 Skill 的默认权限,而应该进入更高风险等级的动作体系。
比如:
• 需要显式授权
• 需要审批流
• 需要审计日志
• 需要回滚路径
• 需要执行前预览
• 需要失败后的复盘能力
所以我会把数据库动作分成三层:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
权限必须显式放开,不能默认拥有。
一个最小权限配置,大概可以长这样:
version: 0.1.0
type: action_skill
mode: readonly
risk_level: low
allowed_actions:
– read_indexes
– read_metadata
blocked_actions:
– execute_dml
– execute_ddl
– create_index
– drop_index
– change_parameter
limits:
timeout_seconds: 30
network_access: false
这段配置里,最重要的不是 readonly 这个词本身。而是它背后的原则:
对数据库来说,"分析"和"执行"不是一个风险等级。
分析慢一点,最多是效率问题。执行错了,可能就是生产事故。
Skill / Executor 不应该直接裸跑。它至少应该运行在一个可控环境里:
• 文件系统范围可控
• 网络访问可控
• 脚本资源使用可控
• 执行时长可控
• 出错后可中断
• 失败后可回收
沙箱的意义不只是安全。它还意味着你能限制它能看到什么、能改什么、能跑多久,也能在异常时把它停下来。
对数据库 Skill / Executor 来说,这一点尤其重要。因为数据库运维里很多动作不是简单的"对"或"错",而是有风险级别的。
我现在越来越不愿意把 Skill / Executor 看成一次性生成物。
比如用 Claude Code 写一个能力,比较合理的方式不应该是:
更稳的方式应该是:
• 按统一规范编写
• 有明确的约束文档,比如 CLAUDE.md
• 通过 Git 管理版本
• 通过评审或审批确认边界
• 审批后再迁移到执行平台
• 变更要有记录
• 回退要有路径
这听起来比 demo 阶段重一些。但如果这些 Skill / Executor 未来要被反复调用,甚至成为 Agent 编排的一部分,这一步迟早绕不过去。
它们不是一次性脚本。它们可能影响后续诊断结论,也可能被多个 SOP 复用。
一个 Skill / Executor 写完之后,也不应该直接扩大范围使用。
更稳的路径应该是:
本地验证 → 沙箱运行 → 测试环境验证 → 小范围灰度 → 逐步扩大使用范围
这和传统系统发布没什么本质区别。只是过去我们发布的是代码、脚本、配置。现在发布的是一种"可被 AI 调用的能力"。
越是这样,越不能一步到位。
尤其在数据库场景里,哪怕只是分析型 Skill / Executor,也会影响人的判断。如果输出不稳定、建议过度、边界不清,就可能影响后续决策。
实现质量:怎样才算写得好
前面讲的是工程化底盘。但一个 Skill / Executor 真正好不好,还要看它本身的实现质量。
这里我不想展开太多 Prompt 技巧,而是只看五个问题。
demo 里,我们经常直接贴一条 SQL。但可用的分析流程,不能只接收一段 SQL。
更准确地说,每个 Skill / Executor 都应该知道自己拿到的上下文是什么。
比如 analyze_explain 这个能力,输入至少要包含:
"db_type": "mysql",
"action": "analyze_explain",
"sql": "select * from orders where user_id = ? order by created_at desc limit 20",
"schema": {
"table": "orders",
"columns": ["id", "user_id", "status", "created_at", "amount"]
},
"indexes": [
"PRIMARY KEY (id)",
"KEY idx_user_id (user_id)"
],
"explain": {
"type": "ref",
"key": "idx_user_id",
"rows": 120000,
"extra": "Using where; Using filesort"
}
}
有了这些信息,它才能做更稳定的判断。
它可以知道 SQL 过滤条件是 user_id,当前只命中了 idx_user_id,扫描行数偏大,排序阶段出现了 Using filesort。
但即使这样,它也不能直接给出"应该建索引"的结论。因为还缺少数据分布、查询频率、写入压力、索引冗余等信息。
所以更合理的表达应该是:
输入设计的价值,不是让格式更好看。而是让它知道自己掌握了哪些证据,又缺了哪些证据。
一个 Skill / Executor 不能一口气做太多事。
如果一个能力同时负责查 SQL、查索引、看监控、做诊断、给建议、生成脚本、执行修复,那它看起来很强,但边界会很乱。
更好的方式,是让每一步都有明确目标。
比如慢查询分析的前处理,可以拆成:
1. parse_sql:识别 SQL 涉及的表、字段和条件
2. read_schema:查询表结构
3. read_indexes:查询现有索引
4. analyze_explain:解析执行计划并提取关键特征
5. generate_advice:生成初步建议和风险边界
每一步都应该能单独验证。
这比"一口气让 AI 分析一下"要稳定得多。
很多 AI 分析结果的问题,是写得很完整,但不好复用。
一大段自然语言,看起来像报告。但如果后面要进入审批、复核、工单、知识库,结构就不够清楚。
我更希望 generate_advice 这类能力输出类似这样的结果:
"problem_type": "possible_missing_composite_index",
"summary": "当前 SQL 命中了 user_id 索引,但排序阶段出现 filesort,扫描行数偏大。",
"evidence": [
"执行计划 key = idx_user_id",
"执行计划 rows = 120000",
"Extra 包含 Using filesort",
"SQL 同时包含 user_id 条件和 created_at 排序"
],
"recommendation": {
"type": "index_review",
"content": "可以评估联合索引 (user_id, created_at) 是否适合该查询模式。",
"risk": "需要结合写入频率、索引选择性和现有索引冗余情况判断。"
},
"confidence": "medium",
"human_review_required": true
}
这里我最关心的不是 JSON 本身。而是输出里必须拆开几件事:
• 问题类型是什么
• 证据是什么
• 建议是什么
• 风险是什么
• 置信度如何
• 是否需要人工确认
这样它才不会把"方向性建议"包装成"最终结论"。
建议层很容易把话说得太满。
比如看到全表扫描,就直接建议加索引。看到扫描行数很大,就直接判断 SQL 有问题。看到连接数偏高,就输出一堆泛泛的优化建议。
这些建议不一定错,但可能不够聚焦,也可能越过了能力单元应该承担的边界。
所以我更倾向于让它输出"初步建议",而不是"最终判断"。
它可以说:
• 可能的问题是什么
• 依据是什么
• 建议方向是什么
• 风险边界是什么
• 置信度如何
但最终要不要执行,仍然需要人判断。
建议不是越多越好,而是越聚焦越有价值。
一个 Skill / Executor 是否可用,不只看它成功时表现如何。更要看它信息不足、执行失败、上下文过长、步骤超时时会不会乱说。
我觉得数据库类能力至少要提前写清楚这些失败策略:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这张表看起来简单,但它决定了能力单元的可信度。
因为真实环境里,信息不完整是常态。
一个不成熟的能力,会在信息不足时继续生成答案。
一个更成熟的能力,应该明确告诉你:
这句话不炫技。但它对数据库工作很重要。
所以,一个能力单元写得好不好,不看它写了多少,而看它的输入、边界、输出和可追溯性是不是稳定。
为什么能跑起来,不等于已经可用
到这里,其实可以回到最开始那个问题。
为什么一个能跑起来的能力单元,不等于它已经可用?
因为它们解决的是两类问题。
demo 关注的是:
• 流程通不通
• 能不能跑
• 能不能出结果
• 能不能验证想法
可用关注的是:
• 有没有边界
• 有没有约束
• 有没有审计
• 有没有灰度
• 有没有一致输出
• 能不能长期维护
这两者不是一个层级。
一个能跑起来的能力单元,解决的是"有没有"。一个可用的能力单元,解决的是"能不能长期可信地用"。
所以我现在越来越不愿意把 Skill 看成一个 Prompt。
Prompt 只是 Skill 里面的一部分。
如果一个能力单元要进入数据库工作流,它就必须被当成一个小型工程交付物来看。
它可以很轻。但不能没有边界。
它可以先只做辅助分析。但必须说清楚自己不能做什么。
它可以给建议。但必须把证据、风险和置信度一起交代清楚。

写在最后
第二篇证明的是:
慢查询分析这个场景,可以被拆解成一组可复用的 Action,再由对应的 Skill / Executor 承接。
这篇想补的是:
它要真正变成一个可长期使用的能力体系,还要补哪些工程化基础。
从 demo 到可用,不只是补功能。更重要的是补:
• 粒度边界
• 权限边界
• 运行隔离
• 输入输出
• 失败策略
• 版本管理
• 审批灰度
• 可追溯性
只有当单个 Action 的定义清楚、单个 Skill / Executor 的边界、输入输出和发布机制先站住,后面谈 SOP 编排、多个 Skill 协同,才不会变成另一种失控。
所以第三篇其实不是绕开了 DB Agent。而是在补它前面必须有的一层基础。

