上个月我把 OpenClaw 接进了飞书,现在团队群里任何人直接 @ 机器人,就能让它查资料、汇总日报、跑定时任务,结果基本都是秒回。当初决定折腾这套联动,纯粹是不想再每天开一堆浏览器标签,在 AI 平台和办公软件之间来回切换。等真正把 OpenClaw 放进飞书之后,所有交互都在 IM 里完成,上下文还能沉淀在会话记录里,比单独开一个 AI 对话框顺手太多。这篇文章我把从环境部署、飞书应用配置到消息桥接、群聊联动、问题排查的完整过程写出来,尽量落到每一步,你照着做就能复现。
1. 为什么要把 OpenClaw 接进飞书
1.1 OpenClaw 到底解决什么问题
OpenClaw 本质上是一个开源的、本地优先的智能助理调度框架,它把大模型调用、工具执行、记忆管理、定时任务这些能力收敛成一个可以自由插拔的平台。你可以把它理解为一个更接近“数字员工”的底座,而不只是一个聊天机器人。它的特点在于:数据默认跑在你自己可控的环境里,很多不愿意把业务数据交给外部云服务的团队,会优先选择这类方案。
我自己团队里的场景其实很典型:日常有大量重复性问答、资料查询、日报汇总、排期提醒。传统做法是拉一个群,人肉回复;稍微好一点的是接一个只能对话的 AI 机器人,但它没有记忆、不能调工具、不能主动触发任务,本质上还是个玩具。OpenClaw 这类框架的出现,相当于把 AI 的“手”和“脑”都接上了——它能分析问题、调用工具、记住上下文,甚至按计划主动执行任务。
但这里有个现实问题:OpenClaw 本身不解决“入口”问题。它默认提供一个网页对话界面,但是放在团队场景里,没人愿意为了问一句话专门打开一个后台页面。团队日常工作的入口在哪?在飞书群里。所以把 OpenClaw 接入飞书的核心价值,就是让它出现在团队成员本来就在的地方。
1.2 飞书作为承载入口的优势
选择飞书而不选其他聊天工具,主要是看中它对企业场景的覆盖能力。飞书开放平台提供了一整套完整的 IM 机器人能力:单聊、群聊、卡片消息、事件订阅,加上多维表格、日历、云文档的 API 都开放得很彻底。这意味着 OpenClaw 接入飞书之后,不只是“在群里聊天”,它还能配合飞书原生的办公能力做深度联动。
举个例子:团队成员在飞书文档里汇总了一周数据,机器人可以自动读取结构化内容,加工成日报推送到群里;多维表格里有一条新的任务记录,机器人能够感知并触发一个处理流程;日历上有会议开始前,机器人主动提醒并整理会议资料。这些都不是“接入个机器人”那么简单,它需要消息链路、数据链路、事件链路三条路都打通。
另外飞书机器人支持“卡片交互”,OpenClaw 可以把结果以按钮卡片的形式推送,团队成员点一下按钮就能触发后续动作。这个体验比纯文本回复强很多,也是我把飞书作为首选入口的很重要的一个原因。
1.3 适合谁参考这套方案
如果你是个人开发者,想在飞书里挂一个自己的 AI 助理,这篇文章够用;如果你是在小团队里做自动化建设,想把 AI 能力聚合到办公协作里,这套方案会更契合。我不建议直接在生产环境照搬代码,但整个配置逻辑、权限模型和排查思路是通用且实用的。
需要说明的是,我没有用 OpenClaw 现成的飞书插件(如果有的话),而是自己写了一个轻量桥接服务,把飞书消息转换成 OpenClaw 能理解的任务,再把它返回的结果包装成飞书消息。原因很简单:可控性最高,逻辑清楚,出问题也好定位。这个思路也推荐你参考。
2. 开启飞书开放平台:账号、应用与权限的隐性门槛
2.1 先决定 OpenClaw 的部署形态
在碰飞书之前,先把 OpenClaw 本身跑起来。它的部署方式有几种:Docker 容器、Python 虚拟环境、或者源码直接运行。我实测下来,Docker 是最省心的方式,尤其是要长期挂着跑的场景,日志管理、进程守护、资源限制都更方便。如果你只是临时测试,也可以直接用 Python 拉起。
部署完成之后,最重要的一件事是确认它能通过 HTTP 或本地接口被外部调用。因为桥接服务的本质就是“收到飞书消息,转发给 OpenClaw,拿到回复,再发回飞书”。OpenClaw 自带的能力接口调用路径很简单,就是标准的 API 请求,你需要关心的是它的鉴权方式、请求体格式和返回结构。不同小版本的接口字段会有差异,所以部署完先用 curl 手测一遍接口,确认能拿到正常响应,再继续往下走。
提示:我一直建议先把 OpenClaw 原生能力测熟,再开始接飞书。否则出了问题你会分不清是 OpenClaw 的问题、桥接服务的问题,还是飞书配置的问题,排查效率会非常低。
2.2 在飞书开放平台创建企业自建应用
打开飞书开放平台后台,选择“企业自建应用”,创建应用后你会拿到两个关键凭证:App ID 和 App Secret。这两个值后面请求飞书 API 获取 token 要用,相当于你应用的身份证和密码。注意 App Secret 只能完整查看一次,之后只能重置,务必先存好。
创建应用之后,还需要做三件基础配置,缺一不可:
- 开启“机器人”能力。在应用功能里添加机器人,它会出现在应用的“能力”列表中,这样应用才能拥有 IM 消息的收发权限。
- 配置“事件订阅”的请求地址。飞书会把消息事件推送到这个地址,这是整个链路的核心。
- 在“权限管理”里开通消息相关的权限。我这边开通了读取用户发给机器人的单聊消息、读取群聊消息、发送消息、获取用户基本信息等等。
这里有个很容易忽略的点:飞书的事件订阅有两种接收模式,一种是 HTTP 回调,一种是长连接(WebSocket)。长连接模式对于没有公网 IP 的本地环境特别友好,因为不需要暴露公网端口;回调模式则需要一个公网可访问的 HTTPS 地址。我因为已经有一台带公网入口的服务器,就直接用了回调模式,简单直接。如果你本机没有公网,可以考虑用长连接模式,同样能完成事件推送,只是对接逻辑略有差异。
2.3 权限模型里藏着很多坑
飞书权限管理做得比较细,同一个接口在“单聊”和“群聊”场景下的权限是分开的。比如“发送消息”权限,你要同时开通单聊发送和群聊发送,如果只开单聊,群里发消息就会报权限错误。更隐蔽的是“获取用户信息”的权限,它和“读取消息内容”是放在不同分组里的,漏掉一个,消息里就解析不出发送人身份。
权限配置完成后,可以在“应用发布”里创建一个版本并提交审核。企业自建应用如果只是自己企业内部使用,审核通常非常快,甚至管理员可以直接通过。切记,没有发布版本的应用无法真正生效,很多人配置了半天发现收不到消息,问题几乎都出在这一步。
权限这一部分,我用一个表格总结一下实测中的关键点:
| 配置项 | 必开权限/能力 | 备注 |
|---|---|---|
| 机器人能力 | 添加机器人 | 在“应用能力”中开启 |
| 接收消息 | 接收单聊消息、接收群聊消息 | 事件订阅的关键权限 |
| 发送消息 | 发送单聊消息、发送群聊消息 | 注意区分场景 |
| 读取用户信息 | 获取用户基本信息 | 用于解析发送人身份 |
| 事件回调 | 配置回调地址或长连接 | 必须发布版本后生效 |
3. 核心实操:搭建飞书消息与 OpenClaw 的桥接服务
3.1 桥接服务的整体结构与技术选型
桥接服务是整个方案的神经中枢。我选的是 Python + Flask,原因只有一个:生态成熟,代码量小,改起来快。实际上换成 Node.js、Go 都完全没问题,核心逻辑不在于语言,而在于消息流转。
整体的数据流是这样的:
- 用户在飞书里给机器人发消息,或者在新群里 @ 机器人;
- 飞书服务器把这条消息封装成事件,推送到你配置的回调地址;
- 桥接服务接收事件,验证合法性,解密消息内容;
- 把消息文本转换成 OpenClaw 的任务请求,调用 OpenClaw 的接口;
- OpenClaw 执行完任务,返回结果;
- 桥接服务把结果包装成飞书消息,调用飞书 API 推回给用户或群。
这个结构非常直观,每一步都只做一件事,出问题时也能精确到某一环。我没有把 OpenClaw 直接挂到飞书回调地址上,而是中间加了一层桥接,最大的好处是可以在中间做权限过滤、消息格式转换、限流和日志记录。比如群里有人发了一条跟任务无关的消息,机器人不应该每次都触发 OpenClaw 去处理,这类过滤逻辑放在桥接层再合适不过。
3.2 处理飞书事件:验证与解密
飞书事件回调走的是 POST JSON 格式。第一次配置事件订阅地址时,飞书会发送一个url_verification类型的请求,要求你在响应里原样返回challenge字段,这用来验证回调地址的合法性。下面是 Flask 里处理验证的代码:
@app.route('/webhook/feishu', methods=['POST']) def feishu_webhook(): data = request.get_json() if data.get('type') == 'url_verification': return jsonify({'challenge': data.get('challenge')}) # 后续处理消息事件如果配置了 Encrypt Key,飞书推送过来的所有事件内容都会被 AES 加密,需要在收到后先解密,再解析事件结构。飞书使用的加密方式是 AES-256-CBC,密钥由 Encrypt Key 经过 MD5 后生成。这里给一个可用的加解密实现:
import base64 import hashlib from Crypto.Cipher import AES def decrypt_feishu(data, encrypt_key): key = hashlib.md5(encrypt_key.encode()).digest() cipher = AES.new(key, AES.MODE_CBC, key[:16]) decrypted = cipher.decrypt(base64.b64decode(data['encrypt'])) return decrypted[:decrypted.rfind(b'}') + 1].decode()这段代码有两点需要注意:一是 AES 的 IV 向量取的是密钥前 16 字节,这是飞书平台的固定约定;二是解密后是 JSON 字符串,但末尾可能带有 PKCS5 填充的补位字符,直接rfind(b'}')截断到完整 JSON 结尾,比暴力去填充更稳。
3.3 事件解析与调用 OpenClaw
解密后的事件结构里,最重要的字段是event.message、event.sender和event.message_type。你可以从event.message.content里拿到消息内容,从event.message.chat_id知道是哪个群或哪个会话,从event.sender.sender_id拿到发送人身份。这部分完整代码可以这样写:
@app.route('/webhook/feishu', methods=['POST']) def feishu_webhook(): data = request.get_json() if data.get('type') == 'url_verification': return jsonify({'challenge': data.get('challenge')}) payload = decrypt_feishu(data, ENCRYPT_KEY) event = json.loads(payload).get('event', {}) message = event.get('message', {}) chat_id = message.get('chat_id') msg_type = message.get('message_type') content = json.loads(message.get('content', '{}')) if msg_type == 'text': text = content.get('text', '').strip() reply = openclaw_chat(text) send_feishu_message(chat_id, reply) return jsonify({'code': 0})调用 OpenClaw 的函数需要根据你部署的 OpenClaw 接口来适配。我这边是直接向 OpenClaw 的本地服务发一个 HTTP 请求,把从飞书收到的文本作为用户输入传入。超时时间建议设置得长一点,比如 60 秒,因为部分任务可能需要调用外部工具,响应不会像普通问答那么快。
注意:如果你的飞书机器人在群里收到消息,记得先判断消息是否 @ 了机器人,再决定要不要回复。否则机器人容易把群里所有消息都当作任务处理,体验非常糟糕。
3.4 把 OpenClaw 的回复发回飞书
发送消息调用的是飞书的“发送消息”接口,需要先通过 App ID 和 App Secret 请求一个tenant_access_token。这个 token 有效期约两小时,建议缓存在内存里,别每次发送都重新请求。
import requests import time token_cache = {'token': None, 'expires_at': 0} def get_tenant_token(): if token_cache['token'] and token_cache['expires_at'] > time.time() + 60: return token_cache['token'] resp = requests.post( 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', json={'app_id': APP_ID, 'app_secret': APP_SECRET} ) data = resp.json() token_cache['token'] = data['tenant_access_token'] token_cache['expires_at'] = time.time() + data['expire'] return token_cache['token']拿到 token 之后,就可以调用发送消息接口。对于文本消息,请求体非常简洁,关键是要把receive_id_type指定为chat_id,然后提供上一步解析出来的chat_id:
def send_feishu_message(chat_id, text): token = get_tenant_token() resp = requests.post( 'https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id', headers={'Authorization': f'Bearer {token}'}, json={ 'receive_id': chat_id, 'msg_type': 'text', 'content': json.dumps({'text': text}) } ) return resp.json()这里有个细节:content字段必须是 JSON 字符串,不是对象。很多人第一次接飞书 API 会在这里报错,提示content format error,其实就是因为传了 Python 字典而不是序列化后的字符串。
3.5 完整测试:飞书消息触达 OpenClaw
把上面几段代码组合成一个app.py,本地跑起来之后,用一个内网穿透工具把公网请求转发到本地端口,再把回调地址填到飞书后台,完整的链路就算通了。我第一次测试时,在飞书里给机器人发了句“帮我查下今天北京天气”,十几秒后机器人回了一条消息,包含天气情况和出门建议,那一刻的成就感还是很直接的。
测试时要按层级验证:先测试飞书后台能不能收到回调事件(后台有推送日志),再测试桥接服务日志里有没有打印出消息内容,最后看 OpenClaw 的日志确认它有没有收到任务。每层都过了,链路才算真正打通。跳过其中任何一步,出了问题都很难定位。
4. 进阶玩法:群聊协同与多维表格联动
4.1 让机器人正确响应群 @ 消息
单聊测试通过后,接下来就是群场景。飞书群聊里要接收消息,需要额外添加“接收群聊消息”权限。但真正让机器人只在被 @ 时回复,需要在桥接层做逻辑判断。飞书事件里有一个字段event.message.mentions,它包含所有被提及的实体信息,可以从中判断机器人是否被 @ 了。
我当时实现了一个简单的规则:如果消息文本里包含机器人的名称,或者mentions列表里存在机器人的 ID,才触发 OpenClaw 处理;否则直接忽略。这样一个群里既有真人聊天,又有机器人任务,互不干扰。
群里消息的chat_id同样可以用来定位群会话,发送消息的逻辑跟单聊完全一致。还有个建议,给机器人设置一个固定称呼,比如“助理”,成员在群里发“助理,汇总一下本周重点”,解析逻辑会简单很多。
4.2 接通飞书多维表格,让 AI 读数据
飞书多维表格的开放接口对自动化玩家来说是一个宝库。接入 OpenClaw 后,可以让它在收到指令时读取某张多维表格的数据,做总结、分类、提醒。我记得有一次团队让我做一个竞品动态周报,我就是让 OpenClaw 从多维表格里拉出一周记录,再自动生成要点摘要发送到群里,省掉了人工整理的时间。
实现方式是在桥接服务里写一个工具函数,调用多维表格的 API。需要先有表格的app_token和table_id,这两个值可以从多维表格的分享链接或者开放平台后台找到。读取数据的接口返回的是记录数组,你把它转成 OpenClaw 能理解的上下文,再拼进提示词让它总结。这等于给 OpenClaw 加了一个动态记忆库,能力边界瞬间宽了很多。
同理,反方向也可以写:把 OpenClaw 的处理结果,比如分类标签、优先级判断,写入多维表格的某个字段。这就形成了一个闭环:任务从表格触发,结果又落回表格。
4.3 定时任务与主动推送
OpenClaw 支持定时任务这个概念。它可以按照预设时间主动执行某个动作,比如每天早上 9 点生成昨天的数据简报。但这里出现了一个很实际的问题:定时任务执行完后,如何把结果推送到飞书群?
我的做法是:在桥接服务里加一个定时器,每周一到周五的 8 点 50 分向指定群主动发送一条消息。消息内容来自 OpenClaw 的定时任务结果,也就是桥接服务固定时间触发一次 OpenClaw 的请求,把返回结果调用发送消息接口推到群里。这样一来,飞书不仅是一个“人类主动求助”的入口,还是一个 AI 主动汇报的出口,这个体验非常接近一个真正的数字员工。
代码实现也不复杂,用 Python 的schedule库就够了:
import schedule import time schedule.every().monday.at("08:50").do( lambda: send_feishu_message( GROUP_CHAT_ID, openclaw_chat("生成昨日数据简报") ) ) while True: schedule.run_pending() time.sleep(1)这一类定时推送特别适合早报、周报、监控告警、任务提醒。熟悉这个模式后,你会发现其实可以把各种事件源都接到飞书里,让它成为团队统一的信息闸门。
5. 常见问题与排查实录:从“收不到消息”到“消息乱回”
5.1 高频报错速查表
接入过程中踩过不少坑,我把最常见的几类问题整理成了速查表,按出现频率排序:
| 现象 | 根本原因 | 解决办法 |
|---|---|---|
| 回调地址一直验证失败 | 响应中缺少 challenge 字段,或者响应格式不是 JSON | 确认url_verification分支正确返回{"challenge": ...} |
| 能收到事件但消息乱码 | 忘了配置 Encrypt Key,或者解密逻辑不对 | 后台开启加密后,必须解密后再解析事件 |
| 发送消息报 permission denied | 权限未开通,或应用版本未发布 | 检查消息权限,并发布最新版本 |
| 群聊里发消息机器人不回复 | 未处理 @ 判断,或没有群聊消息权限 | 增加 mentions 判断,开通群聊消息权限 |
| 调用 OpenClaw 接口超时 | 部分任务耗时较长 | 调大超时时间,或改用异步回调模式 |
| content 字段报格式错误 | 传了对象而不是 JSON 字符串 | 发送前做json.dumps |
5.2 我踩过的几个比较隐蔽的坑
第一个坑是事件订阅的“推送日志”。飞书后台提供事件调试工具,但很多人不知道它只在应用发布且回调地址配置正确时才会记录。我一开始以为配置好了回调地址就会自动生效,结果测了半天一条日志都没有,最后才发现是应用没发布新版本。
第二个坑是消息内容的格式。飞书的文本消息content字段在事件里也是 JSON 字符串,比如{"text":"你好"},不是简单字符串。第一次解析时我直接取event.message.content.text,结果拿到一个字符串而不是字典,折腾了很久才意识到需要二次 JSON 解析。
第三个坑来自 OpenClaw 侧的并发。飞书用户可以连续发多条消息,如果桥接服务是串行处理,前面的任务没结束,后面的消息就会排队等待,看起来就像机器人卡住了。我用线程池简单处理了一下,每个请求独立执行,体验立刻好了很多。
第四个坑是 token 缓存。最开始我没有缓存tenant_access_token,每次发送都重新申请。量小的时候没问题,一旦群里的消息频繁起来,很快就触发飞书接口频率限制,报出Too Many Requests。加了一个简单的内存缓存之后,这个问题彻底消失。
5.3 调优建议与运维经验
如果这套系统要长期跑,我建议你在桥接服务里加日志关键字标记,比如每收到一条消息打一条[FEISHU_IN],每发出一条约[FEISHU_OUT],OpenClaw 调用则标记为[CLAW_CALL]。这样出问题时一键 grep 就能定位到哪一步断了,比看完整堆栈日志高效得多。
另外,飞书机器人发送消息有频控限制,别在高频群聊场景里让 AI 对每条 @ 都快速响应。我后来加了一个简单的冷却机制,同一个群 5 秒内最多触发一次任务,既避免 API 限流,也防止有人连续刷屏把系统拖死。这种小细节,文档里不会写,但在真实生产环境里比什么都重要。
最后说点我自己的体会。整套方案稳定跑了两周之后,最直观的变化是团队群里很多重复性问答不需要再人肉转发,信息汇总和定时播报也自动化了。OpenClaw 的能力边界完全取决于你给它接了多少工具、多少数据源,而飞书只是它的一双眼睛和一只手。如果你也在用 OpenClaw,或者正打算把一个本地 AI 助理推进团队协作场景,飞书这条回路真的很值得一试。按照上面的步骤搭一遍,再根据自己的业务场景加一些自定义工具,你会发现它的价值远超一个“会聊天的机器人”。