OpenClaw接入飞书:从配置到进程守护的AI助手实战
你有没有遇到过这种时刻群里有人问了个问题你刚好不在电脑前等回到工位的时候话题已经翻了十几页。我想把这类重复劳动交给机器人——不是那种只能回复“在的”的玩具客服而是能真正理解上下文、能调用工具、能在凌晨自动整理信息的 AI 助手。翻了一圈方案最后选了 OpenClaw 接入飞书把整个链路跑通之后发现这个组合确实能承担不少日常杂活。这篇文章就是完整落地过程飞书应用怎么建、OpenClaw 怎么配、进程怎么守、消息可靠性怎么保证再加上我实际踩过的几个坑。如果你也打算拿一个开源 AI 助手框架接办公通讯软件这里面的思路和代码可以直接抄。1. 接入前先想明白三件事能省一半返工1.1 你这个助手到底要解决什么问题动手之前先别急着造应用。拿着一张纸写清楚这个机器人是给谁用的是给自己一个人当私人助理还是拉进团队群里让所有人都能召唤这两条路对会话隔离、权限范围和部署位置的要求完全不同。我最初是做个人助手后来发现团队群里的价值更大。比如有人问“这个月公司的放假安排”、有人要“把昨晚上线的版本发布记录整理成摘要”、还有人希望“每天早上九点把待办事项推到群里”。这些需求如果只是自己用单机跑个服务就够了一旦放到团队群里你就要考虑多用户并发、串台、消息重复、权限审核这些破事。另一个维度是场景型需求实时对话型群里一下马上回答和定时任务型每天固定时间推送总结。前者对消息事件订阅依赖强后者更依赖进程守护和定时调度。两者都想做那 OpenClaw 这类带网关、带任务调度能力的框架就比裸调模型 API 合适得多。1.2 OpenClaw 在整条链路里扮演什么角色很多人以为 OpenClaw 就是个聊天机器人其实它更像一个“AI 助手网关”。它的核心价值是把多个平台的输入收拢成一个统一入口再对接模型服务、工具调用、知识库和定时任务。链条大概是这样的飞书客户端 - 飞书开放平台事件网关 - OpenClaw 适配器 - 模型服务 ^ | 工具插件命令、搜索、API调用、定时提醒 OpenClaw 组装回复 - 飞书消息 API - 群聊/私聊为什么中间非要加这么一层因为直接拿飞书的 Webhook 接模型服务你最多只能实现“收到文本 - 调接口 - 回复文本”一旦要加记忆、要调第三方工具、要按不同模型路由、要在多个群之间隔离会话你就得自己写一堆胶水代码。OpenClaw 把这一层抽象好了飞书那边的消息格式被翻译成统一事件模型返回的结果又被翻译回飞书消息。这就是我选它的主要原因。1.3 飞书侧选哪种应用类型飞书开放平台里应用类型大体分两类企业自建应用和商店应用。个人或团队内部用直接选“企业自建应用”审核流程短、权限自己控制要是做对外分发才需要考虑商店应用那套流程复杂得多而且我们这种内部自动化助手一般走不到那步。还有一个容易忽略的点应用创建之后要把它“启用为机器人”。如果只创建了应用但没启用机器人能力后面事件订阅是收不到消息的。我第一次配的时候就是这个环节漏了导致回调地址怎么测都不通。2. 飞书自建应用的配置细节权限、事件订阅和长连接2.1 创建应用并拿到凭证进入飞书开放平台在开发者后台里找到“创建企业自建应用”填上名称、简介和图标创建完成之后会拿到两个关键凭证App ID形如cli_xxxx和 App Secret。这两个东西就是机器人访问飞书 API 的钥匙一个公开一个保密一定要分开存放。创建过程本身没难度真正麻烦的是后面的权限配置。很多新手卡在这里明明在权限列表里勾了一堆接口调用还是报错原因我后面专门讲。2.2 权限范围要克制别一股脑全申请给机器人申请权限我的原则是“够用就行、按需追加”。飞书权限点很多每个权限都意味着机器人能读到或写到更多数据也意味着出问题时影响面更大。下面是我做这套接入时实际用到的权限清单可以参考能力描述权限点名称大体名称用途是否需要接收单聊和群聊消息im:message.receive_v1监听发给机器人的消息必选以机器人身份发送消息im:message:send_as_bot回复群聊/私聊必选读取用户基础信息contact:user.base:readonly按 open_id 查用户姓名头像可选读写云文档docs:doc:readonly等文档摘要等高级场景按需另开注意不同版本或套餐下权限点的展示名称可能不完全一样要以你后台实际看到的为准。但逻辑是通用的接收消息、发送消息这两项是底线其它一律等有实际需求再加。2.3 事件订阅能用长连接就别用回调地址飞书要把消息事件推送给你的服务有两种模式回调地址Webhook和长连接WebSocket。回调地址需要你有公网可访问的 HTTPS 服务还得准备域名、证书、加密 key并且飞书会在事件推送失败时重试处理起来更麻烦。长连接模式则是由你的服务主动往飞书建一个 WebSocket 连接不需要公网入站对部署在办公网内或没有公网 IP 的服务器特别友好。OpenClaw 接入飞书的场景下我的建议是优先走长连接。配置量小、不依赖公网、延迟也更低。后面章节里我按默认长连接模式来写配置如果你所在网络环境不允许只能走回调地址那就把第 5 节的确认机制仔细看完。3. OpenClaw 端配置消息从飞书走到模型再走回来3.1 gateway 配置段OpenClaw 的配置一般是一个 YAML 文件。把新建应用的凭证填进去用环境变量引用别直接写明文。我用的配置文件大体长这样openclaw: gateway: feishu: app_id: ${FEISHU_APP_ID} app_secret: ${FEISHU_APP_SECRET} mode: websocket auto_reconnect: true reconnect_interval: 5 event_timeout: 8 session: isolation: chat_user key_template: {chat_id}:{sender_id}mode: websocket就是长连接模式auto_reconnect和reconnect_interval控制断线后的重连行为这点对 24 小时在线非常重要。event_timeout表示单个事件处理的最大秒数超过这个时间适配器会返回超时避免模型卡住的时候整个事件循环阻塞。模型侧的配置单独一段我接的是一个兼容 OpenAI 接口的服务商配置指向它的 base_url 和模型名model: provider: type: openai_compatible base_url: ${MODEL_BASE_URL} api_key: ${MODEL_API_KEY} default_model: ${MODEL_NAME}如果你用的是其它协议类型改成对应的就行OpenClaw 的模型接入层是插件化的不用改业务代码。3.2 消息格式翻译的几个细节飞书推过来的消息事件是个 JSON核心字段在event.message里其中content是字符串化的对象。纯文本消息时它长这样{ message_id: om_xxxx, chat_id: oc_xxxx, sender: { id: ou_xxxx, sender_type: user }, message_type: text, content: {\text\:\你好帮我写个周报大纲\} }OpenClaw 适配器会把content解析出来转成统一格式的事件。这里有个我实际遇到的坑如果用户在群里 机器人飞书文本里可能带着_user_1之类的占位片段或者含换行时文本被截断。所以我在解析时通常先做一层清洗把 占位符剥掉再做空串判断。另外是否只响应 机器人的消息、还是私聊里全部响应这个开关要按你的使用场景设置。3.3 最小可跑通配置与验证配置写好后先把服务拉起来openclaw doctor openclaw servedoctor子命令会检查配置项格式和凭证连通性是个很好用的自检工具。服务正常启动后到飞书里给机器人发一条私聊消息“你好”然后在群里 它再发一条。如果两条都能正常回复说明基本链路已经通了。第一次跑不通很正常重点看启动日志里有没有gateway connected字样。如果连不上八成是 App Secret 填错或权限没发布生效具体排查我放到第 6 节。4. 24 小时在线不是 nohup 那么简单进程守护与日志4.1 为什么我不能接受裸奔的 nohup有人觉得“服务器上用 nohup 跑起来就行了”实际上我劝你别这么干。nohup只保证你退出终端时进程不挂但它不能解决进程中途崩溃、内存泄漏导致被系统杀掉、断网后连接假死这些问题。我早期测试时用 nohup 跑了一个晚上第二天早上一看机器人已经失联好几个小时了日志只停在某条 websocket 报错那里。24 小时在线意味着你要的不是“能跑”而是“挂了能自动拉起来、日志能查、状态能看”。直接上 systemd 更省心。4.2 用 systemd 做进程守护我用的 service 文件放在/etc/systemd/system/openclaw-feishu.service内容如下[Unit] DescriptionOpenClaw Feishu Gateway Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple Useropenclaw Groupopenclaw EnvironmentFile/etc/openclaw/openclaw.env WorkingDirectory/opt/openclaw ExecStart/usr/local/bin/openclaw serve Restartalways RestartSec5 StartLimitIntervalSec0 StandardOutputappend:/var/log/openclaw/run.log StandardErrorappend:/var/log/openclaw/error.log [Install] WantedBymulti-user.target几个关键点说明一下。Typesimple配合ExecStart/usr/local/bin/openclaw serve意思是让 OpenClaw 以前台进程方式跑systemd 直接管理它的 PID。千万不要用openclaw start这种会 daemonize后台化的命令否则 systemd 会认为主进程瞬间退出触发反复重启。EnvironmentFile指向一个权限收紧的 env 文件里面放FEISHU_APP_ID、FEISHU_APP_SECRET、MODEL_API_KEY这些敏感变量。这样代码仓库里不出现密钥运维上也方便做轮换。Restartalways配合RestartSec5进程因为网络抖动、内存超限等原因退出后会自动重启。StartLimitIntervalSec0是为了避免短时间内频繁重启时被 systemd 限流因为长连接首次连接有时候就是会失败好几次限流反而误伤。启动命令sudo systemctl daemon-reload sudo systemctl enable --now openclaw-feishu sudo systemctl status openclaw-feishu4.3 日志轮转和健康自检跑一段时间后日志文件会变大我加了 logrotate 配置/var/log/openclaw/*.log { daily rotate 14 compress delaycompress missingok notifempty copytruncate }copytruncate很关键OpenClaw 本身可能持有日志文件句柄如果直接 rename 再新建进程写日志会写丢。copytruncate 先把内容复制走再把原文件截断避免这个麻烦。健康自检方面我在 cron 里放了一个探活脚本每分钟检查一次进程和连接状态#!/usr/bin/env bash if ! systemctl is-active --quiet openclaw-feishu; then systemctl restart openclaw-feishu fi # 如果 OpenClaw 暴露了本地 health 接口额外探测一次 curl -sf http://127.0.0.1:8899/healthz || systemctl restart openclaw-feishu有个很容易被忽略的点进程活着不代表连接活着。WebSocket 连接可能因为网络问题进入假死状态进程 PID 还在但收不到消息。有 health 接口就探测接口没有接口就定期查询飞书 API 确认连接状态总之不能只看systemctl is-active。5. 消息链路的可靠性设计确认机制、长消息分片、断线重连5.1 回调确认机制懒确认一定会被飞书重试先说长连接模式和回调地址模式的区别。长连接模式下OpenClaw 收到事件后会自动向飞书返回确认整个过程不需要你操心。但如果你被迫使用回调地址模式飞书要求你的回调服务在 3 秒内返回 HTTP 200否则会认为推送失败并触发重试。问题就出在“3 秒”上。如果后台正好在处理一个耗时操作比如调用模型生成一篇长文3 秒根本不够用。这时候回调服务不能傻等处理完再返回而是要先把事件“接住”并立即返回 200再把事件丢进队列异步处理。也就是“先确认后处理”。同时回调地址模式下建议开启 Encrypt Key。飞书会用 AES 加密推送内容你的服务需要先解密再处理。刚开始不熟悉的人可能会觉得解密麻烦但加密是防止回调地址被伪造的重要手段尤其你的服务有公网暴露面时。5.2 模型长回复必须切片否则发不出去模型输出一大段文字时飞书单条消息有长度限制直接发会失败。我在 OpenClaw 的回复组装层写了一个分片函数核心思路是优先按段落边界切避免把语义打断def split_message(text: str, limit: int 3500) - list[str]: parts [] while len(text) limit: cut text.rfind(\n, 0, limit) if cut -1: cut limit parts.append(text[:cut].strip()) text text[cut:].strip() if text: parts.append(text) return parts然后对每个分片依次发送。注意两个细节一是分片之间做一点延时比如 300 毫秒避免瞬间发太多被限流二是如果消息里有 Markdown 结构切分点尽量选在两个空行之间不要从代码块中间截断否则第二段会变成纯文本残片。另外飞书除了普通文本还支持卡片消息。卡片消息的负载结构更长如果你用卡片模板来发汇总要额外注意卡片 JSON 本身的长度限制和字段规则。卡片好看但调试成本也高前期先用纯文本把链路跑稳再换卡片不迟。5.3 断线重连与心跳监测长连接模式下断线是常态。网络切换、服务器休眠、机房抖动任何一环都可能让 WebSocket 掉线。OpenClaw 的auto_reconnect: true会自动重连这是第一道保险。第二道保险就是 systemd 的Restartalways进程崩溃也能拉回来。我建议再加第三道保险心跳盯梢。方法是在日志里定期检查是否有连接相关的活动日志或者在本地 health 接口做存活探针。实际部署中我还见过一种更简单有效的思路用 cron 定期调一次飞书的“获取机器人信息”接口如果接口返回网络错误就触发 systemd 重启服务。这种探活方式不需要额外暴露端口安全性也更好。6. 实战踩坑记录权限不生效、上下文串台、重复回复6.1 权限明明开了为什么接口还是报无权限这个坑我绝不是一个人踩过。后台权限列表里明明已经添加了接收消息、发送消息的权限结果测试时机器人要么收不到事件要么回消息报 403。根因在于飞书的权限生效分两步第一步是“添加权限点”第二步是“创建版本并发布”。如果你只在后台加了权限没有去“版本管理与发布”里创建一个新版本并提交发布那么这些权限在正式环境中完全不会生效。我当时的排查路径是先看后台“权限管理”里是否添加成功再看“版本管理与发布”里有没有已发布的版本。最后重新发布了一版等了一两分钟机器人立刻恢复正常。所以记住这个顺序改权限 - 发布版本 - 等生效缺一不可。6.2 群聊里多人同时使用上下文串台了把机器人拉进大群后A 问“帮我总结一下这段需求”B 又问“那顺便查下这个接口文档”结果 B 的回答里出现了 A 的聊天内容。这就是典型的上下文隔离没做好。OpenClaw 默认会话是按机器人维度或全局维度保存上下文的多人共用同一个会话 key 时必然串台。解决办法是把会话 key 拆到chat_id sender_id粒度这样群里每个人都有自己的上下文。配置如下session: isolation: chat_user key_template: {chat_id}:{sender_id}如果是私聊场景chat_id和sender_id其实指向同一个对象key 模板要兼容两种情况。另外群聊里机器人通常只应该响应包含 它的消息否则它会把所有人之间的闲聊都当成指令去处理。这里要加一个“仅 时响应”的判断OpenClaw 的事件里可以直接拿到是否被提及的字段。6.3 同一个事件收到两次回复发了两遍有段时间机器人总是重复回复用户发一句话它回两遍甚至三遍。我把日志拉出来对比发现同一事件 ID 被处理了多次。原因有两类。一类是回调地址模式下服务端处理超过 3 秒没返回飞书按策略重复推送另一类是自己代码里有重试逻辑模型请求超时后重试了一次但重试时没有跳过已完成的逻辑。解决思路是加幂等处理。用一个去重表记录已经处理过的事件 ID同一 ID 直接跳过。去重表不需要长期保存保留 24 小时足够。实现很简单from datetime import datetime, timedelta processed {} # event_id - 处理时间 def handle_event(evt): event_id evt.get(event_id) now datetime.now() # 清理过期记录 for key in list(processed): if now - processed[key] timedelta(hours24): del processed[key] if event_id in processed: return # 已经处理过直接忽略 processed[event_id] now # 正常业务处理单实例部署用内存字典就够了多实例部署就要换 Redis 或者数据库做幂等否则每个实例都处理一遍问题依旧。7. 上线前一定要做的安全检查7.1 密钥管理App Secret 不能出现在仓库里我之前看过有人把 App Secret 直接写进 YAML 文件再推到代码仓库这是非常危险的事。飞书应用的 App Secret 有 API 访问权限一旦泄露别人可以冒充你的机器人发消息、读消息。我这边统一的做法是放到/etc/openclaw/openclaw.env权限设为仅 openclaw 用户可读FEISHU_APP_IDcli_xxxx FEISHU_APP_SECRETxxxx MODEL_API_KEYsk-xxxx然后设置文件权限sudo chown openclaw:openclaw /etc/openclaw/openclaw.env sudo chmod 600 /etc/openclaw/openclaw.env还要注意 shell 历史和日志里不要出现 App Secret。我见过有人在调试时echo $FEISHU_APP_SECRET打印出来然后 shell 历史记录留了底。生产环境建议配置定期轮换哪怕没有泄露迹象半年换一次也不算多。7.2 工具插件要锁边界别让机器人拿到万能命令OpenClaw 这类框架强在工具调用但危险也在工具调用。默认情况下它可能具备执行命令、读写文件、访问外部 API 的能力。你需要在配置里显式声明允许哪些工具和白名单命令。比如只允许它调用预设的“查天气”“查会议室”“发日报”这些专用插件而不是给一组通用 shell 命令。如果确实需要命令执行把 shell 限制在一个只读目录禁用rm、wget、curl这类会产生外部影响的操作。内部 API 访问要配域名白名单防止机器人被诱导去请求内网服务。能用容器跑就尽量容器化。容器里以非特权用户运行挂载只读文件系统资源限制加--memory、--cpus这样哪怕某个工具链出了问题炸也炸不到宿主机。7.3 消息内容脱敏与日志策略机器人收到的消息会被发给模型服务处理这意味着群聊里的内容会出你的服务范围。上线前必须确认这件事在你的团队是否合规。我还在 OpenClaw 的消息出口和日志出口各做了一层脱敏手机号、邮箱、密钥、身份证号这些正则匹配后打码日志里不记录消息明文。日志这块尤其要小心很多人排查问题喜欢把整条消息打出来结果日志文件本身就变成了敏感信息库。我的做法是日志只记录 event_id、chat_id、消息类型和耗时不记录 content 字段真有需要排查时再单独开 debug 追踪。到这里整套 OpenClaw 接飞书的链路就完整落地了。我自己的体会是这类自动化助手最考验人的不是某个单一环节而是把应用配置、消息定价、进程守护、幂等处理、安全边界这些事串起来的能力。“先确认再处理”和“会话按人隔离”这两个原则如果一开始就设计好后面能少掉大半的维护烦恼。最后再分享一个小经验上线第一个月每次机器人行为异常优先翻日志而不是立刻改代码。很多问题其实只是飞书重试、服务重启、配置没发布这类外部原因先把根因找到再动手比反复瞎试有效得多。