编写 OpenClaw 技能 —— 助手可以调用的可复用工具
如何编写、测试和发布 OpenClaw 技能:类型化工具调用、Shell 命令、HTTP API,以及 agent-skills 注册中心。
OpenClaw 中的技能(skill) 是助手可以调用的小型、类型化工具。技能是从"聊天玩具"走向"真正能做事的 Agent"的关键——它能拉取日历事件、提交 PR、发消息、执行脚本。本教程带你从零编写、测试、发布自己的技能。
技能长什么样
一个技能就是一个包含两个文件的文件夹:
my-skill/
├── skill.yaml # 名称、说明、参数定义
└── handler.ts # 被调用时执行的 TypeScript
sheet.yaml 是契约——LLM 通过它决定何时调用你的技能;handler.ts 是实现。
一个最小可用的技能
创建文件夹:
mkdir -p ~/.openclaw/skills/greet
cd ~/.openclaw/skills/greet
写 skill.yaml:
name: greet
description: |
用指定语言向一个人打招呼。
用于用户希望发送简短问候的场景
(例如"用德语跟 Anna 打个招呼")。
parameters:
type: object
required: [name, language]
properties:
name:
type: string
description: 对方的名字
language:
type: string
enum: [en, de, zh, ja]
写 handler.ts:
import type { SkillContext } from "openclaw/sdk";
const greetings: Record = {
en: "Hello, {name}!",
de: "Hallo, {name}!",
zh: "{name},你好!",
ja: "こんにちは、{name}さん!",
};
export default async function greet(
input: { name: string; language: string },
ctx: SkillContext
) {
const template = greetings[input.language] ?? greetings.en;
const message = template.replace("{name}", input.name);
ctx.log.info(`greet → ${message}`);
return { message };
}
重新加载 Gateway 以便它发现新技能:
openclaw skills reload greet
现在对助手发消息:
用德语跟 Anna 打个招呼
助手会调用你写的 greet 技能,回复 Hallo, Anna!。
调用 HTTP API
技能非常适合包装第三方 API。下面是一个查询天气的技能:
name: weather
description: |
查询指定城市的当前天气。用于用户问
"X 城市天气怎么样"之类的场景。
parameters:
type: object
required: [city]
properties:
city: { type: string }
export default async function weather(
{ city }: { city: string },
ctx: SkillContext
) {
const url = `https://wttr.in/${encodeURIComponent(city)}?format=j1`;
const res = await fetch(url);
if (!res.ok) {
throw new Error(`weather: ${res.status} ${res.statusText}`);
}
const data = await res.json();
const cur = data.current_condition[0];
return {
city,
temperature_c: Number(cur.temp_C),
feels_like_c: Number(cur.FeelsLikeC),
description: cur.weatherDesc[0].value,
};
}
Gateway 会自动重试瞬时错误、把类型化异常暴露给 LLM,并把返回值纳入回复上下文。
调用 Shell 命令
需要触碰本地文件系统或运行某个二进制的技能,可以使用沙箱化的 shell:
import { sh } from "openclaw/shell";
export default async function listDownloads(_: unknown, ctx: SkillContext) {
const out = await sh("ls -lh ~/Downloads", { cwd: process.env.HOME });
return { files: out.stdout };
}
shell 在文件系统沙箱中运行。默认能读取 ~/Documents、~/Downloads、~/Desktop、~/.openclaw。要访问其他路径,必须显式授权:
const out = await sh("git status", { cwd: "~/Code/myapp", allow: ["~/Code/myapp"] });
如果助手试图读取允许列表之外的路径,调用会以清晰的错误失败,而不是默默泄露数据。
与团队共享技能
OpenClaw 自带一个 agent-skills 仓库(github.com/openclaw/agent-skills),里面是经过整理的"标准技能"。如果你写的技能对其他人也有用,发布流程是:
openclaw skills publish greet
该命令会:
- 把文件夹打包成 tarball;
- 计算内容哈希;
- 推送到 ClawHub(社区技能注册中心 clawhub.ai);
- 返回一个可以在聊天里粘贴的永久 URL:
https://clawhub.ai/skills/greet@1.0.2
安装别人的技能:
openclaw skills install https://clawhub.ai/skills/weather@1.4.0
用 Lobster 组合技能
Lobster 是 OpenClaw 原生的工作流 shell,能把技能和 CLI 工具组合成类型化的、本地优先的流水线。下面是一个简单的 Lobster 配方,把多个技能串成一个"早间简报":
# ~/.openclaw/lobster/morning-briefing.yaml
name: morning-briefing
steps:
- skill: weather
args: { city: "Vienna" }
- skill: calendar.today
- skill: inbox.unread
args: { limit: 5 }
按定时任务运行:
openclaw cron add \\
--name "morning briefing" \\
--at "0 7 * * *" \\
--lobster ~/.openclaw/lobster/morning-briefing.yaml
每天早上 7 点,助手会拉取天气、日程、未读邮件,再发一条 Telegram 消息给你汇总。
测试技能
SDK 自带一个轻量测试框架:
import greet from "./handler";
import { test } from "openclaw/test";
test("greet 返回德语模板", async ({ run }) => {
const out = await run(greet, { name: "Anna", language: "de" });
expect(out.message).toBe("Hallo, Anna!");
});
openclaw skills test greet
下一步
发现问题或需要更正? 联系我们.