Agent工坊

【Agent工坊】OpenClaw插件开发实战:5行代码构建你的第一个AI工具

OpenClaw v2026.5.18 正式发布 defineToolPlugin —— 从此AI Agent的工具扩展不再是黑魔法,5行TypeScript代码就能让Agent学会调用你自己的API、数据库和业务系统。


为什么你需要学会写Agent插件

2026年的AI Agent生态已经非常成熟。Hermes Agent v0.14.0刚落地808个commit,OpenClaw三天两更。但有一个残酷的事实:


现成的工具永远无法覆盖你的具体业务场景。


你做了一个竞品监控系统,想让Agent每天自动帮你查数据?你的内部CRM有独特的API?你希望Agent能在特定条件触发时发企业微信通知?


这些场景,只靠内置工具(web_search、terminal、browser_navigate)远远不够。你需要自己写插件——让Agent长出你需要的"手"。


OpenClaw v2026.5.18(2026年5月18日发布)正式推出了 defineToolPlugin + openclaw plugins build/validate/init 三件套,把插件开发的门槛从"需要理解Agent内部架构"降到了"会写TypeScript函数就行"。


时效性声明:本文基于OpenClaw v2026.5.18(2026-05-18发布)撰写。OpenClaw更新频繁,请以官方文档为准。


OpenClaw Plugin SDK 概览

v2026.5.18 新增的核心能力:


功能说明
defineToolPlugin声明式定义工具插件,一行注册
openclaw plugins init脚手架命令,生成标准插件项目结构
openclaw plugins build编译插件,生成manifest元数据
openclaw plugins validate校验插件格式和参数声明
Context factories插件可以访问运行时上下文(用户信息、会话状态等)

核心理念:你只需要写三个东西——


  1. 工具的JSON Schema(告诉Agent这个工具叫什么、接受什么参数)
  2. 执行函数(工具被调用时实际运行的代码)
  3. 插件的manifest(元数据——名称、版本、描述)

剩下的——工具注册、参数校验、错误处理、调用日志——全部由SDK处理。


动手实践:构建一个"网页截图"工具插件


▲ 插件项目结构与 defineToolPlugin 函数定义


假设你的业务需要Agent定期截图竞品网站首页,检查他们的改版动态。我们来写一个 web-screenshot 插件。


第一步:初始化插件项目

# 确保已安装 OpenClaw(Node.js >= 22.19)


node --version # 应输出 v22.x



# 用脚手架创建插件项目


openclaw plugins init web-screenshot


cd web-screenshot



脚手架会自动生成以下结构:


web-screenshot/


├── package.json # 插件元信息


├── src/


│ └── index.ts # 插件入口——核心代码写在这里


├── tsconfig.json


└── README.md



第二步:编写工具定义和执行函数

打开 src/index.ts,写入以下代码:


import { defineToolPlugin } from "@openclaw/plugin-sdk";



export default defineToolPlugin({


  name: "web-screenshot",


  version: "1.0.0",


  description: "对指定URL进行全页截图,返回截图文件路径",



  tools: [


    {


      // 工具的JSON Schema —— Agent通过这个理解怎么用你的工具


      name: "screenshot_url",


      description: "对给定URL进行网页全页截图。适用于监控竞品网站变化、验证页面渲染效果。",


      parameters: {


        type: "object",


        properties: {


          url: {


            type: "string",


            description: "要截图的网页URL(需包含协议头 "


          },


          fullPage: {


            type: "boolean",


            description: "是否截取全页(默认true)",


            default: true


          },


          width: {


            type: "number",


            description: "视口宽度(像素,默认1920)",


            default: 1920


          }


        },


        required: ["url"]


      },



      // 执行函数 —— Agent调用工具时实际运行的代码


      async execute({ url, fullPage = true, width = 1920 }) {


        // 使用Puppeteer(需在package.json中声明依赖)


        const puppeteer = await import("puppeteer");


        const browser = await puppeteer.launch({ headless: true });


        const page = await browser.newPage();



        await page.setViewport({ width, height: 1080 });


        await page.goto(url, { waitUntil: "networkidle2", timeout: 30000 });



        const screenshotPath = `/tmp/screenshot-${Date.now()}.png`;


        await page.screenshot({


          path: screenshotPath,


          fullPage: fullPage,


        });



        await browser.close();



        // 返回值会被Agent读取——尽量结构化


        return {


          success: true,


          path: screenshotPath,


          url: url,


          timestamp: new Date().toISOString(),


        };


      },


    },


  ],


});



第三步:声明依赖并构建

编辑 package.json,添加 Puppeteer 依赖:


{


  "name": "web-screenshot",


  "version": "1.0.0",


  "dependencies": {


    "puppeteer": "^24.0.0"


  }


}



然后构建:


npm install


openclaw plugins build



构建成功后会在 dist/ 目录生成编译产物,同时自动生成 manifest.json


{


  "name": "web-screenshot",


  "version": "1.0.0",


  "description": "对指定URL进行全页截图",


  "tools": ["screenshot_url"],


  "entry": "dist/index.js"


}



第四步:安装到OpenClaw并测试

# 安装插件


openclaw plugins install ./web-screenshot



# 验证插件是否正确注册


openclaw plugins validate web-screenshot


# 输出:✅ Plugin "web-screenshot" is valid



# 在Agent对话中测试


openclaw chat "帮我截取 的首页截图"



Agent会自动识别 screenshot_url 工具存在,当你要求截图时调用它。执行结果会返回给Agent,Agent可以基于截图做进一步分析——比如"首页的banner改了"、"新加了导航项"等。


插件开发的5个核心模式


▲ 5种核心插件开发模式:从API封装到上下文感知


通过上面的例子,我们可以抽象出插件开发的通用模式:


模式1:API封装型

把你已有的REST API包装成Agent工具。这是最常见的场景。


// 把内部CRM API包装成Agent可调用的工具


{


  name: "get_customer_info",


  description: "根据客户ID查询CRM中的客户详细信息",


  parameters: {


    type: "object",


    properties: {


      customerId: { type: "string", description: "客户ID" }


    },


    required: ["customerId"]


  },


  async execute({ customerId }) {


    const resp = await fetch(` {


      headers: { Authorization: `Bearer ${process.env.CRM_API_KEY}` }


    });


    return await resp.json();


  }


}



模式2:本地脚本调用型

把已有的Shell脚本或Python脚本暴露为工具。


{


  name: "run_data_pipeline",


  description: "触发数据ETL流水线,执行数据清洗和入库",


  parameters: {


    type: "object",


    properties: {


      dataset: { type: "string", description: "数据集名称(如 daily_sales)" },


      date: { type: "string", description: "处理日期(YYYY-MM-DD格式)" }


    },


    required: ["dataset"]


  },


  async execute({ dataset, date }) {


    const { execSync } = await import("child_process");


    const cmd = `python3 /opt/pipelines/${dataset}/run.py ${date || ""}`;


    const output = execSync(cmd, { encoding: "utf-8", timeout: 60000 });


    return { output, dataset, date };


  }


}



模式3:数据库查询型

让Agent能直接查询你的业务数据库,生成报表。


{


  name: "query_sales_db",


  description: "查询销售数据库。适用于生成日报、周报、趋势分析。",


  parameters: {


    type: "object",


    properties: {


      sql: { type: "string", description: "SELECT查询语句(只读)" },


    },


    required: ["sql"]


  },


  async execute({ sql }) {


    // 安全检查:只允许 SELECT


    if (!sql.trim().toUpperCase().startsWith("SELECT")) {


      return { error: "只允许SELECT查询" };


    }


    const mysql = await import("mysql2/promise");


    const conn = await mysql.createConnection({


      host: process.env.DB_HOST,


      user: process.env.DB_READONLY_USER,


      password: process.env.DB_READONLY_PASS,


    });


    const [rows] = await conn.execute(sql);


    await conn.end();


    return { rows, count: rows.length };


  }


}



模式4:通知/推送型

让Agent在特定条件下主动通知你。


{


  name: "send_wechat_notification",


  description: "发送企业微信通知。适用于异常告警、任务完成通知。",


  parameters: {


    type: "object",


    properties: {


      message: { type: "string", description: "通知内容" },


      urgency: { type: "string", enum: ["low", "normal", "high"] }


    },


    required: ["message"]


  },


  async execute({ message, urgency = "normal" }) {


    const webhookUrl = process.env.WECHAT_WEBHOOK_URL;


    const resp = await fetch(webhookUrl, {


      method: "POST",


      headers: { "Content-Type": "application/json" },


      body: JSON.stringify({


        msgtype: "text",


        text: { content: `[${urgency.toUpperCase()}] ${message}` }


      })


    });


    return { sent: resp.ok, urgency };


  }


}



模式5:Context-Aware型(高级)

使用OpenClaw的Context Factories功能,让工具能感知当前会话上下文——比如用户是谁、当前频道是什么。


import { defineToolPlugin, createContextFactory } from "@openclaw/plugin-sdk";



const userContext = createContextFactory(async (runtime) => {


  return {


    userId: runtime.session?.userId,


    channel: runtime.session?.channel,


    preferences: await loadUserPreferences(runtime.session?.userId),


  };


});



export default defineToolPlugin({


  name: "personalized-recommender",


  version: "1.0.0",


  description: "基于用户偏好和上下文提供个性化推荐",



  context: userContext, // 注入上下文工厂



  tools: [{


    name: "recommend_content",


    description: "基于用户历史偏好,推荐相关内容",


    parameters: {


      type: "object",


      properties: {


        topic: { type: "string", description: "感兴趣的主题" }


      }


    },


    async execute({ topic }, context) {


      // context 包含运行时信息


      const { userId, preferences } = context;


      const recommendations = await queryRecommendationEngine(topic, preferences);


      return { recommendations, personalizedFor: userId };


    }


  }]


});



插件开发的7个踩坑提醒

坑1:参数校验不够严格

Agent(由LLM驱动)会传一些你意想不到的参数——类型错误、缺失字段、超长字符串。永远在execute函数开头做参数校验


async execute(params) {


  // ✅ 关键参数校验


  if (!params.url || typeof params.url !== "string") {


    return { error: "url参数必须是非空字符串" };


  }


  if (typeof params.url !== "string" || !params.url.startsWith("http")) {


    return { error: "url必须以 http:// 或 https:// 开头" };


  }


  // ... 正常逻辑


}



坑2:超时不处理

Agent调用工具时有默认超时(通常60-120秒)。如果你的工具需要更长时间(如大文件处理、长时间爬取),Agent会收到超时错误并可能认为工具失效。解决:对于耗时操作,返回中间状态并异步处理。


坑3:敏感信息泄露

execute函数的返回值会完整传给LLM。不要返回数据库密码、API key、内部IP地址等敏感信息。返回值只包含Agent完成任务所需的最小信息集。


坑4:幂等性缺失

Agent可能会因为重试机制多次调用同一工具。确保你的工具是幂等的——同一参数多次调用不产生副作用。比如数据库查询天然幂等;但如果是发送通知、创建订单,需要有去重机制。


坑5:Node.js版本不兼容

OpenClaw v2026.5.18 将最低Node.js版本提升到22.19。如果你的服务器还在用Node 18或20,升级前先确认兼容性:


# 检查当前版本


node --version



# 如果低于22.19,用nvm升级


nvm install 22


nvm use 22



坑6:插件描述写得不够好

Agent通过你的description和参数的description字段来决定何时调用工具。描述要具体,不要抽象


// ❌ 糟糕的描述


description: "查询数据"


parameters: { dataType: { description: "类型" } }



// ✅ 好的描述


description: "查询MySQL销售数据库中的订单数据。


  适用场景:查询某日销售总额、某客户历史订单、按地区统计销售额。"


parameters: {


  dataType: {


    description: "数据类型:daily_sales(日销售额)、customer_orders(客户订单)、


      regional_stats(地区统计)。默认:daily_sales"


  }


}



坑7:忘记处理网络错误

Agent运行在你的服务器上,网络环境可能不同。工具调用外部API时必须处理网络错误、DNS失败、HTTP 5xx等:


async execute(params) {


  try {


    const resp = await fetch(url, { signal: AbortSignal.timeout(10000) });


    if (!resp.ok) {


      return { error: `API返回错误: ${resp.status}`, detail: await resp.text() };


    }


    return await resp.json();


  } catch (err) {


    return { error: `网络请求失败: ${err.message}`, retryable: true };


  }


}



插件部署后的日常运维

查看已安装插件

openclaw plugins list


# 输出:


# web-screenshot (v1.0.0) — 对指定URL进行全页截图


# crm-connector (v1.2.0) — CRM数据查询工具



更新插件

# 全局更新


openclaw plugins update web-screenshot --global



# 或重新构建后安装


openclaw plugins build


openclaw plugins install . --force



卸载插件

openclaw plugins uninstall web-screenshot



调试技巧

当Agent调用工具后行为不符合预期,检查日志:


# 查看Agent调用工具的详细日志


openclaw logs --filter=tool --last=50



# 查看特定插件的错误


openclaw logs --plugin=web-screenshot --level=error



现实的AI Agent工具栈该长什么样


▲ 推荐Agent工具栈架构:内置工具层 + 自定义插件层


对于一个真实的AI创业项目,你的Agent工具栈可能是这样的:


┌─────────────────────────────────────────────┐


│ OpenClaw Agent │


├─────────────────────────────────────────────┤


│ 内置工具 │


│ ├─ web_search (搜索) │


│ ├─ terminal (命令行) │


│ ├─ browser_navigate (浏览器) │


│ └─ read_file / write_file (文件操作) │


├─────────────────────────────────────────────┤


│ 自定义插件(defineToolPlugin) │


│ ├─ crm-connector (查客户数据) │


│ ├─ analytics-reporter (生成分析报表) │


│ ├─ wechat-notifier (企业微信通知) │


│ ├─ data-pipeline (触发ETL流水线) │


│ └─ screenshot-monitor (竞品截图监控) │


└─────────────────────────────────────────────┘



搭配Hermes Agent:如果你同时使用Hermes Agent(它有自己的skill系统),可以在Hermes里写skill来编排OpenClaw的插件——比如Hermes定时cron触发 → 调OpenClaw截图插件 → 用GPT-5.5分析截图 → 推送结果到微信。


总结

defineToolPlugin 把Agent工具开发从"需要贡献到主仓库"变成了"个人5分钟搞定的脚本"。对AI创业者来说这意味着:


  1. 自己的业务系统可以被Agent直接操作——CRM、数据库、内部API,全都可以工具化
  2. 工作流可以全自动化——截图→分析→报表→通知,一条链跑通
  3. 不需要等官方支持——你需要的工具,自己写
  4. 生态可复用——写好的插件可以在多个Agent项目间共享

v2026.5.18 的其他亮点还包括:全新的Mac app设置页、Docker/Podman构建参数统一、Gateway启动延迟降低、HTTPS代理支持。但这些是基础设施优化——对开发者来说,defineToolPlugin 是最能直接产生价值的更新。


行动建议:今天花15分钟,选一个你每天手动做的最无聊的任务(查竞品网站、拉报表、发通知),把它写成一个OpenClaw插件。让Agent替你干,你去干更值钱的事。



本文基于 OpenClaw v2026.5.18 (2026-05-18) 官方Release Notes撰写。OpenClaw 是开源项目,仓库地址 github.com/openclaw/openclaw,插件开发文档详见官方文档。 本文由AI辅助创作,经人工审核编辑发布。

#AI创业 #Agent工坊 #OpenClaw #工具插件 #一人公司


本文由AI辅助创作,经人工审核编辑发布