Clawdbot开发入门:从零开始编写第一个Skill插件

1. 为什么需要自己写Skill插件

Clawdbot(现名Moltbot)最吸引开发者的地方,不是它能多快地回答问题,而是它真正能“做事”。当你在WhatsApp里说“把上周的会议纪要整理成PPT”,它不会只给你一段文字,而是真的打开PowerPoint,生成幻灯片,保存到桌面,再发给你一个下载链接。

这种能力背后,靠的是Skill插件系统。你可以把它理解成手机App——Clawdbot是操作系统,而Skill就是一个个独立运行、各司其职的应用程序。官方预置了50多个常用Skill,比如网络搜索、天气查询、日程管理,但它们只是起点。真正让Clawdbot变成你专属助手的,是你自己写的那个“自动归档发票”、“同步飞书文档到Notion”或者“每天早上8点推送今日待办”的插件。

我第一次写Skill时,想解决一个很实际的问题:团队每周都要手动整理GitHub Issue,复制标题、状态、负责人,粘贴到共享表格里。这个过程重复、易错、耗时。写完插件后,现在只要在群里说一句“同步本周Issue”,它就自动完成所有操作,连格式都按我们团队的习惯调整好了。

这正是Skill开发的魅力所在——它不追求炫技,而是直击工作流中的真实痛点。你不需要成为全栈工程师,只要懂一点基础逻辑和命令行,就能让AI替你扛下那些机械重复的任务。

2. 开发环境准备与快速上手

2.1 环境要求与安装验证

Clawdbot对环境的要求其实很友好。它主要运行在Node.js上,所以第一步是确认你的系统已经装好Node.js。打开终端,输入:

node --version

如果显示版本号在v22.17.0或更高,说明环境已经就绪。如果没有,去nodejs.org下载LTS版本安装即可。

接下来,用官方推荐的方式安装Clawdbot CLI工具。这是你后续开发、调试、打包插件的核心命令行界面:

npm install -g @clawdbot/cli

安装完成后,验证是否成功:

clawdbot --version

你会看到类似clawdbot v1.4.2的输出。CLI工具就像一把万能钥匙,后面所有操作——创建新插件、本地测试、发布到仓库——都靠它完成。

2.2 初始化你的第一个Skill项目

现在,让我们创建真正的第一个插件。在你喜欢的目录下,运行:

clawdbot plugins create my-first-skill

这个命令会引导你完成几个简单选择:

  • 插件名称:回车使用默认的my-first-skill
  • 描述:输入“我的第一个Clawdbot技能插件”
  • 作者:填你的名字或昵称
  • 许可证:选MIT(开源友好)

几秒钟后,一个名为my-first-skill的文件夹就生成了。进入它,用代码编辑器打开,你会看到一个清晰的结构:

my-first-skill/
├── package.json          # 插件元信息,包括名称、版本、依赖
├── skill.js              # 核心逻辑文件,所有功能都在这里定义
├── README.md             # 插件说明文档,用户第一眼看到的内容
└── tests/                # 测试文件夹,暂时为空

这个结构刻意保持极简。没有复杂的构建配置,没有冗余的模板代码,一切围绕“让开发者专注写逻辑”这个目标设计。skill.js是唯一需要你动手修改的文件,它就是整个插件的心脏。

3. 编写核心逻辑:从Hello World到实用功能

3.1 理解Skill的基本构成

打开skill.js,你会看到一段非常干净的代码。它定义了一个对象,包含三个关键部分:

  • name: 插件的唯一标识符,也是你在命令行里调用它的名字
  • description: 一句话说明这个插件是干什么的
  • run: 这是最重要的函数,当Clawdbot决定执行这个Skill时,就会调用它,并传入两个参数:input(用户输入的指令内容)和context(当前运行环境的上下文,比如聊天渠道、用户ID等)

run函数必须返回一个Promise,因为很多操作(比如调用API、读写文件)都是异步的。Clawdbot会等待这个Promise完成,然后把返回值作为结果展示给用户。

3.2 编写你的第一个功能:时间问候

我们先写一个最简单的功能:根据当前时间,向用户发送不同的问候语。修改skill.js中的run函数:

run: async (input, context) => {
  const now = new Date();
  const hour = now.getHours();

  let greeting;
  if (hour < 12) {
    greeting = "早上好!";
  } else if (hour < 18) {
    greeting = "下午好!";
  } else {
    greeting = "晚上好!";
  }

  return `${greeting} 现在是 ${now.toLocaleTimeString('zh-CN')}`;
}

这段代码没有花哨的语法,就是纯JavaScript。它获取当前时间,判断小时数,拼接出一句中文问候,最后返回一个字符串。Clawdbot会原样把这个字符串发回给用户。

3.3 添加实用功能:文件路径解析

一个真正的Skill不能只停留在“打招呼”层面。我们来加一个更实用的功能:当用户发送一个文件路径时,自动解析出它的目录、文件名和扩展名。

继续修改run函数,让它能处理两种情况:

run: async (input, context) => {
  // 如果输入是空的,就返回时间问候
  if (!input || input.trim() === '') {
    const now = new Date();
    const hour = now.getHours();
    let greeting;
    if (hour < 12) greeting = "早上好!";
    else if (hour < 18) greeting = "下午好!";
    else greeting = "晚上好!";
    return `${greeting} 现在是 ${now.toLocaleTimeString('zh-CN')}`;
  }

  // 如果输入看起来像一个文件路径,就进行解析
  if (input.includes('/') || input.includes('\\')) {
    const path = input.trim();
    const lastSlashIndex = Math.max(
      path.lastIndexOf('/'),
      path.lastIndexOf('\\')
    );

    const directory = lastSlashIndex > -1 ? path.substring(0, lastSlashIndex + 1) : './';
    const filename = lastSlashIndex > -1 ? path.substring(lastSlashIndex + 1) : path;
    const extension = filename.includes('.') ? filename.split('.').pop() : '无';

    return ` 路径解析结果:\n- 目录:${directory}\n- 文件名:${filename}\n- 扩展名:${extension}`;
  }

  // 默认返回原输入
  return `收到:${input}`;
}

现在,这个Skill有了明确的“行为模式”:空输入→问候;含斜杠的输入→路径解析;其他输入→原样回显。这种分层逻辑,正是Skill设计的核心思想:用最自然的方式响应用户的意图,而不是要求用户记住特定命令格式。

4. 本地测试与调试技巧

4.1 在Clawdbot中加载并启用插件

写完代码,下一步是让它在Clawdbot里跑起来。回到终端,在my-first-skill文件夹外,确保你已经启动了Clawdbot服务(如果还没启动,运行clawdbot start)。

然后,执行两条命令:

# 安装插件(从本地路径)
clawdbot plugins install ./my-first-skill

# 启用插件
clawdbot plugins enable my-first-skill

如果一切顺利,你会看到类似Plugin 'my-first-skill' installed and enabled的提示。这意味着你的插件已经注册到Clawdbot的技能库中,随时可以被调用。

4.2 使用交互式命令行进行调试

Clawdbot CLI提供了一个强大的调试工具,叫clawdbot run。它允许你模拟一次完整的Skill执行,而无需通过聊天界面触发。这极大提升了开发效率。

my-first-skill文件夹内,运行:

clawdbot run

它会弹出一个交互式界面,让你输入测试用的input。试试输入:

  • 直接回车(测试空输入)
  • /home/user/documents/report.pdf(测试Linux路径)
  • C:\Users\Name\Downloads\image.jpg(测试Windows路径)

每次输入后,你都会立刻看到run函数的返回值。这个过程就像在调试一个普通的Node.js函数,没有任何黑盒。你可以随时修改skill.js,保存,再运行clawdbot run,立即看到效果。

4.3 查看日志与错误定位

开发中难免遇到问题。Clawdbot会把所有插件的执行日志记录下来。如果你想查看最近的运行记录,运行:

clawdbot logs --plugin my-first-skill

日志里会清晰地显示:

  • 每次执行的时间戳
  • 输入的input内容
  • run函数的返回值
  • 如果出错,会完整打印堆栈信息

我曾经在一个Skill里忘记处理undefined的输入,导致报错。通过这条命令,我一眼就看到了错误发生在哪一行,比在聊天窗口里反复试错快得多。

5. API接口调用与外部服务集成

5.1 使用内置HTTP客户端

大多数实用的Skill都需要和外部世界对话,比如查天气、发邮件、调用公司内部API。Clawdbot为开发者封装了一个简洁的HTTP客户端,避免你手动引入axiosnode-fetch

假设你想让Skill能查询当前城市天气。首先,在package.jsondependencies里添加一个轻量级的地理编码库(用于把城市名转成经纬度):

"dependencies": {
  "node-geocoder": "^4.5.0"
}

然后在skill.js顶部引入它:

const NodeGeocoder = require('node-geocoder');
const geocoder = NodeGeocoder({
  provider: 'opencage',
  apiKey: 'your-opencage-api-key' // 你需要去opencagedata.com免费申请
});

注意:API Key不要硬编码在代码里。Clawdbot提供了安全的配置管理方式,稍后会讲。

5.2 构建一个天气查询Skill

现在,我们重写run函数,让它能处理“天气 城市名”这样的指令:

run: async (input, context) => {
  // 检查输入是否以“天气”开头
  const weatherMatch = input.match(/^天气\s+(.+)$/);
  if (!weatherMatch) {
    return "请用‘天气 [城市名]’的格式查询,例如:天气 北京";
  }

  const city = weatherMatch[1].trim();
  if (!city) {
    return "城市名不能为空,请重新输入";
  }

  try {
    // 第一步:地理编码,获取经纬度
    const res = await geocoder.geocode(city);
    if (res.length === 0) {
      return `找不到城市:${city}`;
    }
    const { latitude, longitude } = res[0];

    // 第二步:调用天气API(这里用Open-Meteo,免费且无需Key)
    const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,weather_code&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto`;
    
    const weatherRes = await fetch(weatherUrl);
    const weatherData = await weatherRes.json();

    const currentTemp = weatherData.current.temperature_2m;
    const weatherCode = weatherData.current.weather_code;
    const dailyMax = weatherData.daily.temperature_2m_max[0];
    const dailyMin = weatherData.daily.temperature_2m_min[0];

    // 简单的天气代码映射
    const weatherDesc = {
      0: "晴天", 1: "晴间多云", 2: "局部多云", 3: "多云",
      45: "雾", 48: "冻雾", 51: "毛毛雨", 53: "中雨", 55: "大雨",
      61: "小雨", 63: "中雨", 65: "大雨", 71: "小雪", 73: "中雪", 75: "大雪"
    }[weatherCode] || "未知天气";

    return `🌤 ${city} 天气\n- 当前温度:${currentTemp}°C\n- 天气状况:${weatherDesc}\n- 今日最高:${dailyMax}°C | 最低:${dailyMin}°C`;
  } catch (error) {
    console.error('Weather query failed:', error);
    return `查询失败:${error.message}`;
  }
}

这个例子展示了Skill开发的典型流程:解析用户意图 → 调用外部服务 → 处理返回数据 → 生成友好的用户反馈。整个过程都在一个run函数里完成,逻辑清晰,易于维护。

6. 插件打包与发布流程

6.1 配置管理:安全地存储API密钥

前面例子中用了your-opencage-api-key,这显然不能直接提交到代码库。Clawdbot提供了一套安全的配置机制。

首先,为你的插件设置一个配置项。在my-first-skill文件夹里,创建一个config.schema.json文件:

{
  "opencageApiKey": {
    "type": "string",
    "description": "OpenCage地理编码API密钥",
    "required": true,
    "secret": true
  }
}

"secret": true告诉Clawdbot,这个字段的值在存储和显示时需要被隐藏,防止意外泄露。

然后,在Clawdbot全局配置中设置它:

clawdbot config set plugins.my-first-skill.opencageApiKey "your-actual-api-key-here"

skill.js里,你就可以安全地访问它了:

const config = context.config.get('plugins.my-first-skill') || {};
const apiKey = config.opencageApiKey;
const geocoder = NodeGeocoder({
  provider: 'opencage',
  apiKey: apiKey
});

这样,你的代码库可以公开分享,而敏感的API Key只存在于你自己的Clawdbot配置中。

6.2 打包与发布到NPM

当你对自己的Skill满意后,就可以打包发布了。Clawdbot插件本质上就是标准的NPM包,所以发布流程和普通Node.js包完全一样。

首先,确保package.json里的name字段符合NPM命名规范(通常以@yourname/skill-name开头)。然后,登录NPM:

npm login

最后,发布:

npm publish

发布成功后,其他用户就可以用一行命令安装你的Skill:

clawdbot plugins install @yourname/my-first-skill

6.3 发布到Clawdbot官方插件市场

除了NPM,Clawdbot还有一个官方插件市场。要上架,你需要在插件根目录创建一个market.json文件,提供更丰富的市场信息:

{
  "title": "智能路径解析器",
  "description": "一键解析任意文件路径,清晰展示目录、文件名和扩展名",
  "category": "开发工具",
  "tags": ["文件", "路径", "开发"],
  "author": "你的名字",
  "homepage": "https://github.com/yourname/my-first-skill",
  "repository": "https://github.com/yourname/my-first-skill"
}

然后,向Clawdbot官方提交审核。一旦通过,你的插件就会出现在所有Clawdbot用户的插件列表里,被更多人发现和使用。

7. 实战建议与避坑指南

7.1 从一个小问题开始

我见过太多新手一上来就想写“全能助手”,结果卡在第一步就放弃了。我的建议是:永远从一个具体、微小、你能立刻验证的问题开始。比如:

  • “每次都要手动把截图重命名成日期+序号,太麻烦”
  • “团队用飞书文档,但总有人忘记更新状态栏”
  • “每天要查三次邮箱,看看有没有新发票”

找到那个让你皱眉超过三次的小事,它就是你第一个Skill最好的起点。解决它,你会获得巨大的正向反馈,这种成就感会驱动你继续写下去。

7.2 把错误当成用户反馈

run函数里,我习惯性地把所有可能出错的地方都用try...catch包裹,并返回一句清晰的中文错误提示。比如:

} catch (error) {
  return ` 操作失败:${error.message}。请检查输入是否正确,或稍后重试。`;
}

这比让Clawdbot抛出一长串英文堆栈信息友好得多。用户看到这句话,就知道问题在哪,而不是困惑于“我的AI怎么坏了”。

7.3 利用Git进行版本管理

虽然Clawdbot本身不强制要求,但我强烈建议为每个Skill项目初始化一个Git仓库。原因有三:

  • 协作:如果你和同事一起维护一个团队Skill,Git是唯一的协同方式
  • 回滚:某次更新后发现效果变差,git checkout就能秒级恢复
  • 发布:NPM发布时,它会自动读取Git的tag作为版本号,非常方便

初始化很简单:

git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/yourname/my-first-skill.git
git push -u origin main

7.4 性能与用户体验的平衡

Clawdbot的设计哲学是“快”。用户在聊天窗口里发出指令,期望的是秒级响应。所以,你的Skill应该遵循一个黄金法则:90%的场景,响应时间不超过2秒

如何做到?有两个实用技巧:

  • 缓存:对于不常变化的数据(比如城市列表、公司部门结构),用context.cache.set(key, value, ttl)存起来,下次直接读,不用再请求API
  • 超时控制:所有外部请求都加上超时,避免一个慢接口拖垮整个体验。fetch(url, { signal: AbortSignal.timeout(3000) })就是个好选择

记住,一个响应慢但功能全的Skill,远不如一个响应快但功能精的Skill受欢迎。

8. 下一步:让Skill更智能、更主动

写完第一个Skill,你已经掌握了Clawdbot开发的核心。但真正的乐趣才刚刚开始。Clawdbot的强大之处,在于它不只是被动响应,还能主动出击。

比如,你可以让Skill监听特定事件:

  • 当Clawdbot启动时,自动运行一个初始化脚本(boot-md Skill)
  • 当检测到某个关键词出现在邮件里,自动创建一个待办事项(command-logger配合自定义监听)
  • 每天固定时间,主动推送一份日报(session-memory配合定时任务)

这些能力,都建立在你今天打下的基础上。skill.js里的run函数,就是你通往这些高级特性的入口。它不是一个终点,而是一把钥匙,打开了一个由你定义的、真正属于你自己的AI工作流的大门。

我建议你马上打开终端,运行那条clawdbot plugins create命令。别想太多,就写一个解决你今天工作中那个最烦人小问题的Skill。当你第一次看到它在聊天窗口里准确无误地完成任务时,那种亲手创造价值的感觉,是任何教程都无法描述的。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐