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 最佳实践