
先说我为什么最后选了这套组合。QQ 机器人圈子迭代太快早几年主流方案不是停止维护就是配置链路长得让人劝退。我自己试过 go-cqhttp、Mirai、Koishi折腾一圈下来真正愿意长期维护的搭配是 NapCat NoneBot2NapCat 负责 QQ 账号的登录、消息收发和事件上报NoneBot2 负责把收到的事件交给 Python 插件处理两者通过 OneBot 11 协议通信。这篇部署指南会从环境准备讲到第一个插件跑通再覆盖扫码登录、反向 WebSocket、掉线排查、接入本地大模型这些我从实战里踩出来的经验。目标是让刚接触 QQ 机器人的朋友也能在两小时内把这套东西顺利部署起来。1. 项目整体设计与思路拆解1.1 为什么把登录和业务逻辑拆成两个进程很多第一次接触 QQ 机器人的人会问为什么要装两个东西一个程序直接搞定不是更省事吗实际做下来你会发现登录通信和业务逻辑的职责完全不同混在一起后期会非常痛苦。NapCat 本质上是基于新版 QQNT 客户端改造出的“无头客户端”它模拟普通 QQ 的登录状态把收到的消息、通知、请求统一转换成 OneBot 11 标准结构然后通过 HTTP 或 WebSocket 接口提供给外部程序。NoneBot2 则只负责监听网络接口接收这些事件数据路由给对应插件插件处理完再调用 NapCat 暴露的接口把回复发出去。这种拆分的好处是边界清晰。协议端更新版本或者 QQ 登录策略出了变化业务代码基本不用动反过来你改插件逻辑时只要不破坏事件消息格式也不影响协议端的连接配置。我见过不少项目把登录逻辑和业务逻辑揉在一个框架里协议一升级就得重构。拆成两个进程后排查问题也简单登录不上先看 NapCat 日志插件没反应再看 NoneBot2 日志谁的问题找谁。如果你用过监控摄像头就更好理解了。NapCat 是摄像头负责采集画面NoneBot2 是监控软件负责识别画面并处理事件。摄像头坏了换摄像头识别规则改了就改软件两者互不干扰。1.2 OneBot 11 标准与消息流向OneBot 11 是当前 QQ 机器人生态里事实上的标准协议定义了一组消息事件、通知事件、请求事件以及对应的 API 调用方式。NapCat 在链路里扮演 OneBot 服务端把 QQ 的原始消息包装成 JSON通过 WebSocket 推送出去NoneBot2 安装了nonebot-adapter-onebot适配器后能读懂这些 JSON也能把回复翻译成 OneBot API 调用。我推荐的连接方式是反向 WebSocket。听名字有点绕实际就是 NoneBot2 启动后监听一个本地端口NapCat 作为客户端主动连上去。连接建立后QQ 群里来一条消息事件沿着“QQ 服务器 - NapCat - WebSocket - NoneBot2 - 插件 - 调用发消息接口 - NapCat - QQ 群”这条路走一圈。反向连接非常适合协议端和框架端在同一台机器或者同一内网的场景两边都不需要公网地址配置量小出现连接问题也容易定位。事件类型新手只需要先关注三类消息事件群聊、私聊、临时会话、通知事件有人进群、撤回消息、请求事件好友申请、入群邀请。绝大多数机器人业务本质上都在处理消息事件。1.3 为什么选 NoneBot2 而不是其他框架选框架主要看三点维护活跃度、插件生态、开发门槛。NoneBot2 基于 Python 异步生态底层用了 FastAPI、httpx 这类成熟库插件数量虽然不像 JavaScript 生态那么庞大但质量普遍不错。只要会一点 Python定义一个on_command(hello)函数里面一行await hello.finish(world)一个能响应的命令就出来了。对比几个常见方案Koishi 插件市场很丰富但要写插件得先过 TypeScript 这关Mirai 功能强配置链路长更适合 Java 背景的人go-cqhttp 停更后新项目不建议再基于它。NoneBot2 还有一个好处是适配层做得很干净后续就算 QQ 协议端换了新实现只要它还支持 OneBot 事件插件代码基本不用改。方案语言/生态维护状态适合人群go-cqhttp自研协议端社区广泛已停止维护旧项目迁移NapCat基于 QQNT支持 OneBot 11活跃希望轻量接入MiraiJVM 平台插件丰富活跃但配置重熟悉 JavaKoishiTypeScript插件市场庞大活跃喜欢现成插件NoneBot2Python异步框架活跃Python 开发者我自己选 NoneBot2 还有一个实际原因机器人的业务往往不只是回消息后面还要做数据清洗、拉 HTTP 接口、定时跑任务这些场景用 Python 写起来比 TypeScript 舒服得多。机器人只是入口真正的业务逻辑才是重点。2. 部署前准备与环境检查2.1 硬件、系统与账号准备先明确最低配置。如果只是本机跑着玩Windows 10/11 或 Ubuntu 20.04 以上都行内存建议至少 2GB 可用。NapCat 跑起来大致占 500MB 到 1GB 内存NoneBot2 加上 Python 解释器再占 200MB 左右后面如果还要接本地大模型内存就往 4GB 以上走。云服务器选 2C4G 最低档就够磁盘 20G 比较舒服。账号方面的建议非常简单直接一定要用专用小号不要拿自己平时聊天的主号。第三方 QQ 客户端本身处于“能用但不是官方”的状态随时可能因为账号安全策略调整触发风控小号出事损失可控。新注册的号往往权重低登录时更容易出现“操作频繁”提示所以最好让小号正常使用几天再接入机器人。更不要一次性登录五六个小号去跑这种批量行为很容易被识别为异常。2.2 安装 Python、Docker 与基本工具NoneBot2 需要 Python 3.10 以上我推荐 3.11。Windows 上去 python.org 下载安装包时一定记得勾选“Add Python to PATH”否则命令行里敲python会提示找不到命令。Linux 下用包管理器安装sudo apt install python3 python3-venv python3-pip python3 --version如果打算用 Docker 跑 NapCat还需要装好 Docker。Windows 下用 Docker Desktop 方便但依赖 Hyper-V 或 WSL2Linux 服务器安装后建议执行sudo systemctl enable --now docker否则重启后 Docker 服务不会自动起来机器人也就跟着趴窝。还有一个容易被忽略的工具是curl后续下载资源、测试接口都要用到。Windows 10 以上系统自带 curlLinux 没有就装一下sudo apt install curl。2.3 操作前先建立配置文件的心理地图动手之前建议先记住三样东西会出现在哪里。第一NapCat 的配置目录Windows 解压目录或 Docker 挂载目录下一般有以 QQ 号命名的 JSON 文件记录 OneBot 连接方式第二NoneBot2 项目根目录下的.env文件里面写驱动、端口、访问令牌第三插件代码目录默认在src/plugins。后面所有排障本质上都是沿着这三个配置文件找问题。连接两端的核心钥匙是访问令牌也就是 access token。它是你自定义的一段字符串NapCat 在反向连接时带上它NoneBot2 校验通过才允许建立 WebSocket。不设令牌当然也能跑但一旦 NoneBot2 的端口暴露在公网任何人连上来都能控制机器人这是绝对不允许出现的风险。我的建议是令牌一定设长度不低于 16 位最好用随机字符串。3. NapCat 部署与登录实操3.1 Windows 本机部署步骤Windows 上部署最省事。去 NapCat 的 GitHub Releases 页面下载最新版压缩包解压到一个不含中文和空格的目录比如D:\napcat。解压后运行启动脚本napcat.bat它会拉起一个 QQ 客户端登录窗口。用前面准备好的小号扫码登录登录成功后 NapCat 控制台会打印出服务地址和配置入口提示。这里有个容易踩坑的认知登录用的 QQ 窗口不是给你日常使用的它是协议端在后台维持登录状态的载体。窗口可以最小化但不要随手退出。如果机器人在云服务器上跑且没有图形界面就别用 Windows 本机这套直接看下一节 Docker 方案。第一次启动后NapCat 会生成配置文件默认在解压目录的config/下文件名类似onebot11_你的QQ号.json。后面改连接方式主要就是改这个文件或者通过 WebUI 界面操作具体看版本。3.2 使用 Docker 部署协议端Linux 服务器上跑图形化 QQ 很麻烦所以 Docker 方案是主流。NapCat 的镜像名和参数会随着版本迭代变化最稳妥的方式是到项目文档页复制当前推荐的 docker run 命令。下面是我常用的启动格式实际使用时替换成文档里的真实镜像名docker pull 你的NapCat镜像名 docker run -d \ --name napcat \ --network host \ -e ACCOUNT你的QQ号 \ -e WS_ENABLEtrue \ -e WS_PORT3001 \ -e TOKEN你的令牌 \ -v napcat_config:/app/napcat/config \ --restartalways \ 你的NapCat镜像名:latest解释下关键参数。--network host让容器直接复用宿主机网络容器里监听 3001 端口就相当于监听宿主机 3001 端口少一层端口映射的困扰。WS_ENABLEtrue表示开启 WebSocket 服务端WS_PORT3001让 NapCat 在 3001 端口等待外部连接这个通道也可以作为备用调试入口。TOKEN是连接令牌必须和 NoneBot2 那边保持一致。--restartalways保证容器挂了自动拉起对无人值守的机器人非常重要。启动后用docker logs -f napcat看日志日志里会出现二维码地址或二维码图片路径。用手机 QQ 扫码登录成功后容器保持 running。如果提示扫码失败或操作频繁别马上重试至少等 15 分钟再说。3.3 配置反向 WebSocket 连接接下来让 NapCat 主动连接 NoneBot2。如果还没启动 NoneBot2可以先跳过这一步等第 4 章跑起来再回来配。反向连接地址写ws://127.0.0.1:8080/onebot/v11/ws令牌和后面.env里的ONEBOT_ACCESS_TOKEN保持一致。新版 NapCat 一般提供 WebUI在网络配置或 OneBot 配置页面找到“反向 WebSocket 连接”添加连接并填写 URL 和 token 即可。如果只能改 JSON在onebot11_你的QQ号.json中找到websocketReverse数组加入如下配置{ websocketReverse: [ { enable: true, name: nonebot, url: ws://127.0.0.1:8080/onebot/v11/ws, accessToken: your_token, reconnectInterval: 5000 } ] }reconnectInterval是断线重连间隔单位毫秒写 5000 就是 5 秒重连一次。保存配置后NapCat 会立刻尝试连接日志里会出现“已连接”之类的信息。如果显示失败先不要怀疑配置有问题很可能只是 NoneBot2 还没启动。4. NoneBot2 项目创建与插件开发4.1 使用 nb-cli 初始化项目NoneBot2 官方提供了脚手架nb-cli用法类似 Django 的django-admin。先创建虚拟环境再安装避免污染系统 Pythonmkdir qqbot cd qqbot python -m venv .venv source .venv/bin/activate # Windows 下用 .venv\Scripts\activate pip install nb-cli nb createnb create会进入交互式对话依次让你选择项目名称、驱动、适配器。内置驱动建议选 FastAPI它是 NoneBot2 现在最常用的 ASGI 服务外部驱动选 OneBot V11对应 NapCat 输出的协议。生成后的目录结构大致是qqbot/ .env .env.prod pyproject.toml src/ plugins/.env是开发环境配置.env.prod是生产环境配置。本地调试先用.env就够。4.2 配置驱动、端口和访问令牌打开.env写入ENVIRONMENTdev DRIVER~fastapi~websockets~httpx HOST0.0.0.0 PORT8080 ONEBOT_ACCESS_TOKENyour_token LOG_LEVELINFODRIVER前面的~表示在默认驱动基础上追加。fastapi提供 HTTP 服务websockets让 NoneBot2 能接受 WebSocket 连接httpx是给插件发 HTTP 请求用的客户端三者组合是跑 QQ 机器人最常见的配置。HOST写0.0.0.0表示监听所有网卡本机或局域网都能连如果只在本机调试写127.0.0.1更安全。PORT必须和 NapCat 反向连接 URL 里的端口一致。ONEBOT_ACCESS_TOKEN必须和 NapCat 配置里的 token 相同。改完.env后需要重启 NoneBot2 生效。新手第一坑就是改了 token 忘了重启两边永远对不上日志还只显示连接失败排查半天才发现是配置没重载。4.3 开发第一个插件命令回复在src/plugins/下新建echo.py这是最经典的“回声”插件from nonebot import on_command from nonebot.adapters.onebot.v11 import MessageEvent echo on_command(echo, aliases{回声}) echo.handle() async def handle_echo(event: MessageEvent): text event.get_plaintext().strip() if text: await echo.finish(text) else: await echo.finish(用法/echo 想让我重复的内容)on_command(echo)表示监听以/echo开头的消息aliases里写的“回声”也能触发。get_plaintext()会取出消息里的纯文本去掉图片、CQ 码等附加信息适合绝大多数文本命令场景。await echo.finish(text)会结束当前事件并回复后续的 matcher 不再处理这条消息。启动机器人nb run然后小号在群里或者私聊窗口发送/echo 你好它应该回“你好”。如果没反应先看启动日志有没有报错再看 NapCat 是否已经建立 WebSocket 连接。4.4 用日志确认消息到达命令能跑通后很多新手会想直接做“全自动回复”这时候可以加一个on_message监听器from nonebot import on_message from nonebot.adapters.onebot.v11 import MessageEvent from nonebot.log import logger all_msg on_message(priority10) all_msg.handle() async def log_all(event: MessageEvent): logger.info(f收到消息: {event.get_plaintext()})注意priority10表示优先级较低数字越小越先执行。后续如果加了更具体的命令处理器它默认优先级会比较靠前会优先拦截。这段日志非常适合判断“消息到底有没有到 NoneBot2”是排查机器人不回应时很实用的第一工具。5. 常见问题与排查技巧5.1 登录失败、环境异常、操作频繁最常见的问题集中在 NapCat 启动后扫码登录阶段。QQ 提示“当前环境异常”或“操作频繁”通常有三个原因账号太新、设备信息变化频繁、短时间内多次触发验证。我的处理方式是换一个正常使用超过一周的小号保持设备指纹不变也就是别反复卸载安装、频繁切换服务器 IP遇到提示就停下来等 15 到 30 分钟不要反复扫码。另一个要注意的是 QQ 客户端提示“版本过低”。出现这个提示往往意味着新版 QQ 协议有变化旧客户端已经不被允许登录。这时不要手动升级 NapCat 内置的 QQ 内核因为第三方客户端未必适配新版去 NapCat 发布页看有没有同步新版内核的版本有就升级协议端没有就耐心等适配。5.2 WebSocket 连不上连接问题九成出在 token 不一致、端口写错、路径不对这三件事上。按顺序检查第一.env里的PORT和 NapCat 反向连接 URL 里的端口是否相同第二.env里的ONEBOT_ACCESS_TOKEN和 NapCat 里的accessToken是否完全一致包括结尾的空格第三URL 路径是不是/onebot/v11/ws这是 OneBot V11 适配器默认监听路径写错成/ws会连不上。然后看日志。NoneBot2 收到连接时会输出类似“WebSocket connection”的信息NapCat 日志也会显示“反向 WebSocket 已连接”。两边都没有输出先确认端口在监听ss -lntp | grep 8080端口正常但连不上检查防火墙。Windows 弹出防火墙提示时需要允许 Python 和 Docker 相关进程通过Linux 如果开了 ufw执行sudo ufw allow 8080放行。如果只是本机调试其实没必要把 8080 对公网开放。5.3 命令没反应、权限不足、重复回复插件写好了但发消息没反应第一步先确认消息是否到达了 NoneBot2。如果能打印日志说明到了只是插件没匹配上。这时看命令前缀NoneBot2 默认COMMAND_START[/]消息必须能以/开头才会触发on_command。你发“echo 你好”不带前缀自然不触发。也可以在.env里加COMMAND_START[/, ]让不带前缀也能触发但我不太推荐容易误触发。权限方面默认任何人和任何群都能触发命令。如果只想自己用可以加permissionSUPERUSER同时在.env配SUPERUSERS[你的QQ号]。重复回复也常见通常是同一个插件被加载了两遍或者多个 matcher 都监听了同一条消息。排查时把多余插件文件移出目录再观察日志里的加载次数。5.4 依赖报错与虚拟环境混乱“我明明 pip install 了为什么还提示 ModuleNotFoundError”这个问题几乎每周都有人问。绝大多数情况是安装依赖时用的 Python 环境和运行nb run时的环境不是同一个。最简单的解决方式是全程使用虚拟环境每次打开新终端先激活Windows 下看到命令行前缀变成(.venv)再敲命令。如果项目里用pyproject.toml管理依赖可以直接pip install -e .安装声明好的依赖。NoneBot2 升级后旧适配器可能不兼容需要同步升级nonebot-adapter-onebotpip install --upgrade nonebot-adapter-onebot升级前备份当前.env和插件目录方便出问题后回滚。5.5 快速自检清单现象第一步检查常见原因NapCat 扫码失败看 QQ 提示文案新号、环境异常、频繁操作NoneBot2 没日志确认端口监听和防火墙进程没起、端口被占用NapCat 连不上反向 WS对比 token 和路径token 不一致、路径写错命令不触发看消息是否带/命令前缀不匹配插件重复回复看插件加载日志插件被重复导入依赖缺失确认当前虚拟环境环境切换混乱6. 进阶玩法把机器人接入本地大模型6.1 调用 Ollama 上已经部署好的模型最近很多人折腾本地部署 DeepSeek、Ollama 这类大模型服务其实和 QQ 机器人天然适合组合。比如你本机已经用 Ollama 跑了一个 Qwen 或 DeepSeek 蒸馏模型在 NoneBot2 插件里用 httpx 调用http://127.0.0.1:11434/api/generate机器人立刻就有了一个完全本地的问答大脑。写一个chat命令from nonebot import on_command from nonebot.adapters.onebot.v11 import MessageEvent import httpx chat on_command(chat, aliases{问问}) chat.handle() async def handle_chat(event: MessageEvent): prompt event.get_plaintext().strip() if not prompt: await chat.finish(用法/chat 你的问题) async with httpx.AsyncClient(timeout60) as client: resp await client.post( http://127.0.0.1:11434/api/generate, json{model: qwen2.5:7b, prompt: prompt, stream: False}, ) answer resp.json().get(response, ) await chat.finish(answer[:500])我在.env里已经加了httpx驱动所以插件里可以直接用httpx.AsyncClient。timeout60很重要本地模型生成一长段回复可能要十几秒默认 5 秒超时几乎必超时。截断到 500 字是为了避免刷屏QQ 对超长消息会做分片体验反而不好。6.2 定时任务、管理员保护和群聊白名单机器人接上大模型后必须考虑两个问题谁可以调用、什么场景下调用。我的做法是加一个群聊白名单只有配置里记录的群 ID 才响应 AI 命令同时用nonebot-plugin-apscheduler做定时任务比如每天早上推送天气、每周汇总待办。定时任务本身不复杂难点在于判断哪些事件应该响应、哪些应该忽略。最好把所有敏感操作都加上权限校验比如把.env里的SUPERUSERS设成自己的 QQ 号管理类命令统一permissionSUPERUSER普通用户的聊天请求另走一个 matcher用白名单控制。6.3 合规使用与安全建议这一部分单独拿出来说因为它很重要。使用第三方 QQ 客户端存在账号限制和功能失效的风险所以必须用专用小号不要拿主号测试更不要批量注册账号做营销。机器人在群里发言要克制不要刷屏不要发违规内容尽量遵守每个群自己的规则。安全上NoneBot2 监听端口尽量不要对公网完全开放。如果必须从公网访问建议用带身份认证的网关转发并启用 HTTPS收到文件或链接时插件不要盲目下载执行。访问令牌设置得足够复杂并定期更换风险会低很多。机器人能自动发消息之后就相当于一个有“手”的程序代码里每个finish都可能影响一群真人上线前多测试几轮没有坏处。做这套组合以来我最大的体会是把问题拆分清楚排障就成功了一半。NapCat 负责登录和通信NoneBot2 负责逻辑两边通过 WebSocket 用标准 OneBot JSON 对话机器人出问题时先判断是哪个环节再翻对应日志很少会排查超过十分钟。最后再分享一个小技巧上线前先写一个/ping命令返回当前时间和进程运行时长以后判断机器人是不是“假活”会很有用——很多机器人表面在线其实 WebSocket 早就断了只是没人发现。照着这篇把第一个机器人跑起来之后你可以继续加定时任务、接本地大模型、做管理后台剩下的路就顺了。