从零开始构建自定义 AI 技能 - OpenClaw Skill 开发教程
手把手教你开发 OpenClaw AgentSkill,包括技能结构、工具调用、状态管理、测试调试等完整流程,让你的 AI 助手拥有专属能力。
·
从零开始构建自定义 AI 技能 - OpenClaw Skill 开发教程
一、什么是 OpenClaw Skill?
OpenClaw Skill 是扩展 AI 助手能力的模块化组件。通过 Skill,你可以让 AI 执行特定任务,如:
- 查询天气
- 管理待办事项
- 操作智能家居
- 发布博客文章
- 处理发票验证
核心优势:
- 模块化设计,易于复用
- 标准化接口,快速集成
- 支持工具调用,连接外部服务
- 内置记忆系统,保持上下文
二、Skill 项目结构
my-skill/
├── SKILL.md # 技能描述和触发规则(必需)
├── index.js # 技能主入口(可选)
├── handlers/ # 处理器目录
│ ├── weather.js # 天气处理
│ └── todo.js # 待办处理
├── tools/ # 自定义工具
│ └── api-client.js # API 客户端
├── templates/ # 响应模板
└── tests/ # 测试文件
SKILL.md 标准格式
# Skill Name
## Description
简短描述技能功能
## Triggers
- 当用户询问天气时
- 当用户说"明天会下雨吗"
- 当用户提到城市名 + 天气
## Tools Required
- web_search (可选)
- 自定义工具名
## Configuration
- API_KEY: 环境变量
- ENDPOINT: API 地址
三、开发第一个 Skill:待办事项管理器
3.1 创建项目结构
mkdir todo-skill
cd todo-skill
mkdir handlers tools tests
3.2 编写 SKILL.md
# Todo Skill
## Description
管理用户的待办事项,支持添加、删除、完成、列表查询
## Triggers
- 添加待办、新建任务
- 删除待办、完成任务
- 我的待办、任务列表
- 提醒我、记得做
## Tools Required
- file_write (写入本地文件)
- file_read (读取本地文件)
## Configuration
- TODO_FILE: 待办文件路径,默认 ~/todos.json
3.3 实现处理器 (handlers/todo.js)
// handlers/todo.js
const fs = require('fs').promises;
const path = require('path');
const TODO_FILE = process.env.TODO_FILE || path.join(
require('os').homedir(),
'todos.json'
);
async function loadTodos() {
try {
const data = await fs.readFile(TODO_FILE, 'utf-8');
return JSON.parse(data);
} catch (e) {
return { items: [], createdAt: new Date().toISOString() };
}
}
async function saveTodos(todos) {
await fs.writeFile(TODO_FILE, JSON.stringify(todos, null, 2));
}
async function addTodo(text, priority = 'normal') {
const todos = await loadTodos();
const item = {
id: Date.now().toString(),
text,
priority,
completed: false,
createdAt: new Date().toISOString()
};
todos.items.push(item);
await saveTodos(todos);
return item;
}
async function listTodos(filter = 'all') {
const todos = await loadTodos();
switch (filter) {
case 'active':
return todos.items.filter(t => !t.completed);
case 'completed':
return todos.items.filter(t => t.completed);
default:
return todos.items;
}
}
async function completeTodo(id) {
const todos = await loadTodos();
const item = todos.items.find(t => t.id === id);
if (item) {
item.completed = true;
item.completedAt = new Date().toISOString();
await saveTodos(todos);
}
return item;
}
module.exports = {
addTodo,
listTodos,
completeTodo,
loadTodos,
saveTodos
};
3.4 在 SKILL.md 中定义处理逻辑
## Handlers
### add_todo
**Trigger:** 添加/新建 + 任务内容
**Action:** 调用 addTodo(text, priority)
**Response:** "✅ 已添加:{text}"
### list_todos
**Trigger:** 查看/列出 + 待办/任务
**Action:** 调用 listTodos(filter)
**Response:** 格式化列表
### complete_todo
**Trigger:** 完成/做完 + 任务标识
**Action:** 调用 completeTodo(id)
**Response:** "✅ 已完成:{text}"
四、工具调用与外部 API 集成
4.1 使用内置工具
OpenClaw 提供内置工具:
// 在技能中调用工具
const result = await tools.web_search({
query: 'AI 编程助手对比',
count: 5
});
4.2 创建自定义工具
// tools/weather-client.js
class WeatherClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.weather.com/v1';
}
async getCurrent(city) {
const response = await fetch(
`${this.baseUrl}/current?city=${city}&key=${this.apiKey}`
);
return response.json();
}
async getForecast(city, days = 3) {
const response = await fetch(
`${this.baseUrl}/forecast?city=${city}&days=${days}&key=${this.apiKey}`
);
return response.json();
}
}
module.exports = WeatherClient;
五、状态管理与记忆
5.1 短期记忆(会话内)
// 在会话中保持状态
const sessionState = {
currentCity: null,
lastQuery: null,
preferences: {}
};
async function handleWeatherQuery(city) {
sessionState.currentCity = city;
sessionState.lastQuery = new Date().toISOString();
const weather = await weatherClient.getCurrent(city);
return formatResponse(weather, sessionState.preferences);
}
5.2 长期记忆(跨会话)
使用 MEMORY.md 或记忆文件:
async function saveUserPreference(key, value) {
const memory = await loadMemory();
memory.preferences[key] = value;
await saveMemory(memory);
}
async function getUserPreference(key, defaultValue) {
const memory = await loadMemory();
return memory.preferences[key] || defaultValue;
}
六、测试与调试
6.1 单元测试
// tests/todo.test.js
const { addTodo, listTodos, completeTodo } = require('../handlers/todo');
describe('Todo Skill', () => {
test('should add todo', async () => {
const todo = await addTodo('测试任务');
expect(todo.text).toBe('测试任务');
expect(todo.completed).toBe(false);
});
test('should list todos', async () => {
const todos = await listTodos();
expect(Array.isArray(todos)).toBe(true);
});
test('should complete todo', async () => {
const todo = await addTodo('完成任务');
const completed = await completeTodo(todo.id);
expect(completed.completed).toBe(true);
});
});
6.2 集成测试
# 测试技能触发
openclaw skill test todo-skill --trigger "添加一个待办:买牛奶"
七、发布与分享
7.1 本地安装
# 将技能复制到技能目录
cp -r todo-skill ~/.openclaw/skills/
# 重启 Gateway
openclaw gateway restart
7.2 使用 ClawHub 发布
# 安装 clawhub CLI
npm install -g clawhub
# 发布技能
cd todo-skill
clawhub publish --name todo-skill --version 1.0.0
八、最佳实践
8.1 错误处理
async function safeAddTodo(text) {
try {
return await addTodo(text);
} catch (error) {
console.error('添加待办失败:', error);
return {
error: true,
message: '添加失败,请稍后重试',
details: error.message
};
}
}
8.2 日志记录
const logger = {
info: (msg, data) => {
console.log(`[INFO] ${msg}`, JSON.stringify(data));
},
error: (msg, error) => {
console.error(`[ERROR] ${msg}`, error);
}
};
8.3 性能优化
- 缓存频繁读取的数据
- 批量处理多个操作
- 异步执行非阻塞任务
- 限制 API 调用频率
九、总结
Skill 开发流程:
- 定义技能功能和触发条件
- 设计项目结构
- 实现核心处理器
- 集成外部工具/API
- 添加状态管理
- 编写测试
- 发布与部署
核心要点:
- SKILL.md 是技能的"身份证",清晰描述功能和触发规则
- 处理器要单一职责,每个函数只做一件事
- 错误处理要完善,给用户友好的反馈
- 测试要覆盖主要场景,确保稳定性
系列导航:
更多推荐




所有评论(0)