五月三号下午,我照例更新了 OpenClaw 到 v2026.5.2,然后 QQ Bot 就没动静了。按理说小版本更新不该翻车——结果这次,它不是 bug,是一次架构变更引发的连锁事故。
翻来覆去折腾了一周,到 v2026.5.6 才算真正了结。把整个过程和判断写下来。
现象
openclaw status 的 Channels 表完全空白,配置完好,token 没丢,日志里连个报错都没有——插件直接静默跳过了。
查 dist 目录,Telegram 等正常频道有 20+ 个 JS 文件,QQ Bot 只有元数据空壳。
第一反应是「打包漏了」。江湖上这种事不新鲜——OpenClaw 历史上 #71730、#70096、#61686 都出过同样的问题。翻出 v2026.4.29 的旧版编译 JS 复制过去,重启,好了。看起来就是一次普通的 CI 翻车。
不是漏了,是故意删的
查 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
外置的意图很清晰:按需安装,减小镜像体积,隔离更新节奏。方向没问题。
但执行缺失了三样东西:没有迁移提示、没有自动安装、失败静默跳过。三个缺陷叠加,就是一次完美的静默失联。
加载链解释了为什么刚启动能用、reload 后就不行
startChannels()
→ getChannelPlugin("qqbot")
→ getLoadedChannelPlugin("qqbot") // 查 ~/.openclaw/npm/
→ getBundledChannelPlugin("qqbot") // fallback 到 dist
→ index.js ❌ 不存在 → 静默失败
v2026.5.2 刚启动时能连上,是因为 plugin-runtime-deps 里旧版 QQ Bot 被意外扫进了 Loaded 注册表,第一步就返回了。后来 config reload 清空注册表重建,旧版没再注册回来——fallback 到空壳,就没然后了。
三次修复,前两次是过渡,第三次才是正解
整个事件可以看作三次修复的接力。
第一次:临时 workaround。 从旧版 plugin-runtime-deps 复制 JS 到 dist 目录。粗暴但能用,容器重建就丢失。
第二次:官方安装方案(v2026.5.4)。 openclaw plugins install @openclaw/qqbot 装到 ~/.openclaw/npm/,持久化路径,Docker 重建不丢。同时 #77547 把 dist 目录的 prune 逻辑固化进构建脚本,workaround 不再可用。
第三次:升级保护(v2026.5.5)。 最大的隐患是「每次版本升级都要重装」——而 #77604(升级时自动恢复已配置的外部插件)被作者自己关了,从未进入任何版本。这个坑本来要留很久,但 v2026.5.5 的 changelog 里有一行不起眼的修复:
Plugins/update: keep installed official npm and ClawHub plugins synced during host updates
已安装的 @openclaw/qqbot 在版本升级时会自动保留。不是全自动迁移(从 4→5 的首次安装仍需手动),但后续维护终于不用操心了。
v2026.5.6 实际验证:QQ Bot 正常在线,更新没掉。
还挂着的问题
第一个跟我的使用场景直接相关——AI 回答偶尔就是简短肯定,翻 session 看不全挺烦。后两个影响不大,暂不跟进。
一个教训
遇到这种问题,第一直觉的「打包漏了」要打个问号。翻过几回车看什么都像 CI 翻车。如果能早一点发现 #77483 里说的外置化意图,排查方向会完全不同。
另外也看清楚了 OpenClaw 的插件持久化路径:~/.openclaw/npm/ 是卷挂载持久化的,/app/ 不是。以后涉及插件安装,路径选对就省一半心。
架构变更有两条分量:设计方向和迁移平滑度。这次前者是对的,后者是碎的。好在碎了一个版本集,缝上了。