新功能不该直接塞进 OneBot 代理。我会先写 manifest,把权限、配置和健康检查定下来,再动手写功能代码。
聊天机器人项目很容易越写越像一个大脚本。
一开始只是接收消息、判断关键词、发一条回复。后来要加画图、提醒、总结、文件处理、状态查询、管理员命令,每个功能都往主代理里塞一点逻辑。短期看最快,长期看最难维护。
chatbot-qq 后来把可隔离功能拆成插件。我回看这块时,更关心每个插件是否提前说清自己是什么、要什么、会影响哪里。
功能逻辑别占住传输层
QQ 机器人有一层很现实的传输复杂度:
- NapCat 登录。
- OneBot 事件。
- 群聊和私聊路由。
- 消息发送。
- 重连。
- cc-connect 调度。
这些东西应该留在平台层。
插件只处理功能行为。比如画图插件不该关心 OneBot websocket 怎么连,也不该自己管理 NapCat 生命周期。它只需要判断一条消息是不是触发了画图命令,然后把任务交给宿主提供的命令 API。
这样拆开以后,排查会清楚很多:消息收不到看传输层,触发词解析错看插件,画图任务失败看后端命令。
manifest 先把话说清楚
每个插件目录里都有 plugin.json,它不只是元数据。
它要声明:
- 插件 id。
- 标题和版本。
- host API 版本。
- 最低宿主版本。
- 默认是否启用。
- 适用场景是群聊、私聊还是两者。
- 需要哪些权限。
- 暴露哪些 hook。
- 默认配置。
- 配置 schema。
这份清单让宿主在加载插件前就能知道:这个插件能不能加载、应该给它什么能力、配置是否合法、是否需要拒绝未来版本。
没有 manifest 的插件系统,很容易退化成“约定大家都别乱写”。而机器人项目一旦靠约定,后面一定会被越来越多的功能打破。
权限要显式注入
插件平台里把权限和宿主 API 绑定起来。
例如:
send_message -> ctx.api.sendMessageexec_command -> ctx.api.runCommandschedule -> ctx.api.scheduleread_workspace_file -> ctx.api.readWorkspaceFilewrite_local_file -> ctx.api.writeLocalFile这说明插件不是天然拿到所有能力。它在 manifest 里声明自己需要什么,宿主再按权限注入 API。
对聊天机器人来说,这很重要。不同插件的风险不同:提醒插件需要 schedule,画图插件需要运行任务,状态插件可能只需要 health。把所有能力默认暴露出去,会让一个小功能拥有不必要的破坏面。
权限声明不是安全的全部,但它是最基本的自我约束。
配置 schema 要挡在写入前
插件配置如果只是一个随便写的 JSON,很快会出问题。
比如画图插件有触发词、单群并发数、队列上限。这里每个字段都要写清类型和限制:
triggers是字符串数组。max_concurrent_per_group是整数,并且有上限。queue_max_per_group是整数,并且允许为 0。- 不允许额外字段。
管理员命令修改配置时,应该先过 schema,再写本地配置文件。否则一个拼错字段、类型错误或超大并发值,可能直接让机器人行为变得不可预测。
配置 schema 的好处很直接:错误配置还没写入状态,就先被拦下来。
health 和 capabilities 让插件可观察
插件除了能触发,还要能回答两个问题:
我现在健康吗?我现在提供哪些能力?画图插件的 capabilities 可以返回当前触发词、队列上限和并发上限。health 则交给宿主的 health API 汇总。
这类信息对管理员很有用。机器人出问题时,不需要去翻每个插件源码,先看插件快照就能知道哪些插件启用、哪些失败、哪些配置异常。
可观察性不是服务端系统才需要,聊天机器人同样需要。
插件测试应该就地写
插件目录下有自己的 tests/,例如画图插件会测试:
/img cat能解析出cat。画图cat这种中文触发词能解析。- 普通消息不会误触发。
- 命中后会调用宿主提供的
runCommand。
这些测试很小,但刚好覆盖插件最容易坏的地方。
更重要的是,插件本地测试不需要启动 NapCat,也不需要连真实 QQ。它只构造一个 context,验证插件逻辑和宿主 API 调用即可。
这能避免把所有测试都塞进端到端机器人环境。端到端测试昂贵、慢、还容易受登录状态影响;插件测试应该快、确定、可重复。
circuit breaker 管运行时故障
插件平台还提到 runtime hook 的 timeout 和连续失败计数。插件反复失败后,circuit 会打开,宿主跳过这个插件,直到 reload 或配置变更。
这对聊天机器人很实际。
一个插件坏了,不该拖死整个机器人。尤其是群聊场景里,机器人要先保持基础在线,再局部降级。画图坏了,提醒和状态查询仍然应该工作;某个插件超时,不该阻塞所有消息处理。
这也是插件系统和大脚本的区别:大脚本里一个功能异常可能把主循环带崩,插件系统至少有机会隔离失败。
新功能先问自己六件事
以后给聊天机器人加功能,我会先问:
它的 manifest 是什么?它需要哪些权限?它的配置 schema 是什么?它暴露哪些 hook?它怎么报告 health 和 capabilities?它的插件本地测试覆盖什么?这些问题答不清,就先别写业务逻辑。
聊天机器人越接近真实使用,光靠“先能跑”会很快吃亏。功能会越来越多,群聊和私聊上下文也会越来越复杂。插件清单、权限、配置、健康状态和本地测试,是后面继续维护时最省心的底座。
继续读