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 # 处理逻辑
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 种超能力:
- 🔧 添加新工具
- 💬 添加消息平台
- 🤖 添加 LLM 提供商
- ⚙️ 运行后台服务
- 🌐 提供 HTTP 接口
- 💾 替换存储系统
- 🎨 扩展 CLI 命令
- 🔌 添加 RPC 方法
Hooks 的 28 种触发点:
- 📋 Agent 生命周期(5 种)
- 💬 消息流(3 种)
- 🔧 工具调用(3 种)
- 🧠 Compaction(3 种)
- 👥 子代理(3 种)
- 🔧 会话管理(2 种)
- 🌐 网关事件(2 种)
- ... 更多
🎓 何时使用?
使用 Plugins 的场景:
- ✅ 需要添加全新功能(新工具、新渠道)
- ✅ 集成第三方服务(Jira、Slack、数据库)
- ✅ 团队协作开发(各自开发独立插件)
- ✅ 产品化(打包功能为可复用插件)
使用 Hooks 的场景:
- ✅ 需要监控和记录(审计、日志、统计)
- ✅ 需要修改默认行为(模型选择、消息过滤)
- ✅ 需要在特定时刻执行操作(自动保存、告警)
- ✅ 需要实现复杂的业务逻辑(合规、权限、成本控制)
组合使用的场景:
- ✅ 企业级 AI 助手(认证 + 审计 + 成本控制 + 集成)
- ✅ 智能客服系统(知识库 + 对话记录 + 自动分类)
- ✅ 团队协作助手(任务管理 + 通知 + 自动化)
💡 关键要点
-
Plugins = 能力扩展
- 添加全新功能
- 无需修改核心代码
- 独立开发和部署
-
Hooks = 行为定制
- 监听关键事件
- 修改默认行为
- 实现业务逻辑
-
组合 = 无限可能
- Plugins 提供工具
- Hooks 定义策略
- 协同实现复杂功能
-
安全第一
- 配置验证(JSON Schema)
- 边界检查(防止逃逸)
- 权限控制(基于角色)
-
性能优化
- 并行执行(Void 钩子)
- 配置缓存
- 批量操作
🎉 OpenClaw 的扩展生态
通过 Plugins 和 Hooks 系统,OpenClaw 从一个固定功能的 AI 助手 进化为一个无限可能的 AI 平台:
diff
OpenClaw 核心
↓
+ Plugins(添加能力)
↓
+ Hooks(定制行为)
↓
= 你的专属 AI 助手
开始构建你的第一个插件吧! 🚀