# 官方 QQ 机器人通道(WebSocket) > 状态:**备选(2026-10-18 起不采用)**。当前选型为真实 QQ 号 + OneBot 11,见 > [onebot-channel.md](./onebot-channel.md);本文保留作对比与回退参考。 > 本文件是官方平台接口事实与限制的单一来源。 > 官方文档: ## 1. 选型结论 - 采用 **官方 QQ 机器人开放平台**:WebSocket 收事件 + HTTPS 发消息。 - **不采用** OneBot / 第三方协议端(NapCat、LLBot、Lagrange 等):需要登录真实 QQ 号、 违反平台协议、有封号风险,还要常开 QQ 客户端或额外进程。 - **不采用** Webhook 回调:需要公网 HTTPS 地址,家宽环境不合适;WebSocket 是出站连接, 不需要公网入口。 - 代价:需要注册开放平台机器人并完成认证 / 审核;消息身份只有 openid;主动消息有配额。 ## 2. 凭证 | 凭证 | 用途 | |---|---| | **AppID** | 机器人 ID | | **AppSecret** | 换取 access_token 的密钥 | | **access_token** | 调用 OpenAPI 的凭证,由 AppID + AppSecret 换取 | 获取令牌: ~~~http POST https://api.bot.qq.com/app/getAppAccessToken Content-Type: application/json {"appId": "", "clientSecret": ""} ~~~ - 返回 access_token 与 expires_in(目前 7200 秒)。 - 过期前 60 秒内再次获取会拿到新 token;建议服务端定时提前刷新。 - 所有 OpenAPI 请求头带 **Authorization: QQBot **。 - 失败时 HTTP 可能仍是 200,必须按响应体 code 判断(如 100001 频控、100016 凭证错误)。 ## 3. WebSocket 生命周期 1. 调用「获取通用 WSS 接入点」接口,拿到网关地址(形如 wss://api.bot.qq.com/websocket/)。 2. 建立连接后,平台下发 **op 10 Hello**,d.heartbeat_interval 是心跳周期(毫秒)。 3. 发送 **op 2 Identify** 完成鉴权: ~~~json {"op":2,"d":{"token":"QQBot ","intents":100663296,"shard":[0,1],"properties":{}}} ~~~ 4. 鉴权成功收到 **READY**(t 为 READY,d.session_id 用于 Resume)。 5. 按周期发送 **op 1** 心跳,d 填客户端收到的最新 s;平台回 **op 11 Heartbeat ACK**。 6. 断开后短时间重连可发 **op 6 Resume**(session_id + seq)补发遗漏事件,成功后收 Resumed; Resume 失败则重新走 Identify。 7. **op 7** 表示服务端要求重连;**op 9** 表示 Identify / Resume 参数无效。 **发送消息的接口要求机器人 WebSocket 保持在线**,因此网关断线期间回复会失败。 ## 4. Intents(本项目用到的位) | Intent | 位 | 覆盖事件 | 本项目 | |---|---|---|---| | GROUP_AND_C2C_EVENT | 1 << 25 = 33554432 | 单聊 / 群 @ / 加群 / 主动消息开关等 | 若启用官方方案时 | | INTERACTION | 1 << 26 = 67108864 | 按钮互动 INTERACTION_CREATE | P3 审批用 | 两者都开时 intents = 33554432 + 67108864 = 100663296。 GROUP_AND_C2C_EVENT 下的关键事件: - **C2C_MESSAGE_CREATE**:用户单聊发消息; - **GROUP_AT_MESSAGE_CREATE**:群里 @ 机器人; - **GROUP_MESSAGE_CREATE**:**全量模式**下群里的每条消息(需平台开启「接收所有消息」); - **GROUP_ADD_ROBOT** / **GROUP_DEL_ROBOT**:机器人被拉入 / 移出群; - **GROUP_MSG_RECEIVE** / **GROUP_MSG_REJECT**:群管理员开启 / 关闭机器人主动消息。 ## 5. 事件信封与群消息字段 所有推送统一为: ~~~json {"id":"event_id","op":0,"s":42,"t":"GROUP_AT_MESSAGE_CREATE","d":{}} ~~~ 群消息 d 的关键字段: | 字段 | 说明 | |---|---| | **id** | 消息 ID,被动回复时作为 msg_id | | **content** | 消息文本,**已自动去掉 @机器人 前缀** | | **group_openid** | 群 OpenID | | **author.member_openid** | 群成员 OpenID(群聊场景) | | **author.username** | 昵称 | | **author.bot** | 是否机器人 | | **timestamp** | RFC3339 时间 | | **attachments[]** | 图片 / 语音 / 文件等附件(url、content_type、filename 等) | | **message_scene** / **msg_elements** / **ark_data** | 引用、卡片等扩展内容 | 平台可能**重复推送相同 msg_id**,需要按 msg_id 去重。 ## 6. 发送消息 | 场景 | 接口 | |---|---| | 群聊 | POST /v2/groups/{group_openid}/messages | | 单聊 | POST /v2/users/{user_openid}/messages | 请求体关键字段: | 字段 | 说明 | |---|---| | **msg_type** | 0 文本 / 2 Markdown / 7 富媒体 | | **content** | 文本内容(msg_type=0) | | **markdown** | Markdown 内容(msg_type=2,填写后 content 必须为空) | | **keyboard** | 内嵌键盘(按钮),短形式传模板 id,长形式传 rows | | **msg_id** | 被动回复的消息 ID(5 分钟内有效) | | **event_id** | 被动回复互动事件(INTERACTION_CREATE 等) | | **msg_seq** | 同一 msg_id 多次回复的序号,用于去重 | | **media** | 富媒体(msg_type=7,需先上传得到 file_info) | 限制: - 群消息**不支持流式**; - Markdown 在群聊**只能发、不能收**; - 富媒体需先上传换 file_info,单聊 / 群聊上传接口不互通,file_info 有过期时间; - 按钮回调(action.type=1)触发 INTERACTION_CREATE,可用 event_id 被动回复,适合做审批。 ## 7. 被动消息与主动消息 | 类型 | 条件 | 时效 / 次数 | 配额 | |---|---|---|---| | 群聊被动 | 带 msg_id | 5 分钟,同一条最多 5 次 | 不占主动配额 | | 单聊被动 | 带 msg_id | 60 分钟,同一条最多 4 次 | 不占主动配额 | | 群聊主动 | 不带 msg_id | — | 机器人侧 60 qpm(个人 / 企业认证;未认证 30 qpm)、单群 20 qpm、每群每天 1000 条 | | 单聊主动 | 不带 msg_id | — | 每用户每天 1000 条 | - 用户 / 群管理员可以在机器人资料卡**关闭主动消息**,之后主动发送失败;对应 GROUP_MSG_REJECT(关闭)/ GROUP_MSG_RECEIVE(开启)事件。 - 若将来回退到官方通道:被动优先;窗口过期建议改发主动消息(onPassiveExpired: active), 主动消息失败再降级为等待用户下一条消息。当前选型(真实 QQ 号)不受此限制。 ## 8. 身份 - 不同 bot(AppID)拿到的 openid 互不相同。 - 群聊场景:group_openid(群)+ member_openid(群成员)。 - 单聊场景:user_openid。 - **没有 QQ 号**;白名单、映射、审计都基于 openid。 ## 9. 已知限制与坑 - 全量消息需要平台开启「接收所有消息」;默认只推 @ 机器人的消息。 - 发送接口要求 WebSocket 在线;掉线期间无法回复。 - 网关会断线,必须实现心跳、Resume、重连与事件去重。 - 同一 msg_id + msg_seq 重复发送会失败,多次回复必须递增 msg_seq。 - 消息可能走内容审核(MESSAGE_AUDIT_PASS / MESSAGE_AUDIT_REJECT)。 - 主动消息可被用户 / 群管理员关闭,且受频控(429)。 ## 10. 待实测 - 开启全量模式后,@ 消息是否仍以 GROUP_AT_MESSAGE_CREATE 单独推送(还是只推 GROUP_MESSAGE_CREATE)。 - 非 @ 消息的 d.id 能否用于被动回复(若可以,快路可省主动额度)。 - 主动消息被关闭后的错误码与事件时序。 - 同一 bot 建立多个 WebSocket 连接的行为(是否互踢 / 重复推送)。 ## 参考 - [启动接入](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/getting-started.html) - [获取访问凭证](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/access-token.html) - [API 调用指南](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/api-call-guide.html) - [WebSocket 方式](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/event-emit/websocket.html) - [事件订阅 Intents](https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/event-emit/payload.html) - [消息收发概述](https://bot.q.qq.com/wiki/develop/api-v2/server-inter/message/overview.html) - [发送群聊消息](https://bot.q.qq.com/wiki/develop/api-v2/autogen/api/v2_groups_group_openid_messages.post.html) - [群 @ 机器人消息](https://bot.q.qq.com/wiki/develop/api-v2/autogen/event/group_at_message_create.html)