OpenClaw Plugins 与 Hooks 系统:让 AI 助手无限可能

OpenClaw Plugins 与 Hooks 系统:让 AI 助手无限可能

引言:为什么需要 Plugins 和 Hooks?

想象你购买了一台智能手机,但它只能打电话和发短信。如果想要拍照、听音乐、玩游戏,必须等待厂商发布系统更新。这显然不够灵活。

Plugins(插件) 就像手机的 App Store,让你可以自由安装各种应用扩展功能。 Hooks(钩子) 就像手机的快捷指令,让你可以在特定时刻自动执行某些操作。

OpenClaw 的 Plugins 和 Hooks 系统正是为了解决这个问题:

没有它们的 OpenClaw

  • ❌ 只支持内置的消息平台(Telegram、Discord 等)
  • ❌ 想添加新工具必须修改核心代码
  • ❌ 无法在特定事件发生时自动执行操作
  • ❌ 每个用户的需求都要等待官方开发

有了它们的 OpenClaw

  • ✅ 任何人都可以开发插件添加新功能
  • ✅ 无需修改核心代码,即插即用
  • ✅ 可以监听和修改 OpenClaw 的任何行为
  • ✅ 打造专属于你的 AI 助手

第一部分:Plugins 系统 - 扩展 OpenClaw 的能力

1.1 Plugins 能做什么?

Plugins 提供 8 种扩展方式,让你可以为 OpenClaw 添加几乎任何功能:

🔧 1. 添加新工具(Tools)

用途:让 AI 助手学会新技能

示例场景

  • 添加天气查询工具
  • 添加股票价格查询工具
  • 添加数据库操作工具
  • 添加自定义 API 调用工具

核心代码

typescript 复制代码
// 创建一个天气查询插件
export default {
  id: "weather-plugin",
  register(api) {
    // 注册天气查询工具
    api.registerTool({
      name: "get_weather",
      description: "查询指定城市的天气",
      parameters: Type.Object({
        city: Type.String()
      }),
      async execute(toolCallId, params) {
        // 调用天气 API
        const weather = await fetchWeatherAPI(params.city);

        return {
          content: [{
            type: "text",
            text: `${params.city}的天气:${weather.temperature}°C,${weather.description}`
          }]
        };
      }
    });
  }
};

效果

arduino 复制代码
用户:"北京今天天气怎么样?"
AI:调用 get_weather 工具
返回:"北京的天气:25°C,晴天"

💬 2. 添加新消息平台(Channels)

用途:让 OpenClaw 支持新的聊天平台

示例场景

  • 添加微信支持
  • 添加钉钉支持
  • 添加企业内部通讯系统
  • 添加邮件支持

核心代码

typescript 复制代码
export default {
  id: "wechat-plugin",
  register(api) {
    api.registerChannel({
      plugin: {
        id: "wechat",
        name: "微信",

        // 发送消息
        async send(params) {
          await wechatBot.sendMessage(params.to, params.message.text);
          return { messageId: "msg-123", timestamp: Date.now() };
        },

        // 接收消息
        async onInboundMessage(msg) {
          // 转发给 OpenClaw 处理
          await routeToAgent({
            from: msg.sender,
            text: msg.content,
            channel: "wechat"
          });
        }
      }
    });
  }
};

效果

  • 用户在微信给 AI 发消息
  • AI 在微信回复
  • 完全无缝集成

🤖 3. 添加新 LLM 提供商(Providers)

用途:让 OpenClaw 支持更多 AI 模型

示例场景

  • 添加国产大模型(文心一言、通义千问)
  • 添加私有部署的模型
  • 添加专用领域模型

核心代码

typescript 复制代码
export default {
  id: "baidu-wenxin",
  register(api) {
    api.registerProvider({
      id: "baidu",
      name: "百度文心",
      models: [
        { id: "ernie-4.0", name: "文心一言 4.0" }
      ],
      async callLLM(params) {
        // 调用百度文心 API
        const response = await fetch("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-4.0-8k-latest", {
          method: "POST",
          body: JSON.stringify({
            messages: params.messages,
            access_token: params.apiKey
          })
        });

        return await response.json();
      }
    });
  }
};

效果

json 复制代码
// 配置文件
{
  "agents": {
    "defaults": {
      "model": "baidu/ernie-4.0"  // 使用文心一言
    }
  }
}

⚙️ 4. 添加后台服务(Services)

用途:运行持续的后台任务

示例场景

  • 定期同步数据
  • 监控系统状态
  • 定时发送提醒
  • 数据收集和分析

核心代码

typescript 复制代码
export default {
  id: "monitor-plugin",
  register(api) {
    api.registerService({
      name: "server-monitor",
      async start(runtime) {
        // 每分钟检查一次服务器状态
        const interval = setInterval(async () => {
          const status = await checkServerStatus();

          if (status.error) {
            // 发送告警
            await runtime.channels.send({
              channel: "telegram",
              to: "admin-user-id",
              message: { text: `⚠️ 服务器异常:${status.error}` }
            });
          }
        }, 60000);

        // 返回清理函数
        return () => clearInterval(interval);
      }
    });
  }
};

效果

  • 服务器出现问题时自动发送 Telegram 通知
  • 无需人工监控

🌐 5. 添加 HTTP 接口(HTTP Routes)

用途:为 OpenClaw 添加 Web API

示例场景

  • 提供 Webhook 接入点
  • 创建管理面板 API
  • 对外提供数据接口
  • 集成第三方服务

核心代码

typescript 复制代码
export default {
  id: "webhook-plugin",
  register(api) {
    // 添加 Webhook 接口
    api.registerHttpRoute({
      path: "/webhook/github",
      async handler(req, res) {
        const event = req.body;

        if (event.action === "opened") {
          // 新 PR 创建时通知
          await api.runtime.channels.send({
            channel: "telegram",
            to: "dev-group",
            message: {
              text: `🔔 新 PR:${event.pull_request.title}\n${event.pull_request.html_url}`
            }
          });
        }

        res.json({ status: "ok" });
      }
    });
  }
};

效果

  • GitHub 发生事件 → POST 到 /webhook/github
  • 自动发送 Telegram 通知

💾 6. 替换内存系统(Memory Plugins)

用途:使用自定义的存储后端

示例场景

  • 使用向量数据库(Pinecone、Weaviate)
  • 使用云存储(S3、OSS)
  • 使用企业级数据库
  • 实现加密存储

核心代码

typescript 复制代码
// openclaw.plugin.json
{
  "id": "memory-pinecone",
  "kind": "memory"  // 特殊标记:Memory 插件
}

// index.ts
export default {
  id: "memory-pinecone",
  register(api) {
    const pinecone = new PineconeClient();
    await pinecone.init({
      apiKey: api.pluginConfig.apiKey,
      environment: api.pluginConfig.environment
    });

    // 覆盖默认的 memory_search 工具
    api.registerTool({
      name: "memory_search",
      description: "使用 Pinecone 搜索记忆",
      parameters: Type.Object({
        query: Type.String()
      }),
      async execute(toolCallId, params) {
        // 生成 embedding
        const embedding = await generateEmbedding(params.query);

        // 在 Pinecone 中搜索
        const results = await pinecone.query({
          vector: embedding,
          topK: 10
        });

        return { content: [{ type: "text", text: JSON.stringify(results) }] };
      }
    });
  }
};

配置

json 复制代码
{
  "plugins": {
    "slots": {
      "memory": "memory-pinecone"  // 激活此插件(只能有一个)
    }
  }
}

🎨 7. 添加 CLI 命令(CLI Commands)

用途 :扩展 openclaw 命令行工具

示例场景

  • 添加数据导出命令
  • 添加批量操作命令
  • 添加管理工具

核心代码

typescript 复制代码
export default {
  id: "export-plugin",
  register(api) {
    api.registerCli({
      name: "export",
      description: "导出数据",
      commands: [
        {
          name: "sessions",
          async handler(args) {
            const sessions = await loadAllSessions();
            const json = JSON.stringify(sessions, null, 2);
            await fs.writeFile("sessions-export.json", json);
            console.log("✅ 导出完成:sessions-export.json");
          }
        }
      ]
    });
  }
};

使用

bash 复制代码
openclaw export sessions
# ✅ 导出完成:sessions-export.json

🔌 8. 添加 Gateway 方法(Gateway RPC)

用途:为网关添加自定义 RPC 方法

示例场景

  • 远程控制插件
  • 查询插件状态
  • 触发插件操作

1.2 如何创建插件?

最简单的插件示例

目录结构

perl 复制代码
my-plugin/
├── openclaw.plugin.json    # 插件清单
├── package.json
└── index.ts                # 入口文件

openclaw.plugin.json

json 复制代码
{
  "id": "my-plugin",
  "configSchema": {
    "type": "object",
    "properties": {
      "apiKey": { "type": "string" }
    }
  }
}

index.ts

typescript 复制代码
export default {
  id: "my-plugin",
  name: "我的插件",
  register(api) {
    // 在这里注册工具、钩子等
    api.registerTool({ /* ... */ });
  }
};

就这么简单! 只需要两个文件,就能创建一个功能完整的插件。


1.3 插件实战案例

案例 1:团队协作助手

需求

  • 自动同步 Jira 任务
  • 发送 Daily Standup 提醒
  • 代码审查通知

实现

typescript 复制代码
export default {
  id: "team-helper",
  register(api) {
    // 1. 添加 Jira 查询工具
    api.registerTool({
      name: "jira_query",
      description: "查询 Jira 任务",
      parameters: Type.Object({
        jql: Type.String()
      }),
      async execute(toolCallId, params) {
        const issues = await jiraClient.search(params.jql);
        return { content: [{ type: "text", text: JSON.stringify(issues) }] };
      }
    });

    // 2. 定时发送 Daily Standup 提醒
    api.registerService({
      name: "daily-standup",
      async start(runtime) {
        const schedule = require("node-cron");

        schedule.schedule("0 10 * * 1-5", async () => {
          await runtime.channels.send({
            channel: "slack",
            to: "team-channel",
            message: {
              text: "📅 Daily Standup 时间到了!请分享:\n1. 昨天完成了什么\n2. 今天计划做什么\n3. 有什么阻碍"
            }
          });
        });
      }
    });

    // 3. GitHub PR 通知
    api.registerHttpRoute({
      path: "/webhook/github-pr",
      async handler(req, res) {
        const pr = req.body.pull_request;
        await api.runtime.channels.send({
          channel: "slack",
          to: "dev-channel",
          message: {
            text: `🔍 新 PR 需要审查:${pr.title}\n${pr.html_url}`
          }
        });
        res.json({ status: "ok" });
      }
    });
  }
};

效果

  • 工作日早上 10 点自动发送 Standup 提醒
  • GitHub PR 创建时自动通知 Slack
  • 可以用自然语言查询 Jira:"显示我的未完成任务"

案例 2:智能客服系统

需求

  • 接入企业知识库
  • 记录客服对话
  • 自动分类和标签

实现

typescript 复制代码
export default {
  id: "customer-service",
  register(api) {
    // 1. 知识库查询工具
    api.registerTool({
      name: "kb_search",
      description: "搜索企业知识库",
      parameters: Type.Object({
        query: Type.String()
      }),
      async execute(toolCallId, params) {
        const results = await elasticsearchClient.search({
          index: "knowledge-base",
          body: {
            query: { match: { content: params.query } }
          }
        });
        return { content: [{ type: "text", text: formatResults(results) }] };
      }
    });

    // 2. 记录所有客服对话
    api.on("message_received", async (event) => {
      await database.saveConversation({
        userId: event.message.from,
        message: event.message.text,
        timestamp: Date.now(),
        channel: event.channel
      });
    });

    // 3. 自动打标签
    api.on("agent_end", async (event) => {
      const transcript = await loadSessionTranscript(event.sessionKey);

      // 使用 LLM 分类对话
      const tags = await classifyConversation(transcript);

      await database.updateTags(event.sessionKey, tags);
    });
  }
};

效果

  • AI 自动查询知识库回答问题
  • 所有对话自动存档
  • 自动分类(技术支持、售前咨询、投诉等)

第二部分:Hooks 系统 - 监听和修改 OpenClaw 的行为

2.1 Hooks 是什么?

Hooks(钩子)让你可以在 OpenClaw 运行的关键时刻插入自定义逻辑。

形象比喻

  • 就像门上的挂钩,你可以在"开门"和"关门"时挂上东西
  • 就像手机的快捷指令,"连接 Wi-Fi 时自动关闭蜂窝数据"

OpenClaw 提供 28 种钩子,覆盖整个生命周期:


2.2 两种类型的 Hooks

类型 1:内部 Hooks(文件钩子)

用途:在特定命令或事件发生时执行操作

位置~/.openclaw/hooks/workspace/hooks/

示例场景

  • 用户运行 /new 时自动保存会话
  • 用户运行 /reset 时清理临时文件
  • Gateway 启动时加载自定义配置

目录结构

ruby 复制代码
~/.openclaw/hooks/
└── auto-save-session/
    ├── HOOK.md          # 元数据和文档
    └── handler.ts       # 处理逻辑

HOOK.md

yaml 复制代码
---
name: auto-save-session
description: "自动保存会话到 MEMORY.md"
metadata:
  openclaw:
    events: ["command:new", "command:reset"]
---

# Auto Save Session Hook

在用户运行 /new 或 /reset 时,自动将当前会话保存到 MEMORY.md。

handler.ts

typescript 复制代码
export default async (event) => {
  if (event.type === "command" && ["new", "reset"].includes(event.action)) {
    // 读取当前会话
    const transcript = await readSession(event.sessionKey);

    // 总结会话
    const summary = await summarize(transcript);

    // 追加到 MEMORY.md
    await appendToMemory(summary);

    // 通知用户
    event.messages?.push({
      role: "assistant",
      content: "💾 会话已保存到 MEMORY.md"
    });
  }
};

效果

swift 复制代码
用户:"继续开发新功能"
系统:/new
触发钩子 → 自动保存会话
AI:"💾 会话已保存到 MEMORY.md\n\n好的,我们开始新的对话吧!"

类型 2:Lifecycle Hooks(生命周期钩子)

用途:在 Agent 运行的各个阶段插入逻辑

注册方式 :在插件中通过 api.on() 注册

28 种钩子分类

📋 Agent 生命周期钩子
钩子名 触发时机 用途
before_model_resolve 选择模型前 覆盖用户选择的模型
before_prompt_build 构建系统提示前 注入额外指令或上下文
llm_input 调用 LLM 前 记录输入日志
llm_output LLM 返回后 记录输出和 Token 使用
agent_end Agent 结束时 清理资源、保存状态
💬 消息钩子
钩子名 触发时机 用途
message_received 收到消息时 记录、过滤、预处理
message_sending 发送消息前 修改内容、添加签名、取消发送
message_sent 发送消息后 确认、统计
🔧 工具钩子
钩子名 触发时机 用途
before_tool_call 调用工具前 修改参数、阻止执行、记录
after_tool_call 调用工具后 记录结果、统计耗时
tool_result_persist 保存结果前 修改输出内容
🧠 Compaction 钩子
钩子名 触发时机 用途
before_compaction 压缩前 保存重要信息
after_compaction 压缩后 索引总结内容
before_reset 重置前 备份会话
👥 子代理钩子
钩子名 触发时机 用途
subagent_spawning 创建子代理前 配置线程、设置权限
subagent_delivery_target 确定交付目标时 指定子代理响应的目的地
subagent_ended 子代理结束时 清理资源

2.3 Hooks 实战案例

案例 1:自动切换模型策略

需求:根据问题类型自动选择最合适的模型

实现

typescript 复制代码
export default {
  id: "smart-model-router",
  register(api) {
    api.on("before_model_resolve", async (event) => {
      const userMessage = event.messages[event.messages.length - 1];
      const text = userMessage.content.toLowerCase();

      // 简单问题 → 使用 Haiku(快速 + 便宜)
      if (text.length < 50 || text.includes("你好") || text.includes("谢谢")) {
        return {
          provider: "anthropic",
          model: "claude-haiku-3-5"
        };
      }

      // 代码问题 → 使用 Sonnet(平衡)
      if (text.includes("代码") || text.includes("bug") || text.includes("function")) {
        return {
          provider: "anthropic",
          model: "claude-sonnet-4-5"
        };
      }

      // 复杂问题 → 使用 Opus(最强)
      if (text.length > 500 || text.includes("详细") || text.includes("深入")) {
        return {
          provider: "anthropic",
          model: "claude-opus-4"
        };
      }

      // 默认:使用用户配置的模型
    });
  }
};

效果

arduino 复制代码
用户:"你好"               → 使用 Haiku(0.25美元/M tokens)
用户:"这段代码有什么问题?" → 使用 Sonnet(3美元/M tokens)
用户:"详细分析这个架构"    → 使用 Opus(15美元/M tokens)

省钱效果:自动使用最经济的模型,可节省 60-80% 成本!


案例 2:自动审计和合规

需求:记录所有敏感操作,符合企业合规要求

实现

typescript 复制代码
export default {
  id: "audit-logger",
  register(api) {
    // 1. 记录所有 LLM 调用
    api.on("llm_input", async (event) => {
      await auditLog.write({
        type: "llm_call",
        model: event.model,
        user: event.userId,
        timestamp: Date.now(),
        inputTokens: estimateTokens(event.messages)
      });
    });

    // 2. 记录所有工具调用
    api.on("before_tool_call", async (event) => {
      // 特别关注敏感工具
      if (["exec", "gateway", "cron"].includes(event.tool)) {
        await auditLog.write({
          type: "sensitive_tool",
          tool: event.tool,
          params: event.params,
          user: event.userId,
          timestamp: Date.now(),
          alert: true  // 标记需要人工审查
        });
      }
    });

    // 3. 阻止危险命令
    api.on("before_tool_call", async (event) => {
      if (event.tool === "exec") {
        const dangerous = ["rm -rf", "dd if=", ":(){ :|:& };:"];

        if (dangerous.some(cmd => event.params.command.includes(cmd))) {
          // 阻止执行
          return {
            block: true,
            reason: "危险命令被阻止"
          };
        }
      }
    });

    // 4. 每天生成审计报告
    api.registerService({
      name: "daily-audit-report",
      async start(runtime) {
        const schedule = require("node-cron");

        schedule.schedule("0 0 * * *", async () => {
          const report = await auditLog.generateDailyReport();

          await runtime.channels.send({
            channel: "email",
            to: "security@company.com",
            message: {
              subject: "OpenClaw 每日审计报告",
              text: report
            }
          });
        });
      }
    });
  }
};

效果

  • ✅ 所有 LLM 调用有记录(谁、何时、用了什么模型)
  • ✅ 敏感工具调用实时告警
  • ✅ 自动阻止危险命令
  • ✅ 每日审计报告自动发送

案例 3:Discord 子代理线程绑定

需求:为每个子代理创建独立的 Discord 线程

问题

  • 多个子代理同时运行时,消息混在一起
  • 用户无法区分哪个回复来自哪个子代理

解决方案:使用子代理钩子自动创建线程

实现

typescript 复制代码
export default {
  id: "discord-subagent-threads",
  register(api) {
    // 1. 子代理创建时:创建 Discord 线程
    api.on("subagent_spawning", async (event) => {
      // 仅处理 Discord 渠道
      if (event.requester?.channel !== "discord") {
        return;
      }

      // 创建专用线程
      const thread = await discordClient.channels.fetch(event.requester.channelId)
        .then(channel => channel.threads.create({
          name: `🤖 子代理:${event.agentId}`,
          autoArchiveDuration: 60
        }));

      // 保存线程绑定
      await saveThreadBinding({
        sessionKey: event.sessionKey,
        threadId: thread.id
      });

      return { status: "ok", threadBindingReady: true };
    });

    // 2. 子代理回复时:发送到专用线程
    api.on("subagent_delivery_target", (event) => {
      const binding = getThreadBinding(event.sessionKey);

      if (binding) {
        return {
          origin: {
            channel: "discord",
            channelId: binding.threadId  // 指定线程
          }
        };
      }
    });

    // 3. 子代理结束时:归档线程
    api.on("subagent_ended", async (event) => {
      const binding = getThreadBinding(event.sessionKey);

      if (binding) {
        const thread = await discordClient.channels.fetch(binding.threadId);
        await thread.setArchived(true);
        await deleteThreadBinding(event.sessionKey);
      }
    });
  }
};

效果

arduino 复制代码
用户在 Discord:"分析这个代码库,同时生成文档"
  ↓
创建子代理 1(分析代码)→ 自动创建线程 "🤖 子代理:analyzer"
创建子代理 2(生成文档)→ 自动创建线程 "🤖 子代理:doc-writer"
  ↓
每个子代理在自己的线程中独立工作
  ↓
子代理完成 → 线程自动归档

用户体验

  • ✅ 对话井然有序,不会混乱
  • ✅ 可以同时查看多个子代理的进度
  • ✅ 完成后自动清理

案例 4:成本控制和预算管理

需求:限制 LLM 使用成本,超出预算时自动降级

实现

typescript 复制代码
export default {
  id: "cost-control",
  register(api) {
    let monthlyUsage = 0;
    const MONTHLY_BUDGET = 100;  // 100 美元预算

    // 1. 记录每次调用的成本
    api.on("llm_output", async (event) => {
      const cost = calculateCost(event.model, event.usage);
      monthlyUsage += cost;

      await saveCostRecord({
        model: event.model,
        tokens: event.usage.total_tokens,
        cost: cost,
        timestamp: Date.now()
      });
    });

    // 2. 超出预算时自动降级
    api.on("before_model_resolve", async (event) => {
      if (monthlyUsage > MONTHLY_BUDGET) {
        // 强制使用最便宜的模型
        return {
          provider: "anthropic",
          model: "claude-haiku-3-5"
        };
      }

      // 接近预算时发送警告
      if (monthlyUsage > MONTHLY_BUDGET * 0.8) {
        await api.runtime.channels.send({
          channel: "telegram",
          to: "admin-id",
          message: {
            text: `⚠️ 本月 AI 成本已达 ${monthlyUsage.toFixed(2)} 美元(预算:${MONTHLY_BUDGET} 美元)`
          }
        });
      }
    });

    // 3. 每月初重置计数
    api.registerService({
      name: "monthly-reset",
      async start() {
        const schedule = require("node-cron");

        schedule.schedule("0 0 1 * *", () => {
          monthlyUsage = 0;
          console.log("✅ 月度成本计数已重置");
        });
      }
    });
  }
};

效果

  • ✅ 实时跟踪 AI 成本
  • ✅ 接近预算时自动告警
  • ✅ 超出预算时自动降级到便宜模型
  • ✅ 永远不会超支

案例 5:智能缓存系统

需求:相似问题自动复用之前的答案,节省成本和时间

实现

typescript 复制代码
export default {
  id: "smart-cache",
  register(api) {
    const redis = new Redis();

    // 1. LLM 调用前检查缓存
    api.on("before_prompt_build", async (event) => {
      const query = event.messages[event.messages.length - 1].content;

      // 生成查询指纹
      const fingerprint = await generateSemanticHash(query);

      // 查找相似的历史查询
      const cached = await redis.get(`cache:${fingerprint}`);

      if (cached) {
        // 找到缓存,直接返回(绕过 LLM 调用)
        return {
          skipLLM: true,
          response: cached,
          source: "cache"
        };
      }
    });

    // 2. LLM 返回后保存缓存
    api.on("llm_output", async (event) => {
      const query = event.input.messages[event.input.messages.length - 1].content;
      const fingerprint = await generateSemanticHash(query);

      await redis.setex(
        `cache:${fingerprint}`,
        3600,  // 1 小时过期
        event.response
      );
    });
  }
};

// 语义哈希函数(相似问题产生相似哈希)
async function generateSemanticHash(text: string): Promise<string> {
  // 1. 标准化
  const normalized = text.toLowerCase().trim();

  // 2. 生成 embedding
  const embedding = await generateEmbedding(normalized);

  // 3. 降维 + 哈希
  const hash = simhash(embedding);

  return hash;
}

效果

arduino 复制代码
第一次:
用户:"北京今天天气怎么样?"
→ 调用 LLM(花费 0.001 美元)
→ 缓存结果

第二次(1 小时内):
用户:"北京的天气如何?"
→ 检测到相似问题
→ 直接返回缓存(花费 0 美元,延迟 < 10ms)

节省效果

  • 重复/相似问题节省 100% 成本
  • 响应速度提升 50-100 倍
  • 适合客服、FAQ 等场景

第三部分:Plugins + Hooks 的强大组合

3.1 完整案例:企业级 AI 助手

需求场景

  • 多部门共用一个 OpenClaw 实例
  • 每个部门有独立的工具和权限
  • 自动审计和合规
  • 成本控制
  • 集成企业内部系统

架构设计

markdown 复制代码
┌─────────────────────────────────────────────────┐
│ 插件 1:企业认证系统                             │
│ - 集成 LDAP/AD                                  │
│ - 基于部门的权限控制                            │
└─────────────────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│ 插件 2:部门工具包                               │
│ - HR:简历筛选、面试安排                        │
│ - Finance:报销审批、财务分析                   │
│ - IT:工单管理、故障诊断                        │
└─────────────────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│ 插件 3:审计和合规                               │
│ - 记录所有操作                                  │
│ - 敏感操作需要二次确认                          │
│ - 每日/每月合规报告                             │
└─────────────────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│ 插件 4:成本控制                                 │
│ - 部门级预算管理                                │
│ - 自动模型降级                                  │
│ - 成本透明化报告                                │
└─────────────────────────────────────────────────┘
                     ↓
┌─────────────────────────────────────────────────┐
│ 插件 5:企业通讯集成                             │
│ - 企业微信                                      │
│ - 钉钉                                          │
│ - 飞书                                          │
└─────────────────────────────────────────────────┘

核心实现

typescript 复制代码
// 插件 1:企业认证
export default {
  id: "enterprise-auth",
  register(api) {
    // 在消息处理前验证身份
    api.on("message_received", async (event) => {
      const user = await ldapClient.authenticate(event.message.from);

      if (!user) {
        throw new Error("未授权用户");
      }

      // 注入用户信息到上下文
      event.context.user = user;
      event.context.department = user.department;
      event.context.permissions = user.permissions;
    });

    // 根据部门过滤工具
    api.on("before_tool_call", async (event) => {
      const allowedTools = DEPARTMENT_TOOLS[event.context.department];

      if (!allowedTools.includes(event.tool)) {
        return {
          block: true,
          reason: `您的部门(${event.context.department})无权使用此工具`
        };
      }
    });
  }
};

// 插件 2:HR 工具包
export default {
  id: "hr-tools",
  register(api) {
    // 简历筛选工具
    api.registerTool({
      name: "screen_resume",
      description: "筛选简历",
      parameters: Type.Object({
        jobId: Type.String(),
        requirements: Type.Array(Type.String())
      }),
      async execute(toolCallId, params) {
        const resumes = await hrSystem.getResumes(params.jobId);

        // 使用 LLM 分析每份简历
        const scored = await Promise.all(
          resumes.map(async resume => {
            const analysis = await analyzedResume(resume, params.requirements);
            return { ...resume, score: analysis.score, reason: analysis.reason };
          })
        );

        // 按分数排序
        scored.sort((a, b) => b.score - a.score);

        return {
          content: [{
            type: "text",
            text: JSON.stringify(scored.slice(0, 10), null, 2)
          }]
        };
      }
    });
  }
};

// 插件 3:审计系统
export default {
  id: "audit-system",
  register(api) {
    // 记录所有工具调用
    api.on("before_tool_call", async (event) => {
      await auditDB.log({
        user: event.context.user.email,
        department: event.context.department,
        tool: event.tool,
        params: redactSensitive(event.params),
        timestamp: Date.now()
      });
    });

    // 敏感操作需要二次确认
    api.on("before_tool_call", async (event) => {
      const SENSITIVE_TOOLS = ["approve_payment", "delete_data", "grant_access"];

      if (SENSITIVE_TOOLS.includes(event.tool)) {
        // 发送确认请求
        const confirmed = await requestConfirmation({
          user: event.context.user.email,
          action: event.tool,
          params: event.params
        });

        if (!confirmed) {
          return { block: true, reason: "用户取消操作" };
        }
      }
    });
  }
};

// 插件 4:成本控制
export default {
  id: "cost-control",
  register(api) {
    // 部门级预算管理
    const departmentBudgets = new Map();

    api.on("llm_output", async (event) => {
      const dept = event.context.department;
      const cost = calculateCost(event.model, event.usage);

      const current = departmentBudgets.get(dept) || 0;
      departmentBudgets.set(dept, current + cost);
    });

    api.on("before_model_resolve", async (event) => {
      const dept = event.context.department;
      const budget = DEPARTMENT_BUDGETS[dept];
      const used = departmentBudgets.get(dept) || 0;

      if (used > budget * 0.9) {
        // 强制降级
        return {
          provider: "anthropic",
          model: "claude-haiku-3-5"
        };
      }
    });
  }
};

效果

  • ✅ HR 可以用 AI 筛选简历,但无权访问财务工具
  • ✅ Finance 可以分析财务报表,但无权查看 HR 数据
  • ✅ 所有操作有审计记录
  • ✅ 敏感操作需要二次确认
  • ✅ 每个部门有独立的成本预算
  • ✅ 集成企业内部通讯系统

3.2 最佳实践

1. 插件设计原则

单一职责

markdown 复制代码
❌ 错误:mega-plugin(包含 20 种功能)
✅ 正确:
   - auth-plugin(仅负责认证)
   - hr-tools(仅提供 HR 工具)
   - audit-logger(仅负责审计)

可配置性

typescript 复制代码
// ❌ 硬编码
const API_KEY = "sk-xxx";

// ✅ 从配置读取
const API_KEY = api.pluginConfig.apiKey;

错误处理

typescript 复制代码
// ❌ 不处理错误
const data = await externalAPI.call();

// ✅ 优雅降级
try {
  const data = await externalAPI.call();
  return data;
} catch (err) {
  api.runtime.logger.error("API 调用失败", err);
  return { error: "服务暂时不可用" };
}

2. 钩子使用原则

避免阻塞主流程

typescript 复制代码
// ❌ 在钩子中执行耗时操作
api.on("message_received", async (event) => {
  await slowDatabaseQuery();  // 阻塞 10 秒
});

// ✅ 异步处理
api.on("message_received", async (event) => {
  // 快速返回,后台处理
  processInBackground(event).catch(err =>
    api.runtime.logger.error("Background processing failed", err)
  );
});

优先级设置

typescript 复制代码
// 高优先级:需要先执行的逻辑
api.on("message_received", handler1, { priority: 2000 });

// 普通优先级
api.on("message_received", handler2, { priority: 1000 });

// 低优先级:清理性工作
api.on("message_received", handler3, { priority: 500 });

3. 性能优化

缓存配置

typescript 复制代码
let cachedConfig;

export default {
  register(api) {
    // ✅ 缓存配置,避免重复解析
    cachedConfig = api.pluginConfig;

    api.registerTool({
      async execute() {
        const apiKey = cachedConfig.apiKey;  // 直接使用缓存
      }
    });
  }
};

批量操作

typescript 复制代码
// ❌ 每次记录一条日志(频繁 I/O)
api.on("llm_output", async (event) => {
  await db.insert(event);
});

// ✅ 批量写入
const buffer = [];
api.on("llm_output", async (event) => {
  buffer.push(event);

  if (buffer.length >= 100) {
    await db.insertMany(buffer);
    buffer.length = 0;
  }
});

总结

Plugins 和 Hooks 的核心价值

🎯 为什么需要它们?
问题 解决方案
❌ 核心功能无法满足特定需求 ✅ Plugins 添加自定义功能
❌ 需要修改核心代码才能扩展 ✅ 即插即用,无需改动核心
❌ 无法监控和干预运行过程 ✅ Hooks 在关键时刻插入逻辑
❌ 团队协作困难,相互冲突 ✅ 插件独立开发,互不干扰
❌ 无法适应企业特定流程 ✅ 完全自定义,无限可能

🚀 能做什么?

Plugins 的 8 种超能力

  1. 🔧 添加新工具
  2. 💬 添加消息平台
  3. 🤖 添加 LLM 提供商
  4. ⚙️ 运行后台服务
  5. 🌐 提供 HTTP 接口
  6. 💾 替换存储系统
  7. 🎨 扩展 CLI 命令
  8. 🔌 添加 RPC 方法

Hooks 的 28 种触发点

  • 📋 Agent 生命周期(5 种)
  • 💬 消息流(3 种)
  • 🔧 工具调用(3 种)
  • 🧠 Compaction(3 种)
  • 👥 子代理(3 种)
  • 🔧 会话管理(2 种)
  • 🌐 网关事件(2 种)
  • ... 更多

🎓 何时使用?

使用 Plugins 的场景

  • ✅ 需要添加全新功能(新工具、新渠道)
  • ✅ 集成第三方服务(Jira、Slack、数据库)
  • ✅ 团队协作开发(各自开发独立插件)
  • ✅ 产品化(打包功能为可复用插件)

使用 Hooks 的场景

  • ✅ 需要监控和记录(审计、日志、统计)
  • ✅ 需要修改默认行为(模型选择、消息过滤)
  • ✅ 需要在特定时刻执行操作(自动保存、告警)
  • ✅ 需要实现复杂的业务逻辑(合规、权限、成本控制)

组合使用的场景

  • ✅ 企业级 AI 助手(认证 + 审计 + 成本控制 + 集成)
  • ✅ 智能客服系统(知识库 + 对话记录 + 自动分类)
  • ✅ 团队协作助手(任务管理 + 通知 + 自动化)

💡 关键要点

  1. Plugins = 能力扩展

    • 添加全新功能
    • 无需修改核心代码
    • 独立开发和部署
  2. Hooks = 行为定制

    • 监听关键事件
    • 修改默认行为
    • 实现业务逻辑
  3. 组合 = 无限可能

    • Plugins 提供工具
    • Hooks 定义策略
    • 协同实现复杂功能
  4. 安全第一

    • 配置验证(JSON Schema)
    • 边界检查(防止逃逸)
    • 权限控制(基于角色)
  5. 性能优化

    • 并行执行(Void 钩子)
    • 配置缓存
    • 批量操作

🎉 OpenClaw 的扩展生态

通过 Plugins 和 Hooks 系统,OpenClaw 从一个固定功能的 AI 助手 进化为一个无限可能的 AI 平台

diff 复制代码
OpenClaw 核心
    ↓
+ Plugins(添加能力)
    ↓
+ Hooks(定制行为)
    ↓
= 你的专属 AI 助手

开始构建你的第一个插件吧! 🚀

相关推荐
FE_winter2 小时前
OpenClaw Skills 进阶实战:前端开发者的 AI 技能库搭建指南
前端·后端·程序员
Java编程爱好者2 小时前
用Spring的ApplicationEventPublisher进行事件发布和监听
后端
Mintopia2 小时前
OpenClaw在日常开发中的应用实践与全场景解析
人工智能·openai·ai编程
Java编程爱好者2 小时前
MySQL索引优化实战:从原理到调优
后端
梁大虎2 小时前
Electrobun 开发必看:CEF 依赖下载失败?手动解压一招搞定!
前端·javascript·后端
狂奔小菜鸡2 小时前
Day41 | Java中的锁分类
java·后端·java ee
神奇小汤圆2 小时前
Redis缓存三大问题实战:穿透、雪崩、击穿怎么解决
后端
晚星star2 小时前
震惊!这个GitHub项目竟然能让你拥有专属域名邮箱!
后端
倚栏听风雨2 小时前
AI Agent 核心原理解析:一文看懂 ReAct 规划框架(附手搓代码)
后端