插件基础结构

奶狗 发表于 4 周前 浏览 44 字数 1854 阅读时长 10分钟

1. 插件基础结构

1.1 目录结构

所有插件放在 plugins/ 目录下,每个插件一个子目录,目录名必须与 meta.id 一致:

plugins/
├── smart/                  # 智能助手(内置核心,AI 兜底)
├── reply/                  # 关键词/指令回复(内置)
├── reminder/               # 定时提醒(内置)
├── memory/                 # 用户画像(内置)
├── mcp/                    # MCP 协议(内置)
├── qqbot/                  # QQ 机器人网关(内置常驻模块)
├── weather/                # 天气查询(市场插件示例)
├── aidraw/                 # AI 绘图(命令型市场插件示例)
├── market/                 # 用户上传的自定义插件
│   └── mp-xxxx/index.js    # 每个上传插件一个子目录
└── 你的插件/
    └── index.js
  • plugins/market/ 存放用户在插件市场上传的插件(不支持 npm 依赖)。
  • 目录名必须与 meta.id 一致,这是文件系统定位的依据。
  • 自定义插件不要使用内置 ID(replyremindermcpsmartmemoryqqbot)。

1.2 最小可用插件

module.exports = {
  meta: {
    id: 'my-plugin',              // [必填] 唯一标识,必须与目录名一致
    name: '我的插件',              // [必填] 后台/市场展示名称
    version: '1.0.0',             // 版本号
    author: '开发者',              // 作者
    category: '工具',             // 分类
    description: '做什么的',       // 一句话描述
    entry: 'my-plugin/index.js',  // [推荐] 入口相对路径,用于安装定位
    usage: '发送「触发词」即可',   // [推荐] 使用说明,出现在帮助菜单
  },

  async onMessage(msg, ctx) {
    const text = (msg.content || '').trim();
    if (text !== '触发词') return false;   // 不匹配 → 交后续插件
    // … 业务逻辑 …
    return true;                          // 已处理 → 阻止后续插件
  },
};

1.3 meta 完整字段

字段 类型 必填 说明
id string 唯一标识,必须与目录名一致
name string 显示名称
version string 版本号(建议语义化 x.y.z
author string 作者
category string 分类:AI对话 / 信息获取 / 工具 / 娱乐 / 消息处理 / AI 创作
description string 简短描述
entry string 推荐 入口相对路径,如 my-plugin/index.js
usage string 推荐 使用说明,出现在帮助菜单(发「菜单」即可看到)
builtin boolean true 时不在插件市场展示(内置功能专用,自定义插件不要设)
configurable boolean 是否有设置页面,默认 true。设为 false 则不在设置面板出现
settingsSchema array 设置项定义,见第2节
customConfig string 自定义设置组件名(如 'smart_ai'),需前端配合渲染
aiTools array AI 工具声明,对接智能助手 function calling,见第4节
commandPrefix string[] 命令前缀列表,智能助手遇到这些前缀会主动让位给该插件
channels string[] 显式声明支持的渠道 ['wechat','qq'],见第5节
member_only boolean 设为 true 则仅会员可安装使用

1.4 onMessage 返回值

返回值 行为
false 未命中,交后续插件继续处理
true 已处理,阻止后续插件
{ reply: '文本' } 框架自动调用 ctx.sendText('文本') 发送,并阻止后续插件
undefined 等同于 false(继续后续插件)

1.5 执行顺序(重要)

消息到达后的处理链(固定指令/关键词类插件优先于 AI,smart 总是最后兜底):

1. 文本是「菜单/帮助/help/menu」?  → 输出帮助文本,结束
2. 命中 memory 指令(画像)?        → memory 处理,结束
3. 触发通用钩子(不阻断主流程)
4. 遍历启用插件,逐个调用 onMessage
   ├─ 市场插件 + 内置模块在此步执行
   ├─ smart(智能助手)在此轮被跳过(留到最后兜底)
   └─ 命中(返回 true 或 {reply})→ 结束
5. 没有任何插件命中 → smart 兜底(自然语言 AI / 图片识别 / 语音识别)

所以你的精确匹配插件不会被 AI 抢走commandPrefix 是双保险——即使 smart 已被触发,遇到这些前缀也会让位。