ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

飞书与腾讯会议对接实战:从机器人指令到自动创建会议

飞书与腾讯会议对接实战:从机器人指令到自动创建会议 1. 为什么要把飞书和腾讯会议这两套系统打通1.1 一个每天都在发生的低效场景我先说一个真实到不能再真实的场景。我所在的团队内部沟通全部走飞书群聊、文档、审批都在里面但对外会议基本都用腾讯会议客户评审、跨团队例会、线上培训一天下来能有好几场。最让人抓狂的操作是每到开会前总有人要在飞书群里发一条带会议链接的消息。他得先切到腾讯会议客户端手动创建一个会议等它生成会议号复制入会链接再回到飞书粘贴到群里。运气好的时候链接和会议号一次粘贴成功运气不好链接带了一堆参数发出来被群里的换行截断参会的人点进去又说无效。这种重复劳动看起来不起眼但每天都在消耗团队注意力而且特别容易出错。后来我们决定做一件事把飞书和腾讯会议对接起来让用户不用再打开腾讯会议客户端直接在飞书群里机器人用一句话发起会议。这个需求听起来不算复杂实际落地过程中却牵扯出飞书开放平台、腾讯会议企业API、服务端鉴权、消息卡片、事件订阅一整条链路。这篇文章就把我们完整的对接过程、代码思路和踩过的坑写出来给同样想打通这两套系统的团队一个参考。1.2 对接完成之后的变化项目第一版上线后日常使用体验发生了明显变化原先要打开腾讯会议客户端、手动创建会议、复制链接、回飞书粘贴现在只需要在群里输入/会议 明天14:00 客户需求对齐一句话。机器人自动创建会议并把会议主题、时间、会议号、入会链接整理成一张卡片发回群里参会人只需要点卡片上的按钮就能入会。会议结束后服务端还能拉取会议时长和参会人列表把会议纪要自动同步到飞书云文档整个闭环不再依赖人工。这套能力后面也延伸到了飞书日历场景用户可以直接在日历事件里绑定腾讯会议链接省掉了以前来回切换系统的麻烦。2. 对接前必须想清楚的架构链路2.1 飞书和腾讯会议开放平台的能力差异先说飞书。飞书开放平台的模型是企业自建应用开发者可以在后台创建一个应用给它开机器人能力、申请各种API权限、配置事件订阅。整个体系围绕“应用”展开应用既可以通过 webhook 接收消息事件也可以主动调用 API 发送消息、读写云文档、操作通讯录。对我们这种场景来说飞书主要负责三件事接收用户消息、展示会议卡片、调用后续文档能力。腾讯会议开放平台则更像一个纯 REST API 池子。它不关心你是不是要做机器人只给你提供会议管理、录制管理、直播管理这类接口。开发者需要先在腾讯会议开放平台注册应用拿到一组凭证然后通过签名换取访问令牌再调用对应接口创建会议、查询会议号。两边的核心差异我整理成一张表方便后续设计架构时对齐维度飞书自建应用腾讯会议企业API开发者入口飞书开放平台开发者后台腾讯会议开放平台控制台能力载体应用 机器人 事件订阅应用凭证 REST API鉴权方式Tenant Access Token应用签名 访问令牌主要能力IM、云文档、通讯录、日历会议创建、会议查询、录制管理消息推送支持 Webhook 和长连接不支持需要主动轮询或回调这个差异决定了整体架构不能简单做一个“双向同步”而是要明确哪个系统是入口哪个系统是被调用的服务。2.2 整体调用流程是怎么设计的我们的最终链路是这样的用户在飞书群里 机器人发送一条包含会议意图的消息。飞书后台通过事件订阅把消息内容推送到我们的应用服务。应用服务解析消息内容提取会议主题、开始时间、参会人等字段。应用服务调用腾讯会议开放平台的鉴权接口获取访问令牌。应用服务调用腾讯会议“创建会议”接口拿到会议号和入会链接。应用服务把腾讯会议返回的数据拼装成飞书消息卡片。飞书开放平台把卡片消息发送到原始群聊。看起来步骤很多实际调用链只有三个角色飞书负责接收和展示腾讯会议负责创建会议我们自己写的应用服务负责逻辑编排和数据转换。2.3 动手前需要准备的清单开始写代码之前有几个前置条件必须准备好一个飞书企业管理员账号用于在开发者后台创建自建应用并完成发布。一个腾讯会议开放平台账号最好是企业版权限因为个人版账号很多会议管理 API 都用不了。一台有公网地址的开发服务器或者使用飞书推荐的长连接模式这样不一定需要公网回调地址。企业内部的应用标识信息因为腾讯会议创建会议时一般需要传入企业用户 ID 或 meeting userid。如果团队之前没碰过这两类开放平台建议先把文档里“创建应用”的章节过一遍我后面也会把每一步的关键细节写出来。3. 飞书侧配置自建应用和机器人的完整过程3.1 创建自建应用登录飞书开放平台开发者后台选择“创建企业自建应用”填写应用名称、图标、描述提交后系统会生成一个 App ID 和 App Secret这两个值相当于飞书应用的登录凭证后面服务端换取的tenant_access_token就是依赖它们。这一步有两点容易忽略一是应用创建完成后默认处于“测试状态”如果想让全公司的人都能使用必须走一遍版本发布流程。建议先在小范围测试群里试用确认没问题后再申请发布。二是 App Secret 只会完整展示一次后续想再查看可能需要重置密钥。开发阶段一定要把 App ID、App Secret 存到服务端的配置中心或者环境变量里不要写死在代码仓库中。3.2 开启机器人和事件订阅在应用的“添加应用能力”里找到机器人启用之后应用才会出现在飞书群的 列表里。启用机器人时记得设置一个相对好记的名字比如“会议助手”这样用户输入指令时不会找错对象。接下来配置事件订阅。飞书提供了两种接收方式一种是传统的 Webhook 回调地址需要你在服务端提供一个公网可访问的 URL另一种是基于 WebSocket 的长连接模式飞书 SDK 会主动建立连接并推送事件。我们最终选了长连接模式主要原因是公司内网服务器没有固定的公网地址长连接省去了回调地址的暴露和签名验证环节。在“事件与回调”配置页添加事件im.message.receive_v1接收消息事件这个事件会在群成员 机器人并发送消息时触发。保存后飞书会推送一条url_verification验证消息Webhook 模式需要服务端返回一个叫challenge的字段验证通过后事件订阅才会真正生效。3.3 申请必要的权限范围飞书 API 的权限申请是最容易卡住的环节很多接口调用报错都是因为权限没开。我们这次至少需要以下几类权限权限标识说明im:message读取用户发给机器人的消息内容im:message:send_as_bot作为机器人发送消息im:chat:readonly读取群基础信息用于获取 chat_id 对应的群名称contact:user.base:readonly读取用户基本信息用于把 open_id 映射为用户名docx:document云文档相关权限后续做会议纪要同步时使用申请后在开发者后台提交上线等待管理员审核即可。特别注意飞书权限是按“应用”维度生效的不是在接口调用时临时获取的如果某天新增了接口需求需要回到后台补充权限并重新发布版本。3.4 测试机器人是否正常接收消息配置完成后在飞书群里 机器人发一条“Hello”服务端会收到一条事件推送。我们在这一步的逻辑很简单收到消息事件后先读取header.event_type确认是im.message.receive_v1再读取event.message.content里面是一段 JSON 字符串存放消息文本内容。实测下来长连接模式下的消息到达延迟在几十毫秒级别完全够用。唯一需要注意的是飞书长连接 SDK 内部会做断线重连不能简单地在服务启动后就不管了建议把连接状态监控暴露一个健康检查接口方便运维观察。4. 腾讯会议企业 API 的接入准备4.1 获取应用凭证进入腾讯会议开放平台创建一个“企业应用”创建完成后可以获得三个关键凭证App ID、Secret ID、Secret Key。App ID 用于标识应用Secret ID 和 Secret Key 用于生成调用签名。这里有个细节让我们当时绕了一圈腾讯会议 API 调用时很多接口要求X-TC-Key请求头直接放 App ID而不是 Tencent Cloud Account 的 ID两者长得像但含义完全不同。如果你用错了 ID签名校验会直接报错排查时容易误以为是密钥问题。4.2 签名机制是绕不开的一关腾讯会议企业 API 使用的是 HMAC 签名机制而不是简单的 Token。签名生成需要把多个字段按固定顺序拼接然后用 Secret Key 做 HMAC-SHA256 运算。每个请求都需要生成一次签名核心字段包括appId应用 IDsecretId应用 Secret IDtimestamp当前 Unix 时间戳nonce随机字符串或数字ver版本号一般固定为 1拼接规则是类似appIdxxxsecretIdxxxtimestampxxxnoncexxxver1这样的 URL 编码形式然后使用 Secret Key 计算哈希值最终把签名放到请求头X-TC-Signature中。实际编码时建议直接用官方提供的签名工具类或者参考语言对应的 SDK而不是自己手写拼接逻辑因为字段顺序和编码方式很容易出错。4.3 获取访问令牌并缓存签名通过后调用腾讯会议的鉴权接口获取访问令牌后续创建会议的请求都需要携带这个 Token。令牌有一个有效期短则一小时长则一天不同环境不一样。千万不要每次调用会议接口都重新换一次 Token腾讯会议侧对接口调用频率控制得比较严格频繁换取容易触发限流。我们的做法是在服务端加了一层缓存以 App ID 为键缓存访问令牌在过期前 5 分钟进行一次预刷新。这个策略后来在会议并发场景下效果不错没有因为 Token 过期导致创建会议失败。5. 核心功能落地从机器人指令到自动建会5.1 服务端接收飞书消息的代码骨架我用 Go 语言做了服务端长连接接事件订阅用的飞书官方 SDK消息处理的骨架大概是这样的func handleMessage(ctx context.Context, event *lark.EventV2) error { eventType : event.Header.EventType() if eventType ! im.message.receive_v1 { return nil } msg : event.Event[message].(map[string]interface{}) chatID : msg[chat_id].(string) content : msg[content].(string) msgType : msg[message_type].(string) if msgType ! text { return nil } // content 是 JSON 字符串解析后拿到 text 字段 var data struct { Text string json:text } _ json.Unmarshal([]byte(content), data) go handleCommand(ctx, chatID, data.Text) return nil }需要注意飞书推送的content字段是字符串里面嵌套着 JSON必须先反序列化一次才能拿到用户发的文本内容。如果用户在消息里 了机器人文本内容里会带上机器人的 open_id 前缀解析指令时需要过滤掉。5.2 解析指令并调用腾讯会议 API我们的指令设计成了两种格式一个是指令加参数的/会议命令另一个是纯文本的自然语言解析用正则提取时间和主题。自然语言的准确性暂不做保证正则优先匹配“明天/今天/具体日期时间主题”的模式。解析完成后调用腾讯会议创建会议接口。腾讯会议创建会议的接口路径是 POST/v1/meetings请求体示例{ title: 客户需求对齐, start_time: 1719907200, end_time: 1719910800, userid: zhangsan, type: 1, settings: { mute_enable: 1, allow_enter_watermark: true, auto_record: 1 } }几个关键字段的注意点start_time和end_time是 Unix 时间戳单位是秒而且是 UTC 时间戳。如果直接传 JavaScript 的Date.now()毫秒值或者传了本地时间的秒值会导致会议时间偏差差 8 个小时的情况我们遇到过不止一次。userid必须传入腾讯会议侧的会议发起人 ID一般是企业通讯录里的用户名不是飞书的 open_id。如果两边身份体系没有打通这里需要做一层映射否则会议创建成功但发起人不匹配后续无法用接口操作会议。type表示会议类型0 代表普通预约会议1 代表固定会议号会议2 代表网络研讨会。具体看场景需求内外部沟通我们一般用 1方便用户记住会议号。调用成功后接口会返回包括meeting_id、meeting_code、join_url在内的信息。5.3 把会议信息封装成飞书卡片腾讯会议返回的内网数据格式比较原始直接文本丢到群里也能看但体验一般。我们最终做的是飞书消息卡片格式类似{ msg_type: interactive, card: { header: { title: {tag: plain_text, content: 会议创建成功} }, elements: [ {tag: div, text: {tag: lark_md, content: **主题**客户需求对齐\n**时间**6月20日 14:00-15:00}}, {tag: div, text: {tag: lark_md, content: **会议号**123456789}}, {tag: action, actions: [ {tag: button, text: {tag: plain_text, content: 加入会议}, url: https://meeting.tencent.com/dm/link...} ]} ] } }发送接口是飞书的 POST/open-apis/im/v1/messages需要在 URL 参数里指定receive_id_typechat_id请求体里的receive_id填群聊的 chat_id。同样要带上飞书的tenant_access_token这个 token 是用 App ID 和 App Secret 换取的。卡片发出去后用户点“加入会议”按钮就能直接跳转到腾讯会议客户端整个流程不需要手动复制任何内容。6. 实测过程中遇到的那些坑6.1 飞书事件验证一直不通过第一次配置 Webhook 回调时飞书后台提示“验证 URL 失败”。原因是我返回的响应体结构不对。飞书要求回调接口在收到url_verification事件时直接返回一段 JSON里面必须包含challenge字段并且Content-Type必须是application/json。当时我写的是纯文本返回导致验证一直失败。如果你用的是长连接模式不会遇到这个问题但如果团队服务器有公网地址、又想用 Webhook这个细节要多留意。6.2 腾讯会议创建会议返回 401创建会议的请求一直返 401最初以为是 Token 没带上排查后发现问题出在签名上。签名里的nonce我用的是一个固定字符串而不是每次请求生成随机值。腾讯会议侧的校验会把nonce作为签名内容的一部分如果两次请求 nonce 相同哪怕时间戳变化也会被判定为非法请求。解决办法是每次请求都重新生成 nonce推荐用 UUID 或随机数。6.3 会议时间差 8 小时这是最经典的坑。我最初在前端写了一个测试脚本把参数里的时间直接传成了本地时间的new Date()毫秒值结果腾讯会议后台显示的会议时间比预期晚了 8 个小时。原因就是start_time需要的是 UTC 时间戳。后排问题时我们用了一个笨办法把服务端日志里的请求体打印出来再和腾讯会议后台的实际时间串在一起对比才定位到时间戳单位问题。提醒一下对接时所有时间参数尽量统一用 UTC 时间戳前端展示时再转本地时区不要在服务端做任何时区换算。6.4 用户身份映射不一致飞书侧拿到的用户 ID 是open_id腾讯会议侧需要的是会议室系统里的userid。两者不是一个体系如果企业内部没有统一身份源就需要在服务端维护一个映射表或者通过飞书通讯录里的企业邮箱/工号字段去和腾讯会议的企业通讯录匹配。这个映射表在初期问题不大但随着人员变动会变得很头疼建议尽早接统一身份源。6.5 飞书发送消息偶发下拉限流上线初期群消息发送偶尔会失败错误信息是“请求过多”。排查后发现是飞书开放平台对机器人发消息有频控尤其是同一群聊里短时间连续发多条消息时。我们的解决办法是在发送侧做了一个简单的带令牌桶的限流并且对发送失败的消息做了三级重试第一级 5 秒重试第二级 30 秒重试第三级转入死信队列由人工处理。另外如果服务端收到飞书事件后有大量异步任务建议先入队再处理不要直接在事件回调线程里执行耗时操作。7. 后续可以继续扩展的几个方向7.1 会议纪要自动同步飞书云文档会议结束后腾讯会议侧会生成录制文件和参会人记录。我们可以通过腾讯会议的“查询会议”接口拿到会议持续时间、参会人列表再结合飞书云文档的异步任务接口把一份自动生成的会议纪要写入飞书文档。实现起来有几个前置条件需要飞书应用有云文档写权限同时云文档需要被设置为“组织内部可阅读”否则生成的文档默认只有机器人自己能看影响实际使用。7.2 给机器人加上 AI 能力对接 Dify最近很多团队在做 AI 知识库飞书云文档作为企业内部知识的承载者扮演了重要角色。我在实践过程中发现一个经常被问到的点初次使用 Dify 接入飞书云文档时授权凭证到底去哪里拿。实际上就是在飞书开放平台创建一个自建应用在权限管理里开通docx:document和drive:drive相关权限然后把应用的 App ID 和 App Secret 填到 Dify 的飞书云文档集成页面里Dify 会引导你完成授权流程。如果你已经按照这篇文章建好了一个飞书应用只需要在原有应用上补权限重新发布即可不需要再额外建一套应用。有了 AI 能力之后会议助手的对话就不再只是简单的指令解析了它可以做到用户发一句“帮我总结上次的客户会议”机器人自动去腾讯会议拉取最近一次会议的参会名单和时间再结合飞书云文档里的历史记录生成一段结构化总结。我们目前已经在公司内部尝试这个方向。7.3 从飞书日历事件一键拉起会议比起在群里发指令很多用户更习惯在飞书日历里建日程。如果日历事件能一键带上腾讯会议入会链接体验会更顺滑。实现方式是通过飞书日历的事件订阅接口监听某个日程的创建事件然后把腾讯会议创建的入会链接写入事件的location字段。要注意的是飞书日历事件更新接口的权限和消息模块权限相互独立需要单独申请。上面这些就是我在飞书和腾讯会议对接过程中从架构设计到落地实现再到排错的全过程。最后再分享一点个人心得这类系统对接项目真正的复杂度往往不在代码本身而在两端平台的口径差异上——时间戳单位、ID 体系、权限模型、签名规则每个点都可能让排查变成一个下午的事。建议正式开始前把双方的官方文档通读一遍尤其是权限范围和参数含义部分然后先做最小闭环验证再逐步加复杂功能这样后面踩坑的密度会小很多。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表