【QQ机器人】简易部署,仅使用官方开源python代码,无需外部框架接入

【QQ机器人】简易部署,仅使用官方开源python代码,无需外部框架接入
官方最近对使用AIGC接口的机器人进行了封禁,且以往的WebSocket服务将陆续不再支持,故本文旨在以最为基础的办法,不使用外部框架,利用Webhook方式接入机器人

准备工作

前往QQ开放平台注册机器人账号

沙箱配置

“沙箱配置”中配置用于机器人测试的群聊、私聊账号以及频道信息

开发管理

“开发管理”中可以看到机器人的ID、密钥等信息,很重要,后续需要使用。IP白名单中需要放行你的服务器公网IP

回调配置

“回调配置”中需要配置Webhook服务使用的回调地址,需要准备一个已备案的域名,并且域名需要解析到你的公网IP上。同时,域名需要部署SSL证书(能用https访问)。

可以仿照我的后缀写,后续配置Webhook时需要使用

你的域名/qqbot-webhook/callback

填写好此时会提示“校验失败”,不用着急,因为Webhook服务还没有启用,过一会儿会回来重填

篇幅原因,不介绍服务器租用、公网购买、证书部署等相关的知识,网上有文章很多可自查

添加事件省事建议全选,也可以自选需要的,选好后需要在右下角确认配置

阿里云的免费SSL个人测试证书不含CA,回调地址验证时会失败,建议使用腾讯云的免费SSL证书(腾讯云免费SSL证书

 

代码部署

本文疏于解释的地方可参考官方文档官方源代码

创建python环境

在自己的服务器上合适的位置(本文使用/opt/qqbot)创建用于管理机器人代码的文件夹,并从代码仓库导入文件

git clone https://github.com/Space-ash/QQbot.git

在你的项目目录创建python虚拟环境

# 进入你的项目目录 cd /opt/qqbot # 建议使用虚拟环境 python3 -m venv .venv source .venv/bin/activate

安装依赖

# 安装依赖 pip install --upgrade pip pip install fastapi uvicorn pynacl # 改为你的requirements.txt路径 pip install -r /opt/qqbot/requirements.txt

端口放行

阅读官方API文档中“事件订阅与通知”一节,回调地址允许配置的端口号为:80、443、8080、8443,因此需要在服务器对应的端口配置回调代码

此外需要在服务器安全组放行6196端口

端口描述类型
6195企业微信默认端口可选
6199QQ 个人号(aiocqhttp)默认端口可选
6196QQ 官方接口(Webhook)默认端口需要
本文使用的是apache,如果你需要使用nginx或caddy等,可以自行查阅相关资料或询问AI

找到解析到服务器的域名对应的apache配置文件,文件名通常为"你的域名.conf"

<VirtualHost *:80> # ... # 此处是默认有的一大段代码,不用管 # ... # 只用插入这一段,反代 AstrBot 回调 ProxyPass "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback" ProxyPassReverse "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback" </VirtualHost> <VirtualHost *:443> # ... # 此处是默认有的一大段代码,不用管 # ... # 只用插入这一段,反代回调,需要在相应的地方改为你的回调地址后缀 ProxyPass "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback" ProxyPassReverse "/qqbot-webhook/callback" "http://127.0.0.1:6196/qqbot-webhook/callback" # 如果以后用 WS,把升级头转过去 RewriteEngine On RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteRule ^/qqbot-webhook/(.*) ws://127.0.0.1:6196/qqbot-webhook/$1 [P,L] </VirtualHost>

重启apache服务,加载配置文件

service httpd restart

qqbot_webhook.py

使用Webhook服务的主要文件,打开后你需要填入“开发管理”中查看到的机器人ID和密钥

# ======= 明文写入(仅用于你这台服务器;不要提交到仓库)======= APP_ID = "your_app_id_here" # 替换为你的 Bot AppID BOT_SECRET = "your_bot_secret_here" # Bot Secret / AppSecret # ============================================================

如果需要保存日志,则将此处的LOG_DIR改为你的地址

# ---------------- 日志配置 ---------------- LOG_DIR = "/opt/qqbot/logs" # 替换为你的webhook日志地址 os.makedirs(LOG_DIR, exist_ok=True) def write_log(level: str, msg: str): """单文件临时日志,全部写到 qqbot_webhook.log""" path = os.path.join(LOG_DIR, "qqbot_webhook.log") line = f"{datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} | {level} | {msg}\n" with open(path, "a+", encoding="utf-8") as f: f.write(line) f.flush() # -----------------------------------------

回调地址后缀"/qqbot-webhook/callback"则需要改为你希望填写在“回调配置”中的地址后缀

@app.post("/qqbot-webhook/callback") # 改为你的回调地址 async def qqbot_callback(request: Request): write_log("INFO", "=== 收到Webhook请求 ===") # 读取原始 body(验签与 op=13 都可能用到) raw = await request.body()

qqbot_webhook.service

service文件用于服务器后台挂载Webhook服务,需要将WorkingDirectory改为你的service地址,ExecStart改为你的unicorn地址

# /opt/qqbot/qqbot_webhook.service [Unit] Description=QQ Bot Webhook (FastAPI) After=network.target [Service] User=www-data WorkingDirectory=/opt/qqbot # 替换为你的service文件的地址 ExecStart=/opt/qqbot/.venv/bin/uvicorn qqbot_webhook:app --host 127.0.0.1 --port 6196 # 替换为你的uvicorn文件地址 Restart=always RestartSec=3 [Install] WantedBy=multi-user.target

启用Webhook服务

把你的项目路径下的service单元链接进系统搜索路径

sudo systemctl link /opt/qqbot/qqbot_webhook.service

启用服务,以后每次修改Webhook相关的代码,均需要重新启用服务

sudo systemctl daemon-reload sudo systemctl enable --now qqbot_webhook sudo systemctl restart qqbot_webhook sudo systemctl status qqbot_webhook

验证是否启用成功

curl -v -i http://127.0.0.1:6196/qqbot-webhook/callback \ -H 'Content-Type: application/json' \ -d '{"op":13,"d":{"plain_token":"Arq0D5UvOp","event_ts":"1741"}}'

如果终端返回200 OK以及一个含有"plain_token"和"signature"的json,则说明服务启用成功了

* Trying 127.0.0.1:6196... * Connected to 127.0.0.1 (127.0.0.1) port 6196 > POST /qqbot-webhook/callback HTTP/1.1 > Host: 127.0.0.1:6196 > User-Agent: curl/8.5.0 > Accept: */* > Content-Type: application/json > Content-Length: 76 > < HTTP/1.1 200 OK HTTP/1.1 200 OK < date: Tue, 21 Oct 2025 13:37:25 GMT date: Tue, 21 Oct 2025 13:37:25 GMT < server: uvicorn server: uvicorn < content-length: 181 content-length: 181 < content-type: application/json content-type: application/json < * Connection #0 to host 127.0.0.1 left intact {"plain_token":"Arq0D5UvOp","signature":"d7d2e0...83d605"}

如果出现400,404,500等各种各样的报错,可以在终端查看日志。排查错误

journalctl -u qqbot_webhook -n 100 -f

成功后回到官方的“回调配置”网页,在请求地址中填入你的回调地址,发现不再提示校验失败

你的域名/qqbot-webhook/callback

保存配置后,在终端进入项目的python虚拟环境,并运行机器人

# 启用虚拟环境 source .venv/bin/activate # 运行机器人 python3 ./yourbot/demo_yourbot.py

可以看到终端输出,则说明机器人启动成功了

[INFO] (client.py:162)_bot_login [botpy] 登录机器人账号中... [INFO] (robot.py:65)update_access_token [botpy] access_token expires_in 2964 [INFO] (client.py:181)_bot_init [botpy] 程序启动... [INFO] (connection.py:60)multi_run [botpy] 最大并发连接数: 1, 启动会话数: 1 [INFO] (client.py:242)bot_connect [botpy] 会话启动中... [INFO] (gateway.py:115)ws_connect [botpy] 启动中... [INFO] (gateway.py:142)ws_identify [botpy] 鉴权中... [INFO] (gateway.py:85)on_message [botpy] 机器人「说怪话-测试中」启动成功! [INFO] (gateway.py:223)_send_heart [botpy] 心跳维持启动... [INFO] (demo_chimera.py:17)on_ready robot 「说怪话-测试中」 on_ready!

打开QQ,私聊机器人,可以看到机器人回复了你的消息

如果机器人没有回复,可以查看logs/qqbot_webhook.log中的信息,或者利用journalctl -u qqbot_webhook -n 100 -f查看终端的运行日志进行调试

正常的配置到此就结束了!如果有后续扩展功能需求的可以往后看。

功能扩展(施工中)

鄙人能力有限,所以也只能本着摸着石头过河的原则,遇到一些对开发有用的信息便记录在此处,如有谬误,望各位大佬指出!

PS.吐槽一句官方文档太久不更新了,查阅了好多资源也比较零碎,整理不易,望海涵

发送私聊消息C2C_MESSAGE_CREATE

这是我配置的第一个测试事件,花费了大量的时间。本质上就是下面这段代码

# 目前这段代码在qqbot_webhook.py中,后续可以单独打包 import botpy from botpy.http import BotHttp from botpy.api import BotAPI from botpy.message import C2CMessage from botpy.types.gateway import MessagePayload from yourbot.demo_yourbot import MyClient # 导入 demo_chimera.py 中的 MyClient def build_message_payload(event: dict) -> MessagePayload: # 补全缺失字段 return { "author": event.get("author", {}), "channel_id": event.get("channel_id", ""), # C2C消息可能没有,可设为"" "content": event.get("content", ""), "guild_id": event.get("guild_id", ""), # C2C消息可能没有,可设为"" "id": event.get("id", ""), "member": event.get("member", {}), # C2C消息可能没有,可设为{} "message_reference": event.get("message_reference", {}), "mentions": event.get("mentions", []), "attachments": event.get("attachments", []), "seq": event.get("seq", 0), "seq_in_channel": event.get("seq_in_channel", ""), "timestamp": event.get("timestamp", ""), } # --- 普通事件(op=0)需要验签 --- if op == 0: # ... # 前面是验签的代码 # ... # 获取事件数据 event = payload.get("d", {}) event_type = payload.get("t", "") # 检查是否为 C2C 消息创建事件 if event_type == "C2C_MESSAGE_CREATE": write_log("INFO", "=== C2C_MESSAGE_CREATE事件 ===") http = BotHttp(timeout=5, app_id=APP_ID, secret=BOT_SECRET) api = BotAPI(http) event_id = event.get("id", "") payload = build_message_payload(event) message = C2CMessage(api, event_id, payload) intents = botpy.Intents(public_messages=True) client = MyClient(intents=intents) await client.on_c2c_message_create(message) 

主要是最后await传递的数据格式需要对应,从而需要有正确的http,api,payload读入。因此需要查阅botpy库中的相关代码(message.py, aip.py, gateway.py, http.py),需要了解各个class之间是怎么传递数据的。

比较坑的一点是payload格式没有统一,在不同的使用场景都会缺失参数,导致C2CMessage传参错误。比如私聊消息的时候,返回的payload是不带channel_id的,所以我自己写了一个build_message_payload函数用于匹配payload格式,空缺的参数设为空,这样传参才不会报错。

关联代码片段1:demo_yourbot.py

# demo_yourbot.py import botpy from botpy import logging from botpy.ext.cog_yaml import read from botpy.message import C2CMessage test_config = read(os.path.join(os.path.dirname(__file__), "config.yaml")) _log = logging.get_logger() class MyClient(botpy.Client): async def on_ready(self): _log.info(f"robot 「{self.robot.name}」 on_ready!") async def on_c2c_message_create(self, message: C2CMessage): _log.info(f"收到消息: {message.content} 来自 {message.author.user_openid}") await message._api.post_c2c_message( openid=message.author.user_openid, msg_type=0, msg_id=message.id, content=f"我收到了你的消息:{message.content}" ) 

关联代码片段2:message.py

传参格式:C2CMessage(api, event_id, data),api来自于BotAPI,event_id来自返回的json格式的payload中的"id",data需要用函数build_message_payload修正格式后的payload
class C2CMessage(BaseMessage): __slots__ = ("author",) def __init__(self, api: BotAPI, event_id, data: gateway.MessagePayload): super().__init__(api, event_id, data) self.author = self._User(data.get("author", {})) def __repr__(self): slots = self.__slots__ + super().__slots__ return str({items: str(getattr(self, items)) for items in slots if not items.startswith("_")}) class _User: def __init__(self, data): self.user_openid = data.get("user_openid", None) def __repr__(self): return str(self.__dict__) async def reply(self, **kwargs): return await self._api.post_c2c_message(openid=self.author.user_openid, msg_id=self.id, **kwargs)

关联代码片段3:api.py

传参格式:BotAPI(http),http来自于BotHttp
class BotAPI: """ 机器人相关的API接口类 使用注意: - 如果要直接使用api,可以通过client的内部成员变量,通过`self.api.xx`来使用 - 设置超时时间: Client(timeout=5) - API当前返回的所有自定义类型数据为字典数据,通过TypedDict进行类型提示 """ def __init__(self, http: BotHttp): """ Args: http (BotHttp): 用于发送请求的 http 客户端。 """ self._http = http

关联代码片段4:http.py

传参格式:BotHttp(timeout, app_id, secret)
class BotHttp: """ TODO 增加请求重试功能 @veehou TODO 增加并发请求的锁控制 @veehou """ def __init__( self, timeout: int, is_sandbox: bool = False, app_id: str = None, secret: str = None, ): self.timeout = timeout self.is_sandbox = is_sandbox self._token: Optional[Token] = None if not app_id else Token(app_id=app_id, secret=secret) self._session: Optional[aiohttp.ClientSession] = None self._global_over: Optional[asyncio.Event] = None self._headers: Optional[dict] = None

关联代码片段5:gateway.py

需要完整的payload,因此使用函数build_message_payload对接收到的payload进行修正
class MessagePayload(TypedDict): author: UserPayload channel_id: str content: str guild_id: str id: str member: Member message_reference: MessageRefPayload mentions: List[UserPayload] attachments: List[MessageAttachPayload] seq: int seq_in_channel: str timestamp: str

 

Read more

免费部署openClaw龙虾机器人(经典)

免费部署openClaw龙虾机器人(经典)

前几天出了个免费玩龙虾的详细教程,很多小伙伴觉得不错,但是还有一些新手留言反馈内容不够详细,这次我将重新梳理一遍,做一期更细致的攻略,同时扩展补充配置好之后的推荐(我认为是必要)操作,争取一篇文章让大家可以收藏起来,随时全套参照复用。 先看效果测试 部署完成基础运行效果测试,你可以直接问clawdbot当前的模型: 1.Token平台准备 首先,还是准备好我们可以免费撸的API平台 这里我找到了两个可以免费使用的API,测试之后执行效率还可以,下面将分别进行细致流程拆解。 1.1 硅基流动获取ApiKey (相对免费方案 推荐) 硅基流动地址:https://cloud.siliconflow.cn/i/6T57VxS2 如果有账号的直接登录,没有的注册一个账号,这个认证就送16元,可以直接玩收费模型,真香。认证完成后在API秘钥地方新建秘钥。 硅基流动里面很多模型原来是免费的,有了16元注册礼,很多收费的模型也相当于免费用了,我体验一下了原来配置免费模型还能用,也是值得推荐的。建议使用截图的第一个模型体验一下,我一直用它。 1.2 推理时代

By Ne0inhk

Flutter 三方库 angular_bloc 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致响应、工业级的 AngularDart 与 BLoC 协同架构实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 angular_bloc 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致响应、工业级的 AngularDart 与 BLoC 协同架构实战 在鸿蒙(OpenHarmony)系统的桌面级协同(如分布式办公网页版)、后台管理终端或高度复杂的 Web 仪表盘开发中,如何将经典的 BLoC 状态管理应用于 AngularDart 环境?angular_bloc 为开发者提供了一套天衣无缝的组件化连接器。本文将实战演示其在鸿蒙 Web 生态中的深度应用。 前言 什么是 Angular BLoC?它是一套专门为 AngularDart 框架设计的 BLoC 实现。通过指令(Directives)和管道(Pipes),它实现了由于数据流变化触发的 UI

By Ne0inhk
n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

n8n飞书webhook配置(飞书机器人、飞书bot、feishu bot)Crypto节点、js timestamp代码、Crypto node

自定义机器人使用指南 利用 n8n 打造飞书 RSS 推送机器人 文章目录 * 自定义机器人使用指南 * 注意事项 * 功能介绍 * 在群组中添加自定义机器人 * 操作步骤 * 邀请自定义机器人进群。 * - 进入目标群组,在群组右上角点击更多按钮,并点击 设置。 * - 在右侧 设置 界面,点击 群机器人。 * - 在 群机器人 界面点击 添加机器人。 * - 在 添加机器人 对话框,找到并点击 自定义机器人。 * - 设置自定义机器人的头像、名称与描述,并点击 添加。 * 获取自定义机器人的 webhook 地址,并点击 完成。 * 测试调用自定义机器人的 webhook 地址,向所在群组发送消息。 * -

By Ne0inhk
【AI】——SpringAI通过Ollama本地部署的Deepseek模型实现一个对话机器人(二)

【AI】——SpringAI通过Ollama本地部署的Deepseek模型实现一个对话机器人(二)

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大三学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL,Javaweb,Rust,python】 🎈热门专栏:🎊【Springboot,Redis,Springsecurity,Docker,AI】  感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️ 目录 🎈Java调用Deepseek  🍕下载Deepseek模型  🍕本地测试  🍕Java调用模型 🎈构建数据库  🍕增强检索RAG  🍕向量数据库  🍕Springboot集成pgvector 🎈chatpdf 🎈function call调用自定义函数 🎈多模态能力 🎈Java调用Deepseek 本地没有安装Ollama、Docker,openwebUI,可以先学习一下这篇文章:【AI】——结合Ollama、Open WebUI和Docker本地部署可视化AI大语言模型_ollma+本地大模型+open web ui-ZEEKLOG博客

By Ne0inhk