🛠️ Agent Skills 开发指南

发布于 2026-04-14 | 阅读时间 12 分钟

"我把一个 Skill 封装了99次,第100次才明白——最好的 Skill,是让用户忘记 Skill 的存在。"

什么是 Agent Skills?

Agent Skills 是 OpenClaw 的核心概念。你可以把它理解为 Agent 的"超能力插件"——每个 Skill 都是封装好的功能模块,让你的 AI 能执行特定任务。

就像钢铁侠的装甲可以换装不同武器,你的 Agent 也可以通过 Skills 获得网页抓取、文件处理、数据分析、消息推送等各种能力。

核心概念

Skill 的三层结构

my-skill/
├── skill.json          # 技能元信息(名称、描述、依赖)
├── src/
│   └── index.js        # 主逻辑实现
└── schemas/
    ├── input.json      # 输入参数校验
    └── output.json     # 输出结构定义

创建你的第一个 Skill

Step 1: 初始化 Skill 项目

# 使用 CLI 创建 Skill 模板
openclaw skill create my-first-skill

# 或者手动创建目录结构
mkdir -p my-skill/src my-skill/schemas
cd my-skill
npm init -y

Step 2: 编写 skill.json

{
  "name": "web-content-extractor",
  "version": "1.0.0",
  "description": "从网页提取结构化内容",
  "author": "your-name",
  "tags": ["web", "scraping", "content"],
  "dependencies": {
    "cheerio": "^1.0.0"
  },
  "entry": "src/index.js",
  "config": {
    "timeout": {
      "type": "number",
      "default": 30000,
      "description": "请求超时时间(毫秒)"
    }
  }
}

Step 3: 实现核心逻辑

// src/index.js
const cheerio = require('cheerio');

module.exports = class WebExtractor {
  constructor(config) {
    this.timeout = config.timeout || 30000;
  }

  async execute({ url, selector }) {
    try {
      const response = await fetch(url, {
        signal: AbortSignal.timeout(this.timeout)
      });
      
      const html = await response.text();
      const $ = cheerio.load(html);
      
      const content = $(selector).text().trim();
      
      return {
        success: true,
        data: { content, url },
        metadata: {
          length: content.length,
          timestamp: new Date().toISOString()
        }
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
        code: 'EXTRACTION_FAILED'
      };
    }
  }
};

Step 4: 定义输入输出 Schema

// schemas/input.json
{
  "type": "object",
  "required": ["url", "selector"],
  "properties": {
    "url": {
      "type": "string",
      "format": "uri",
      "description": "目标网页 URL"
    },
    "selector": {
      "type": "string",
      "description": "CSS 选择器,用于定位内容"
    }
  }
}

// schemas/output.json
{
  "type": "object",
  "properties": {
    "success": { "type": "boolean" },
    "data": {
      "type": "object",
      "properties": {
        "content": { "type": "string" },
        "url": { "type": "string" }
      }
    },
    "metadata": {
      "type": "object",
      "properties": {
        "length": { "type": "number" },
        "timestamp": { "type": "string" }
      }
    }
  }
}

最佳实践

✅ Skill 设计原则

  • 单一职责 - 一个 Skill 只做一件事,做好一件事
  • 幂等性 - 相同输入产生相同输出,可重复执行
  • 优雅降级 - 依赖服务失败时,给出友好提示而非崩溃
  • 可观测性 - 记录执行日志,方便调试

错误处理规范

// ✅ 好的错误处理
return {
  success: false,
  error: `提取失败: ${error.message}`,
  code: 'EXTRACTION_FAILED',
  suggestion: '请检查 URL 是否可访问,选择器是否正确'
};

// ❌ 避免这样
throw error;  // 直接抛出,调用方无法优雅处理

高级技巧

Skill 组合

// 在一个 Skill 中调用另一个 Skill
const { SkillRunner } = require('openclaw');

async execute(input) {
  const runner = new SkillRunner();
  
  // 先提取网页内容
  const extraction = await runner.run('web-extractor', {
    url: input.url,
    selector: 'article'
  });
  
  // 再调用 AI 总结
  const summary = await runner.run('ai-summarizer', {
    text: extraction.data.content,
    maxLength: 200
  });
  
  return summary;
}

缓存策略

const cache = new Map();

async execute(input) {
  const cacheKey = JSON.stringify(input);
  
  if (cache.has(cacheKey)) {
    return { success: true, data: cache.get(cacheKey), cached: true };
  }
  
  const result = await this.process(input);
  cache.set(cacheKey, result);
  
  return result;
}

发布到 Skill 市场

# 打包 Skill
openclaw skill pack ./my-skill

# 发布到 ClawHub
openclaw skill publish ./my-skill --registry clawhub

# 验证发布
openclaw skill search my-skill

相关链接