前言
在 OpenClaw 的架构中,插件系统是扩展功能的核心机制。本文将分享我开发的 default-processor 插件,它实现了工具调用的拦截与路由,让技能可以接管内置工具的执行。
问题背景
在开发过程中,我遇到了几个痛点:
- 内置工具不稳定:
memory_search在国内经常 403,无法正常使用 - TTS 需要云端:内置 TTS 走云端服务,延迟高且有隐私顾虑
- 无法灵活替换:想用自己的本地服务替代内置工具,但没有标准机制
解决方案:default-processor 插件
核心思路
通过 OpenClaw 的 before_tool_call 钩子,在工具调用前进行拦截,根据配置将请求路由到对应的技能脚本。
插件架构
extensions/default-processor/
├── package.json # 插件配置
├── tsconfig.json # TypeScript 配置
├── src/
│ └── index.ts # 插件源码
└── dist/
└── index.js # 编译输出
关键代码
// 技能执行映射
const SKILL_EXECUTORS = {
// memory_search -> memory-v2 技能
'memory_search': async (params) => {
const query = params.query || params.text || '';
const script = `${WORKSPACE}/skills/memory-v2/scripts/hybrid-search.mjs`;
const { stdout } = await execAsync(`node "${script}" "${query}"`);
return { ok: true, result: stdout };
},
// tts -> voice-skill 本地 TTS
'tts': async (params) => {
const text = params.text || '';
const script = `${WORKSPACE}/skills/voice-skill/scripts/tts-voice.sh`;
const { stdout } = await execAsync(`bash "${script}" "${text}"`);
return stdout.trim();
},
};
插件注册
function register(api) {
// 注册 before_tool_call 钩子
api.on('before_tool_call', async (event, ctx) => {
const { toolName, params } = event;
const skillName = overrides[toolName];
if (!skillName) return; // 无覆盖配置,使用内置工具
const executor = SKILL_EXECUTORS[toolName];
const result = await executor(params);
// 返回结果,阻塞原工具调用
return {
result,
block: !result.ok,
blockReason: result.ok ? undefined : result.error
};
}, { priority: 100 });
}
配置方式
在 openclaw.json 中配置插件:
{
"plugins": {
"entries": {
"default-processor": {
"enabled": true,
"config": {
"overrides": {
"memory_search": "memory-v2",
"tts": "voice-skill"
}
}
}
}
}
}
开发踩坑记录
1. TypeScript 编译问题
现象:切换模型时报错 Cannot read properties of undefined
原因:OpenClaw 加载插件时找不到编译后的 .js 文件,直接加载 .ts 失败
解决:
- 添加
tsconfig.json配置 - 编译输出到
dist/index.js - 更新
package.json的main和openclaw.extensions指向编译后的文件
2. 参数格式兼容
现象:插件加载成功但工具调用报错
原因:官方插件用 parameters + @sinclair/typebox,我的插件用 inputSchema,格式不兼容
解决:统一使用 parameters 格式:
parameters: Type.Object({
query: Type.String(),
})
3. 双目录配置
注意:workspace/skills/default-processor-plugin 和 extensions/default-processor 两个目录的 package.json 都要更新,确保一致。
实际效果
配置完成后:
| 工具 | 原来 | 现在 |
|---|---|---|
memory_search | 云端 API,经常 403 | 本地向量数据库,毫秒响应 |
tts | 云端 TTS | 本地 MeloTTS,Intel GPU 加速 |
日志验证:
[default-processor] Plugin loaded
[default-processor] Intercepting memory_search -> memory-v2
[default-processor] Skill memory-v2 executed: success
总结
default-processor 插件实现了:
- ✅ 工具调用拦截(
before_tool_call钩子) - ✅ 技能路由(配置化映射)
- ✅ 本地服务替代(避免云端依赖)
- ✅ 零侵入切换(随时回退到内置工具)
这套机制让 OpenClaw 的扩展性大大提升,任何内置工具都可以被技能无缝替换。