lark2lark.md 4.7 KB

飞书群聊全自动跨群转发机器人架构需求文档

1. 项目背景与目标

  • 业务需求:实现飞书源群聊到目标群聊的消息全自动、低延迟转发。
  • 功能要求:支持包括文本、图片、超链接、富文本以及常见附件(Word、PDF 等)在内的多种消息载体无损流转。
  • 运行环境要求:系统需实现“云端代挂”,完全脱离用户的本地 PC,不需要用户保持个人飞书客户端的登录状态,实现 7x24 小时无人值守。

2. 整体系统架构选型

  • 应用形态:飞书企业自建应用(Custom App),以“机器人(Bot)”身份运行。这使得程序拥有独立的 Tenant Access Token 进行鉴权,彻底与个人飞书账号解绑。
  • 事件订阅通道:采用 WebSocket 长连接模式(Long Connection)。
  • *优势*:极大地简化了网络配置,无需配置公网 IP、无需域名、无需繁琐的 Webhook 签名校验,只需服务器能访问外网即可建立安全的双向通信。

  • 部署架构:Linux 云服务器(如阿里云、腾讯云的基础款轻量应用服务器,1核1G配置即可满足)结合 Docker 容器化部署,实现全天候云端运行。

3. 核心功能模块设计

3.1 监听与事件接收模块

  • 事件订阅:在飞书开发者后台订阅 im.message.receive_v1(接收消息事件)。
  • 逻辑过滤:
  • 群组白名单:解析接收到的 JSON 载荷,提取 chat_id,仅当该 ID 匹配预设的“源群组”时才放行。
  • 防死循环机制:严格校验 sender_type 字段,丢弃所有 sender_type == "bot"(机器人发出)的消息,防止 A 群与 B 群之间产生无限转发风暴。

3.2 消息转发与处理模块

根据业务需求,消息转发建议采用官方原生转发接口 (Forward API),此方案开发成本最低且支持格式最全。

  • 转发链路:提取源事件中的 message_id,直接调用 POST /open-apis/im/v1/messages/:message_id/forward 接口。
  • 格式支持:该原生接口不仅支持文本、链接,还天然支持包含图片、视频、Word、PDF 等在内的富文本与文件卡片,无需开发者在云服务器上先下载二进制文件再重新上传,极大节省了服务器带宽与 I/O 成本。

3.3 幂等性与去重模块

  • 去重机制:由于网络波动时飞书云端可能会重发推送,必须建立幂等性保护。程序不应依赖外部的 event_id,而应在本地内存或轻量级数据库(如 SQLite / Redis)中缓存已处理过的 message_id。接收到新推送时,若 message_id 已存在则直接丢弃。

3.4 流量控制模块(限频缓冲)

  • 飞书官方对于发送消息有严格的频率限制:向同一群组发送消息的上限为 5 QPS(即每秒 5 条)。
  • 削峰设计:在代码内部引入本地消息队列(如 Python 的 asyncio.Queue 或 Go 的 Channel)。监听模块收到消息后即刻推入队列,由一个单独的 Worker 消费线程以低于 5 QPS 的速度匀速向目标群组调用发送接口,防止因群聊消息瞬时并发而触发 API 封禁错误。

4. 飞书开放平台权限清单 (Scopes)

在开发前,需在飞书开发者后台向租户管理员申请并发布以下权限:

  1. im:message.group_msg:获取群组中所有消息(核心权限,用于静默监听源群组内所有人的聊天内容)。
  2. im:message:send_as_bot:以应用的身份发消息(用于在目标群组中执行推送)。
  3. im:resource(备选):如果未来需要自行下载、解析并重新组装图片或 Word/PDF 文件,必须申请此“获取消息中的资源文件”权限。若仅调用原生 Forward 接口则非必须,但建议一并申请。

5. 开发语言与 SDK 推荐

  • 推荐语言:Python 或 Go。
  • 官方 SDK:
  • Python 使用 lark-oapi。
  • Go 使用 oapi-sdk-go。

  • 官方 SDK 已将底层的 Token 获取、刷新以及 WebSocket 长连接的心跳保活机制全部封装,开发者只需实现极简的事件回调函数即可。

6. 约束与系统局限性说明

需要提前规划或在业务层面注意以下飞书官方的系统级限制:

  1. 不支持的类型:官方转发接口不支持转发红包、投票、语音、日程转让及端到端加密消息。
  2. 禁止转发限制:如果源消息的发送者或源群主将特定消息设置了“禁止转发”,API 将无法越权转发。
  3. 合并转发的二次限制:如果源群里有人发了一条“合并转发”的消息包,你的机器人无法通过 API 剥离该包内的子消息并进行二次转发。