乐于分享
好东西不私藏

写一个OpenClaw自定义Skill——从设计到落地的完整指南

写一个OpenClaw自定义Skill——从设计到落地的完整指南

前言

上个月有读者问我:”13个技能不够用怎么办?我想让 AI 查一下公司内部的数据库,但 OpenClaw 没有这个技能。”

答案是:自己写一个。

OpenClaw 的 Skill 体系设计得很克制——它不内置所有功能,而是给你一个扩展接口。任何一个能力,只要你能写成 Skill,AI 就能用。

这篇从设计理念讲到实现细节,再讲到发布和踩坑。目标是让你看完之后,能自己写出第一个 Skill。

(文章末尾附一个可以直接用的 MySQL 查询 Skill 模板。)

一、Skill 的设计哲学

在看代码之前,先理解 Skill 是什么、不是什么。

Skill 是什么

Skill 是 AI 能力的”最小可控单元”。

不是函数(Function),不是工具(Tool),不是插件(Plugin)。它的核心设计是:给 AI 一个明确的、可独立调用的能力边界。

每个 Skill 做一件事,且只做一件事。比如:

  • file skill → 读写文件
  • exec skill → 执行命令
  • web-search skill → 联网搜索

不能有一个”全能 Skill”既读文件又执行命令——那样 AI 的行为边界就模糊了。

为什么不直接用 Function Calling

你可能会问:OpenAI 的 Function Calling 也能做类似的事,为什么 OpenClaw 要搞一套自己的?

维度 OpenAI Function Calling OpenClaw Skill
定义方式 JSON Schema Markdown 文档
AI 如何调用 解析 JSON Schema 理解 Markdown 描述
能力边界 每个 function 是一个 API 每个 skill 是一个独立模块
配置复杂度
是否需要写代码 需要6 可选

核心区别:Function Calling 要求你写严格的 JSON Schema(字段类型、枚举值、必填/可选),而 Skill 只需要写一份 Markdown 文档告诉 AI”你能做什么、怎么用”。

OpenClaw 选择的路径是:让 AI 理解你的意图,而不是让你去适应 AI 的接口。

什么时候该写一个 Skill

  • OpenClaw 内置的 13 个技能覆盖不了你的需求
  • 你想让 AI 操作一个特定的外部系统(数据库、企业内部 API)
  • 你想把重复操作封装成一个可复用的能力

如果只是简单问几个问题,不需要写 Skill——直接用对话就行。

二、Skill 的结构

一个 Skill 本质上是一个文件夹,包含以下文件:

my-skill/
├── SKILL.md       # 技能描述(必须)
├── README.md      # 使用说明(推荐)
├── config.json    # 配置参数(可选)
└── 其他资源文件    # 按需

核心文件是 SKILL.md。AI 通过读这个文件来理解 Skill 能做什么、怎么调用。

三、写一个 MySQL 查询 Skill

从需求出发:我想让 AI 能查我的 MySQL 数据库。

Step 1:确定能力边界

这个 Skill 能做什么、不能做什么:

能做:

  • 执行 SELECT 查询
  • 查看表结构(DESCRIBE)
  • 返回查询结果(最多 100 行)

不能做:

  • 执行 INSERT/UPDATE/DELETE
  • 修改数据库结构
  • 删除数据
  • 访问环境变量中的密码以外的文件

这些约束写在 SKILL.md 里。如果 AI 试图执行不允许的操作,Skill 会拒绝。

Step 2:写 SKILL.md

---
name: mysql-query
description: 查询 MySQL 数据库
---


# MySQL 查询工具

## 能力范围

- 执行 SELECT 语句读取数据
- 查看表结构
- 返回结果最多 100 行
- 查询超时 10 秒

## 不允许的操作

- INSERT / UPDATE / DELETE
- DROP / ALTER / CREATE
- 跨库查询
- 执行存储过程

## 使用方式

当用户需要查询数据库时,生成对应的 SQL 并调用此工具。

## 示例

用户:"查一下 users 表有多少人"
AI:SELECT COUNT(*) FROM users

这份文档就是 AI 理解这个 Skill 的说明书。越详细,AI 调用越准确。

Step 3:实现执行逻辑

SKILL.md 描述了”AI 能做什么”,还需要一个执行引擎来”真正去做”。

Skill 的执行逻辑用 Node.js 写:

// index.js
export default async function execute({ query, params }) {
  const mysql = require('mysql2/promise')
  const connection = await mysql.createConnection({
    host: process.env.MYSQL_HOST,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DATABASE,
  })
  
  try {
    const [rows] = await connection.execute(query, params || [])
    return { successtruedata: rows.slice(0100), rowCount: rows.length }
  } catch (error) {
    return { successfalseerror: error.message }
  } finally {
    await connection.end()
  }
}

关键设计:返回结构化数据而非原始输出。AI 读结构化数据比读原始控制台输出快得多。

Step 4:配置

{
  "skills": {
    "custom": "~/my-skill"
  }
}

重启 Gateway 后生效:

supervisorctl restart openclaw-gateway

Step 5:测试

"查一下 users 表有几个用户"
→ AI 应该调用 mysql-query skill
→ 返回用户总数
→ AI 用自然语言回复你

四、踩坑记录

踩坑1:SKILL.md 写得太简单,AI 调用不准确

第一次只写了 3 行描述,结果 AI 把 MySQL 查询技能用成了文件读取——它以为”查询”可以是任何东西。

解决: SKILL.md 必须写清楚”能做什么”和”不能做什么”。能力范围越精确,AI 调用越准确。

踩坑2:环境变量泄漏

在代码里写死了数据库密码,差点提交到 GitHub。

解决: 用环境变量引用,密码写在 .env 里,不进入git。

password: process.env.MYSQL_PASSWORD

踩坑3:没有限制查询时间

某次 AI 跑了一个全表 JOIN,查询跑了 3 分钟才超时。

解决: 在代码里加上查询超时:

const connection = await mysql.createConnection({ ... })
await connection.query('SET max_execution_time = 10000')  // 10秒超时

踩坑4:多个 Skill 的上下文冲突

AI 同时调用了 mysql-query 和 file skill,结果把查询结果写到了文件里——不是我想要的。

解决: 在 SKILL.md 里明确”这个 Skill 不负责写文件”,或者在 Agent 配置里让这两个 Skill 分给不同的 Agent:

{
  "agents": {
    "analyst": { "skills": ["mysql-query"] },
    "operator": { "skills": ["file", "exec"] }
  }
}

五、对比:自定义 Skill vs 其他扩展方式

维度 自定义 Skill 写一个插件 用 MCP Server
复杂度 低(写一个文件) 中(npm包结构) 中(要写Server)
灵活性
可复用 当前实例 可发布到社区 跨平台兼容
适用场景 快速验证一个能力 分享给其他人用 多个平台共用

如果只是自己用,写 Skill 最快。如果要分享给别人,封装成插件。如果要兼容 OpenAI/Anthropic 等多个平台,走 MCP。

六、什么时候不该写 Skill

不是所有能力都值得封装成 Skill。

两条判断标准:

1. AI 直接做比写 Skill 更好

有些事 AI 直接用对话就能完成——”写一封邮件”不需要 Skill,让 AI 在对话里生成邮件内容就行。

2. 需要 AI 独立操作外部系统时,才值得写 Skill

  • 操作数据库 → ✅ 写 Skill
  • 调用企业内部 API → ✅ 写 Skill
  • 读文件 → ❌ 内置 file skill 就够了
  • 写邮件 → ❌ 对话生成内容就够了

七、锐度:Skill 体系设计得好不好

OpenClaw 的 Skill 体系有一个值得讨论的取舍——它的设计哲学是”AI 理解人类语言描述”,而不是”人适应机器接口”。

这个选择的好处是上手快(不需要学 JSON Schema),代价是长尾场景的精确性不如 Function Calling。

对于 80% 的场景,Skill 的 Markdown 描述足够精确了。如果你刚好在另外 20%,可以在 SKILL.md 里写更详细的约束,或者考虑用 MCP 协议做精确控制。

彩蛋:一个可直接使用的 Skill 模板

说好的彩蛋。一份可以直接用的 Skill 项目结构:

mkdir -p ~/.agents/skills/mysql-query
cd ~/.agents/skills/mysql-query

# 创建 package.json
cat > package.json << 'EOF'
{
  "name""mysql-query",
  "version""1.0.0",
  "main""index.js"
}
EOF

# 创建 .env
cat > .env << 'EOF'
MYSQL_HOST=localhost
MYSQL_USER=root
MYSQL_PASSWORD=your_password_here
MYSQL_DATABASE=your_database
EOF

# 创建 index.js(见上文代码)
# 创建 SKILL.md(见上文内容)

# 测试
node -e "const s = require('./index.js'); s.execute({query:'SELECT 1'}).then(console.log)"

配置到 OpenClaw 只需要一行:

{ "skills": { "custom": "~/.agents/skills/mysql-query" } }

重启即生效。

总结

写一个自定义 Skill 只需要三步:

  1. 确定能力边界——这个 Skill 能做什么、不能做什么
  2. 写 SKILL.md——告诉 AI 怎么用
  3. 实现执行逻辑——用 Node.js 写具体的操作逻辑

最难的不是写代码,是定义清楚”AI 能做什么、不能做什么”。边界越清晰,AI 的表现越可控。

你现在有需要自己写 Skill 的场景吗?你有需要自己写Skill的场景吗?

觉得有用?点个「在看」👇