OpenClaw 技能系统完全指南:扩展 AI 的能力边界
OpenClaw 技能系统完全指南:扩展 AI 的能力边界
技能(Skills)是 OpenClaw 最强大的功能之一,它让 AI 不再局限于聊天,而是能够执行实际任务、集成外部服务、自动化工作流程。本文将深入讲解 OpenClaw 的技能系统,从基础概念到高级应用,帮助你构建强大的自定义技能。
什么是 OpenClaw 技能?
OpenClaw 技能是可插拔的功能模块,赋予 AI 执行特定任务的能力。每个技能就像一个"工具",AI 可以根据用户需求调用相应的技能来完成任务。
技能的核心价值
- 功能扩展:让 AI 能够执行各种具体任务
- 模块化:独立的技能可复用、可组合
- 可定制:根据需求自定义技能行为
- 生态丰富:社区贡献的技能不断丰富功能
技能架构
技能目录结构
skills/
├── my-skill/
│ ├── skill.yaml # 技能配置
│ ├── index.js # 技能入口
│ ├── utils/ # 工具函数
│ ├── handlers/ # 事件处理
│ └── tests/ # 测试文件
├── another-skill/
│ └── ...
└── package.json # NPM 包配置(可选)
技能配置文件
每个技能需要 skill.yaml 定义:
# skill.yaml
name: "weather" # 技能名称
version: "1.0.0" # 版本号
description: "查询城市天气信息" # 技能描述
# 触发条件
triggers:
# 关键词触发
- "天气"
- "weather"
- "查询天气"
# 正则表达式触发
patterns:
- "^天气\\s*(.+)$"
- "^weather\\s+(.+)$"
# 输入参数
parameters:
- name: "city"
type: "string"
required: true
description: "城市名称"
default: "北京"
- name: "units"
type: "string"
required: false
description: "温度单位"
default: "celsius"
options:
- "celsius"
- "fahrenheit"
# 输出格式
output:
type: "text"
template: "{city}今天天气{condition},温度{temperature}°C"
# 依赖
dependencies:
- axios
- dotenv
创建你的第一个技能
步骤 1:创建技能目录
mkdir -p skills/my-first-skill
cd skills/my-first-skill
步骤 2:编写技能配置
# skill.yaml
name: "my-first-skill"
version: "1.0.0"
description: "我的第一个技能"
triggers:
- "你好"
- "hello"
- "打招呼"
parameters: []
output:
type: "text"
步骤 3:编写技能逻辑
// index.js
module.exports = {
name: 'my-first-skill',
// 技能描述
description: '一个简单的打招呼技能',
// 执行函数
async execute(params, context) {
// params: 用户输入的参数
// context: 上下文信息
const hour = new Date().getHours();
let greeting;
if (hour < 12) {
greeting = '早上好';
} else if (hour < 18) {
greeting = '下午好';
} else {
greeting = '晚上好';
}
const username = context.user?.name || '朋友';
return {
type: 'text',
content: `${greeting},${username}!很高兴见到你!`
};
},
// 可选:验证函数
validate(params) {
return true;
},
// 可选:初始化函数
async init(config) {
console.log('技能初始化完成');
},
// 可选:清理函数
async destroy() {
console.log('技能销毁');
}
};
步骤 4:注册技能
在 config/skills.yaml 中:
skills:
- path: "./skills/my-first-skill"
enabled: true
技能开发进阶
1. 带参数的技能
module.exports = {
name: 'calculator',
async execute(params, context) {
const { operation, a, b } = params;
let result;
switch (operation) {
case 'add':
result = a + b;
break;
case 'subtract':
result = a - b;
break;
case 'multiply':
result = a * b;
break;
case 'divide':
if (b === 0) {
return { type: 'text', content: '除数不能为零!' };
}
result = a / b;
break;
default:
return { type: 'text', content: '不支持的操作' };
}
return {
type: 'text',
content: `计算结果:${a} ${operation} ${b} = ${result}`
};
}
};
对应配置:
parameters:
- name: "operation"
type: "string"
required: true
options:
- "add"
- "subtract"
- "multiply"
- "divide"
- name: "a"
type: "number"
required: true
- name: "b"
type: "number"
required: true
2. 调用外部 API
const axios = require('axios');
module.exports = {
name: 'weather',
async execute(params, context) {
const { city, units = 'celsius' } = params;
try {
const response = await axios.get(
`https://api.weather.example.com/v1/current`,
{
params: {
city,
units,
apiKey: process.env.WEATHER_API_KEY
}
}
);
const { condition, temperature, humidity, wind } = response.data;
return {
type: 'text',
content: `【${city}】\n天气:${condition}\n温度:${temperature}°${units === 'celsius' ? 'C' : 'F'}\n湿度:${humidity}%\n风速:${wind}km/h`
};
} catch (error) {
return {
type: 'text',
content: `抱歉,无法获取 ${city} 的天气信息。错误:${error.message}`
};
}
}
};
3. 使用记忆功能
module.exports = {
name: 'preference-setter',
async execute(params, context) {
const { key, value } = params;
const userId = context.user?.id;
if (!userId) {
return { type: 'text', content: '无法识别用户' };
}
// 存储到记忆系统
const memoryKey = `preference:${userId}:${key}`;
await context.memory.set(memoryKey, value);
return {
type: 'text',
content: `已记住您的偏好:${key} = ${value}`
};
}
};
module.exports.getPreference = {
name: 'preference-getter',
async execute(params, context) {
const { key } = params;
const userId = context.user?.id;
const memoryKey = `preference:${userId}:${key}`;
const value = await context.memory.get(memoryKey);
if (value) {
return { type: 'text', content: `您的 ${key} 偏好是:${value}` };
} else {
return { type: 'text', content: `您还没有设置 ${key} 偏好` };
}
}
};
4. 异步任务
module.exports = {
name: 'long-task',
// 支持异步长时间运行任务
async execute(params, context) {
const { taskId } = params;
// 立即返回进度
context.notifier.notify('任务已开始...');
// 后台执行耗时任务
const task = async () => {
try {
// 模拟耗时操作
for (let i = 0; i < 10; i++) {
await new Promise(r => setTimeout(r, 1000));
context.notifier.notify(`进度:${(i+1)*10}%`);
}
// 完成任务
context.notifier.notify('任务完成!');
} catch (error) {
context.notifier.notify(`任务失败:${error.message}`);
}
};
// 启动后台任务
task();
return {
type: 'text',
content: `任务 ${taskId} 已启动,请在后台查看进度`
};
}
};
技能组合与工作流
1. 技能组合
多个技能可以组合使用:
skills:
- path: "./skills/search"
enabled: true
- path: "./skills/summarize"
enabled: true
- path: "./skills/translate"
enabled: true
工作流示例:搜索 → 摘要 → 翻译
2. 技能链
// skills/workflow/index.js
module.exports = {
name: 'research-assistant',
async execute(params, context) {
const { topic, targetLanguage = 'zh' } = params;
// 步骤 1:搜索
const searchResult = await context.callSkill('search', {
query: topic,
limit: 10
});
// 步骤 2:摘要
const summaryResult = await context.callSkill('summarize', {
content: searchResult.content,
maxLength: 500
});
// 步骤 3:翻译
if (targetLanguage !== 'en') {
const translateResult = await context.callSkill('translate', {
text: summaryResult.content,
to: targetLanguage
});
return translateResult;
}
return summaryResult;
}
};
技能市场与分享
发布技能到社区
{
"name": "@your-org/awesome-skill",
"version": "1.0.0",
"openclaw": {
"skill": {
"name": "awesome-skill",
"description": "一个很棒的技能",
"author": "your-org",
"tags": ["utility", "productivity"]
}
}
}
使用社区技能
skills:
- package: "@openclaw/weather"
version: "^1.0.0"
enabled: true
- package: "@openclaw/search"
version: "^2.0.0"
enabled: true
技能开发最佳实践
1. 错误处理
module.exports = {
name: 'my-skill',
async execute(params, context) {
try {
// 业务逻辑
return { type: 'text', content: '成功' };
} catch (error) {
// 记录日志
context.logger.error('Skill error', { error: error.message });
// 返回友好的错误信息
return {
type: 'text',
content: '抱歉,处理您的请求时出现问题。请稍后重试。'
};
}
}
};
2. 输入验证
module.exports = {
name: 'validate-skill',
async execute(params, context) {
// 参数验证
if (!params.email || !isValidEmail(params.email)) {
return {
type: 'text',
content: '请提供有效的邮箱地址'
};
}
if (!params.age || params.age < 0 || params.age > 150) {
return {
type: 'text',
content: '请提供有效的年龄'
};
}
// 验证通过后继续
}
};
3. 日志记录
module.exports = {
name: 'logged-skill',
async execute(params, context) {
const startTime = Date.now();
context.logger.info('Skill started', {
params,
userId: context.user?.id
});
// 业务逻辑
context.logger.info('Skill completed', {
duration: Date.now() - startTime
});
}
};
4. 单元测试
// tests/my-skill.test.js
const mySkill = require('../index');
describe('my-skill', () => {
test('should return greeting', async () => {
const result = await mySkill.execute(
{},
{ user: { name: 'Test' } }
);
expect(result.type).toBe('text');
expect(result.content).toContain('Test');
});
});
常见问题
问题 1:技能不触发
检查:
- 触发词是否在 triggers 中
- 正则表达式是否正确
- 技能是否在 config/skills.yaml 中启用
- 插件是否正确加载
问题 2:参数解析错误
检查: - YAML 配置的参数名与代码中是否一致 - 参数类型是否正确 - 必填参数是否提供
问题 3:技能执行超时
解决方案: - 优化技能执行逻辑 - 增加超时配置 - 使用异步任务
问题 4:依赖安装失败
解决方案: - 检查 package.json - 手动安装依赖 - 检查网络连接
总结
OpenClaw 的技能系统是扩展 AI 能力的核心机制。通过本文,你应该已经掌握了:
- ✅ 技能的基本概念和架构
- ✅ 创建和注册新技能
- ✅ 处理参数和外部 API 调用
- ✅ 技能组合与工作流
- ✅ 最佳实践和错误处理
技能系统让 OpenClaw 不仅仅是一个聊天工具,而是一个真正能够执行任务的智能助手。发挥你的创造力,构建强大的自定义技能吧!
相关阅读: - OpenClaw 技能开发进阶 - OpenClaw 定时任务 - OpenClaw 自动化工作流 - OpenClaw 最佳实践