做 QQ 机器人,最值得先确定的不是代码能不能写,而是走哪条 API 路线。目前最稳妥、也最适合快速启动的,就是在 QQ 开放平台申请官方机器人,用官方接口接收群聊或私聊消息,再把这些消息交给 AI 模型生成回复,最后由机器人账号把回复发回对话窗口。整个过程如果注册和审核都已完成,单机跑通一条固定回复确实可以在 5 分钟内完成。但这句话有一个前提,你走的是官方接口,而不是去研究非官方协议。
我推荐官方路线,主要原因有三个。第一,官方机器人有完整的应用审核、消息事件和上线流程,适合做客服问答、群通知、AI 聊天助手、定时任务这类真实场景。第二,官方机器人不会给普通用户造成“这个号是私人号”的困惑,行为边界清晰,也更容易通过审核。第三,从开发成本看,官方 SDK 已经封装了连接、事件分发和回复逻辑,不需要从零处理登录态、心跳和消息协议。
这篇文章会按实际落地顺序拆解:先讲前置条件,再讲怎么在开放平台拿到机器人的身份信息,然后写最小可运行 Demo,最后接入 AI 模型。文中的代码是简化示例,真正使用时要以你拿到的官方 SDK 版本和开发文档为准,但排查思路和参数取舍可以通用。
1. 做 QQ 机器人前,先把开发路径和预期理清
1.1 官方机器人方案到底适合做什么
很多人一提到“QQ机器人”,下意识想到的是自动回复、水群、关键词触发。用官方机器人完全可以实现,只是它更适合被称为“服务型机器人”,而不是“模拟一个真实 QQ 账号去闲聊”。
常见能落地的场景包括:
- 群聊里通过 @机器人 触发 AI 问答。
- 私聊窗口里的客服助手、资料查询、每日天气或新闻摘要。
- 定时任务机器人,比如每天早上把日报推送到指定群。
- 内部工具查询,比如查订单、查库存,前提是机器人后台接上内部系统。
这类功能都需要机器人在线、稳定、有日志、有异常处理,正好是官方机器人最擅长的地方。
如果你的目标是做一个“像真人那样主动私聊所有人、批量加好友、自动拉群”的营销工具,那不适合公开分享,也不建议做。正常开发者用量下,官方机器人的限频和审核规则足够用,但它的边界也写得很清楚:机器人是服务入口,不是营销工具。
1.2 前置条件:四样东西缺一不可
真正动手之前,先把这些准备好:
- 一个 QQ 号。这个 QQ 号用来登录 QQ 开放平台,注册开发者账号。
- 可以完成开发者认证的账号信息。不同时期的认证要求不一样,按照开放平台页面提示填写即可。
- 一台能运行 Python 脚本的设备。笔记本、台式机、云服务器都可以,Windows、macOS、Linux 都行。
- 一个可用的 AI 接口。如果暂时没有,可以先不接,用固定回复完成第一轮测试。
AI 接口这里多说一句:无论你用的是在线模型服务,还是本地部署的模型服务,只要它提供 OpenAI 兼容的接口格式,就可以接入。你不需要懂模型训练,只要知道怎么构造请求、怎么读取返回文本就行。
1.3 “5分钟”能完成什么,不能完成什么
“5分钟快速制作”这句话很容易让人误解。它能完成的准确范围是:
- 前提:已经注册好开发者账号,机器人应用已经创建,AppID 和 AppSecret 已经拿到。
- 能完成:把官方 SDK 下载下来,填入两个密钥,启动程序,然后在允许的测试群里 @机器人,收到一条固定回复。
- 不能完成:跳过平台审核,立即在全网任意群使用;也不能保证 AI 接口不需要花钱或不需要额外配置。
所以,更符合实际的说法是:接入整条链路只需要 5 分钟看到结果,但前面注册、认证、审核、配置环境需要额外时间。先把这个预期放平,后面才不会觉得自己被骗了。
2. 在开放平台创建机器人应用,拿到身份密钥
2.1 创建应用的基本流程
打开 q.qq.com,用 QQ 号登录后,进入开发者中心或机器人管理页面,找到“创建机器人”或者“创建应用”入口。流程大致如下:
- 阅读平台规则,点击创建机器人。
- 填写应用名称、头像、简介。应用名称会展示在机器人身份上,尽量起一个一眼能看懂功能的名称,比如“AI问答助手”。
- 选择接入场景。根据你要开发的机器人类型,勾选频道、群聊或私聊能力。
- 提交后,进入机器人详情页,就能看到 AppID 和 AppSecret。
AppID 是机器人的身份标识,AppSecret 是访问密钥。AppSecret 泄露后,别人可以冒充你的机器人,所以一定不要把它提交到 Git 仓库,也不要写死在代码里。
2.2 配置沙箱环境
官方机器人从创建到正式上线,会经过一个沙箱测试阶段。你需要在开放平台后台配置沙箱成员,比如把自己常用的测试 QQ 号加进去,或者在测试频道里创建测试环境。只有沙箱成员触发的消息,机器人才能收到并回复。这样做的目的是避免机器人还没测试好,就开始影响真实用户。
首次调试时,优先使用沙箱环境,这是最安全也最不容易出事的做法。
有一类问题很常见:开发者觉得机器人创建成功了,于是直接拉进一个正式群测试,结果发现机器人完全没反应。其实不是代码问题,而是那个群根本不在测试范围内。遇到这种情况,先回后台看沙箱成员有没有配置好。
2.3 连接方式:WebSocket 还是 Webhook
官方机器人通常支持两种消息接收方式。
WebSocket 模式下,机器人主动和 QQ 服务器建立长连接。因为没有公网回调地址,很适合本机开发调试。启动一个 Python 进程,配置好 AppID 和 AppSecret,SDK 会自动建立连接。
Webhook 模式下,QQ 服务器把消息推送到你提供的公网接口。这需要一台有公网地址或内网映射能力的服务器,并配置回调 URL。
如果只是本机先跑通,WebSocket 最省事。等以后部署到云服务器,再决定是否继续用 WebSocket 还是改成 Webhook。两种方式的核心逻辑差不多,差别主要体现在网络接入层。
2.4 事件订阅:不是所有消息都会推给你
机器人不是默认接收所有消息的。你需要在后台或代码中声明关心哪些事件。常见事件包括:
- 群聊消息:群成员 @机器人 时触发。
- 单聊消息:用户直接给机器人发消息时触发。
- 消息表情回应:用户对机器人消息点赞或点踩,如果你要做反馈统计,可以订阅。
刚开始只订阅需要的事件,不要全开。事件开得越多,回调越频繁,也越容易触发限频。等基础链路跑通了,再按需增加。
3. 先跑通最小 Demo,把链路打通再谈 AI
3.1 创建项目目录和虚拟环境
我建议在本地新建一个文件夹,比如qq-bot-ai。然后在这个目录里创建 Python 虚拟环境,避免依赖和系统环境冲突。这步看着多余,但对后面部署服务器很有帮助。虚拟环境里的 Python 版本和依赖是固定的,换机器后不容易出现“在我本机明明能跑”的问题。
mkdir qq-bot-ai cd qq-bot-ai python -m venv .venv # Windows .venv\Scripts\activate # macOS / Linux source .venv/bin/activate如果 Python 版本太老,有些异步语法和类型注解会报错。建议使用 Python 3.10 及以上版本。
3.2 安装官方 Python SDK
官方 Python SDK 的包名在不同版本有过调整,以 QQ 开放平台开发文档里的安装命令为准。安装完成后,如果可以在 Python 里执行import botpy成功,就说明装对了。
pip install qq-botpy这里最容易踩的坑是:从搜索引擎复制了一段旧命令,结果装成了一个非官方包,项目一启动就报错。解决办法是先去官方开发文档找到“快速开始”,直接把文档给的安装命令复制进来。
3.3 最小可运行代码
下面的代码是官方 SDK 的简化写法,作用是:机器人上线后,在群里被 @时,回一句固定内容。
import os import botpy from botpy.message import GroupMessage class MyBot(botpy.Client): async def on_group_at_message_create(self, message: GroupMessage): # 这里还没有接入AI,先回一句固定内容验证链路 await message.reply(content="机器人已上线,AI功能正在调试中。") if __name__ == "__main__": intents = botpy.Intents(group_messages=True) client = MyBot(intents=intents) client.run( appid=os.getenv("QQ_BOT_APPID"), secret=os.getenv("QQ_BOT_SECRET"), )保存为main.py。在启动之前,先设置两个环境变量:
export QQ_BOT_APPID="你的AppID" export QQ_BOT_SECRET="你的AppSecret"Windows 下可以用set命令,也可以在项目根目录创建.env文件,再用python-dotenv读取。第一次测试,直接环境变量最简单。
3.4 运行和验证
启动脚本:
python main.py观察终端日志,如果出现连接成功、同步成功这类关键词,说明机器人已经在线。然后去开放平台配置的测试群, @机器人 发一句话。比如发“你好”,如果群里出现“机器人已上线,AI功能正在调试中”,说明链路完全打通。
这里不要急着接 AI,也不要急着调参数。先把固定回复跑通,相当于确认整条水管没漏,再决定装什么净水器。
4. 核心代码的关键细节:消息清洗、异步请求和日志
4.1 消息内容清洗
接入 AI 后,第一个要注意的是message.content内容。当用户用 “@机器人 你好” 这种方式发消息时,SDK 拿到的内容一般会包含机器人的名称或 @ 标记,直接交给 AI 会导致模型不理解用户意图。
所以需要先做一步清洗:
import re def clean_text(raw: str) -> str: # 去掉 @机器人 这一段 text = re.sub(r"@[^\s]+", "", raw).strip() return text清洗后拿到的text才是真正想问的内容。在群聊场景里,建议同时判断消息是否以特定指令开头,比如/ai 你的问题。这样机器人不会对群里的任何 @ 都响应,也不会被高频消息搞崩。
4.2 同步调用还是异步调用
AI 接口调用是网络请求,通常耗时 1 到 10 秒。如果在事件处理函数里用requests.post,会阻塞事件循环,导致其他消息排队,体验会明显变差。
推荐使用异步 HTTP 客户端:
import httpx async def ask_ai(prompt: str, base_url: str, api_key: str, model: str) -> str: url = f"{base_url}/v1/chat/completions" payload = { "model": model, "messages": [ {"role": "user", "content": prompt} ], "temperature": 0.7, "max_tokens": 500, } headers = {"Authorization": f"Bearer {api_key}"} async with httpx.AsyncClient(timeout=30.0) as client: resp = await client.post(url, json=payload, headers=headers) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"]如果项目里还没有httpx,先安装:
pip install httpx4.3 完整回调逻辑
把清洗、调用 AI、异常处理组合到一起,是一个比较完整的回调:
class AIChatBot(botpy.Client): async def on_group_at_message_create(self, message: GroupMessage): text = clean_text(message.content) if not text: return try: answer = await ask_ai(text, AI_BASE_URL, AI_API_KEY, AI_MODEL) except Exception as e: logging.error("AI request failed: %s", e) await message.reply(content="我暂时没想好怎么回答,稍后再试试。") return await message.reply(content=answer)这里先做了异常捕获。AI 接口不可用时,至少机器人还能给用户一个明确提示,而不是沉默或直接崩溃。
4.4 日志是调试时的第一朋友
第一次跑通后,不要只盯着终端里的输出。建议给脚本加上日志,输出内容包括:收到消息的时间、群 ID、用户 ID、清洗后的文本、AI 返回状态、发送成功还是失败。这样以后机器人报错,你能知道是从哪一步断的。
import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s", filename="bot.log", )日志不是给机器人用户看的,是给未来的你看的。很多“机器人没反应”的问题,翻日志就会看到两种情况:要么消息根本没收到,要么请求 AI 时报错了。
4.5 常见误区
误区一:以为拿到 AppID 就能随便发群消息。实际上,开发者沙箱环境和正式上线后的权限不同,别急着把机器人拉进自己的真实群里测试。
误区二:AI 请求失败了好几次,于是反复重发同一条消息。这容易触发平台限频。正确做法是记录日志、做指数退避,而不是暴力重试。
误区三:把AppSecret写进代码里然后发到 GitHub。这属于安全事件,应该立刻到开放平台重置密钥,不是简单改个变量名就能解决的。
5. 接入 AI 模型,把固定回复换成智能问答
5.1 整体数据流
接入 AI 之后,机器人处理一条消息的完整链路是:
- 用户 @机器人 并发送消息。
- SDK 收到消息,触发
on_group_at_message_create回调。 - 脚本清洗消息文本,判断是否需要回答。
- 脚本调用 AI 接口,传入历史记录或当前问题。
- AI 返回文本。
- 脚本把文本通过
message.reply发回群聊。
关键点在于:QQ 侧的连接和 AI 侧的接口是两个独立系统,中间唯一要保证的就是超时和错误处理。
5.2 接入 OpenAI 兼容接口
代码示例已经在上文出现过。实际使用前,你需要理解三个参数:
base_url:接口基础地址,常见形式是https://api.xxx.com/v1。api_key:密钥,有些服务用sk-开头,有些是自己生成的长字符串。model:模型名称,比如gpt-4o-mini、qwen-plus、deepseek-chat,或本地模型服务里自定义的名称。
这三个参数都用环境变量管理,不要写死在代码里:
export AI_BASE_URL="你的接口地址" export AI_API_KEY="你的密钥" export AI_MODEL="模型名称"如果你用的是本地模型服务,比如通过 Ollama 这类工具启动本地模型,只要它暴露了 OpenAI 兼容接口,同样可以直接用。
5.3 上下文的简单实现
如果每个问题都是独立对话,用户体验会很差。最简单的上下文方案,是在内存里维护一个字典:
- key 可以是
群ID_用户ID。 - value 是最新的对话消息列表,比如最近 5 轮。
- 每次收到新消息,把用户问题追加进列表,调用 AI 时把整个列表作为
messages传过去。 - AI 返回后,再把助手回复追加进去。
- 如果列表超过预设数量,就删除最早的一条。
SESSION = {} MAX_HISTORY = 5 def get_history(session_key: str): return SESSION.get(session_key, []) def append_history(session_key: str, role: str, content: str): SESSION.setdefault(session_key, []) SESSION[session_key].append({"role": role, "content": content}) if len(SESSION[session_key]) > MAX_HISTORY * 2: SESSION[session_key] = SESSION[session_key][-MAX_HISTORY * 2:]调用 AI 时,把messages=history传进去,而不是只传prompt。这样模型才能理解上下文,而不是每次从零开始。
内存方案适合单进程、低并发场景。如果机器人准备长期跑,建议换成 Redis,同时给不同会话设置过期时间,避免内存无限膨胀。
5.4 长回复和异常回复
AI 生成内容有时会很长,超出 QQ 单条消息长度限制。常见处理方式有两种:
- 限制
max_tokens,让 AI 直接生成短内容。 - 判断回答长度,超过限制就拆成多条消息顺序发送。
另外要加一层内容过滤。 QQ 平台本身会有风控,但机器人开发者也有责任做一些基础内容判断,比如敏感词命中时不回复。开放平台审核时也比较看重这点。
5.5 从文本回复到更丰富的能力
AI 接入跑通之后,可以继续扩展:
- 把部分高频问题做成固定关键词回复,减少 AI 调用次数,也降低延迟。
- 让 AI 输出结构化 JSON,比如查询天气、查询订单,再转成友好文本。
- 在回答前加一个命令白名单,只有订阅了特定指令的用户才能触发 AI。
这些扩展不是必须一开始就做的,但提前考虑一下,能帮你少走很多回头路。
6. 常用配置、部署和安全建议
6.1 核心配置项参考
为了便于维护,可以把配置集中写在一个.env文件里。常见配置如下:
| 配置项 | 作用 | 参考值 |
|---|---|---|
| QQ_BOT_APPID | 机器人身份ID | 开放平台获取 |
| QQ_BOT_SECRET | 机器人密钥 | 开放平台获取,注意保密 |
| AI_BASE_URL | AI接口地址 | 根据服务商填写 |
| AI_API_KEY | AI密钥 | 根据服务商填写 |
| AI_MODEL | 模型名称 | 根据服务商填写 |
| AI_TIMEOUT | AI请求最大等待时间 | 10-30秒 |
| AI_TEMPERATURE | 温度,控制随机性 | 0.3-0.8 |
| AI_MAX_TOKENS | 单次最大返回长度 | 200-800 |
| MAX_HISTORY | 上下文轮数 | 5 |
| BOT_ACTIVE_TIME | 机器人活跃时间段 | 可选 |
.env文件示例:
QQ_BOT_APPID=123456789 QQ_BOT_SECRET=your_secret_here AI_BASE_URL=https://api.example.com/v1 AI_API_KEY=sk-xxxx AI_MODEL=gpt-4o-mini AI_TIMEOUT=30 AI_TEMPERATURE=0.7 AI_MAX_TOKENS=5006.2 频率限制怎么理解
无论 QQ 平台还是 AI 服务商,都有频率限制。QQ 侧限制解决的是“机器人别刷屏”,AI 侧限制解决的是“别把模型服务打爆”。
判断标准很简单:先单条测试,再逐步提高并发。不要一上来就写一个循环,把群里 100 条历史消息全部请求一遍 AI。这样大概率会触发限频,还会造成账单暴涨。
稳妥做法是加一个简单的限速器,比如同一个群 3 秒内最多调用一次 AI:
import time LAST_CALL = {} def rate_limit(key: str, seconds: float = 3.0) -> bool: now = time.time() if key in LAST_CALL and now - LAST_CALL[key] < seconds: return False LAST_CALL[key] = now return True如果对并发要求更高,就要考虑任务队列。先接收消息,再把 AI 请求放进队列,由一个或几个 worker 异步处理。这样能避免短时间大量请求直接把 AI 接口打挂。
6.3 部署上线需要做的几件事
开发阶段在笔记本上跑没问题,但要给真实用户用,机器人必须 7x24 在线。部署时建议:
- 使用 Linux 云服务器,安装 Python 3.10+。
- 用 systemd 或 supervisor 托管机器人进程,实现开机自启和崩溃重启。
- 日志写到独立文件,定期清理。
- 使用进程守护工具,不要用单纯
nohup python main.py &。
使用 systemd 管理 Python 进程是一个稳定选择。下面是一个简化示例:
[Unit] Description=QQ AI Bot After=network.target [Service] User=ubuntu WorkingDirectory=/home/ubuntu/qq-bot-ai ExecStart=/home/ubuntu/qq-bot-ai/.venv/bin/python main.py Restart=always RestartSec=5 EnvironmentFile=/home/ubuntu/qq-bot-ai/.env [Install] WantedBy=multi-user.target把上面内容保存到/etc/systemd/system/qq-bot-ai.service,然后:
sudo systemctl daemon-reload sudo systemctl enable qq-bot-ai sudo systemctl start qq-bot-ai之后就算代码异常退出,systemd 也会在几秒内重新拉起进程。
6.4 上线审核
机器人功能开发完成后,还要在开放平台提交上线申请。审核内容包括应用名称、头像、功能简介、隐私说明等。审核期间机器人会被人工查看,所以不要在上线申请里写跟实际功能不符的内容。
如果只是自己内部测试,可以一直留在沙箱环境里,不需要提交上线。但如果机器人要给更多人用,就一定要走完流程。审核不通过时,后台一般会给出原因,按提示修改后重新提交即可。
7. 常见问题排查清单
7.1 消息根本收不到
按顺序排查:
- 确认机器人进程已经启动,日志显示连接成功。
- 确认当前触发消息的 QQ 号在沙箱成员列表里。
- 确认触发方式是 @机器人,而不是直接在群里发消息。
- 确认订阅了对应事件。群消息事件和单聊事件是不同的。
- 确认没有在后台关闭沙箱模式。
如果以上都正常,仍然收不到,就看日志里有没有连接断开或鉴权失败的记录。
7.2 AI 请求一直超时
先看日志里的错误状态码。常见情况:
- 401:API Key 错误。
- 403:没有权限或余额不足。
- 404:base_url 拼错,或者 model 名称不存在。
- 429:请求太频繁,触发限频。
- 5xx:模型服务本身异常。
本机能正常请求 AI 接口,不代表服务器上也行。有个容易忽略的问题是服务器所在网络对某些接口访问不稳定。遇到这种情况,先在同一台服务器上用 curl 测试 AI 接口能不能连通。
curl -X POST https://api.example.com/v1/chat/completions \ -H "Authorization: Bearer $AI_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"你好"}]}'这条命令可以帮你快速分清是代码问题,还是环境和网络问题。
7.3 机器人发了消息但群里看不到
有可能发送成功了,只是内容被折叠或触发风控。常见原因:
- 回复频率太高。
- 多条消息内容完全一致,被判定为刷屏。
- 消息里包含特殊字符或外链。
- 机器人不在该群的可用范围。
处理方法是降低频率,给回复内容加一点变化,避免外链。如果确实需要发链接,尽量使用文字描述而不是完整 URL。
7.4 机器人进程自动退出
本机能跑,服务器上跑一会儿就退出,大概率不是代码问题,而是依赖、权限或进程管理问题。
- 检查是不是用了
sudo后环境变量没传过去。 - 检查是不是内存不足被系统杀掉。
- 检查是不是没有 systemd 配置,SSH 断开后进程被一起结束。
- 检查日志里的 Traceback,看是哪一个依赖缺失。
7.5 正式上线后功能不稳定
沙箱环境和正式环境最大的区别是流量和触达范围。正式环境里,机器人可能同时收到多个群的消息,如果代码里没有控制并发和频率,很容易出现延迟、乱序、甚至风控。
建议上线初期先做灰度:只开放少量群,观察一天日志,确认稳定后再放开更多群。另外,AI 接口的响应时间也要监控。如果某个模型经常超过 15 秒,建议换更快的模型,或者给回复加缓存。
8. 最后说一点真实落地建议
做 QQ 机器人最容易被忽略的,是“把功能做出来”和“把服务运行好”之间的距离。第一次跑通 Demo 可能只要几分钟,但想让机器人稳定运行,你还要处理超时、限频、上下文存储、日志、崩溃重启和审核上线这些事。
我的建议是分三步走:本机沙箱先跑通固定回复,再接入 AI 接口处理单条问题,最后加上下文和限速,部署到服务器。每一步都验证完再进入下一步,不要一口气写完一个巨大脚本,出了问题很难定位。
如果你的目标只是学习 AI 接入和事件回调,这个项目本身就足够练手。如果目标是做一个真实可用的群机器人,那就把重点放在稳定性、成本和安全上,尤其不要把 AI 请求直接暴露给所有群。先学会控量、再放开,要比追求功能数量重要得多。