OpenClaw 第3章:实战集成飞书,构建自动化办公智能体
这个系列写到第3章,终于到了我踩坑最多、也最值得拿出来分享的环节——把 OpenClaw 接进飞书。前面两章分别解决了"本地跑通 OpenClaw"和"让它具备基本工具调用能力"的问题,但那时候的智能体还只是个终端里的命令行玩具。真正让它变成团队能用的办公助手,需要一个天然的入口:飞书群聊。这章我直接讲实战,从怎么建应用、配权限,到消息怎么在飞书和 OpenClaw 之间流转,再到日程、审批、知识库这些高频办公场景怎么落地,全程用我实际调通过的代码和配置说话。内容适合已经能跑起 OpenClaw、想把它接入真实办公环境的开发者,也适合做企业内部工具集成、研究智能体落地的同学做参考。
1. 为什么选飞书作为智能体的"办公入口"
1.1 对比过企微、钉钉之后,我为什么押注飞书开放平台
在做集成之前,我先把市面上主流的办公 IM 平台过了一遍。企业微信的开放能力不弱,但它的接口设计更偏向"跟微信生态打通",权限申请链路长;钉钉的生态很完善,可它的老接口文档维护得比较乱,新老 API 混在一起,对开发者不太友好。飞书(Lark)在这三者里反而是最舒服的:开放平台文档清晰,权限模型统一,而且对事件回调、消息卡片这类 IM 机器人的核心能力支持得最完整。
从办公自动化这个角度看,飞书有几个点是别的平台很难替代的:
- 多维表格(Base)和云文档的 API 成熟度高:日程、审批、知识库这些场景,飞书都有一整套对应的开放接口,而且稳定性实测不错。比如用 API 创建日程、读取多维表格记录、给审批流发卡片,都是官方支持的一等公民能力。
- 消息卡片交互能力强:飞书生消息卡片支持按钮回调、表单提交、卡片更新这类交互,这意味着智能体不只是"被动回复文字",还能主动推送待办卡片,等用户点按钮再做后续动作。这对做审批类流程来说几乎是必需品。
- 事件订阅机制设计很完整:支持 Webhook 长连接、消息加密、签名校验,安全性和可靠性都在线。
当然,选飞书还有一个务实的理由:团队内部用飞书的越来越多,把智能体直接接入现有的群聊和审批流,学习成本几乎为零,不需要额外装任何客户端。
1.2 智能体在办公场景里的真实价值边界
接飞书不是为了让机器人"会说话",而是为了让重复劳动真正被替代。我的初始目标场景是这几个:
- 群内自动问答:把 OpenClaw 的推理能力接到群聊里,成员 @ 机器人就能拿到答案,不再需要人工翻文档。
- 日程助手:通过自然语言直接创建飞书日程,比如"帮我约下周三下午3点和产品同学开会一小时",智能体自动调日历接口完成创建。
- 审批卡片:当某个流程需要审批时,智能体主动推送一张带"通过/拒绝"按钮的卡片,审批人点一下按钮,智能体再调对应接口完成流转。
- 知识库检索:对接多维表格或云文档,让智能体基于内部文档回答问题,而不是全靠通用知识硬编。
这几个场景的共同点是:结构清晰、重复度高、对准确率的要求相对弹性,非常适合作为智能体的第一批落地任务。我建议任何人做同类集成时,都不要一开始就贪多,先把两三个场景跑通跑稳,后面再加能力会轻松很多。
2. 飞书侧应用创建与权限配置:全流程实录
2.1 企业自建应用的创建步骤
飞书开放平台的环境分"企业自建应用"和"商店应用",我们做内部工具只需要自建应用,不用上架商店。整个流程是:进入开发者后台 → 创建企业自建应用 → 填写应用名称和描述 → 创建完成。这里有一个经常被忽略的细节:应用创建者本人必须是该企业的管理员或在开放平台上有对应权限,否则后面审批环节会把开发流程卡死,我第一次做这个就走到一半发现没权限配机器人和事件订阅,只能找管理员临时开权限,非常耽误时间。
创建应用后,在"应用能力"里要开通两个核心能力:机器人和网页应用。机器人是让应用能出现在群聊里被 @ 的基础;网页应用则用于后续调用用户身份相关的 API(比如读取用户日历),两者建议一起开通。
2.2 最容易踩坑的权限配置清单
飞书的权限模型是"先加权限,再等审批,最后生效",这里强烈建议在写代码之前就把权限梳理清楚,否则代码写完了才发现权限没开,回调一直报 403,排查起来会很闹心。我把办公智能体常用到的权限整理成了一张清单,照着申请就行:
| 能力场景 | 权限点 | 说明 |
|---|---|---|
| 机器人基础 | im:message,im:message.group_at,im:chat | 收/发群消息、被 @ 后接收事件 |
| 日程管理 | calendar:calendar,calendar:calendar_event | 读取/创建/更新日程事件 |
| 审批流 | approval:approval,approval:instance | 获取审批定义、查询/创建实例 |
| 多维表格 | bitable:app,bitable:record | 读取/写入多维表格记录 |
| 云文档 | docs:doc只读 | 读取文档内容用于知识库检索 |
| 用户信息 | contact:user.base:readonly | 获取用户 open_id,用于识别会话身份 |
每一项权限在开发者后台都有对应的开关,申请后需要企业管理员在管理后台点"通过"才会生效。这里有个实用经验:权限生效有分钟级延迟,开通后不要立刻跑完整流程,先等两三分钟,或者重新登录一下开发者后台确认权限状态已经是"已开通",再继续配事件订阅。
2.3 事件订阅与加密策略
飞书机器人主动收消息,靠的是"事件订阅"。在应用配置的"事件与回调"页面,需要订阅接收消息和接收消息(群聊中@机器人)这两个事件。飞书支持两种接收方式:Webhook 回调地址和长连接。
我最终选了 Webhook 方式,原因是排查方便——用 curl 就能手动模拟事件推送,调试效率高。长连接省公网 IP,但出了问题你得在日志里翻半天,反而不直观。如果你有自己的公网服务器,我建议直接上 Webhook。
配置回调地址的时候,飞书会要求填一个Encrypt Key和一个Verification Token。这两个值不是摆设,后续所有回调请求都会用 Encrypt Key 做 AES 加密,用 Verification Token 做请求头校验。代码里必须正确处理,否则回调根本进不来。我后续会专门写一小节讲这个,因为这里报错概率极高。
3. OpenClaw 接入飞书的架构设计与消息流转链路
3.1 架构总览:飞书、回调服务、OpenClaw 三方怎么配合
接入层的整体架构我画一条线就能说清:飞书 → 回调服务 → 消息解析 → OpenClaw 推理 → 工具调用 → 飞书 API 返回结果。
回调服务我用了 FastAPI + uvicorn 跑一个独立进程,端口单独冲突开(比如 9001),不干扰 OpenClaw 主服务。回调服务收到飞书推送后,先做解密和签名校验,然后判断事件类型,把文本消息和会话上下文整理成一个统一格式,丢给 OpenClaw 的接口;OpenClaw 返回结果后,回调服务再调飞书的消息发送 API,把答案推回对应群聊。
这套设计的好处是把"接收事件"和"推理执行"解耦了。如果 OpenClaw 推理时间长,飞书那边有超时限制(一般 3 秒内必须返回响应),所以回调服务必须立刻给飞书一个 200 响应,然后把处理逻辑放到后台任务队列里跑。这也是很多做 IM 机器人的项目踩过的坑——你必须在回调接口里同步处理还是异步处理之间做明确选择。我的方案是:收到请求后先返回 200,再通过 FastAPI 的BackgroundTasks或一个简单的线程池丢到后台处理。
3.2 消息事件解密与签名校验:这步做不对,回调永远不通
飞书的所有回调请求体都经过 AES 加密,并且 header 里带了X-Lark-Request-Timestamp和X-Lark-Request-Nonce。校验流程是这样的:
- 用 Encrypt Key 的前 16 位作为 AES key,解密请求里的
encrypt字段,得到明文 JSON; - 用 Verification Token 加上 timestamp 和 nonce 做 SHA256 签名校验;
- 校验通过后再解析事件内容。
这一步是配置接入时最容易卡住的地方。拿 Python 的cryptography库举例,解密代码核心逻辑是这样的:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes import base64 import hashlib import json def decrypt_event(encrypt_data: str, encrypt_key: str) -> dict: # AES-256-CBC,key 取 encrypt_key 的前 16 个字符 key = encrypt_key[:16].encode("utf-8") iv = key # 飞书的 iv 固定为 key 的一部分 cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) decryptor = cipher.decryptor() raw = base64.b64decode(encrypt_data) decrypted = decryptor.update(raw) + decryptor.finalize() # 飞书会在解密结果末尾带 PKCS7 padding,需要去掉 pad_len = decrypted[-1] return json.loads(decrypted[:-pad_len])签名校验的代码也不复杂,核心就是拼字符串、做 HMAC-SHA256、再和请求头里带的签名比对。我更推荐的做法是直接用飞书官方 SDK,比如 Python 的lark-oapi,这些细节它内部都封装好了,我只需要传入 Encrypt Key 和 Verification Token。除非你和我一样有自定义网关需求,否则别自己手写加解密,真的没必要。
3.3 消息路由与上下文管理
解密出事件后,关键是在回调服务里维护一套会话状态。飞书群聊里同一群发的消息是同一个chat_id,但 OpenClaw 要识别每次对话的上下文,就得靠session_id。我的做法是:以chat_id + 消息发送者的 open_id作为 session key,存到内存字典里(生产环境换 Redis),这样群里每个人和机器人的对话上下文是彼此隔离的,不会串场。
同时,飞书的事件结构里有message.event.mention数组,能拿到被 @ 的机器人信息。我做了个过滤:只有消息里包含机器人的 open_id,或者是在p2_im_message_receive_v1里标记了群聊且包含机器人 mention 时,才把消息投递给 OpenClaw。这样避免机器人对群里所有消息都做无差别回复,既省 token 又省流量。
从 OpenClaw 的角度,我给它封装了一个FeishuToolkit,里面注册了send_text_message、create_calendar_event、send_approval_card、query_docs_content这几个工具函数。OpenClaw 在推理到对应意图时,会按工具调用的规则,把参数以 JSON 形式传给我定义的函数,我再在函数体里调飞书 API。这就是"智能体主动执行"的核心机制,本质上完全依赖 OpenClaw 的工具调用框架。
4. 落实到具体场景:自动问答、日程助手、审批卡片、知识库检索
4.1 群内自动问答:让团队用大白话拿到内部信息
我做的第一个场景是自动问答。场景是:某研发团队的运维知识分散在十几个文档里,每次有人问"这个服务怎么部署""监控报警怎么看",都得有人翻文档回复。我的方案是把 OpenClaw 接进团队群,让它基于一份整理好的知识库文档回答问题。
这一步本质上不需要太复杂的逻辑:OpenClaw 本身就是个大模型,工具函数里给它提供一个search_docs函数,它的工作方式就是"用户提问 → 触发检索 → 读取相关文档内容 → 总结回答"。我注册的搜索逻辑是先去多维表格里的知识库目录表查关键词,拿到对应文档的 token,再调云文档接口读取内容,最后把内容作为上下文交还给 OpenClaw。
实际体验下来,最难的不是技术,而是控制回答的确定性。同一个问题,OpenClaw 的回答可能每次措辞都不一样,有时候会漏掉关键步骤。我的解决办法是在 prompt 里明确约束:"回答必须基于检索到的文档内容,不得补充文档之外的推测信息;如果文档没有相关内容,直接回复暂时未找到并提示转人工。"这样约束之后,回答的可靠性明显提升。
4.2 日程助手:一句话创建一场会议
日程助手是我觉得最能体现"智能体价值"的场景。用户在群里说"帮我约下周三下午3点和产品团队开需求评审会,时长一小时",OpenClaw 需要做三件事:
- 从自然语言里提取时间、参会人、会议主题等结构化信息;
- 调用飞书日历 API 检查目标时间的空档;
- 创建日程,并在群里回一条确认消息。
时间解析这一块,如果完全依赖大模型输出,格式经常不稳定。我的工具函数里对参数做了严格约束:
def create_calendar_event(summary: str, start_time: str, end_time: str, participant_emails: list = None): # start_time 和 end_time 必须是 UTC 时间戳(秒) # participant_emails 是可选的,用分号分隔的邮箱列表 ...OpenClaw 在调用这个函数之前,需要自己先把"下周三下午3点"换算成正确的时间戳,这对大模型来说有挑战,尤其是跨时区情况。我的经验是在 prompt 里给它一个"当前时间"作为基准,它推算起来会准确很多。另外必须让用户明确会议时长,否则 OpenClaw 默认按半小时创建,这跟使用者预期会有偏差。
4.3 审批卡片:从纯文本到按钮交互
纯文本的问答已经不够看了,飞书卡片让审批类场景有了质的提升。我做的审批卡片长这样:机器人推送一张卡片,标题是"待审批:某同学申请开通测试环境权限",正文是申请理由、申请人、申请时间,底部两个按钮:通过和拒绝。审批人点按钮后,飞书会回调一个Card Action事件到我们配置的回调服务,服务再根据action.value判断同意还是拒绝,调用审批接口完成流转,最后更新卡片状态为"已处理"。
实现卡片交互的代码核心是配置回调路由:
@app.post("/webhook/feishu/card") async def handle_card_action(): event = decrypt_event(...) action = event["action"]["value"] approval_id = action["approval_id"] decision = action["decision"] # "approved" or "rejected" # 调用审批 API 更新审批实例状态 ...这个场景我在实际使用中最大的体感是:卡片是人类和智能体之间最好的交互形态。它把"智能体替你做决定"的风险降下来了,变成"智能体把决策材料整理好,你来拍板",信任度会高很多。在自动化办公场景里,凡是涉及钱、权限、资源审批的,都建议走"卡片确认"而不是"全自动执行"。
4.4 知识库检索:让 OpenClaw 基于内部文档回答问题
几乎所有办公场景最终都会回到知识库。我的第四个场景是把飞书云文档、多维表格作为 OpenClaw 的外挂知识源,实现"问文档,答答案"。
具体配置上是这样做的:多维表格里建了一张"知识文档索引"表,字段包括文档标题、文档链接、文档 token、关键词标签。OpenClaw 收到问题后,先调search_knowledge_base工具,在这张表里按关键词匹配来找到候选文档,然后读取文档正文,最后汇总回答。整个过程用表格描述:
| 步骤 | 智能体动作 | 调用的飞书 API |
|---|---|---|
| 1 | 解析问题关键词 | im:message事件接收 |
| 2 | 多维表格检索 | bitable:record.search |
| 3 | 读取命中文档 | docs:doc.content.get |
| 4 | 总结回答并发送 | im:message.create |
这个链路跑通后,团队的新人入职指南、操作手册、故障排查手册都能被同一个机器人覆盖,不需要给每个场景单独写会话逻辑。
5. 上线后遇到的问题清单和完整排查链路
5.1 回调验签失败的排查记
项目跑通后的第一天,我就收到了一个告警:回调服务频繁报signature mismatch。排查这个问题的过程,很值得做一个复盘。
第一步,我先手动用飞书开放平台后台的"调试工具"重放了一条事件,确认服务能收到请求,但验签就是过不了。第二步,我把请求头里的 timestamp、nonce、签名值,以及 Encrypt Key 拉出来,按文档里的签名算法手写比对了一遍,发现问题是出在"签名拼串顺序"上——飞书的签名计算要求把timestamp、nonce、Verification Token按固定顺序拼接后再做 HmacSHA256,但当时代码里把顺序弄反了,导致验签失败。第三步,修正后我用同样的方式重放,签名校验成功。
这个坑的教训是:涉及加解密和签名的逻辑,不要只看文档的描述性文字,必须对着示例代码仔细核对拼接顺序和编码方式。这也是我前面强烈建议用官方 SDK 的原因——这些坑官方都提前替我们踩平了。
5.2 消息重复推送与幂等处理
飞书的事件推送机制是"至少一次"语义,也就是说服务端可能在网络抖动时重复推送同一事件。如果我们的回调逻辑里有副作用操作(比如创建日程、发消息),重复消费就会导致用户收到两条重复回复,或者日程被建两次。
我的解决方案是在回调服务入口加一层幂等 redis:每次收到事件,先根据事件的message_id(或event_id)去 redis 里 setnx,如果 key 已存在,直接跳过处理。缓存时间设了 5 分钟,覆盖飞书可能重试的时间窗口。加了这层之后,重复消息的问题基本消失了。这个思路对所有对接 IM 平台的项目都通用,不管接的是飞书还是别的什么,幂等处理都建议提前做,否则运营阶段会被这种"幽灵重复"搞得很头疼。
5.3 图片与附件消息的边界处理
办公群里不可能只有纯文本,总有人发截图、传文件。最初我的代码没有对消息类型做过滤,结果 OpenClaw 收到一条图片消息,传参里只有file_key和image_key,没有可解析的文本内容,整个推理链路直接报错,机器人在群里就没反应了。
后来我加了消息类型分拣:只处理text类型和post富文本类型;图片、文件、语音类消息统一回复"我目前只支持文字消息,您可以描述一下具体需求"。这个处理很简单,但它让机器人从"偶尔出错"变成了"稳定可控"。做 IM 智能体的同学一定要记住:用户不会按你的设计输入,永远要在输入边界上多做一层防护。
5.4 权限生效时间和租户 Token 的选择
飞书 API 的鉴权分两种:tenant_access_token(租户令牌)和user_access_token(用户令牌)。租户令牌适合机器人主动发消息、读写日程等"以应用身份操作"的场景;用户令牌则需要走 OAuth 授权,适合"以用户身份操作"的场景。在办公智能体里,绝大多数场景用租户令牌就够了,它的获取方式是拿 App ID 和 App Secret 调用接口换 token。但这里有个细节:租户令牌有有效期(一般是 2 小时),必须做缓存刷新,不能每次调用都重新换。我用 Redis 缓存 token,并提前 10 分钟自动刷新,避免因并发调用导致 token 过期。
权限生效时间的问题前面提过,这里再强调一遍:配置完权限后如果一直报permission denied,先去开发者后台看权限状态,确认已经是"已开通",再等几分钟重试。我遇到过最夸张的一次是权限审核通过后 20 分钟才真正生效,中间我不停地排查代码,结果问题根本不在代码侧。
6. 从 Demo 到团队正式使用:稳定性与安全的底线建议
6.1 回调服务的稳定性建设
调试阶段的回调服务,跑在单进程单机没有任何问题,但一旦机器人进了正经工作群,稳定性要求就完全不同了。如果回调服务挂掉,最直观的表现是机器人"叫不应"——用户 @ 它没有任何反应,因为飞书根本没法把事件推送到你这里。
我建议至少做这几件事:
- 用 systemd 或进程守护工具托管回调服务进程,挂了自动拉起;
- 把服务部署到能公网访问的固定地址上,并保证 HTTPS(飞书要求回调地址必须为 HTTPS);
- 在回调服务里做一层简单的速率限制,防止被高频请求打崩;
- 给飞书 Webhook 配一个专门的日志文件,记录每一次收到的加密原始请求、解密后的明文事件、响应状态码。排查问题的时候,这份日志是无价之宝。
6.2 敏感信息保护:App Secret 与 Encrypt Key
飞书的这两个密钥,任何一个人拿到都能控制你的机器人,能读你的内部消息内容。我做了一个在团队里绝对有效的约定,也给看我文章的同学一个硬性建议:App Secret 和 Encrypt Key 永远不要出现在前端代码、配置文件明文、或任何能进 Git 仓库的地方,一律走环境变量,拉代码后用脚本把.env.example复制成.env,填上真实值且.env必须进.gitignore。
也不要觉得这是小事。我见过因为配置不小心提交到远程仓库,导致整个飞书应用凭据被刷新的真实案例,被迫全部重新配置密钥和回调地址,影响所有在用的群。做企业应用的接入,安全意识就是生产力。
6.3 灰度发布和人机协同边界
最后一个经验,是真正从"能用"走向"好用"的关键一步。
机器人上线后不要全量铺群。我的做法是先拉一个"内部测试群",管理员群、技术群、种子用户群,让信任度高、愿意反馈的同事先跟机器人磨合两星期。这一阶段重点收集两类反馈:一是理解错误(用户明明问 A,机器人答成了 B),二是执行错误(时间解析错、文档检索错、审批动作错)。根据反馈不断修 prompt 和工具参数,稳定后再逐步扩大到更大范围。
同时要有一条明确边界:凡是涉及最终决策的,机器人永远只做建议或待办整理,不做最终执行。比如它可以整理好一份待审批清单、生成一份日程安排的草稿,但真正点"同意"的,必须是人。这个边界跑了一段时间后,团队对机器人的信任度和依赖度才会同步上升,自动化办公才能真正落地,而不是变成一个新的麻烦制造机。
说到这,OpenClaw 第3章的核心内容就差不多齐了。最后分享一个我个人的心得:做这类 IM 智能体集成,最值钱的不在模型推理能力,而在工程细节——解密、幂等、权限、日志,每一件琐碎事都是真正的分水岭。把地基打牢,OpenClaw 才能从一个"能聊天的终端玩具"变成"团队里值得信赖的数字化同事"。