FEATURED · 精选文章

基于Shamrock与Flask搭建可定制QQ机器人:从协议到消息推送的完整实践

发布时间 / 2026/8/13 21:16:08
来源 / 创域科博编辑部
栏目 / 资讯中心
基于Shamrock与Flask搭建可定制QQ机器人:从协议到消息推送的完整实践 1. 项目缘起为什么现在还需要自己搭QQ机器人最近在折腾一些自动化通知和群管理的小工具发现很多朋友还在到处找现成的QQ机器人框架结果要么是年久失修要么是配置复杂得让人头疼。正好看到Shamrock这个项目最近更新挺活跃社区反馈也还不错就决定自己动手搭一个试试水。我的核心需求很简单能稳定接收QQ消息能调用外部API比如我自己的天气查询服务或者AI接口然后能把处理结果发回QQ。说白了就是想要一个轻量、可控、能自己定制的“消息中转站”。你可能要问现在不是有很多成熟的机器人平台吗干嘛要自己搭原因有几个第一自己搭建意味着数据完全掌握在自己手里没有隐私泄露的担忧第二定制化程度高想加什么功能就写什么代码不受平台功能限制第三学习成本其实没想象中高尤其是对于有一定Python或Web开发基础的朋友来说这就是一个标准的“后端服务HTTP API”的集成问题。Shamrock作为一款基于Mirai的衍生框架它提供了稳定、高效的QQ协议实现而我们只需要关心业务逻辑这大大降低了开发门槛。这次搭建我会重点结合Qmsg酱这个免费的消息推送服务来演示。Qmsg的好处是它提供了现成的HTTP API我们不用自己处理复杂的QQ消息发送逻辑只需要向Qmsg的服务器发一个POST请求它就能帮我们把消息推送到指定的QQ或QQ群非常适合用来做通知类机器人。整个技术栈非常清晰Shamrock负责登录QQ并监听消息我们自建一个Flask Web服务作为“大脑”来处理消息和决策最后通过调用Qmsg的API来发送回复。下面我就把从零开始搭建的完整过程包括几个关键的避坑点详细拆解一遍。2. 环境准备与核心组件选型解析动手之前我们得先把“厨房”收拾好把需要的“食材”备齐。这个项目的核心是三个部分QQ客户端环境、消息处理后端、以及消息发送通道。2.1 Shamrock为什么选它作为QQ协议端Shamrock是目前社区内比较活跃的一个Mirai系框架。选择它主要是基于以下几点考虑协议兼容性与稳定性它持续跟进QQ的新协议减少了因为协议更新导致机器人掉线的风险。对于需要7x24小时运行的机器人来说稳定性是第一位的。开发友好性它提供了完善的HTTP API和WebSocket API。这意味着我们可以用任何熟悉的编程语言Python、Java、Go等来编写业务逻辑通过标准的HTTP请求与QQ客户端交互解耦做得非常好。社区与文档虽然不如一些明星项目火爆但它的文档和社区问答足够解决大部分部署问题遇到坑的时候能找到参考。部署Shamrock我推荐使用Docker这是最干净、最避免环境冲突的方式。你需要先确保服务器上安装了Docker和Docker Compose。2.2 业务后端为什么是Flask消息处理的后端我选择了Python的Flask框架。这是一个非常轻量级的Web框架对于我们这个主要处理HTTP API请求的场景来说它足够简单、灵活且生态丰富。几行代码就能拉起一个服务非常适合快速原型开发和中小型应用。相比Django等“全家桶”框架Flask给了开发者更大的自由去组合需要的组件比如数据库连接池、任务队列等不会引入不必要的复杂性。2.3 消息推送Qmsg酱的妙用Qmsg酱是一个免费的QQ消息推送平台。它的角色很关键它充当了我们自建后端与QQ之间的一个可靠、免鉴权的发送通道。我们自己搭建的后端服务Flask应用在需要发送消息时无需直接与复杂的QQ协议打交道只需向Qmsg提供的固定API地址发送一个携带了密钥和消息内容的HTTP POST请求Qmsg服务器就会帮我们把消息送达目标QQ或群。这样做的好处显而易见简化发送逻辑我们不需要在Flask服务里维护QQ的登录状态或处理发送重试。提升可靠性Qmsg作为专业服务其发送成功率通常高于我们自己实现的简易客户端。规避风险将协议层面的操作交给专门的客户端Shamrock和推送服务Qmsg我们的业务代码可以更专注于逻辑结构更清晰。注意Qmsg免费版有频率限制对于个人或小规模使用完全足够。如果你的机器人需要极高的消息推送频率需要关注其使用条款或考虑升级。3. 一步步搭建从零到一的完整实操理论说完了我们开始动手。请严格按照步骤操作我会指出其中容易出错的地方。3.1 第一步部署Shamrock服务首先在你的服务器上创建一个工作目录例如qq_bot。然后在这个目录下创建docker-compose.yml文件。version: 3.8 services: shamrock: image: whitechi73/opengot:shamrock container_name: shamrock restart: unless-stopped network_mode: host # 使用host网络模式避免复杂的端口映射问题 environment: - TZAsia/Shanghai # 设置时区 - SHAMROCK_HTTP0.0.0.0:8080 # 启用HTTP API监听所有网卡的8080端口 - SHAMROCK_WS0.0.0.0:8081 # 启用WebSocket API端口8081 volumes: - ./shamrock_data:/data # 将容器内的/data目录挂载到本地持久化配置和登录数据解释一下关键配置network_mode: host: 让容器直接使用宿主机的网络栈。这样容器内服务监听的端口8080 8081就直接暴露在宿主机上Flask应用可以直接通过localhost:8080来访问Shamrock的API省去了配置Docker网络和端口映射的麻烦。volumes: 挂载卷至关重要。它把Shamrock的配置、缓存和关键的登录凭证设备文件保存在宿主机上。即使容器被删除重建只要挂载卷还在重新登录的步骤都可以省略机器人可以快速恢复上线。创建好文件后在终端进入该目录执行命令启动服务docker-compose up -d使用docker logs -f shamrock可以查看实时日志。当你看到日志里出现等待登录或相关的启动成功信息时说明Shamrock服务已经正常运行。3.2 第二步登录QQ并获取Session KeyShamrock启动后它只是一个空壳我们需要让它登录一个QQ号。这里我们使用其提供的HTTP API来完成认证。获取登录验证码Shamrock支持多种登录方式。对于首次登录我们通常使用扫码。向它的API发送请求curl -X POST http://localhost:8080/auth执行后查看Shamrock的日志或返回的JSON响应里面会包含一个二维码链接url字段或Base64格式的二维码图片数据。用你的手机QQ扫描这个二维码完成登录。验证并获取Session Key扫码授权成功后需要验证登录会话并获取一个关键的session_key。这个key是后续所有API调用的凭证。curl -X POST http://localhost:8080/verify \ -H Content-Type: application/json \ -d { qq: 你的QQ号, verifyKey: 从/auth响应中获取的verifyKey }这个请求的响应中会包含session_key。请妥善保存这个key下面的Flask服务配置会用到它。踩坑提示session_key是有时效的也可能在Shamrock重启后失效。在生产环境中你需要编写逻辑在Flask服务启动时或检测到session失效时自动重新执行这个验证流程来获取新的key。可以将这个逻辑封装成一个函数在应用启动时调用。3.3 第三步编写Flask消息处理后端现在我们来创建机器人的“大脑”。在qq_bot目录下与docker-compose.yml同级新建一个app.py文件。from flask import Flask, request, jsonify import requests import json import logging # 配置日志方便排查问题 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logger logging.getLogger(__name__) app Flask(__name__) # 核心配置区 # 这里填写你从Shamrock获取的实际信息 SHAMROCK_BASE_URL http://localhost:8080 # Shamrock HTTP API 地址 SESSION_KEY 你的SessionKey # 替换为实际的session_key BOT_QQ_NUMBER 你的机器人QQ号 # 替换为机器人的QQ号 # Qmsg酱的配置 QMSG_KEY 你在Qmsg官网获取的KEY # 在 https://qmsg.zendee.cn 注册后获取 QMSG_API_SEND https://qmsg.zendee.cn/send/ # Qmsg发送消息API # 工具函数 def send_via_qmsg(qq, message, msg_typeprivate): 通过Qmsg酱发送消息 :param qq: 接收者的QQ号私聊或群号群聊需在Qmsg后台绑定 :param message: 要发送的消息内容 :param msg_type: 消息类型private 或 group (需Qmsg付费版支持) # Qmsg免费版主要支持私聊这里以私聊为例 if msg_type private: api_url f{QMSG_API_SEND}{QMSG_KEY} else: # 群聊逻辑可能需要不同的API或处理方式 api_url f{QMSG_API_SEND}{QMSG_KEY}?qq{qq} # 请根据Qmsg最新文档调整 logger.warning(群聊发送可能需付费版支持请查阅Qmsg文档。) data { msg: message, qq: qq # 对于私聊这里是接收者QQ } headers {Content-Type: application/x-www-form-urlencoded} try: resp requests.post(api_url, datadata, headersheaders, timeout5) resp.raise_for_status() # 如果状态码不是200抛出异常 result resp.json() if result.get(success): logger.info(f通过Qmsg向{qq}发送消息成功) return True else: logger.error(fQmsg发送失败: {result.get(reason)}) return False except requests.exceptions.RequestException as e: logger.error(f调用Qmsg API时发生网络错误: {e}) return False except json.JSONDecodeError as e: logger.error(f解析Qmsg响应JSON失败: {e}) return False # 消息路由与处理 app.route(/webhook, methods[POST]) def webhook(): 接收Shamrock转发过来的QQ消息。 Shamrock需要配置将消息事件POST到这个地址。 try: data request.json if not data: logger.warning(收到空的POST请求) return jsonify({code: 400, msg: Invalid data}), 400 # 解析通用字段 post_type data.get(post_type) message_type data.get(message_type) raw_message data.get(raw_message, ).strip() sender_id data.get(user_id) if message_type private else data.get(group_id) user_id data.get(user_id) # 发送者QQ号 logger.info(f收到事件: post_type{post_type}, message_type{message_type}, sender{sender_id}, msg{raw_message[:50]}...) # 只处理私聊和群聊的消息类型 if post_type message: # 示例1私聊消息且包含“天气”关键词 if message_type private and 天气 in raw_message: # 这里可以调用真实的天气API例如和风天气 # weather_info get_weather_from_api(北京) # reply_msg f北京的天气是{weather_info} reply_msg 【示例】今天北京晴转多云15~25℃微风。 # 使用Qmsg回复私聊 send_via_qmsg(qquser_id, messagereply_msg, msg_typeprivate) # 示例2群聊消息且了机器人 elif message_type group and f[CQ:at,qq{BOT_QQ_NUMBER}] in raw_message: # 移除机器人的CQ码获取纯文本指令 command raw_message.replace(f[CQ:at,qq{BOT_QQ_NUMBER}], ).strip() if command 帮助: reply_msg 我是测试机器人支持命令\n1. 天气 [城市] - 查询天气\n2. 帮助 - 显示此帮助 # 注意Qmsg免费版向群发送可能需要特殊配置这里先回复到私聊 # 更常见的做法是直接使用Shamrock的API回复群消息见下文备选方案 send_via_qmsg(qquser_id, messagereply_msg, msg_typeprivate) # 或者使用Shamrock API直接回复到群推荐但需处理session # send_via_shamrock_group(group_idsender_id, messagereply_msg) # 示例3简单的复读机测试用 elif message_type private and raw_message.startswith(echo ): reply_msg raw_message[5:] # 去掉‘echo ’前缀 send_via_qmsg(qquser_id, messagereply_msg, msg_typeprivate) return jsonify({code: 0, msg: success}), 200 except Exception as e: logger.exception(f处理webhook请求时发生未预期错误: {e}) return jsonify({code: 500, msg: Internal server error}), 500 # 备选发送方案直接调用Shamrock API def send_via_shamrock_private(target_qq, message): 直接通过Shamrock API发送私聊消息需有效session api_url f{SHAMROCK_BASE_URL}/send_private_msg payload { sessionKey: SESSION_KEY, target: target_qq, messageChain: [{type: Plain, text: message}] } try: resp requests.post(api_url, jsonpayload, timeout5) resp.raise_for_status() return resp.json().get(code) 0 except Exception as e: logger.error(f通过Shamrock发送私聊消息失败: {e}) return False if __name__ __main__: # 启动Flask应用监听5000端口允许外部访问host0.0.0.0 app.run(host0.0.0.0, port5000, debugFalse) # 生产环境务必设置debugFalse这个app.py是整个机器人的逻辑核心我把它分成了几个部分来便于理解。首先是配置区这里需要你填入三个关键信息Shamrock的地址、刚才获取的session_key、以及机器人的QQ号。然后是send_via_qmsg函数它封装了调用Qmsg API发送消息的所有细节包括错误处理这样我们在业务逻辑里调用它就会非常干净。最核心的是/webhook这个路由。Shamrock会把收到的所有QQ消息事件以JSON格式POST到这个地址。我们在函数里解析这个JSON根据消息类型私聊/群聊、发送者、消息内容来决定如何回复。我写了三个简单的示例逻辑私聊查询天气、群聊中机器人后响应帮助、以及一个私聊的复读机。你可以在这里无限扩展你的机器人功能比如接入ChatGPT、查询数据库、监控服务器状态等等。重要提示session_key直接写在代码里是不安全的尤其是在开源或共享代码时。正式部署时务必通过环境变量、配置文件或密钥管理服务来读取这些敏感信息。例如可以使用os.environ.get(SHAMROCK_SESSION_KEY)来从环境变量获取。3.4 第四步配置Shamrock的消息上报我们的Flask服务写好了但Shamrock还不知道要把消息往哪里送。我们需要告诉Shamrock“嘿以后收到消息都发到http://我的Flask服务器IP:5000/webhook这个地址。”通过调用Shamrock的配置API来完成curl -X POST http://localhost:8080/config \ -H Content-Type: application/json \ -d { sessionKey: 你的SessionKey, config: { enableWebhook: true, webhookUrls: [ http://你的Flask服务器IP:5000/webhook ] } }请将你的Flask服务器IP替换为运行app.py的那台机器的真实IP地址。如果Shamrock和Flask运行在同一台机器可以用http://host.docker.internal:5000/webhookDocker容器内访问宿主机或者直接使用宿主机在局域网内的IP。3.5 第五步注册Qmsg并获取KEY访问 Qmsg酱 官网例如qmsg.zendee.cn请以最新搜索为准。使用QQ登录。在控制台你可以找到你的唯一KEY。这个KEY是用来标识你的身份的所有通过你代码发送的消息Qmsg都靠这个KEY知道要推送给哪个QQ。通常你需要将接收消息的QQ号可以是你的个人QQ也可以是机器人QQ与这个KEY进行“绑定”或“添加”这样Qmsg才有权限向这个QQ发送消息。具体操作请遵循官网指引。将获取到的QMSG_KEY填入上面app.py的配置区。3.6 第六步启动与测试启动Flask服务在qq_bot目录下运行python app.py。你应该看到输出表明服务在0.0.0.0:5000上启动。测试消息流用你的手机QQ给机器人QQ号发送一条包含“天气”二字的私聊消息。观察Flask服务的日志输出应该能看到它收到了消息事件。同时你的手机QQ应该会很快收到一条来自“Qmsg酱”的天气回复消息。测试群聊如果配置了将机器人拉入一个群。在群里 机器人 并输入“帮助”。观察日志和私聊回复。4. 关键问题排查与进阶优化按照上面的步骤大部分朋友应该能成功跑通。但如果遇到问题别慌我们来系统性地排错。4.1 网络连接与防火墙检查这是最常见的问题。请确保以下网络通路是畅通的宿主机内部Flask应用localhost:5000能否访问到Shamrocklocalhost:8080可以用curl http://localhost:8080/about测试。容器与宿主机如果Flask也在Docker中运行需确保两个容器在同一个Docker网络下或者使用host网络模式。服务器防火墙确保服务器的防火墙如ufw, firewalld或云服务商的安全组规则放行了5000Flask和8080Shamrock API端口。Shamrock的host模式意味着它直接使用宿主机的端口防火墙必须允许8080端口入站。公网访问如果你的Flask服务部署在公网服务器Shamrock配置的webhookUrls必须是公网可访问的URL。可以用curl -X POST 你的公网URL/webhook简单测试。4.2 Shamrock Session失效与自动维护session_key不是永久的。Shamrock重启、QQ长时间未操作都可能使其失效。一个健壮的机器人需要能自动处理这种情况。我们可以在Flask应用启动时以及每次调用Shamrock API失败返回特定的认证错误码如3时触发一个重认证流程。思路如下将获取和验证session_key的逻辑封装成函数get_valid_session_key()。在应用启动时调用一次将获取到的key存入一个全局变量或缓存如Redis。在send_via_shamrock_private等函数中如果请求返回code3或对应的认证错误则捕获异常调用get_valid_session_key()刷新key然后重试发送操作。可以考虑增加一个定时任务如使用APScheduler每隔一段时间如23小时主动刷新一次session防患于未然。4.3 Qmsg发送失败的可能原因KEY错误或未绑定检查QMSG_KEY是否填写正确以及这个KEY是否在Qmsg后台绑定了接收消息的QQ号。频率超限免费用户有发送频率限制。如果短时间内触发大量消息会被限流。需要在代码中做好限流和队列处理或者考虑升级服务。网络超时Qmsg服务器偶尔可能不稳定。在send_via_qmsg函数中我们已经增加了超时设置和异常捕获并记录了日志。如果发送失败可以根据业务需求决定是否重试。消息格式问题Qmsg对消息内容可能有长度或字符限制。如果发送超长或包含特殊字符的消息失败可以尝试截断或转义。4.4 性能与扩展性考量当前的架构Flask单进程适合低并发场景。如果机器人需要处理大量群消息或复杂计算需要考虑使用生产级WSGI服务器用Gunicorn或uWSGI替代Flask自带的开发服务器以支持多Worker并发处理请求。引入消息队列当收到一个消息事件Flask的Webhook处理器只负责快速解析和验证然后将任务如“查询北京天气”放入Redis或RabbitMQ这样的消息队列。再由后台的Worker进程从队列中取出任务执行耗时的操作如调用外部API最后调用发送函数。这样能避免HTTP请求阻塞大幅提升吞吐量。无状态化与水平扩展将session_key等状态信息存入Redis这样多个Flask实例或Worker可以共享状态。结合负载均衡可以实现机器人的水平扩展。4.5 安全加固建议校验消息来源理论上任何知道你的Webhook地址的人都可以伪造消息POST过来。虽然Shamrock的请求来自本地或内网风险较低但在公网环境下建议在Flask的/webhook端点中校验请求头中的某个由Shamrock设置的特定Token如果Shamrock支持配置或者至少校验来源IP。敏感信息脱敏绝对不要将SESSION_KEY、QMSG_KEY等硬编码在代码或提交到公开仓库。使用.env文件配合python-dotenv库或直接使用环境变量。限制命令权限在消息处理逻辑中对于“重启服务”、“执行系统命令”等高危指令可以校验发送者的QQ号是否在白名单内。整个搭建过程就像搭积木Shamrock是连接QQ世界的桥梁Flask是我们自定义逻辑的车间Qmsg则是一个高效的物流配送员。这个组合的优势在于每一层都职责清晰可以独立替换或升级。比如你觉得Qmsg不够用完全可以替换成直接调用Shamrock的发送API或者接入其他推送服务你觉得Flask太重也可以用FastAPI、Go、Node.js重写逻辑部分只要保持HTTP接口一致就行。这种灵活性正是自建机器人的魅力所在。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻