Skip to content

对接 IM 平台 ​

你想让 ZCBOT 连上一个真实的聊天软件,让机器人能收发消息——这就是这篇要解决的问题。

框架本身协议无关:「消息怎么来、怎么发」全由接入端插件负责。所有接入端默认都是关闭的,需显式启用;最常用的是 onebot_adapter(OneBot 11,常用来接 QQ);热路径性能敏感时可换 rust_accel(同一协议的 Rust 加速接入端,默认关,见下表);另外还有 QQ 官方、Telegram、Discord、出站 WS 等,同样默认关闭,填好凭证再开。

先确认要不要读完

框架能启动、命令能注册、定时任务能跑——都不需要接聊天平台。 只有「要和某个聊天软件收发消息」时才需要这篇。

接入端是怎么工作的(以默认 OneBot 为例) ​

┌──────────┐   反向 WebSocket    ┌─────────────────┐
│ NapCat / │  ────────────────►  │  ZCBOT          │
│ Lagrange │  连到 :6830        │  onebot_adapter  │
│ (OneBot) │  ◄────────────────  │  → 内核 → 插件   │
└──────────┘   回复也走这条      └─────────────────┘
  1. 框架起一个 WebSocket 服务端(默认 0.0.0.0:6830);
  2. OneBot 实现端(NapCat、Lagrange…)以反向 WebSocket 连进来;
  3. 消息推给框架,插件处理完再经同一连接发回平台。

换一个 ProtocolAdapter 就能接别的事件源。这里默认走 onebot_adapter。

其它官方接入端(默认全关) ​

插件平台怎么开(core_plugins.yaml)
onebot_adapterQQ(经 NapCat 等)默认关闭,需启用;设 access_token 更安全
rust_accelQQ(同上,OneBot 11)Rust 加速接入端(默认关):enabled: true;启用前先停 onebot_adapter,监听独立端口 6831
qq_officialQQ 官方机器人enabled: true + app_id / app_secret
telegramTelegramenabled: true + token(找 @BotFather 要)
discordDiscordenabled: true + token(开发者门户;MESSAGE_CONTENT Intent 需开)
kookKOOKenabled: true + token(开发者后台,连接模式选 WebSocket)
matrixMatrix(含自建 homeserver)enabled: true + homeserver / access_token / user_id
ws_client任意 WS 总线enabled: true + url(主动连出去)
http_inject不接 IM / Webhookenabled: true + 地址端口

这些接入端都实现了统一连接自描述,后台「接入端连接」页可以改配置;图片统一支持 base64://。

能力差异(先看再选):

  • 收发消息、文本回复:各端统一走事件与 send_text / 动作名。
  • 群管理(踢人 / 禁言等):目前完整支持在 OneBot 11;QQ 官方 / Telegram / Discord 等端对这类动作多返回「不支持」,群管类插件换端后请先验证。
  • 媒体出站:Telegram / Discord 支持本地上传与 base64;QQ 官方需先走富媒体上传接口;KOOK 要求资源由机器人自己上传后引用,Matrix 需先 /_matrix/media/v3/upload(后两者本端暂只发文本)。

失败是怎么报给你的 ​

各平台的错误模型不一样,接入端会把它们统一成同一套 retcode,插件不需要按平台分支:

retcode含义触发例子
0成功—
-1失败(平台业务错误,或接入端未连接)Telegram chat not found、Discord 403 缺权限、KOOK code=40000
-2请求超时OneBot 等待响应超 10s
-3网络/连接异常发不出去、连接已断
-4被平台限流HTTP 429;带 throttled: true 与 retry_after(秒)
-10该端不支持此动作例如 KOOK 主动私聊、Matrix 媒体出站

几个容易踩的点,接入端已经处理:

  • HTTP 200 不代表成功。 QQ 官方失败时仍返回 200,业务码在 body 的 code 里; 官方文档明确写了 message 只用于人工排查、内容可能随时调整,所以判据只取 code。
  • 限流必须按平台给的等待时间。 自己拍一个更短的间隔重试会被继续限,越试越久。 各端都会读 retry_after / retry_after_ms / Retry-After,原样放在返回值里。
  • 凭证类错误不重试。 Discord 的 4004/4013/4014、KOOK 的 40101/40103、 Matrix 的 M_UNKNOWN_TOKEN、Telegram 的 401,都会停止重连并打印原因—— 这类错误重连一万次也不会好,还会把配额烧光(Discord 限 1000 次 IDENTIFY/天)。
  • Telegram getUpdates 与 webhook 互斥。 配过 webhook 的 bot 轮询会一直返回 409, 接入端会只提示一次并给出 deleteWebhook 的修法。

默认路线:OneBot 11(QQ) ​

1. 确认接入端已启用 ​

编辑根目录 core_plugins.yaml(首次启动会自动生成):

yaml
core_plugins:
  onebot_adapter:
    enabled: true
    listen_host: 0.0.0.0
    listen_port: 6830
    access_token: ''    # 公网务必改成强随机字符串
字段说明
enabled关掉则完全不启这个接入端(纯定时场景可关)
listen_host / listen_port服务端监听地址——客户端连这里
access_token连入校验令牌;本地调试可空,公网必须设

改完重启框架,日志应出现类似:

OneBot 适配器已启动 (ws://0.0.0.0:6830)

2. 让客户端连进来 ​

以 NapCat 为例:网络配置 → 新增「反向 WebSocket 客户端」:

设置项填什么
目标地址ws://127.0.0.1:6830
AccessToken与 access_token 一致(本地可留空)

等价 JSON:

json
{
  "WebSocketReverse": {
    "Enable": true,
    "URL": "ws://127.0.0.1:6830",
    "AccessToken": ""
  }
}

Lagrange、go-cqhttp 等同理:填同一个 ws://地址 和令牌即可。

3. 验证连上了 ​

框架日志出现:

[bot_xxxxxx] OneBot 客户端已连接

多账号时每个客户端独立;回复会自动用「消息来源那个号」,插件一般不用手动选 bot。

4. 发一条消息试试 ​

对机器人发:

/echo 你好

回 你好 就通了。/help 看全部命令。

这条 /echo 由内置的 echo 自检插件(core_plugins/echo,默认开启)提供, 覆盖所有接入端(OneBot / QQ 官方 / Telegram / Discord / WS / HTTP 注入), 发什么回什么——专门用来验证「消息进得来、命令路由得通、回复发得出」整条链路。 若你手动关掉了 echo 插件,需重新启用才会响应。

同理,/help(及别名 /帮助、/菜单)由内置的 help 插件(core_plugins/help,默认开启) 提供,列出当前所有已注册命令——这也是教程让你「发 /help 看命令清单」的对应实现,覆盖全部接入端。


其它平台(简要) ​

以 Telegram 为例,三步:

  1. core_plugins.yaml 里 telegram.enabled: true,填 token
  2. 重启,日志确认接入端就绪
  3. 给机器人发 /echo 你好(内置 echo 自检插件响应)

Discord、QQ 官方同理:开插件 → 填 token/app 凭证 → 重启 → 发 /echo 你好 自测。 详细字段说明见 配置系统 · 各接入端。


插件里怎么发消息 ​

消息进框架后,插件只用统一的 ctx,不必关心底下是 OneBot 还是别的协议。

通用文本 ​

python
ctx.send_msg(user_id=uid, group_id=None, message="你好")      # 私聊
ctx.send_msg(group_id=gid, user_id=None, message="大家好")     # 群
# 异步 handler 里用 await ctx.asend_msg(...)

富媒体(OneBot / CQ 码) ​

python
ctx.send_msg(group_id=gid, message="[CQ:image,file=file:///path/to/a.png]")
ctx.send_msg(group_id=gid, message=f"[CQ:at,qq={uid}] 看这里")
ctx.send_msg(group_id=gid, message=f"[CQ:reply,id={msg_id}] 收到")

CQ 码是 OneBot 11 的写法。其它平台图片语法不同,但文本发送接口不变。

需要跨协议统一处理图片/语音/视频的插件,请改用规范消息段: ev.images / ev.voices / ev.videos / ev.files 在所有接入端上都能读到, 详见 接入端契约与规范消息。

群管 / 查询(依赖 OneBot 接入端) ​

python
ctx.ban(group_id, user_id, duration=600)      # 禁言(秒,0 解禁)
await ctx.akick(group_id, user_id)            # 踢出
ctx.mute_all(group_id, True)                  # 全员禁言
members = ctx.get_member_list(group_id)

# 或经 ctx.onebot 调任意 OneBot action
ctx.onebot.send_group_msg(group_id=123, message="hi")
info = ctx.onebot.get_login_info()

在命令匹配前截获原始消息 ​

python
def register(ctx):
    ctx.on_raw_message(raw_handler)

async def raw_handler(raw_event, bot_name):
    if 需要接管:
        return True     # True = 吃掉这条,后续命令/关键词都不跑
    # 其它情况返回 None/False,继续正常流程

多个原始处理器按插件 priority 升序执行,单个异常不影响别人。


安全须知 ​

  • 公网部署:web.host 保持 127.0.0.1 + 反代;access_token 设强随机值;按需 IP 白名单
  • 启动时若提示「监听 0.0.0.0 且 token 为空」,请立刻处理
  • 多账号时注意权限边界,别把超管能力随便开给所有 bot

下一步 ​

基于 MIT + Apache 2.0 双协议发布