我与 NapCat 二三事
2026 年 2 月 21 日下午,QQ 协议端 NapCat 的 1、3、4 号群聊全部解散。惊闻此事,笔者内心百感交集,遂作此篇。
笔者研究 QQ Bot 的时间并不算长,满打满算也就是自从笔者高考之后,也就是 2023 年下半年开始的事情了。那时因为 Mirai 和 go-cqhttp 相继停止开发,开发者社区又对新版本的 QQ 协议——后来我们称之为 NTQQ——研究不足,所以在那时,QQ Bot 的生态可以说是刚刚经历了一场浩劫,只剩残垣断壁,只剩下 Chronocat 和 Shamrock 之类的并不算成熟的解决方案仍在被小范围的使用,还有部分账号仍然可以登录旧版 QQ 的用户仍在使用 Mirai 或 go-cqhttp。
在那条著名的、实质上相当于给 go-cqhttp 判了死刑的 Issue 里,Mrs4s 明确提出了一个在 NTQQ 时代可能有效的解决方案,那就是 “黑进” PC NTQQ 客户端。我们知道新版的 PC QQ 客户端基于 Electron 开发,自然就引入了 Chromium 内核和 Node.js 运行时,这就为我们提供了一个非常好的切入点,那就是将 JS 代码注入这些环境,让它们去调用 QQ 在 wrapper.node 中封装好的原生 API,从而使得自定义的逻辑得以在 NTQQ 客户端中运行。我们将这种思路称为 Hook,而上面提到的 Chronocat 就是基于 Hook 思路的早期项目。Hook 的好处在于它不需要我们去逆向分析 NTQQ 协议的细节,也不需要我们去从头实现一个客户端,只需要弄清楚这些 API 是怎么封装的,以及怎么调用它们就行了。
第一个真正意义上的成熟的 Hook 项目是 LLOneBot(现已改名为 LuckyLilliaBot)(不是 NapCat,很意外吧),它在 2024 年年初就已经实现了很多 OneBot 11 标准中规定的 API,通过一个名为 LiteLoaderQQNT 的框架将 JS 代码注入到 NTQQ 客户端中,在 NTQQ 客户端的 Node.js 环境中启动了一个 HTTP 服务器来接受来自外部的请求,并将这些请求转换成对 NTQQ 客户端原生 API 的调用。LLOneBot 的出现让 NTQQ 时代的 QQ Bot 生态有了一个真正意义上的起点,虽然它的 API 覆盖率在当时并不算高,但它的设计思路和实现方式却为后来者提供了非常宝贵的参考。在这些(其实为数不多的)后来者中,最为人熟知的就是 NapCat 了。
在开始下面的故事之前,有必要先认识一下几个主要人物:
- linyuchen - 又名林雨辰,LLOneBot(现名 LuckyLilliaBot)的主要开发者
- MliKiowa - 又名拾雪,NapCat 的主要开发者
还有一个,那当然是鄙人了。不过笔者并没有持续高强度参与任何一个项目的开发,所以在下面的故事里笔者更多是一个旁观者的角色。
2024 年 3 月,笔者进入了 LLOneBot 的群聊。当然,在彼时,笔者只是一个无名之辈,甚至都没怎么用过 LLOneBot,只是尝试自己在客户端运行了一下。当时的 LLOneBot 仍然依赖 LiteLoaderQQNT 来加载,因此必须运行在有 GUI 的环境中,这就导致了它的用户群体主要是一些在 Windows 上使用 PC QQ 的用户,而对于那些在 Linux 或者没有 PC QQ 的用户来说,LLOneBot 就不太友好了。此外,受 LiteLoaderQQNT 架构所限,LLOneBot 使用了 IPC 通信机制来调用底层 API,这就导致了它的性能并不算太好。MliKiowa 在群聊中提出了一个大胆的想法,那就是从头实现一个基于 Hook 思路的 ”无头“ 框架,彻底抛弃对 GUI 和 IPC 的依赖,以期降低占用、提高性能上限。linyuchen 给这个想法起了个名字,叫做 NapCat。这个名字将框架描述为一只睡着的猫,比喻它的 “无头” 和低占用的特性。
NapCat 的开发进展神速,但在最初的几个月里,它的功能覆盖率并不算高,代码质量更是相当糟糕,到处充斥着 Side Effect 和不合理的设计。例如,NapCat V1 的代码中,QQ 原生 API 的封装对象(WrapperSession)直接被写在了一个全局对象里,而在框架启动时,QQ 的相关功能未必已经完全加载,这就导致了很多业务的初始化逻辑竟然被写成了 setTimeout 的形式,等待 QQ 加载完成后再执行,这严重影响了代码的可维护性。尤其是后来笔者尝试将框架移植到 LiteLoaderQQNT 上时,发现框架的代码库甚至存在着循环依赖等问题。因此,2024 年 8 月,NapCat 迎来了一次重大的重构,而这次重构的主要负责人就是 MliKiowa 和笔者。经过重构,NapCat 的代码库不再有启动时的 Side Effect 和循环依赖,所有代码按顺序加载,业务逻辑所需的 API 封装对象由构造器注入的方式提供。重构后的 NapCat V2 在性能和稳定性上都有了显著的提升,用户群体也逐渐扩大了。顺带一提,截至本文成稿,NapCat 的源码仓库的 Contributor 排行中笔者仍然排在第二位,有着大量的代码行数增减,其实就是来源于此次重构了。
此后,笔者就较少参与 NapCat 的开发了,但仍然密切关注 NapCat 这一项目的发展。V3 之后的 NapCat 引入了一个重要特性,那就是 Native Hook。在此之前,NapCat 都局限于在 JS 层调用封装好的 NTQQ API,这导致 NapCat 只支持电脑端 QQ 的操作,而对于其他一些比较常用的,但 PC NTQQ 不支持的操作,例如设置群成员专属头衔,则未能支持。引入 Native Hook 后,NapCat 能够直接控制 QQ 数据包的收发,这使得框架可以构造一些 PC NTQQ 本不支持发送(而安卓端 QQ 协议中存在)的数据包,从而实现一些之前无法实现的功能。这让 NapCat 的功能覆盖率有了一个飞跃式的提升,用户群体也因此得到了进一步的扩大,各种辅助项目例如 NapCat-Desktop、NapCat-Docker 也相继出现。
值得一提的是,这时 NapCat 和 LLOneBot 的关系相当融洽,两个框架甚至共用两个群聊:其中一个群聊的群主是 linyuchen,另一个群聊的群主则是 MliKiowa。
然而,就在 2024 年底,MliKiowa 对 LLOneBot 以及 linyuchen 的态度急转直下。MliKiowa 认为 linyuchen 及其维护的 LLOneBot 未经许可使用了 NapCat 的源码,并且没有给予原作者相应的尊重。而 linyuchen 则以 NapCat 的代码以 MIT 协议开源,并且指出 NapCat 的代码库中也存在来自 LLOneBot 的代码为由,反驳了 MliKiowa 的指责。MliKiowa 率先在以 linyuchen 为群主的群聊中进行了激烈的指责,随后 linyuchen 以及一部分 LLOneBot 的用户也加入了这场争论,双方在群聊中互相指责。最终,这场争论造成了两个框架分道扬镳,二者井水不犯河水,不再共用群聊,各自维护自己的框架和用户群体。NapCat 的用户群体逐渐转移到了 MliKiowa 的群聊中,而 LLOneBot 的用户则留在了 linyuchen 的群聊中。
2025 年 3 月,MliKiowa 再一次以此事为由进入 linyuchen 的群聊进行指责,而 linyuchen 以 Word 文档的形式再次进行了回击。此事以 NapCat 在项目 README 中特别声明自己使用了 LLOneBot 代码,同时 NapCat 将开源协议从 MIT 切换为了自行拟定的 License,禁止任何项目未经许可使用 NapCat 的代码告终,两个框架的关系就此彻底破裂,而 NapCat 项目开始着手开发一套新的 WebUI,以取代之前基于 LLOneBot 的 WebUI。
NapCat 的 WebUI 发展迅速,在产生之后的很短时间内,就已经支持了远程登录、服务器状态监控、OneBot 11 服务配置、文件管理、远程终端等诸多功能,并且在设计上也非常现代化,采用了 React 和 TypeScript 来实现,NapCat 的用户群体也因此得到了进一步的扩大,此时项目的 Star 数量已经超过了 5k。同时,也有人指出,WebUI 在安全性上存在问题,例如:默认监听 0.0.0.0 的特定端口,并且默认 token 是固定字符串 napcat;特征过于明显,并且对搜索引擎没有应对措施,导致 WebUI 容易被扫描,乃至在 Google、Bing 等搜索引擎中能够搜索到大量暴露在公网的 NapCat 实例;WebUI 的权限过高,支持对宿主机的高危操作,例如访问任意文件、执行任意指令。
这些问题大多数以 Issue 和群聊讨论的形式反馈到 NapCat 的开发团队,但并没有得到足够的重视,最终导致了 2025 年 9 月份发生的恶性事件:攻击者通过 WebUI 的特征扫描暴露在公网的 NapCat 服务,并且操纵其暴露的 OneBot 11 API 在 QQ 群中发布违法信息,导致所有受到波及的 QQ 账号和群聊都遭到永久封禁(相关讨论见笔者的另一篇文章)。NapCat 的开发团队在事后发布了一个安全公告,将责任归结于用户没有正确配置 WebUI 的安全设置,并且在 WebUI 中增加了许多安全措施,但这件事情仍然引发了用户群体的极大恐慌,NapCat 项目的声誉也受到了严重的打击。笔者自 2024 年起一直是 NapCat 群聊的管理员,在撰写上述文章并且进行了一定程度的传播后,笔者的管理员权限也被 MliKiowa 取消。此后的一段时间里,NapCat 没有出现过与上述事件恶性程度相当的事件。
时间来到 2026 年 1 月,此时的 NapCat 项目 Star 数目已逾 7k,项目的开发重心转移到了插件系统和插件市场的建设上。所谓插件系统,即允许第三方开发者利用 NapCat 提供的 API 编写自定义应用逻辑,并且将这些逻辑以插件的形式内嵌到 NapCat 中运行。NapCat 插件市场的第一个插件是 builtin,其功能是检测用户发送的 #napcat 消息,并且在收到消息后在群聊中发送当前 NapCat 实例的版本、平台和运行时长,并且在 NapCat 中默认启用。NapCat 插件系统的产生标志着 NapCat 的定位从一个单纯的 NTQQ 协议端框架扩展到支持一定的应用端功能的框架,这也使得 NapCat 的用户群体有了一个新的增长点,当然,也有部分用户认为此举过于激进,认为 NapCat 应该专注于协议端的功能。但无论如何,这个 builtin 插件的出现让 NapCat 用户群聊的群规产生了一个重大变化:此前,NapCat 群聊是严格禁止自建 QQ Bot 加入的,因为频繁的指令触发会导致刷屏,影响群聊的正常交流,但在 builtin 插件出现后,NapCat 群聊放宽了对 QQ Bot 账号的限制,转而禁止普通用户发送 #napcat 消息,避免触发 builtin 插件的功能导致刷屏。
随着时间的推移,NapCat 的插件市场积累了数十个插件,其中不乏用户 lengxi-root 编写的实用插件,同时也有其他一些基础插件和实用插件。然而,在春节前夕,lengxi-root 在自己的群聊中释出了一个用于抢红包的插件,虽然并没有在 NapCat 插件市场中发布,但仍然不乏部署了此插件的 NapCat 用户,严重影响了红包金额分配的公平性,遭致了大量反对,相关消息也在其他 QQ Bot 相关群聊引发了讨论。NapCat 群聊的一个管理员也在部署此插件的用户之列,在群情激愤下,此管理员主动退出了 NapCat 群聊,此后 NapCat 群聊也对疑似抢红包插件的使用者进行了清退,并且在群规中明确禁止使用任何形式的抢红包插件。
好景不长,2026 年 2 月 21 日下午,又有用户发现自己登录了 NapCat 实例的 QQ 账号在凌晨添加了某个官方 Bot 的好友,发送一条消息,又悄悄地删除好友。此举被指出是 lengxi-root 的插件所为,证据是 lengxi-root 在其插件源码中插入了一个 ts 文件,用于从某一 API 获取需要加好友发送信息的 Bot QQ 号,并且在每天凌晨 4:17 执行这一逻辑。由于这一逻辑使用了在 NapCat 源码中并未实现的主动加好友行为(这一行为十分容易被黑灰产业链利用,因此 NapCat 拒绝实现),并且并非插件的预期行为,因此 lengxi-root 再次在 NapCat 群聊中引发了轩然大波,并且消息在整个 QQ Bot 社区迅速传开,很多并不相干的用户也开始质疑 NapCat 引入插件系统的合理性,认为 NapCat 的开发团队没有对插件系统进行足够的安全审查和限制,导致了这一事件的发生。种种因素之下,MliKiowa 最终做出了解散 NapCat 群聊的决定。
NapCat 群聊解散后,笔者承认,因为上面所说的原因,自己甚至一度感到有些庆幸,觉得自己终于可以摆脱这个充斥着争吵和指责的环境了。但冷静下来后,笔者又不禁思索:到底是什么,导致了 NapCat 从一个充满希望的项目,发展成为一个充斥着争吵和指责的项目,甚至最终走向了分裂和解散的结局呢?笔者认为,主要有以下两个方面的原因:
第一,“树大招风” 是一个重要的因素。截至成稿,NapCat 的 Star 总数超过 7k,其中虽然不乏专业用户,但也不缺少在 QQ Bot 领域认知相对不足的用户,乃至毫无基础、只是因为一则营销号的视频或文章就来到这里的 “小白” 用户。这些用户的存在,使得 NapCat 的用户群体变得非常复杂,难以管理和维护,用户群体知识水平的巨大差异也使得很多决策都变得非常困难,例如:该不该给 WebUI 设置默认的简单 token?该不该默认监听 0.0.0.0?该不该允许用户在插件中使用某些高危 API?等等。笔者认为,NapCat 的开发团队对用户群体的复杂度估计不足,导致在做出一些决策时没有充分考虑到这些决策可能带来的安全风险,从而引发了后续的一系列问题。
第二,NapCat 开发团队对于既发问题的复盘和处理有不足之处。例如,在 2025 年 9 月份的恶性事件发生后,NapCat 的开发团队虽然发布了安全公告,并且在 WebUI 中增加了安全措施,但并没有对事件进行深入的复盘和分析,也没有对用户群体进行充分的沟通,而是一味地将责任归结于用户。虽说 “开源用户不欠着谁“,但在安全事件发生后,开发团队如果能够更积极地与用户沟通,分析事件的原因,并且将这些因素充分纳入后续的设计和决策中,或许,就不会在插件系统上重蹈覆辙了。
虽然 MliKiowa 在 README 中声明项目的开发并不会因为群聊的解散而终止,但不可否认,历经种种波折,NapCat 的开发团队和用户群体的心态都受到了严重的打击,MliKiowa 也在 README 中更新了寻找新的维护者的公告。用户社群的解散无疑是 NapCat 社区乃至整个 QQ Bot 社区的重大损失,不由得令笔者叹惋。NapCat 的未来充满了不确定性,但无论如何,笔者大概永远都不会忘记 NapCat 曾经带给我们的那些美好时光,以及它在 NTQQ 时代的 QQ Bot 生态中所扮演的重要角色。最后,笔者都衷心期望 QQ Bot 社区能够从 NapCat 的经历中吸取教训,避免重蹈覆辙,让 QQ Bot 生态能够健康、稳定地发展下去。
CC BY-NC 4.0 2026 © Wesley Young.我大概,一辈子都不会忘记 NapCat 了吧。