在实际项目中,给QQ群或QQ频道接入一个AI聊天机器人,核心链路并不复杂:机器人收到一条消息,解析消息内容,调用大模型服务生成回复,再把回复发回对话窗口。把这条链路跑通之后,自动问答、社群客服、活动提醒、知识库检索等能力都能在此基础上扩展。
本文围绕“QQ机器人”和“AI模型接入”两条主线,基于QQ开放平台的官方机器人API,写一个最小可运行的Python机器人。标题里说的“5分钟”,指的是在你已经完成QQ开放平台账号注册、创建好机器人并拿到AppID、ClientSecret等凭证,且本地具备Python环境的前提下,从填充配置到启动服务,再到群里收到第一句AI回复,这个过程确实可以在几分钟内完成。账号申请、机器人资料审核、功能开通这类前置流程需要的时间不在这5分钟里,不同账号、不同机器人类型、不同审核节奏差异较大,需要提前预留时间。
读完这篇文章后,你可以得到一个可运行的“QQ消息 -> 大模型 -> 回复”最小闭环项目,理解QQ机器人接入的关键API和事件机制,掌握本地调试和常见问题排查方法,并知道从个人项目升级到稳定服务时还需要补齐哪些工程能力。如果把多轮记忆、知识库、定时任务、群管理等功能一层层加上去,这套骨架还可以继续演变成一个真正可用的社群机器人系统。
1. 开发路线怎么选:官方开放平台是底线也是起点
1.1 官方QQ机器人能覆盖哪些场景
QQ开放平台为开发者提供了正式的机器人接入能力。开发者可以创建一个机器人应用,让它进入指定的QQ频道或QQ群,通过事件订阅接收消息,再通过消息接口发送回复。
这个能力覆盖的场景包括:
- 社群自动问答:收到用户提问后从知识库或大模型中检索答案。
- 聊天娱乐互动:接入大模型后做角色扮演、文案生成、游戏互动。
- 定时提醒:结合定时任务,到点发送通知到频道或群。
- 辅助管理:在平台允许的范围内做关键词提醒、入群欢迎、常用问答沉淀。
- 企业客服:把机器人和企业内部的工单系统、订单系统打通,承接常见咨询。
官方机器人方案的特点是接口公开、权限受控、有审核机制。它不是所有能力都对所有账号开放,公域机器人和私域机器人的消息权限、发送频率、事件范围都不一样。实际开发前,先确认你自己的账号类型和机器人类型支持哪些事件和接口,比先写代码更重要。
1.2 为什么只讨论官方路线
在搜索QQ机器人相关资料时,你可能会看到一些非官方实现方式:通过模拟客户端协议、构建非官方框架、或者让你提供QQ账号授权的方式运行机器人。这类方案看起来上手快、功能花样多,但存在几个很现实的问题:
- 违反平台使用规范,账号一旦被识别异常行为,存在封禁风险。
- 非官方协议不是公开接口,平台升级后可能突然不可用,线上服务稳定性没有保障。
- 这类方案往往需要你把账号权限或登录凭证交给第三方程序,数据安全和隐私边界很难评估。
- 一旦出了问题,没有官方技术支持,排查时只能依赖社区经验,很难定位。
所以本文所有代码和流程,全部基于QQ开放平台的官方机器人API。如果你在别处看到需要提供QQ密码或模拟登录的机器人方案,不建议使用,更不建议把它接入到正式业务环境。
技术选型本质上是风险与成本的平衡。官方开放平台的限制更多,但换来的是合规、稳定和可维护。做个人玩具可以追求快,做生产服务不能赌账号安全。
1.3 “5分钟”指的是核心代码,不是全流程
“5分钟快速制作”这个说法很容易被误解。完整做一个QQ AI机器人,时间分布大致是这样:
| 阶段 | 主要工作 | 典型耗时 |
|---|---|---|
| 前置准备 | 注册开放平台、创建机器人应用、提交资料审核、开通权限 | 数小时到数天 |
| 功能开发 | 编写接入代码、配置大模型API、本地调试 | 几分钟到几十分钟 |
| 联调验证 | 拉机器人进频道或群、发消息测试、调整prompt和参数 | 几分钟到几十分钟 |
| 生产固化 | 断线重连、内容安全、日志监控、限流、审核上线 | 半天到数天 |
如果已经有现成的机器人应用和可用的模型API,只缺代码,那5分钟确实能做到。如果你是第一次接触,建议把心态调整为“先花一小时理解流程,再花五分钟复制代码”。了解每一步在做什么,后面排查问题时才有方向。
2. 准备阶段:把页面操作放到代码之前
2.1 在开放平台创建机器人,拿齐核心凭证
在写代码之前,先到QQ开放平台完成机器人创建。大体流程如下:
- 注册并登录QQ开放平台。
- 完成开发者主体认证,个人开发者也可以按页面提示完成实名信息登记。
- 创建机器人应用,填写名称、头像、简介、功能描述等信息,这些资料会用于审核。
- 选择机器人形态,常见的是群聊机器人和频道机器人,不同形态支持和限制不同。
- 创建完成后,在控制台找到并记录AppID。
- 生成并保存ClientSecret,这个值相当于机器人身份的密钥,不要泄露。
- 根据需要申请消息接收事件、消息发送等权限。
到这里,你已经拿到最核心的三类信息:AppID、ClientSecret、机器人自身的一些标识信息。它们会用在鉴权和事件订阅流程中。
这里有一个容易踩的坑:有些开发者在控制台直接看到AppID就复制进代码,却忽略ClientSecret需要主动生成,导致启动时鉴权失败。还有人在公网仓库里提交了包含ClientSecret的配置文件,这是非常危险的操作,一定不要做。
2.2 本地环境要求
示例代码使用Python实现,开发环境建议满足这些条件:
- Python 3.9及以上版本。
- pip可正常使用。
- 本机能够访问QQ开放平台的API域名。
- 本机能够访问你准备接入的大模型API服务。如果是公司内网的模型服务,需要保证网络链路可达;如果是云上的模型服务,需要确认访问域名和鉴权方式。
- 不建议在Windows命令行里直接粘贴带特殊字符的密钥,推荐统一通过
.env文件管理配置。
不同大模型服务的接入方式差异比较大,但大多数云模型平台都提供Chat Completions风格的接口,也就是发送一个messages数组,服务端返回一个包含回复文本的choices数组。下面的示例会统一采用这种协议风格,方便你适配到自己的模型服务。
2.3 项目结构和依赖
用最小项目结构展示,后续添加功能时再按职责拆分文件。
qq-ai-bot/ ├── .env.example ├── requirements.txt ├── bot.py └── llm_client.pybot.py负责QQ开放平台接入、WebSocket事件接收和消息回复;llm_client.py负责调用大模型API;.env.example保存配置模板;requirements.txt声明依赖。
依赖文件内容如下:
websockets>=12.0 requests>=2.31.0 python-dotenv>=1.0.0.env.example内容如下:
# QQ 开放平台机器人凭证 QQ_APP_ID= QQ_CLIENT_SECRET= QQ_API_BASE=https://api.sgroup.qq.com # 大模型 API 配置 LLM_API_BASE= LLM_API_KEY= LLM_MODEL=说明一下各个变量的用途:
QQ_APP_ID:机器人在开放平台的唯一标识。QQ_CLIENT_SECRET:用于获取接口访问令牌的身份密钥。QQ_API_BASE:QQ开放平台API的根地址,示例里给了一个默认值,正式环境以官方文档为准。LLM_API_BASE:大模型服务的接口地址,示例会按Chat Completions风格拼接/chat/completions。LLM_API_KEY:调用大模型服务的密钥。LLM_MODEL:要使用的模型名称。
不要手工修改.env.example,正确做法是复制一份为.env,再在.env里填写真实值。
3. 最小可运行实现:把整条链路拼起来
3.1 主程序bot.py:接入WebSocket并处理消息事件
QQ开放平台机器人接收消息的主流方式是WebSocket长连接。机器人和QQ服务端建立连接后,服务端会把订阅的消息事件推送到你的程序里。你需要完成鉴权获取令牌、获取Gateway地址、建立WebSocket连接、发送心跳、订阅事件、处理消息事件这几件事。
下面是一份最小可运行的bot.py:
import asyncio import json import os import requests import websockets from dotenv import load_dotenv from llm_client import chat_with_llm load_dotenv() QQ_API_BASE = os.getenv("QQ_API_BASE", "https://api.sgroup.qq.com") APP_ID = os.getenv("QQ_APP_ID", "") CLIENT_SECRET = os.getenv("QQ_CLIENT_SECRET", "") access_token = "" def get_access_token(): """使用 AppID 和 ClientSecret 换取访问令牌""" resp = requests.post( f"{QQ_API_BASE}/app/getAppAccessToken", json={"appId": APP_ID, "clientSecret": CLIENT_SECRET}, timeout=5, ) resp.raise_for_status() data = resp.json() return data.get("access_token", "") def get_gateway_url(): """获取 WebSocket 网关地址""" resp = requests.get( f"{QQ_API_BASE}/gateway", headers={"Authorization": f"QQBot {access_token}"}, timeout=5, ) resp.raise_for_status() return resp.json().get("url", "") def send_channel_message(channel_id, content): """发送频道消息,群聊等场景请按官方文档调整接口和字段""" headers = { "Authorization": f"QQBot {access_token}", "Content-Type": "application/json", } body = {"content": content} resp = requests.post( f"{QQ_API_BASE}/channels/{channel_id}/messages", headers=headers, json=body, timeout=5, ) return resp.json() async def send_heartbeat(ws, interval_ms): """定时发送心跳帧,维持 WebSocket 连接""" while True: await asyncio.sleep(interval_ms / 1000) await ws.send(json.dumps({"op": 1, "d": None})) async def handle_dispatch(data): """处理服务端下发的事件帧""" t = data.get("t") d = data.get("d") if t == "READY": print("机器人已上线:", d.get("user", {}).get("username", "")) return if t == "AT_MESSAGE_CREATE": channel_id = d.get("channel_id", "") raw_content = d.get("content", "") author = d.get("author", {}) print(f"收到频道消息: {author.get('username')} -> {raw_content}") prompt = raw_content.strip() if not prompt: return print("调用大模型 ...") reply = await asyncio.to_thread(get_reply_from_user_text, prompt) print("发送回复:", reply) send_result = await asyncio.to_thread(send_channel_message, channel_id, reply) print("发送结果:", send_result) def get_reply_from_user_text(user_text: str) -> str: """同步调用大模型,供 asyncio.to_thread 包装""" return chat_with_llm(user_text) async def connect(): global access_token access_token = get_access_token() if not access_token: raise RuntimeError("获取 access_token 失败") ws_url = get_gateway_url() print("Gateway:", ws_url) async with websockets.connect(ws_url) as ws: hello = json.loads(await ws.recv()) if hello.get("op") != 10: raise RuntimeError("没有收到 hello 帧") interval = hello["d"]["heartbeat_interval"] heartbeat_task = asyncio.create_task(send_heartbeat(ws, interval)) identify = { "op": 2, "d": { "token": f"QQBot {access_token}", # 事件订阅位掩码,按当前官方文档定义填写 "intents": 1 << 30, }, } await ws.send(json.dumps(identify)) async for raw in ws: msg = json.loads(raw) op = msg.get("op", 0) if op == 0: await handle_dispatch(msg) elif op == 11: # 心跳确认帧 pass if __name__ == "__main__": asyncio.run(connect())这段代码有几个关键点需要理解。
get_access_token不是一次性设置后就永久有效。QQ开放平台的访问令牌有有效期,生产环境需要在令牌过期前自动刷新,不能只在启动时获取一次。当前示例为了控制篇幅,只在启动时获取,实际项目需要增加定时刷新逻辑。
send_heartbeat负责周期性发送心跳帧,心跳间隔由服务端下发的heartbeat_interval决定,单位是毫秒。没有心跳的WebSocket连接很容易被服务端判定为失活断开,这也是很多新手“机器人在线但收不到消息”的原因之一。
intents字段决定程序订阅哪些事件,1 << 30是很多QQ官方示例中用于订阅消息类事件的位掩码。这里特别提醒:事件订阅的位掩码可能随官方文档更新调整,如果你在运行时收到“invalid intent”或收不到消息,请打开当前版本的官方文档,对照intents的说明重新计算。
3.2 大模型客户端llm_client.py:用统一协议风格调用模型
llm_client.py只负责一件事:把用户的文本发给模型服务,拿到回复文本后返回。这里使用requests同步实现。
import os import requests SYSTEM_PROMPT = ( "你是一个QQ群里的AI助手,回复简洁、友好、安全。" "不要编造事实,涉及不确定的信息时请明确说明。" ) def chat_with_llm(user_text: str) -> str: api_base = os.getenv("LLM_API_BASE", "") api_key = os.getenv("LLM_API_KEY", "") model = os.getenv("LLM_MODEL", "") if not api_base or not api_key or not model: raise RuntimeError("LLM_API_BASE / LLM_API_KEY / LLM_MODEL 未配置") url = api_base.rstrip("/") + "/chat/completions" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", } payload = { "model": model, "messages": [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": user_text}, ], "temperature": 0.7, "max_tokens": 500, } resp = requests.post(url, headers=headers, json=payload, timeout=30) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"]LLM_API_BASE需要填成根地址,例如https://your-model-endpoint/v1,程序会拼接出https://your-model-endpoint/v1/chat/completions。如果你的模型服务地址不同,可能需要自行调整拼接方式。
SYSTEM_PROMPT是系统提示词,作用是告诉模型它现在扮演什么角色、用什么语气回答、有哪些红线。系统提示词写得越清楚,模型输出越可控。不要在生产环境省略这一步,否则同一套代码在开放聊天场景里会出现完全不可控的输出风格。
失败处理这里没有写复杂逻辑,只让异常向上抛,目的是让日志里能看到完整报错。真实项目中要根据模型服务的错误码区分限流、参数错误、余额不足、模型不存在等情况,再做不同处理。
3.3 为什么不直接在事件回调里同步调用模型
注意到代码里用了asyncio.to_thread包住chat_with_llm和send_channel_message,这是因为bot.py是异步事件循环,而requests库是同步阻塞的。
如果在handle_dispatch里直接执行chat_with_llm(user_text),大模型接口每次请求可能需要几秒甚至几十秒,这段阻塞时间里WebSocket的事件接收、心跳发送都会卡住,最终导致连接超时断开。
asyncio.to_thread的作用是把同步函数放到线程池中执行,不阻塞事件循环。这是Python异步代码里比较常见的处理方式,但也要注意,如果并发消息很多,线程池会被占满,需要后续引入队列和并发控制。
3.4 在本地运行
安装依赖、配置环境变量后启动:
pip install -r requirements.txt cp .env.example .env # 编辑 .env,填入真实凭证 python bot.py正常情况下,日志会先打印Gateway地址,再打印“机器人已上线”,说明WebSocket连接和事件订阅已经生效。
如果日志里一直没有“机器人已上线”,优先检查:
- AppID和ClientSecret是否正确。
- 本机能否访问QQ开放平台API域名。
- 是否收到hello帧,如果连hello都没收到,说明网络层或域名访问有问题。
- intents值是否合法,是否触发了协议错误。
4. 关键细节:消息解析、大模型参数和频控
4.1 消息解析不是只取content就行
AT_MESSAGE_CREATE代表机器人被@的消息事件。真实场景下,content字段里通常包含@机器人的占位符,比如<@!123456789> 你好,如果直接把整段文本丢给大模型,模型会看到一串无意义字符。
需要做文本清洗,把@占位符、换行符、多余空格处理掉:
import re def clean_prompt(raw_content: str) -> str: # 去掉 @机器人的占位符 text = re.sub(r"<@!?\d+>", "", raw_content) # 去掉多余空白 text = re.sub(r"\s+", " ", text).strip() return text清洗后得到的才是用户真正想问的内容。如果清洗后为空字符串,直接返回,不要调用模型接口,省一次调用成本,也避免因空输入产生奇怪回复。
另外要注意消息重复问题。群聊环境中,消息事件存在重复推送给客户端的可能,尤其是程序断线重连之后。生产级实现需要记录最近处理过的消息ID,在一定时间窗口内只处理一次。
4.2 大模型参数速查
接入大模型API时,最常调整的参数是model、temperature、max_tokens、timeout和重试次数。
| 参数 | 含义 | 常见值 | 调大/调小的影响 |
|---|---|---|---|
| model | 使用的模型名称 | 按你的模型服务实际情况填写 | 不同模型知识量、速度、价格差异很大 |
| temperature | 输出随机性 | 0.2 ~ 0.8 | 调大更发散,调小更稳定 |
| max_tokens | 单次回复最大长度 | 500 ~ 1000 | 调大回复更长,但耗时和费用更高 |
| timeout | 请求超时时间 | 15 ~ 30秒 | 太短容易误判失败,太长让用户等待 |
| top_p | 核采样范围 | 0.7 ~ 1.0 | 和temperature配套使用,一般固定即可 |
如果是客服或知识问答机器人,temperature建议调低,比如0.2到0.4,减少随机发挥。如果是创意写作、角色扮演机器人,可以调高到0.8以上。
max_tokens不是越大越好。QQ单条消息本身有长度限制,大模型回复几百字已经比较长,把max_tokens设成5000不仅成本高,而且发送时还要截断。建议先设500,测试后再按实际效果调整。
4.3 回复长度、超时和重试
大模型输出长度超出QQ消息限制时,不能直接发送,否则接口会报错。一个简单处理方案是做截断,然后加省略号:
def truncate_reply(text, max_len=400): if len(text) <= max_len: return text return text[: max_len - 1] + "…"更友好的做法是把长回复拆成多条消息发送,但多条消息发送要注意频控限制,避免触发限流。
重试逻辑也要谨慎。模型接口偶尔超时或返回5xx,重试1到2次是合理的。但用户发一条消息后你并没有收到回复,用户可能会手动再发一次,如果程序对每条消息都做重试,群里就可能出现重复回复。比较好的做法是:以消息ID做去重,在重试窗口内同一消息只处理一次;重试之间加退避时间,不要固定间隔狂试。
4.4 密钥管理
.env文件不要提交到Git仓库,建议在.gitignore中加入.env。配置文件里的真实密钥不要打印到日志里,错误信息也要做脱敏。
# .gitignore .env __pycache__/如果发现密钥已经泄露,立即去开放平台或模型服务商后台重置,不要只改代码里的字符串。对于线上服务,建议使用环境变量或密钥管理服务注入配置,不落盘到项目目录。
5. 运行验证和问题排查
5.1 正常运行的验证路径
启动服务后,按以下路径做一次完整验证:
- 看启动日志:确认Gateway地址获取成功、机器人已上线。
- 打开QQ,把机器人拉入目标频道或群。
- 在聊天窗口@机器人并发一条测试消息,例如“你好”。
- 观察程序日志:应该出现“收到频道消息”,然后是“调用大模型”。
- 程序会打印“发送回复”,QQ聊天窗口应该能看到AI回复。
如果中间任何一步断了,参考下面的排查链路。
5.2 最常见问题和排查顺序
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 启动时报鉴权失败 | AppID或ClientSecret错误 | 检查.env配置和控制台凭证 | 重新生成ClientSecret或复制正确AppID |
| 获取Gateway地址失败 | 网络无法访问API域名 | curl测试API地址 | 检查网络、DNS、代理设置 |
| 机器人已上线但收不到消息 | 事件订阅intents不对 | 核对官方文档intents定义 | 按文档重新计算位掩码 |
| 收到消息但模型无回复 | 大模型API地址或密钥错误 | 单独测试LLM接口 | 用curl或脚本直接调用模型API定位问题 |
| 模型有回复但发送失败 | 发送接口路径或字段不对 | 查看“发送结果”日志 | 按机器人类型核对接口路径和字段 |
| 连接频繁断开 | 心跳异常或网络抖动 | 观察WebSocket错误日志 | 增加心跳补偿和自动重连 |
排查顺序很重要。建议先确认输入,再确认路径,再确认依赖版本,再确认配置是否生效,最后看日志。很多问题并不是代码逻辑错误,而是环境变量没加载、字段名和官方文档不一致、机器人权限不对。
5.3 一条完整排查示例
假设你现在遇到的现象是:机器人能收到消息,日志里也打印了“调用大模型”,但群里没有回复。
按顺序排查:
- 先单独验证大模型接口。写一个临时脚本,直接调用
chat_with_llm("你好"),看是否有返回。如果这里报错,不涉及QQ任何逻辑,问题在模型API配置。 - 确认模型返回正常后,再看“发送回复”日志是否打印。如果没有打印,说明模型调用抛异常或超时,需要看完整堆栈。
- 如果“发送回复”打印了,再看“发送结果”日志。如果这里出现错误码,就去官方文档查对应错误码含义。
- 如果发送结果正常,再看QQ侧有没有消息到达。此时要考虑机器人是否被移出会话、是否触发频控、消息内容是否合规被拦截。
这个链路的核心思想是:先把系统切成“QQ接入”和“模型接入”两段单独验证,再合起来看。不要一上来就怀疑QQ接口,也不要一上来就改大模型参数。
调试联调阶段,日志是唯一的可信依据。不要靠猜,把每一步的输入输出都打出来,问题范围会迅速缩小。
6. 从能跑到能上线:还需要补齐的工程能力
6.1 内容安全不能跳过
大模型输出在开放群聊和频道场景里,天然存在内容风险。模型可能生成违法、色情、暴力、歧视、广告导流等内容,也可能被恶意用户通过prompt注入诱导出危险回答。
上线前必须至少做到:
- 对用户输入做敏感词检测,命中高风险时直接拒绝。
- 对模型输出做二次审核,不能把模型原样输出直接发到群里。
- 设置角色边界,系统提示词要明确禁止模型生成违法违规内容。
- 保留消息日志,便于出现问题时追溯。
- 未成年人可见场景还要考虑内容分级和防沉迷引导。
这里不建议用“只加一个关键词列表”就认为安全了。比较稳妥的做法是接入专业内容审核服务,同时保留本地敏感词拦截作为第一道防线。平台对机器人内容的监管是持续的,不是审核上线后就结束。
6.2 连接稳定性:心跳重连、断线恢复和消息去重
当前示例代码只实现了最简单的WebSocket连接,生产环境必须补上:
- 断线自动重连,不能进程退出后一直不恢复。
- 恢复会话尽量使用resume机制,避免事件丢失。
- 心跳任务要管理好,重连后旧心跳任务要取消。
- 接收到的消息要做去重,防止重连后重复处理。
- 避免重启服务时丢失正在处理的回复,考虑引入任务队列或持久化待发消息。
推荐做法是,不要从零手写WebSocket重连逻辑,优先看官方维护的SDK和示例。如果语言受限必须手写,也要把重连、退避、心跳补偿、事件重放这些细节都考虑进去。
6.3 日志、监控和告警
生产环境必须能回答这些问题:当前机器人是否在线?今天处理了多少条消息?模型调用成功率是多少?平均响应时间多久?是否触发过限流?
需要增加的工程组件包括:
- 结构化日志:记录消息ID、用户ID、会话ID、模型耗时、响应码。
- 指标上报:消息处理数、模型调用次数、失败次数、平均延迟。
- 错误告警:连续鉴权失败、模型接口连续失败、WebSocket频繁断开时通知值班人员。
不要只在控制台打印print,一旦进程重启日志就没了,后面根本没法排查。
6.4 上线前自查清单
| 检查项 | 说明 |
|---|---|
| 凭证是否已从代码中移除 | 使用环境变量或密钥管理服务 |
| 是否接入内容审核 | 至少包含敏感词过滤和基础输出校验 |
| 是否处理断线重连 | 不能靠手动重启 |
| 是否设置请求超时 | 模型调用设置15秒以上超时并做超时处理 |
| 是否做了消息去重 | 防止重复处理导致的重复回复 |
| 是否控制并发和频控 | 对模型接口做限流,避免超出配额 |
| 是否保留业务日志 | 便于问题追踪和内容安全审计 |
| 是否对照官方规范自查 | 确认机器人名称、头像、简介、功能描述合规 |
| 是否准备回滚方案 | 出问题时可以快速下线机器人或切换备用模型配置 |
这九个检查项都做完,机器人才能算“能上线”,而不是“能跑通”。
6.5 后续扩展方向
这套最小骨架可以继续扩展的方向很多:
- 多轮记忆:维护每个用户的会话上下文,让机器人记住前文。
- 知识库问答:把业务文档切片,通过向量检索把相关片段拼进提示词,让模型基于资料回答。
- 工具调用:模型判断需要查天气、查日历、查订单时,调用外部API再返回结果。
- 定时任务:在消息事件之外增加定时触发逻辑,实现每日提醒、定时播报。
- 群管理联动:在平台允许的范围内做入群欢迎、关键词提醒、违规消息提示。
- 多机器人路由:如果后面要接入多个QQ群或频道,需要考虑配置中心和服务路由。
扩展时不要一次性全做。保持当前模块边界清晰:消息接入归bot.py,模型调用归llm_client.py,新功能按模块加入,这样每一步都容易验证。
把QQ机器人和AI模型接入这件事拆开看,最大的时间成本其实不在写代码,而在理解平台边界和补齐工程底线。运行完这份最小示例后,建议第一时间补上内容安全、断线重连、日志和频控四个点,再考虑加记忆、加知识库、加花哨玩法。
对新接触这个方向的开发者来说,一个值得坚持的练习方式是:先跑通,再破坏,再修复。先改一改系统提示词,观察不同temperature下回复的变化;再手动断开网络,看重连逻辑是否能恢复;再加一个敏感词过滤,观察被拦截消息的行为。这几轮做下来,你对这套系统的理解会比单纯复制代码深入得多。
下一步如果想继续深入,可以从“多轮记忆”和“知识库问答”开始,这两项对QQ机器人体验的提升最直接。前提始终是,底线能力已经顾好。