接入本身不难,难的是「收不到消息」时不知道卡在哪一步
把「飞书 AI 机器人」拆开看,它其实就是三件事的组合:一个应用身份(谁在说话)、一条收消息的通道(用户说的话怎么到你这里)、一条发消息的通道(你的回答怎么回到对话里)。
| 段 | 做什么 | 失败时的典型症状 |
|---|---|---|
| 身份 | 创建自建应用,拿到 App ID 与 App Secret | 调接口一律返回鉴权失败 |
| 收消息 | 事件订阅回调 或 长连接 | 后台日志一条请求都没有 |
| 发消息 | 调发消息接口,把回答写回会话 | 收到了请求,但群里没反应 |
这三段是串联关系:前一段不通,后一段永远看不到现象。所以排错的第一原则是按段验证,而不是一上来就怀疑模型或代码。
在飞书开放平台后台创建企业自建应用,创建后会得到两个关键值:App ID 和 App Secret。这两个值的作用是换取访问凭证(tenant access token),后续所有接口调用都靠它鉴权。
这一步的验证方法很简单:先用凭证换一次 token,能拿到就说明身份段通了。
# 换取访问凭证(示意,字段以官方文档为准)
POST /open-apis/auth/v3/tenant_access_token/internal
{
"app_id": "cli_xxx",
"app_secret": "xxx"
}
# 成功返回 access_token 与 expire(秒)
要点:token 有有效期,不要每次请求都重新换,也不要把 token 写死在代码里长期使用。正确做法是缓存 + 提前刷新(比如剩余有效期不足 5 分钟就重换一次)。
飞书的权限是按能力逐项申请的,不是「开了机器人就全通」。AI 机器人场景通常涉及三类权限:
| 权限类别 | 用途 | 漏了会怎样 |
|---|---|---|
| 消息与群组 | 接收消息事件、发送消息、读取群信息 | 能收到事件但发不出去,或干脆收不到 |
| 通讯录(按需) | 把用户身份映射到内部账号 | 无法判断「谁在问」,权限分层做不了 |
| 云文档 / 知识库(按需) | 让机器人读企业文档回答问题 | 知识问答答不出,或答非所问 |
要点:权限申请后通常需要发布版本并等待管理员审核才会生效。很多人改完权限立刻测试,发现还是不通,其实是版本没发布。这一步的验证方法是:在后台的权限页确认状态是「已生效」,而不是「已申请」。
这是整篇最关键的一个选择。飞书支持两种把消息送到你服务端的方式,它们的适用场景完全不同:
| 维度 | 事件订阅回调(Webhook) | 长连接 |
|---|---|---|
| 原理 | 飞书主动 POST 到你的公网地址 | 你的服务主动连到飞书,保持长连接 |
| 需要公网地址 | 需要,且必须 HTTPS | 不需要 |
| 需要处理验签 | 需要 | 不需要(连接本身即鉴权) |
| 适合场景 | 已有公网服务的团队 | 内网部署、本地开发、私有化环境 |
| 主要风险 | 地址不可达、证书问题、验签失败 | 连接断开后需自动重连 |
判据很直接:你的服务有没有一个可被公网访问的 HTTPS 地址?有就优先回调(更标准、更易排查);没有(内网、私有化、本地调试)就用长连接。
如果企业整体走私有化部署路线,长连接通常是更省事的选择,数据边界也更容易讲清楚——私有化部署的整体考量见《AI 私有化部署方案怎么选》。
选了回调方式,服务端要处理的不只是「收到消息」,还有三件容易被忽略的事:
配置回调地址时,飞书会先发一个校验请求,你需要把其中的 challenge 值原样返回,地址才会被标记为验证通过。这一步不通,后面所有事件都不会推过来。
校验通过后,正式事件会带签名头。服务端必须用应用凭证按官方算法重算签名并比对,不一致直接拒绝。不做验签等于把你的机器人接口暴露给任何人,这是安全底线,不是可选项。
回调接口要尽快返回成功,业务处理(尤其是调用大模型)放到异步队列里做。同步等模型生成完再返回,很容易超时,飞书会重推事件,导致同一条消息被处理多次。
幂等性是这里最容易漏的一条:事件可能重复投递,处理逻辑必须按事件 ID 去重,否则用户会看到机器人重复回答同一句话。
权限和通道都通了,还有一步:机器人必须在会话里。群聊场景下,机器人需要被拉进群;默认情况下它只在被 @ 时才收到消息,这是产品设计而非 bug。
| 场景 | 触发条件 | 注意点 |
|---|---|---|
| 群聊 | 被 @ 提及 | 消息内容里通常带 @ 占位符,取问题时要去掉 |
| 单聊 | 直接发消息给机器人 | 需要开放单聊能力并发布版本 |
| 话题群 | 在被 @ 的话题内 | 回复要落在同一话题,否则会跑到主群 |
多平台并存的团队还要注意一件事:不同 IM 的消息结构、@ 语法、富文本格式都不一样。把「取用户问题」这段逻辑做成平台无关的中间层,后面接企微、钉钉时就不用重写业务逻辑——横向差异见《钉钉、飞书、企业微信 AI 机器人怎么选》。
AI 回答通常需要几秒到几十秒。如果等全部生成完再一次性发出去,用户会觉得「机器人卡住了」。流式回复的做法是:先发一条占位消息,再按增量更新这条消息的内容。
# 思路示意(接口与字段以官方文档为准)
1. 收到事件 → 立即返回成功
2. 发送一条占位消息,拿到 message_id
3. 模型流式输出 → 按节流间隔(如 300-500ms)更新该消息
4. 生成结束 → 做最后一次完整更新
要点:更新频率不要太高,飞书接口有频率限制,逐 token 更新会被限流;也不要太低,否则和一次性发送没区别。实践上 300–500ms 一次是比较稳的区间,并且要处理「更新失败时降级为一次性发送」。
接入完成不等于可以上线。下面这张表建议逐项打勾,任何一项没验过都不要宣布「接好了」。
| # | 验收项 | 判据 |
|---|---|---|
| 1 | 凭证可换取 token | 独立脚本调用成功,不依赖业务代码 |
| 2 | 权限已生效 | 后台状态为「已生效」,不是「已申请」 |
| 3 | 收消息通道通 | 服务端日志能看到真实事件,不是只有校验请求 |
| 4 | 验签已开启 | 伪造请求被拒绝,有明确日志 |
| 5 | 幂等已实现 | 同一事件重复投递只处理一次 |
| 6 | 群聊 / 单聊都测过 | 两种入口都能正常回答 |
| 7 | 流式回复正常 | 首字延迟可感知地短于完整生成时间 |
| 8 | 异常有兜底 | 模型超时 / 限流时有用户可读的提示,不是静默 |
先查回调地址是否通过 URL 校验,再查事件是否真的订阅了(订阅了权限但没订阅事件,同样不会推)。
多半是权限未生效或版本未发布。确认后台权限状态,并重新发布一次版本。
检查是否用了原始请求体参与签名(很多框架会自动解析 JSON,导致签名对不上)。要拿未解析的原始 body 计算。
通常是缺发消息权限,或用了错误的会话标识。确认消息是发到 chat_id 还是 open_id,两者不能混用。
确认机器人已被拉进群、且事件订阅包含群消息事件。私聊正常但群里没反应,基本就是这一条。
回调超时导致飞书重推。把业务处理改成异步,并按事件 ID 做幂等去重。
降低更新频率到 300–500ms 一次,并在限流时降级为一次性发送,而不是直接报错。
先确认部署环境能否访问外网(换 token 需要)。内网环境直接改用长连接,别在出网策略上死磕。
飞书 AI 机器人的接入,难点不在写代码,而在把四段链路拆开、每段单独可验证。身份、权限、收消息、发消息,任何一段黑了,现象都是「没反应」——没有分段验证,就只能靠猜。
把本文的 7 步当作施工顺序,把 8 条排错清单当作卡住时的检索表,把验收表当作上线闸门。这套顺序走完,接入本身大概半天到一天,剩下的时间应该花在「回答质量」和「权限边界」上,那才是真正决定这个机器人有没有人用的部分。