问题背景

在 QQ 里挂一个 AI 机器人,需求通常长这样:它能回私聊,能进群接话,能记住你说过的事,最好还能看图、听语音。听着像个小项目,真动手会发现要先搞明白一堆名词——AstrBot、OneBot、NapCat、go-cqhttp、协议端、框架端,每个都能单独写一篇。

这些名词其实是三个层次的东西,理清了就不乱:

  • QQ 协议端:负责真正登录 QQ、收发消息。QQ 官方没有开放个人号机器人接口,所以社区走的是「在本地跑一个 QQ 客户端 + 注入/挂载协议实现」这条路。
  • OneBot 规范:一套统一的机器人应用接口标准,把「协议端」和「框架端」解耦。协议端按 OneBot 说人话,框架端就只认 OneBot,换协议端不用改框架。
  • 框架端:真正写业务逻辑的地方,管插件、管人格、管上下文、对接大模型。本文用的 AstrBot 就是这一层。

所以「用 AstrBot 和 OneBot 部署 QQ 机器人」翻译过去就是:AstrBot(框架端)+ 一个 OneBot 实现(协议端)+ 一个 QQ 小号。

本文把这条路线整理成一份能照着走的说明。需要先声明:下面每个命令都来自各项目的官方文档或官方 compose 文件,我把来源逐条标了出来,但没有在自己的机器上跑通全流程——所以你在执行时,请以官方文档为准,遇到不一致以官方为准。

1. 整体架构

QQ 小号
   │  (扫码登录)
   ▼
协议端:NapCat  ──┐
                 │  WebSocket
                 ▼
框架端:AstrBot ──┬── DeepSeek / 通义千问 等(对话)
                 ├── 视觉模型(看图)
                 └── 本地嵌入模型(记忆检索)

各组件职责与端口:

组件角色默认端口说明
QQ 小号消息收发载体—强烈建议用小号,有风控概率
NapCatOneBot 协议端6099(WebUI)登录 QQ、把消息转成 OneBot 事件
AstrBot框架端6185(管理面板)、6199(WS 接入)插件、人格、记忆、模型调度
模型服务大脑—对话模型、视觉模型、嵌入模型

端口来源:AstrBot 官方 Docker 文档的 docker run 命令里映射的是 6185 和 6199(AstrBot Docker 部署文档);NapCat Docker 的 README 与 compose 里 WebUI 是 6099(NapCat-Docker)。

2. 选型:为什么是这两个

2.1 协议端为什么不用 go-cqhttp

go-cqhttp 是很多老教程里的默认答案,但它自己的 README 已经把话说明白了。原文(Mrs4s/go-cqhttp README「重要信息」段):

由于 QQ 官方针对协议库的围追堵截,不断更新加密方案,我们已无力继续维护此项目。

同一时间点的官方 issue #2471(《QQ Bot 的未来以及迁移建议》,至今 open)里的结论句更直接:

协议库的时代已经过去,接下来是 Hook 官方客户端的时代了。

也就是说,官方自己认为”协议库”这条技术路线已经结束了——这正是 NapCat 这类「Hook 官方客户端」方案成为主流的原因。

客观状态数据(gh api repos/Mrs4s/go-cqhttp,撰写时实测):

  • archived = false(仓库没有被 GitHub 归档标记)
  • pushed_at = 2026-10-20(但这是 Dependabot 依赖升级)
  • stargazers_count = 10616
  • open_issues_count = 314
  • 最后一次人工提交是 2024-05-09(Merge pull request #2526 from Mrs4s/dev)
  • 最新 release 停在 v1.2.0(2023-10-09)

所以准确的表述是:官方明确声明已无力继续维护、实质停更,但仓库未被归档。写”已被官方归档”是不准确的,写”还能用”同样不准确。

2.2 NapCat 的现状

先说一个容易被忽略的事实:AstrBot 官方文档列出的 OneBot v11 实现端只有三个——NapCat(QQ)、OneDisc(Discord)、Tele-KiraLink(Telegram)。也就是说,在 AstrBot 的官方语境里,做 QQ 只有 NapCat 这一条被文档背书的路线。

NapNeko/NapCatQQ 最新 release 为 v4.18.42(发布于 2026-10-30),配套的 NapNeko/NapCat-Docker 在同日更新。

⚠️ 许可证要看清:NapCat 用的不是标准开源许可,而是自定义的「Limited Redistribution License for NapCat」,其中明确写着:

This code is not to be used for any commercial purposes.

个人玩没问题,要商用得先把条款读完。

其他 OneBot v11 实现(理论都能用,因为它们实现的是同一个规范;但它们不在 AstrBot 官方文档的列表里,遇到问题时不要指望官方文档有答案):

项目协议支持备注
NapCatQQOneBot 11AstrBot 官方文档列出的实现端,本文使用
LuckyLilliaBotOneBot 11 / Satori / Milky原 LLOneBot,多协议
onebot-kotlinOneBot 11原 cqhttp-mirai
node-onebotOneBot 11Node 实现

顺带把另一个容易混的点说清:AstrBot 声明支持「所有适配了 OneBot v11 反向 WebSocket 的协议端」,所以上面这些都能连。但「能连」和「官方支持」是两件事,写教程时不该混着说。

2.3 框架端为什么选 AstrBot

AstrBot 官方文档的定位原文是「开源的一站式 Agentic 个人和群聊助手」,它官方支持的消息平台包括(节选自官方 README 的 Supported Messaging Platforms 表格):

平台维护方
QQOfficial
OneBot v11 protocol implementationOfficial
Telegram / 企业微信 / 微信公众号 / 飞书 / 钉钉Official
Slack / Discord / LINE / KOOK / Misskey / MattermostOfficial
SatoriOfficial
Matrix / Rocket.Chat / VoceChatCommunity

注意第二行:OneBot v11 是官方维护的适配器。这意味着 AstrBot 原生就懂 OneBot,不需要额外装桥接插件——这正是本文路线的技术前提。

几个动手前该知道的硬信息(撰写时实测):

项值
最新版本v4.29.4(2026-10-31)
许可证AGPL-3.0
Python 要求3.12+(requires-python = ">=3.12",走 uv 部署时卡这个)
仓库AstrBotDevs/AstrBot
文档https://docs.astrbot.app

⚠️ AGPL-3.0 值得留意:如果你修改了 AstrBot 的代码,并把它作为带有商业盈利性质的网络服务对外提供,按这个许可证你必须开源你的修改。自己用无所谓,对外提供服务前先想清楚。

3. 部署 AstrBot(框架端)

官方 README 的 Quick Start 给出五种部署方式,按场景选:

方式适用场景官方出处
云一键部署不想管服务器RainYun 一键部署
uv 一键部署熟悉命令行、想快速体验uv tool install astrbot --python 3.12
Docker / Compose稳定、适合生产官方 Docker 文档
桌面应用桌面端用 ChatUIAstrBot-desktop
Launcher桌面端、多实例隔离astrbot-launcher

此外官方文档还列了宝塔面板、1Panel、CasaOS、源码部署等方式。

3.1 Docker 部署

官方文档给出的通用命令(原文,端口 6185 是管理面板):

mkdir astrbot
cd astrbot
sudo docker run -itd -p 6185:6185 -p 6199:6199 \
  -v $PWD/data:/AstrBot/data \
  -v /etc/localtime:/etc/localtime:ro \
  -v /etc/timezone:/etc/timezone:ro \
  --name astrbot soulter/astrbot:latest

中国大陆网络环境的镜像加速(官方文档特别提示):

sudo docker run -itd -p 6185:6185 -p 6199:6199 \
  -v $PWD/data:/AstrBot/data \
  -v /etc/localtime:/etc/localtime:ro \
  -v /etc/timezone:/etc/timezone:ro \
  --name astrbot m.daocloud.io/docker.io/soulter/astrbot:latest

Windows 下不需要 sudo;Windows 同步宿主机时间需要 WSL2,卷路径写 \\wsl.localhost\<你的-wsl-发行版>\etc\timezone:/etc/timezone:ro。

查看日志:

sudo docker logs -f astrbot

启动成功的标志是日志里出现「🌈 管理面板已启动,可访问」以及几条链接。

两个容易踩的点(均来自官方文档的 TIP):

  1. 不能用 localhost 访问管理面板。Docker 隔离了网络环境,要用宿主机 IP。
  2. 首次登录密码在启动日志里,用户名通常是 astrbot。官方明确要求登录后立即修改。

忘记密码可以在容器内重置:

sudo docker exec -it astrbot astrbot password
# 同时改用户名
sudo docker exec -it astrbot astrbot password --username <新用户名>

改完要重启容器才生效:sudo docker restart astrbot。

3.2 和 NapCat 一起用 Compose 起

这是最省事的方式,因为协议端和框架端会落在同一个 Docker 网络里,不用管宿主机端口暴露。

官方 AstrBot 文档给的步骤是直接取 NapCat 官方维护的 compose 模板:

mkdir astrbot
cd astrbot
wget https://raw.githubusercontent.com/NapNeko/NapCat-Docker/main/compose/astrbot.yml
sudo docker compose -f astrbot.yml up -d

这个模板的原文(NapNeko/NapCat-Docker/compose/astrbot.yml)是:

services:
  napcat:
    environment:
      - NAPCAT_UID=${NAPCAT_UID:-1000}
      - NAPCAT_GID=${NAPCAT_GID:-1000}
      - MODE=astrbot
    ports:
      - 6099:6099
    container_name: napcat
    restart: always
    image: mlikiowa/napcat-docker:latest
    volumes:
      - ./data:/AstrBot/data
      - ./napcat/config:/app/napcat/config
      - ./ntqq:/app/.config/QQ
    networks:
      - astrbot_network
  astrbot:
    environment:
      - TZ=Asia/Shanghai
    image: soulter/astrbot:latest
    container_name: astrbot
    restart: always
    ports:
      - "6185:6185"
    volumes:
      - ./data:/AstrBot/data
    networks:
      - astrbot_network
networks:
  astrbot_network:
    driver: bridge

注意 compose 文件顶部的用法注释(原文):

# NAPCAT_UID=$(id -u) NAPCAT_GID=$(id -g) docker-compose -f ./compose/astrbot.yml up -d

也就是带上当前用户的 UID/GID 启动,避免挂载目录的读写权限问题——NapCat 官方 README 明确说「NAPCAT_UID、NAPCAT_GID 指定运行用户,挂载目录需允许该用户读写」。

两个值得注意的细节:

  • napcat 的环境变量里是 MODE=astrbot,而 NapCat 独立部署的示例里是 MODE=ws。据 NapCat 官方 README:「MODE=ws 启用正向 WebSocket;反向连接使用 reverse_ws / reverse_http,并设置 ONEBOT_URL」,并且「WEBUI_TOKEN、MODE 仅初始化缺失的配置。已有部署在 WebUI 中修改」。所以 MODE 是给初次启动写默认配置用的,起过一次之后要改就得进 WebUI 改,改 compose 文件不会覆盖已有配置。

  • ⚠️ astrbot 服务的 6199 端口在这个模板里是被注释掉的(原文写的是 #- "6199:6199")。而官方步骤明确要求把它取消注释再启动:

    ports:
      - "6185:6185"
      - "6199:6199"   # 把这一行开头的 # 去掉

    不取消也能跑——因为两者同处 astrbot_network,NapCat 用容器名 ws://astrbot:6199/ws 直连就行,不必经过宿主机端口。但取消注释才是官方给的做法:一旦你把 NapCat 挪到另一台机器、或拆进另一个 compose,宿主机端口不暴露就连不上了。

4. 单独部署 NapCat

如果不想用 Compose 捆绑,或者想把协议端放在另一台机器上(比如 Windows 本机扫码更方便),就单独装 NapCat。

NapCat 官方 README 给的最小 compose 示例(原文):

services:
  napcat:
    image: mlikiowa/napcat-docker:latest
    restart: unless-stopped
    environment:
      MODE: ws
      WEBUI_TOKEN: replace-with-your-own-token
    ports:
      - "127.0.0.1:6099:6099"
      - "127.0.0.1:3001:3001"
    volumes:
      - ./data/qq:/app/.config/QQ
      - ./data/config:/app/napcat/config
      - ./data/plugins:/app/napcat/plugins
docker compose up -d
docker compose logs -f napcat

打开 http://127.0.0.1:6099/webui 登录。

⚠️ 注意 WEBUI_TOKEN 官方写的是 replace-with-your-own-token——这是占位符,必须换成自己的值。另外示例里端口绑定写的是 127.0.0.1:6099:6099,即只监听本机;要远程访问得调整绑定地址或走 SSH 转发。

其他运维要点(官方 README):

  • 更新:docker compose pull && docker compose up -d,三个数据目录保留。
  • 固定版本:把 latest 换成发布标签。
  • 镜像拉取的代理要配在 Docker daemon 里,不是容器里。
  • 需要调试 core dump 时设 NAPCAT_ENABLE_COREDUMP=1。
  • 群晖还需要给共享目录设置 ACL。

不想用 Docker 的话

NapCat 官方也提供各平台的一键安装,最常见的两种:

Linux(官方一键脚本):

curl -fL --connect-timeout 20 --max-time 1800 -o napcat.sh \
  https://raw.githubusercontent.com/NapNeko/NapCat-Installer/main/script/install.sh \
  && bash napcat.sh --docker n --cli y --github-proxy 0

Windows(很多人选这条,因为扫码登录最方便):装好 QQ 后解压 NapCat.Shell.zip,双击 launcher.bat(Win10 用 launcher-win10.bat);或者用一键包 NapCat.Shell.Windows.OneKey.zip,运行 NapCatInstaller.exe,再双击 napcat.bat。

⚠️ Windows 上有个真实的坑:QQ 自动更新之后可能直接失效——第 9 节的踩坑实录里有具体案例。如果打算 7×24 挂机,要么锁住版本,要么干脆走 Docker。

无论哪种装法,首次启动后都用手机 QQ 扫码登录小号。

5. 让两端连起来

5.1 先分清楚方向(这里最容易错)

OneBot 的连接方向有两种,名字极易搞混:

方式谁主动配置位置
正向 WebSocket框架端主动连协议端框架端填协议端地址
反向 WebSocket协议端主动连框架端协议端填框架端地址

本文的路线用的是反向 WS:AstrBot 在 6199 上提供 WebSocket 服务,NapCat 作为客户端连过去,所以配置动作在 NapCat 侧。

NapCat 官方术语表特意写明了这个坑:

WebSocket 服务端 = 通常指正向 WS
WebSocket 客户端 = 通常指反向 WS

所以在 NapCat 里必须选「WebSocket 客户端」——虽然直觉上”服务端”看起来更像在提供服务的那一方。选错的症状是 AstrBot 里始终看不到适配器连接,遇到先回头查这里。

5.2 地址填什么

在 NapCat 的 WebUI(http://127.0.0.1:6099/webui)里,或者配置文件 config/onebot11_<QQ号>.json 里,加一个 WebSocket 客户端。

地址取决于两端分别怎么部署(官方 FAQ 给了三种组合):

部署组合URL
NapCat 和 AstrBot 都在 Dockerws://astrbot:6199/ws(用容器名,需在同一 Docker 网络)
只有 NapCat 在 Dockerws://<宿主机IP>:6199/ws
都不在 Dockerws://127.0.0.1:6199/ws

5.3 AstrBot 侧怎么配

新建平台适配器,类型选 QQ(aiocqhttp),端口 6199。这两个值来自 AstrBot 官方文档,与大肥鱼项目的部署指南一致。

AstrBot 侧的源码默认值(astrbot/core/config/default.py),对不上时可以拿来核对:

字段默认值说明
ws_reverse_host0.0.0.0一般直接填这个
ws_reverse_port6199
ws_reverse_token空只有 NapCat 侧配了 token 才需要填

5.4 怎么确认真的连上了

官方文档给的判据只有一个 —— AstrBot 的 WebUI 日志出现这一行:

aiocqhttp(OneBot v11) 适配器已连接

反面判据同样明确:若干秒后出现 aiocqhttp 适配器已被关闭 就是没连上。

连上之后还有个小惊喜:群聊里机器人不会每条消息都回。你需要 @ 它,或者用唤醒词(默认是 /),比如发一句 /你好。管理员 ID 可以用 /sid 指令拿到。

6. 接入模型服务

AstrBot 官方 README 有完整的 Supported Model Services 章节,下面是按用途分类的常见搭配:

用途建议关键配置
对话主力DeepSeek(deepseek-chat)官方 API https://api.deepseek.com/v1
看图通义千问 VL 系列填到「图片转述提供商」
听语音通义千问 ASR 系列需要语音转写
说话(TTS)百炼音色复刻 + TTS 模型先在控制台复刻音色拿 voice_id
记忆检索本地嵌入模型(如 bge-m3)走 Ollama,免费且数据不外传

最后一行是这套架构里比较划算的一环:嵌入模型本地跑,记忆检索不上云。

如果 AstrBot 需要走 HTTP 代理,官方文档说明代理地址由容器内部访问,所以:

  • Mac / Windows(Docker Desktop):http://host.docker.internal:7890
  • Linux:http://172.17.0.1:7890(换成实际的 docker0 网关)
  • 代理与 AstrBot 在同一 Docker 网络:用容器名,如 http://clash:7890

并且提醒一句官方原话的坑:代理端口写成 127.0.0.1:7890:7890 时,「其他容器从网关进不去」。

7. 装插件与配人格

到这一步,一个能回消息的裸机器人应该已经跑通了。接下来才是让它「像个角色」。

社区里有个把这条路走得很完整的开源项目可以借鉴:大肥鱼(whyever77/dafeiyu-astrbot,MIT,197 stars)。它的 README 自述是「AstrBot QQ 机器人全家桶:会看会听会说话、有记忆、会主动找你的鲸鱼娘」,并明确说明大肥鱼是 DeepSeek 蓝鲸 logo 的社区二创形象(非官方)。

它的能力清单可以作为「一个完整的 QQ 机器人可以做到什么程度」的参考:

感官能力实现思路
看图片 / 表情包 / 视频(默认前 5 分钟,最多 16 帧)qwen3-vl 转述 + ffmpeg 抽帧
听语音消息 / 视频音轨NapCat 转码 + qwen3-asr-flash
说语音条(含自定义音色)百炼音色复刻 + TTS
表情真实 QQ 表情自研插件把 [旺柴] 转成表情段
记长期记忆livingmemory + bge-m3 嵌入
群聊@ / 引用 / 唤醒词NapCat 群消息 + 唤醒词
隔离每个私聊、每个群各自一册记忆记忆插件的 session 作用域

它的插件(plugin/astrbot_plugin_face_convert/)做了一个很关键的设计:出站整形 + 入站翻译。

  • 出站:QQ 不会渲染机器人发的纯文本表情码,所以要把 [旺柴] 这类中括号表情名转成真正的 QQ 表情段;另外要做气泡合并,避免表情夹在句子中间时把一句话拆成三条消息。
  • 入站:纯表情消息的文本是空的,会被上游当成「空消息」直接跳过——所以要把它翻译成 [旺柴] 这样的文本,机器人才能反应过来。

安装方式(README 原文步骤):

  1. 把 plugin/astrbot_plugin_face_convert/ 整个文件夹放进 AstrBot 的 data/plugins/,重启。
  2. 在 AstrBot 里新建人格,把 persona/大肥鱼-人格.md 的正文整段粘贴进去,设为默认人格。
  3. 需要语音 / 记忆 / 自定义音色,再按 docs/导入指南.md 继续。

8. 安全设置(必做,不是可选)

先看 AstrBot 官方文档里那句语气最重的话(aiocqhttp 接入页原文):

如果您对部署、网络配置不了解,请千万不要在公网暴露 NapCat 的端口。

NapCat 官方讲的是同一件事:「如果采用服务端工作模式且未配置鉴权,将应用暴露在公网环境中会带来严重安全风险」。

换句话说:6099 默认只应该监听 127.0.0.1,要远程访问就老实用 SSH 转发。 这不是”建议”,是两边官方都在用警告的语气说的事。

在此之上,大肥鱼项目的部署指南把安全单列了一节,这几条值得照抄思路:

  • 访问控制白名单:只放行你自己的会话,例如 qq:FriendMessage:<你的QQ>。默认不要开放给陌生人。
  • 好友手动通过:给机器人加好友必须你手动确认——第一道门永远在人手里。
  • 主动消息设免打扰时段:例如 23-8,注意跨午夜的写法。
  • 小号手机端偶尔挂着:降低被判定为异常登录的概率。
  • 注意防提示词注入:机器人会读到陌生人发来的文本,这是一条真实的攻击面。

9. 踩坑实录

以下每一条都来自大肥鱼项目的 docs/踩坑合集.md(23 条)与官方文档,挑几条最容易被卡住的:

1)纯表情消息会被整条跳过。 上游把「文本为空」判定为空消息,直接丢弃。表现是「她装死不回表情」。解法见上一节的入站翻译。

2)NapCat 连接断线不自愈。 表现是「发消息没反应」。这是运维层面最常遇到的一类问题,需要做健康检查或受控重启。

3)同一大版本 QQ,不同构建号结果天差地别。 该项目的记录里,QQ 9.9.33-52230 在 Win11 25H2 上注入会崩(0x80000003 @ QQNT.dll+0x26b6e3a),而 9.9.35-52892 能跑。看构建号,不看大版本号;且 QQ 自动更新后可能再次失效——长期跑建议锁版本,7×24 建议直接走 Docker。

4)插件市场装不上。 通常是 GitHub 访问被卡住,需要给 AstrBot 配 HTTP 代理(见第 6 节的代理写法)。

5)语音合成有两个常见坑。 一是需要源码补丁才能让语速/音高生效;二是分段回复 + TTS 时,表情会把一句话拆成多条,语音被逐条重置语调——正确做法是显示照常分泡,语音按完整语义合成一次。

6)消息「回声病」。 人格指令打不过她自己最近说过的话,需要在文本层面做擦除。

这些坑的完整版在项目仓库的 docs/踩坑合集.md,一共 23 条,分 QQ/NapCat 侧、AstrBot/插件侧、大模型侧、工程杂项四类。如果你的机器人行为开始变得奇怪,先去这份清单里找——大概率有人踩过了。

10. 合规与风险

这一节不能跳过。

  • 个人 QQ 号挂机器人属于非官方接口路线,存在被风控、被限制登录乃至封号的概率。所以社区的一致建议是用小号。
  • 不要把机器人暴露给陌生人使用,不要让它在大量群聊里主动发言,行为越像「正常用户」越安全。
  • 大肥鱼项目的默认设计是「逐条审批 + 白名单 + 专用小号」,这个保守程度值得参考。
  • 如果只是想要一个 QQ 里的 AI,也可以考虑官方路线(企业/个人开发者机器人平台),但那是完全不同的接入方式,与本文的 OneBot/NapCat 路线无关。

11. 小结

把这条路线压缩成一句话:

AstrBot(框架端)+ NapCat(OneBot 协议端)+ 一个 QQ 小号 + 一个对话模型 = 一个能进群的 QQ 机器人。

几个关键决策点:

  1. 协议端选活跃项目。go-cqhttp 主干已两年多未更新、积压 314 个 issue,新部署建议用 NapCat 这类活跃实现。
  2. AstrBot 原生支持 OneBot v11(官方维护的适配器),所以不需要额外的桥接层。
  3. 两端连接用反向 WS:AstrBot 在 6199 提供服务,NapCat 配 WebSocket 客户端连过去;同 Docker 网络时用容器名而不是 127.0.0.1。
  4. 嵌入模型放本地,记忆检索这一环不上云。
  5. 先跑通裸流程,再叠加人格与插件。一上来就全家桶,出问题时分不清是哪一层坏了。

最后重复一次开头的声明:本文的命令与配置均来自各项目的官方文档、官方 compose 文件与官方 README,并按来源逐条标注;我没有在自己的机器上完整执行过这套流程,所以执行时请以官方文档为准。文中涉及的版本号与仓库状态为撰写时的实测值(gh api 查询),这类信息会变化,动手前建议自行复核。

参考来源