这篇教你搭一个真正能用的 QQ 群 AI 助手:群成员 @ 它就能得到答复,问知识库覆盖的问题会基于你的文档回答,发一句固定命令还能把监控面板的实时截图发回群里。全程用一个不承载重要资产的专用 QQ 小号,不需要企业资质。
先说清楚成品长什么样,你好判断值不值得跟着做:
@助手 gpt-5.5 多少钱→ 基于你的知识库回答价格@助手 [报错截图] 这个咋办→ 看懂截图 + 结合文档给排查建议@助手 查状态→ 回传一张监控页面截图- 知识库没覆盖的问题 → 明确说"这个我还答不了",绝不瞎编
下面按"选型 → 接入 → 知识库 → 体验打磨 → 部署"的顺序走一遍,每一步都告诉你为什么这么选、怎么落地。
一、先选路线:怎么让机器人进群
这是第一个坎,有三条路,直接决定后面所有工作。
QQ 官方开放平台机器人:最合规、最稳、最省资源(纯服务端,百来兆内存)。但对个人开发者,2026 年这条路基本堵死了——官方沙箱从 2026 年 1 月 31 日起不再支持添加 QQ 群(只剩频道和私聊),非企业认证账号改不了群沙箱配置,个人开发者也不被允许接入 AI。如果你有企业主体,优先走这条;个人玩家直接跳过。
专用 QQ 号 + NapCat(推荐):用一个普通 QQ 小号,通过 NapCat 把它接入 OneBot 11 标准协议。原理是跑一个真实的官方 QQ 客户端,NapCat 注入进去转协议。好处是它就是个普通 QQ 号,谁都能拉进群,在群里和真人无异;代价是非官方方案,有风控和掉线风险,所以只用专用小号、只进你自己授权的群。本文用的就是这条路。
SnowLuma 这类"独立协议"方案:会看到一些宣称"无需 QQ 客户端"的项目。实测要小心——很多在 Linux 下的官方部署仍然是一个内置了 QQ + Xvfb + VNC 的 Docker 镜像,本质还是在跑 QQ 客户端,省不了资源,而且协议模拟的风控风险通常更高,有的还禁止商用。别被宣传语带偏,一定去抠它的实际部署方式。
一个能帮你少走弯路的架构建议:把协议接入层抽象成一个独立模块,业务逻辑只依赖"收到群消息 / 回文字 / 回图片"这几个动作,不感知底层是 NapCat 还是别的。这样将来想换协议端,业务代码一行不用动。
二、接入:把 NapCat 跑起来并接上你的 Bot
NapCat 官方提供 Docker 镜像,Linux 上这样起(端口只绑回环,不暴露公网):
docker run -d --name napcat --restart=unless-stopped \
--memory 900m \
-e ACCOUNT=你的QQ号 \
-p 127.0.0.1:6099:6099 \ # WebUI
-p 127.0.0.1:3002:3002 \ # OneBot WebSocket
-v /opt/napcat/qq-data:/app/.config/QQ \
-v /opt/napcat/config:/app/napcat/config \
mlikiowa/napcat-docker:latest
启动后从容器日志拿到 WebUI 的一次性 token,浏览器进 127.0.0.1:6099(服务器上就用 SSH 隧道转发),扫码登录你的专用 QQ 号。登录态保存在挂载卷里,加上 -e ACCOUNT 后续重启会自动快速登录,不用反复扫码。
登录后在 WebUI 里配置一个 OneBot v11 WebSocket 服务端:端口 3002、消息格式选 array、设一个长随机 token、不上报自身消息。这个 token 后面你的 Bot 要用同一个。
有个坑提醒:NapCat 与 QQ 的兼容性要看 NapCat Release 里标注的 NTQQ 内部 buildVersion,别拿应用的显示版本号去对。
你的 Bot 侧就是连这个 ws://127.0.0.1:3002、带上 token,然后:校验登录的 QQ 号是不是你的、群在不在白名单、消息里有没有 @ 到自己——三个都过了才处理。回复用标准的 OneBot 消息段拼"回复 + @ + 文本/图片"。
安全边界:WebUI(6099)和 OneBot(3002)一律只监听回环地址或可信私网,绝不直接暴露公网;token 用长随机串;机器人 QQ 号、群号一律当字符串处理,避免 JS 大整数精度问题。
三、知识库:别急着上向量 RAG
要让机器人基于你的资料回答,很多人第一反应是 RAG——切块、embedding、向量库、语义检索。但如果你的知识库就是几十份文档,向量 RAG 大概率是过度设计:全部索引塞进 prompt 都绰绰有余,根本用不上向量近似检索;而且向量的"语义相似"经常形似神不似,答错了很难调试,相似度是个黑盒。
更简单也更好调的做法是 文档 + 索引 + 渐进式披露(Claude Skills、llms.txt 都是这个路子):
知识库就是一个 Markdown 文件夹——一份 index.md 索引 + 若干 docs/*.md。索引里每份文档一个条目,写清楚它能回答哪类问题:
## docs/pricing.md
价格与支持的模型:充值比例、计费倍率、可用模型列表。
典型问题:多少钱?倍率是多少?支持哪些模型?
用户提问后走两跳:
- 路由跳:把索引交给模型,问"这个问题该看哪份文档",输出结构化 JSON。索引很小,这跳快且便宜。
- 回答跳:读取命中的文档全文,连同问题生成回答。
最大的好处是检索决策全透明:答错了,看日志就知道路由到了哪份文档,是路由错就改索引、是内容不对就改文档,没有任何调参玄学。
落地时三个细节必须做对:
- 防路径逃逸:路由跳返回的文档路径,必须在索引枚举的白名单里校验。模型返回一个不存在的、或者试图
../../.env的路径,一律当未命中,绝不真去读任意文件。 - 严格拒答:这是知识库助手的生命线。回答跳的提示词明确"只依据给定资料,资料不足就输出固定标记";未命中或命中标记时,回一句固定的"这个我还答不了",不许自由发挥。宁可少答不能乱答。把没答上的问题记进日志,定期回看补文档——这就是越用越准的进化循环。
- 追问要带上下文:用户问"401 怎么办"、接着问"那 404 呢",第二句没上下文路由会懵。把最近几轮对话也喂给路由跳就能解决。两跳架构里,上下文不能只给回答跳。
四、把体验做对:这些细节直接决定好不好用
功能通了不等于能用,几个 QQ 场景特有的坑:
- QQ 不渲染 Markdown:模型默认输出的加粗、井号标题在群里是原样符号。两层处理——提示词里明确要求输出纯文本(根因),回复发出前再跑一遍 Markdown 剥离(兜底)。双保险比只做一样稳。
- @ 后加个空格:默认
@用户名回复挤在一起,加空格变@用户名 回复,观感差很多。 - 支持发图提问:用户爱直接甩报错截图。需要解析保留图片段、下载转 base64、消息走多模态格式、模型换成视觉模型。设计上让路由跳和回答跳都能看到图——用户只发图不打字时,纯文字路由根本不知道话题。
- 多级限流:消息去重、同用户回复冷却、AI 并发上限、截图冷却与缓存。群聊是高并发场景,没有这层保护很容易被刷爆或重复回复。
五、部署:你需要多大的机器
这是最容易被低估的一步。NapCat 方案不是只跑一个 Node 进程,实际是三部分,务必按峰值算内存:
| 组件 | 常驻内存 | 说明 |
|---|---|---|
| QQ 客户端 + NapCat | ~400–600M | Linux 无头。这是"伪装成真实群成员"的入场费,省不掉 |
| 你的 Bot(Node) | ~100M | 业务本体,很轻 |
| 截图用的无头浏览器 | 常驻 0,截图瞬间峰值 +300–500M | 每次截完就关,不常驻 |
也就是常驻大约 500–700M,截图瞬间再叠约 400M。给它一台 2C2G 起步的机器就很宽裕。别只看常驻内存就上 1G 的小机器,截图峰值会把你打爆。
如果你打算把它和别的重要服务放同一台机器,有三条防御必须写进部署,别当可选项:
- 用 systemd/容器给机器人和 NapCat 都设内存上限,超了先杀它自己;
- 调 OOM 优先级,让内存不够时系统优先牺牲机器人,而不是你别的服务;
- 代码里加一个全局截图并发闸——多个群同时截图时,同一时刻只开一个浏览器,排队处理,避免峰值叠加。
国内服务器还有个现实问题:拉不到 Docker Hub。解决办法是在能联网的机器上 docker pull + docker save 打包,传上去 docker load,别赌公共加速源。
六、长期维护:知识库怎么更新
给知识库做个管理后台?不建议。对一人维护的工具,一个后台就是一个新的工作入口、新的维护成本。
更划算的做法:知识库就是 git 仓库里的 Markdown,git 是唯一权威来源。更新走一条单向管道——本地改文档 → 校验脚本把关(索引与文档一一对应、不超长)→ 提交 → 同步到服务器 → 重启生效。服务器上的文件只读,绝不 SSH 上去直接改,否则版本漂移、绕过校验、无法回退。贴着"改文件 + git"这个你本来就熟悉的方式运行,比再造一个系统省太多。
把运维封装成一个 skill
到这一步,更新知识库还是得手敲那串命令。可以再进一步,把整条管道封装成一个 AI 会话触发的能力(Claude Code 里叫 Skill,其它 Agent 工具有类似机制):之后你想更新知识库,只要在对话里说一句"把某某文档改成 xxx,发布",它就自动跑完"改文档 → 校验 → 提交 → 同步 → 重启 → 核对"。
下面是我们实际在跑的这个 skill 的完整内容,敏感路径和服务器别名替换成了占位符,其余一字未改:
---
name: qq-bot-kb
description: 改动或排查群助手(本地项目 qq-bot)的知识库时用。适用情形:要新增/修改/删除知识文档或调整索引;机器人答错、答不上或答偏了某类问题;要把知识改动发布上线;想看用户没答上的问题(unmatched.log)。不涉及机器人的代码逻辑、限流/截图/图片功能、NapCat 容器或部署环境——那些不在本 skill 范围。
---
# qq-bot 知识库
助手的知识库是本地 git 仓库里的一批 Markdown。git 是唯一权威来源,服务器上的
副本只读——一切改动在本地做,单向发布上去。它不是、也不会变成管理后台/CMS/素材库。
## 事实
- 仓库 <仓库路径>(git,分支 main),知识库在 data/knowledge/:
index.md(索引)+ docs/*.md(文档)+ unmatched.log(未命中提问,仅存在于服务器)。
- 校验:npm run kb:check(离线)。这是发布的硬前置——不过就不发布。
- 服务器:ssh <服务器别名>,部署在 /opt/qq-bot(属主 qqbot),
重启 systemctl restart qq-bot。协议端是 NapCat 容器 napcat,与知识库无关。
## 索引契约
index.md 每份文档一个条目:
## docs/<文件名>.md
覆盖范围一句话。
典型问题:问法1?问法2?问法3?
- 条目记的是「问题模式」,不是逐条累积用户真实提问(真实提问归 unmatched.log)。
- 条目与 docs/ 文件一一对应;单文档约 3000 字上限,超了拆分。
kb:check 会挡住死链、孤儿文档、超长。
- 文档内保留 Markdown 无妨——它是给模型读的材料,机器人回复时会自动转纯文本。
## 发布
顺序是 kb:check → 提交(只 commit data/knowledge/)→ rsync → 重启
→ 核对日志里 knowledgeDocs 等于 index.md 条目数。rsync 的 exclude 较多,照抄:
rsync -az --delete \
--exclude node_modules --exclude .env --exclude data/auth \
--exclude data/screenshots --exclude data/cache --exclude .downloads \
--exclude .playwright-cli --exclude dist \
--exclude "*.log" --exclude "data/knowledge/unmatched.log" \
<仓库路径>/ <服务器别名>:/opt/qq-bot/
unmatched.log 不参与同步——要看它得上服务器读。
## 红线
- 服务器上不改知识文件(漂移、绕过校验、无法回退)。
- 只动知识内容,不碰代码逻辑、.env、凭证、NapCat。
- unmatched.log 只做补文档/改索引的依据,由用户定夺,不自动学习、不自动改索引。
- 不建任何后台/界面/平台。
## 维护
事实、契约或发布管道变了,就地更新本文件并提交(私有仓库,保持 private)。
几个刻意为之的设计,值得单独点一下:
description 里没有一句功能介绍,全是触发条件和不适用范围。 它的职责不是"介绍我是干嘛的",而是让模型在每一轮对话里判断"眼下这个场景该不该加载我"。写成"本 skill 用于管理知识库并发布"这种简介反而没用——真正决定命中率的是"出现哪些问题时用",以及那句"不涉及代码逻辑、部署环境"的排除项,后者专门用来防止它在改机器人代码时误触发。
正文里没有一步"怎么操作"的说明。 改 Markdown、按什么顺序跑命令,一个够强的模型自己就会编排,写进去只是占上下文、把它往预设的窄路上带。留下的全是它推导不出来的:仓库在哪、索引长什么样、哪些红线碰不得、还有"unmatched.log 不参与同步"这种非踩不可的坑。
判断"该不该写进 skill",我用的标准是——补知识差,还是补能力差。 补知识差的(你的路径、你的约定、你的红线),模型永远不可能自己知道,随它变强只会更值钱;补能力差的(教它规划、教它按步骤做事),随模型变强持续贬值,甚至变成负资产——模型本可以做得更好,却被你写死的菜谱框住。写每一段都过一遍这个标准,是前者就留,是后者就删。这也是为什么这个 skill 通篇没有"教程"味。
七、运维现实:账号会被风控,而且死得很隐蔽
这一节是大多数教程不会告诉你的,但对这个方案至关重要:你的专用 QQ 号有一定概率被腾讯风控,尤其在服务器(数据中心 IP)上跑自动化时。这是普通账号非官方自动化的固有代价,躲不掉,只能管理。
真正麻烦的不是风控本身,而是它挂得极其隐蔽。真实踩过一次:机器人连续十几个小时没回复,但你上去看,一切正常——进程活着、NapCat 显示账号在线、每小时的时间同步照常、连 API 请求都能正常响应。哪儿都不像坏了。
问题出在一个"僵尸会话":账号的登录态还挂着,但新消息的接收管道已经悄悄断了。NapCat 心跳、生命周期这些事件照发,唯独群消息事件一条都不推过来。于是你发消息,机器人收不到,也就不回,而所有监控都显示"健康"。
这里有个能救命的诊断原则:"账号在线"不等于"消息能通",判活要看你是否真的收到消息事件。别信进程状态、别信"在线"标识——写个小脚本连上 OneBot 的 WebSocket,监听 post_type 为 message 的事件,自己发一条消息看探针收不收得到。收得到才是真活着;只收到心跳、收不到消息,就是僵尸会话。
一旦确认是风控(NapCat 登录日志会明确报"账号存在安全风险,请登录最新手机 QQ 恢复"),恢复只能靠账号所有者在真实手机 QQ 上按提示走账号恢复流程,服务端做不了任何事。恢复后重新扫码登录即可。
两条务实建议:
- 加一个存活探测:定时用上面那个"监听消息事件"的方法确认管道真的通,一断就主动告警。否则你只能等用户来问"机器人怎么不理我了",中间可能已经黑了半天。
- 别让这个号承载要紧的事,也别指望它绝对稳定。风控偶发一次,申诉恢复即可;如果反复被风控,说明这个号或这套行为模式不适合长期自动化,该考虑换个更"养熟"的老号、降低操作频率,或者回到本文开头的判断——有企业主体就走官方机器人。
你需要准备什么
跟着做之前,备齐这些:
- 一个不承载重要联系人或资产的专用 QQ 小号,和一个你有管理权的测试群;
- 一台 2C2G 起步的服务器(国内机器注意镜像拉取);
- 一个 OpenAI 兼容的大模型接口(要支持发图问答就选带视觉的模型);
- 如果要监控截图功能,装 Playwright 的无头 Chromium。
最后提醒一句风险:普通 QQ 号自动化不属于官方 API,有登录验证、功能限制、掉线甚至封号的可能。只用专用账号、只进明确授权的群,别拿它承载重要联系人或商业服务。想清楚这条边界,剩下的就是照着上面五步搭起来的事了。
xhyapi