Files
qqbotsdk/dist/README.md
T
snowy-yang 7603db7fd9 feat!: 文档部署改为 docs 分支自动同步,移除 Gitea 工作流与 wrangler 脚本
Gitea 已配置为 GitHub 的镜像,主仓库落在 GitHub:

- 删除 .gitea/(runner 已弃用,六轮实跑不稳定)与
  scripts/deploy_docs.sh(wrangler Direct Upload 路径随之退役,
  CLOUDFLARE_* secrets 不再被 CI 需要)
- deploy-docs.yml 重写:main 的文档文件变更时自动把纯文档组装进
  docs 孤儿分支并强推——Cloudflare Pages 直连 GitHub、生产分支选
  docs、构建命令留空、输出目录 / 即完成零构建接入
- index.html 仓库链接与 README/GUIDE 安装命令补 GitHub 地址;
  CHANGELOG 合并原先两条 CI/部署条目
2026-09-24 21:19:15 +08:00

5.8 KiB
Raw Blame History

qqbotsdk

QQ 官方机器人 Python SDK(Python 3.13 / asyncio / aiohttp),支持 WebSocket 与 Webhook 两种接入方式。

使用指南 · API 参考 · 架构 · 示例 · 更新日志

架构

flowchart TB
    subgraph 接入层
        WS["WebsocketConnecter(ws 长连接 / 重连 / 心跳看门狗)"]
        WH["WebhookConnecter(http 回调 / 验签 / 去重)"]
    end
    subgraph 协议层
        WSP["WebsocketProtocol(握手 / 会话 / 序列号)"]
        WHP["WebhookProtocol(op=13 验证应答)"]
    end
    subgraph 分发层
        Q[("EventQueue<br/>业务事件 op=0")]
        EE["EventEmitter(路由 / 参数注入 / 异常隔离)"]
    end
    subgraph 业务层
        API["BotApi(REST + ApiError)"]
        USER["用户 handler @ee.on(...)"]
    end
    QQ["QQ 开放平台"]

    WS -. "逐帧 on_frame" .-> WSP
    WH -. "op=13 逐帧 on_frame" .-> WHP
    WS -->|"业务事件"| Q
    WH -->|"业务事件"| Q
    Q --> EE
    EE --> USER
    USER --> API
    API --> QQ
    WS --> QQ

组件在 run_loop 显式装配,并按类型登记到 emitter.services 供 handler 参数注入(无全局单例);协议帧由连接适配器交给各自的协议处理器就地处理,只有 op=0 的业务事件经队列进入分发——依赖关系与设计决策详见 docs/ARCHITECTURE.md。

特性

  • 内置协议处理器(ws_protocol.py / webhook_protocol.py):HELLO 鉴权(IDENTIFY/RESUME 自动切换)、READY 会话捕获、INVALID_SESSION 会话失效处理;心跳由连接器按连接生命周期驱动
  • 断线自动重连(指数退避 + 心跳看门狗),重连时自动 RESUME 续传
  • Webhook 接入自带 Ed25519 验签、op=13 验证应答与 60s TTL 事件去重
  • 事件订阅由项目根目录的 intents.toml 控制,按大类(Intents 分组)开关,将对应分组改为 true 即可
  • Markdown 与内嵌按钮一等支持:post_group_message(..., markdown=..., keyboard=...) 自动置 msg_type=2,respond_interaction() 回应按钮回调
  • 组件在 run_loop 显式装配(无 DI 框架依赖),全 SDK 共享一个 HTTP 连接池

配置

.env(APPID/APPSECRET 必填,缺失启动即报错):

APPID=你的AppID
APPSECRET=你的AppSecret
BASE_URL=https://api.bot.qq.com   # 可选,默认官方地址
TIMEOUT=5000                      # 可选,毫秒
CONNECTER=websocket               # websocket 或 webhook

# 仅 webhook 接入时
WEBHOOK_HOST=0.0.0.0
WEBHOOK_PORT=8080
WEBHOOK_PATH=/qqbot/webhook

使用

编写入口(如 main.py),把自己构造的 EventEmitter 传给 main():

from qqbotsdk import EventEmitter, main

ee = EventEmitter()

# 方式一:裸参数(d 为原始事件数据)
@ee.on("GROUP_AT_MESSAGE_CREATE")
async def on_group_message(d):
    print("收到群消息:", d)

# 方式二:类型化 payload(dataclass,见 qqbotsdk.payloads)
from qqbotsdk.payloads import GroupAtMessage

@ee.on("GROUP_AT_MESSAGE_CREATE")
async def on_group_message(msg: GroupAtMessage):
    print(msg.group_openid, msg.user_openid, msg.content)

# 方式三:参数注入(按形参标注装配,payload 与 `BotApi` 等组件可任意组合)
from qqbotsdk.api import BotApi
from qqbotsdk.events import Event
from qqbotsdk.payloads import GroupAtMessage

@ee.on("GROUP_AT_MESSAGE_CREATE")
async def handle(msg: GroupAtMessage, event: Event, api: BotApi):
    print(event.event_id)  # 信封信息(op/t/d/id)经 Event 取用,事件字段走 payload
    # 被动回复:带 msg_id(群聊 5 分钟/单聊 60 分钟内有效,最多分别回复 5/4 次);
    # 同一条消息多次回复递增 msg_seq
    await api.post_group_message(
        msg.group_openid,
        content=f"你说:{msg.content}",
        msg_id=msg.id,
    )   # 失败抛 ApiError;富媒体先 upload_group_file 拿 file_info

# 业务事件(op=0)才进分发,返回值不回流,回复请显式调 BotApi;
# 协议帧(HELLO/READY/INVALID_SESSION/op=13)由各接入方式的协议处理器
# 在连接器内就地处理,不进队列、也不会触达 handler。
# 单个 handler 抛异常不会影响其他 handler 和主循环,异常会被记录。

if __name__ == "__main__":
    main(ee)

运行:

uv run python main.py

Webhook 接入:将 .env 中 CONNECTER 改为 webhook,运行后把 http://<你的域名>:8080/qqbot/webhook 配置到 QQ 开放平台回调地址(仅支持 80/443/8080/8443 端口,需公网 HTTPS)。

完整可运行示例见 examples/:群机器人(文本/图片回复、入群欢迎、单聊回复)与 Webhook 最小接入。

开发

uv run pytest    # 单元测试
uv run ruff check src tests examples && uv run pyright

推送到 main 与 Pull Request 会由 Gitea Actions 自动执行同样的 ruff + pyright 检查(.gitea/workflows/ci.yml)。

文档站点基于 docsify(无需构建,仓库根 index.html + Markdown),本地预览:

npx docsify-cli serve    # 打开 http://localhost:3000

线上部署在 Cloudflare Pages(Direct Upload,Gitea 无法走 Pages 的 Git 直连):bash scripts/deploy_docs.sh 组装 dist/ 并经 wrangler 上传,站点地址 https://<项目名>.pages.dev;项目名默认 qqbotsdk-docs,可传参或 PROJECT_NAME 覆盖。CI 自动部署:Gitea 仓库配置 CLOUDFLARE_API_TOKEN(权限 Account → Cloudflare Pages → Edit)与 CLOUDFLARE_ACCOUNT_ID 两个 secrets 后,main 上文档文件变更即自动部署(.gitea/workflows/deploy-docs.yml)。

待完善

  • 更多 OpenAPI 封装(按需在 api.py 的 BotApi 上加薄封装即可)