5月3日下午,我照例更新了 OpenClaw 到 v2026.5.2,然后 QQ Bot 就没动静了。后来查 GitHub 才发现,这不是 bug——而是一次设计变更带来的迁移事故。
现象
更新完,QQ Bot 不回消息。openclaw status 的 Channels 表空白。配置完好,token 没丢。去 session 文件看,最后一次连接停在更新前。日志里连个错都没有——插件直接不加载了。
翻 dist 目录,正常的频道插件(比如 Telegram)长这样:
/app/dist/extensions/telegram/
index.js ✅
api.js ✅
... 20+ JS 文件
QQ Bot 长这样:
/app/dist/extensions/qqbot/
openclaw.plugin.json ← 只有元数据
package.json ← 只有包描述
skills/ ← 空目录
零个 JS 文件
第一反应当然是「打包漏了」。从 plugin-runtime-deps 翻出旧版(v2026.4.29)的编译 JS,22 个文件,全部复制到 dist 目录,重启容器,好了。确认兼容性没问题,旧版 JS 在新版 gateway 上跑得挺稳。
到这里我以为是 OpenClaw 的 CI 构建又掉了链子。这种事情历史上出过好几次——#71730、#70096、#61686,打包和依赖缺失算是老毛病。
等一下,不是漏掉的,是故意删掉的
查到 GitHub 才发现事情没那么简单。
#77483 解释了一切:v2026.5.x 系列把 25 个频道和非频道插件从「内置 bundled」(JS 随 Docker 镜像分发)改为「外置 external」(独立 npm 包,按需安装)。QQ Bot 是其中之一。受影响的全列表:
acpx, bluebubbles, brave, codex, diagnostics-otel, diagnostics-prometheus,
diffs, discord, feishu, google-meet, googlechat, line, lobster,
memory-lancedb, msteams, nextcloud-talk, nostr, qqbot, synology-chat, tlon,
twitch, voice-call, whatsapp, zalo, zalouser
外置化的意思:这些插件的独立 npm 包(如 @openclaw/qqbot)已发布到 npm registry,Docker 镜像就不再带它们的编译产物了。dist 目录里只留元数据——plugin.json 和 package.json,用于提供插件清单信息(比如 config schema、catalog 注册等),但不包含实际可运行的代码。
所以不是我一开始以为的「漏了」,是有意为之。
但问题出在迁移上——从 v2026.4.x 升级到 v2026.5.x 时:
这三个缺陷加起来就是一次完美的静默失联。
2026.5.2 刚重启为啥能用?
因为插件加载走两条路:Loaded 注册表(外部安装的)优先,Bundled(镜像自带的)兜底。
v2026.5.2 刚启动时,plugin-runtime-deps 里旧版 QQ Bot 被扫进 loaded 表,第一步就命中了。后来 openclaw.json 被写入触发了 config reload,loaded 表清空重建,旧版插件没再注册回来——fallback 到 bundled,发现是空壳,就没了。
到 v2026.5.3 完全重启,loaded 表从零开始,从头就找不到。
这个设计变更是怎么被补上的
发现的时候(5/4),社区已经有人在跟进了。
我是看了 #77424——另一位用户遇到了完全一样的问题,不过是 Feishu 插件。同一个 Docker 镜像,同一个症状,同一个根因。
OpenClaw 团队的回应(5/4 夜间,GMT+8 今早)是三个 PR:
另外还有个附带修复——#77450 修了 plugin API 版本比较 bug:v2026.5.3-1 的 -1 后缀被通用 semver 比较当 prerelease 拒绝,导致所有 >=2026.5.3 的插件都装不了。这个跟 Docker 镜像 dist 缺失是两回事,但对通过 npm 安装插件的人影响很大。这是 #77293 被关闭的原因——但 #77293 的 issue 里另一个问题(install.runtime-*.js 缺失)其实没修。
正确姿势 vs 现在的凑合
未来的正确姿势:
openclaw plugins install @openclaw/qqbot --dangerously-force-unsafe-install
现在我用的 workaround(v2026.5.3-1 上)
从旧版 plugin-runtime-deps 复制编译 JS 到 dist 目录。能用,但有一个隐患:#77547 引入的 prune 脚本会在未来的 Docker 镜像构建时主动清理外置插件 dist 目录。等到更新到包含 #77547 的版本时,这个 workaround 可能就不奏效了(如果 prune 在容器启动时也执行的话),或者至少文件结构会跟官方预期不一致。
届时需要:清理手动复制的旧 JS 文件 → 用 openclaw plugins install @openclaw/qqbot 正式安装。
还挂着的问题
结论
这个问题的完整面貌:
对我个人来说,workaround 在 v2026.5.3-1 上能用,等后续版本出来要切到正式的 openclaw plugins install @openclaw/qqbot 方案。
也给自己留个教训:遇到这种问题,第一直觉的「打包漏了」要打个问号。如果能早一点发现 #77483 里说的外置化意图,排查方向就会完全不同。