最近花了两天时间做了一件事:让飞书里躺着的一个机器人真正能和同事对话。用的就是 openclaw + ollama + 飞书机器人这套组合,openclaw 负责把消息接进来、做会话管理,ollama 在本地跑开源大模型,飞书则是最前端的聊天入口。搭好之后,同事在群里 @一下机器人,它就能回答问题,后续我还给它加了文档检索和定时推送。
这套方案解决的核心问题,说白了就是“用本地模型 + 一个能跑起来的智能体框架 + 一个现成的办公 IM,快速造一个团队可用的 AI 助手”。我不需要把任何对话数据送到外部服务,不用按 token 付费,也不用从零写 IM 协议解析。它特别适合三类人:本地模型玩家、想给团队配一个可控助手的开发者,以及出于是数据边界和成本考虑不想用云端大模型 API 的团队。
这篇文章我会从方案选型讲起,把安装、配置、联调的全过程按步骤拆开,最后把我在实操里踩到的坑和排查方法整理出来。只要你懂一点命令行,跟着走完,大概率能把这套东西在自己机器上跑起来。
1. 整体方案:为什么是这三件套
1.1 一个接线员、一个专家、一个前台
最开始我其实想得特别简单:飞书机器人本身就有 webhook,写个脚本接收消息、调用模型、再把结果发回去,不就成了吗?真正做起来才发现,聊天机器人根本不是“收到一条消息就吐一段文本”这么简单。要管多轮会话,要处理 @ 事件,要做权限校验,要考虑群里多人同时提问的并发,还要为以后加工具能力留口子。这些逻辑如果全部塞进一个脚本里,很快就会变成一团乱麻。
openclaw 在这里扮演的正是“接线员”的角色。它是一个开源的智能体框架,专门处理消息路由、会话管理、事件订阅、工具调用这些基础设施,把我在协议层要重复造轮子的工作挡在了外面。ollama 则是那个“背后思考的专家”:它让开源大模型跑在本地,对外提供一个标准 API 给 openclaw 调用。飞书是“前台”,负责收集同事发来的消息,也负责把机器人的回答贴回群里。三者各管一段,职责边界非常清晰,后面出问题的时候能精确定位到是哪一层出了问题。
1.2 这套组合解决了什么真实痛点
我梳理过为什么最终敲定这个组合,主要对应三类痛点。
第一类是对话上下文的管理。飞书消息是一粒一粒的,但机器人必须有记忆。openclaw 默认带有会话机制,同一会话内的消息会先拼接成完整的对话历史,再一起发给模型,避免每次都是“失忆式问答”。这个点自己写很容易忽略:如果只把当前一条消息发给模型,很多追问就完全接不上,体验会非常差。
第二类是数据边界和成本的平衡。模型权重全部放在本地,对话过程不经过任何第三方。对于内部信息比较敏感的团队来说,这比把聊天记录发到云端 API 要放心得多,长期使用也没有按 token 计费的问题。代价是需要一台带独立显卡的机器,算力成本前置,但一次性投入对一台已经在用的开发机来说几乎可以忽略。
第三类是接入飞书办公生态的“最后一公里”。飞书开放平台提供了足够完整的机器人 API,但直接对接要处理鉴权签名、长连接、消息类型解析这些细节。openclaw 把这些封装好了,填上 App ID、App Secret,它就自动订阅事件、自动发消息。这对交付速度的提升是决定性的。
1.3 横向对比:为什么不做“更简单”的方案
我也考虑过两条看上去更省事的路。
一条是直接用云上现成的大模型 API 插件。这种方案接入工作量最小,但每一条消息都要带着聊天记录跑到外部服务,对某些场景不可接受;而且按 token 计费,等机器人真的在群里高频跑起来,长期账单不比电费便宜。
另一条是维护一套自研的聊天机器人框架。这条路最自由,但等于是同时维护 IM 接入、会话管理、鉴权、限流、以及后续模型切换这一整套工程,人力和时间成本直接拉满。
我把几个方案放在一个表里对比:
| 方案 | 控制力 | 交付速度 | 长期成本 |
|---|---|---|---|
| 云端模型 API 插件 | 低,数据出内网 | 最快 | 按量计费,越用越贵 |
| 自研机器人框架 | 最高 | 慢 | 人力维护成本高 |
| openclaw + ollama + 飞书 | 高,本地可控 | 较快 | 一次性硬件投入,运行成本低 |
这个对比不是为了评价孰优孰劣,而是想说明,这套组合取了一个很舒服的中间点:既有“模型在本地、数据不出内网”的控制力,又不需要我从零开始把 IM 机器人的轮子造一遍。
2. 动手之前先把三块“地基”打牢
2.1 Ollama 本地模型部署:模型选型与显存预算
Ollama 这一层部署起来最省心。Windows 直接下载官方安装包,Linux/macOS 一条脚本装完。装好之后拉取模型同样是单行命令,比如:
ollama pull qwen2.5:7b我自己的开发机是 16G 显存,拉的是 qwen2.5:7b 这个版本,量化之后占用大概五六个 G,还留出了上下文缓存的余量。模型选型这块我的建议很直接:中文对话优先 qwen2.5 系列,逻辑推理场景可以看 deepseek-r1 的蒸馏版本;显存只有 8G 就老老实实选 1.5B 或 7B 量化版,14B 以上建议 16G 显存起步。与其追大参数量,不如先把显存余量留足,否则上下文一长,模型很容易被挤出显存,性能反而更差。
部署完成之后,用一条命令验证 API 通不通:
curl http://127.0.0.1:11434/api/tags能返回一长串模型列表,说明 Ollama 服务已经起来了。它默认监听 11434 端口,这就是 openclaw 要连的地址。
2.2 OpenClaw 安装与初始化
OpenClaw 的安装方式和大多数 Python 项目一样,clone 官方仓库代码、创建虚拟环境、安装依赖三步。我这边用的是 Python 3.11,建议版本不要低于 3.10,否则依赖解析偶尔会报兼容问题。初始化完成之后,项目里会生成配置目录,里面包含主配置文件、日志目录和插件目录。
这里有个非常重要的小建议:第一次安装时,务必先做最小化验证,只跑通 OpenClaw 自带的命令行通道,确保它能正确调用 Ollama 并返回一句话。这一步把“模型可用”和“飞书可接入”两件事彻底隔离了,后面联调出现问题时,你能一眼判断问题出在模型层还是接入层,而不是对着黑盒瞎猜。
2.3 飞书机器人创建与权限开通
飞书这边的准备工作主要是在开放平台的开发者后台操作。打开后台,创建企业自建应用,在“应用能力”里添加机器人能力,然后配置事件订阅。我选择的是长连接(WebSocket)模式,好处是不需要任何公网回调地址,开发机上跑着就行,特别适合本地部署。
关键点是权限配置。机器人要能读消息、能发消息,至少需要 im:message 和 im:message:send_as_bot 这两类权限。权限开完之后要把应用发布上线,如果当前账号是管理员,点发布即可生效。最后,把 App ID 和 App Secret 记下来,这两个值就是 OpenClaw 连接飞书的钥匙。如果配置了加签,还会多一个加密密钥,同样记录下来。
3. 打通配置:从“各自孤立”到“聊起来”
3.1 飞书接入的配置段:核心参数一次说清
做好了各自的部分,接下来就是让它们互相认识。OpenClaw 的配置文件里有一个飞书机器人接入块,和下面这个结构类似:
[bots.feishu] app_id = "cli_xxxxxxxx" app_secret = "xxxxxxxxxxxx" encrypt_key = "xxxxxxxxxxxx" event_type = "im.message.receive_v1" transport = "websocket"具体字段名不同版本可能略有差异,以官方示例为准,但思路是一样的。填完这些配置,启动 OpenClaw 进程,它就会以长连接方式订阅飞书事件。这时候打开飞书开发者后台的事件调试工具,给机器人发一条测试消息,能看到事件日志在滚动,说明订阅链路已经通了。
3.2 一条消息的完整旅行
从同事在群里发消息,到机器人回复出来,中间经过的关键环节是这样的:
- 同事 @机器人 发消息,飞书服务器把它包装成事件,通过长连接推给 OpenClaw;
- OpenClaw 收到事件后做校验,解析消息内容;
- OpenClaw 根据会话 ID 找到或创建对应的会话上下文;
- 拼接历史消息和系统提示词,组装成完整 prompt;
- 调用 Ollama 接口,把 prompt 发给本地模型;
- 模型生成回复文本返回;
- OpenClaw 再调用飞书接口,把回复发送回群里。
理解这条链路最大的价值是:出问题的时候能按顺序一段一段查。很多新人遇到机器人不回复,第一反应就是改模型提示词,其实问题可能早在事件推送环节就断了。
有一个细节很容易被忽略:机器人主动发消息和回复消息,走的是飞书的不同接口。回复时携带 msg_id,飞书才能在会话里插入引用式回复;主动推送则走创建消息接口。OpenClaw 内部已经处理好了这两个场景,但如果你后续自己扩展功能,一定要注意区分。
3.3 模型参数与 prompt 调优
Ollama 暴露了 temperature、top_p、max_tokens 这些常见参数,OpenClaw 的模型配置块里可以设置。我的经验是:如果机器人定位是“答疑助手”,temperature 设在 0.3 到 0.5 之间最稳,太低显得机械,太高容易在专业内容里一本正经地胡说;如果定位是闲聊陪伴或者文案创意,可以放到 0.8 左右。
比参数更影响体验的,是系统提示词。我最初写的提示词只有一句话“你是 AI 助手”,后来发现完全不够。目前用的版本大致是这样的:
你是一个部署在团队协作平台上的 AI 助手。 回答要简洁、准确,优先使用简体中文。 不知道的信息不要编造,直接说明不清楚。 在群聊环境中,回答字数控制在 150 字以内,必要时分点。最后一条尤其重要。群聊里如果不限制字数,模型经常写出长篇小作文,同事划半天屏幕才能看到重点,几次下来就没人愿意用了。
3.4 资源测算与并发策略
我的开发机是 16G 显存,跑 qwen2.5:7b 量化版,单次回复大约两三秒,应付团队十几个人偶尔问问题完全够用。但如果群聊活跃度很高,并发消息涌进来,就不能让 OpenClaw 无限并发调用模型了。显存一旦吃紧,所有请求都会变慢甚至失败。
Ollama 侧我调了环境变量来控并发:
OLLAMA_NUM_PARALLEL=2 OLLAMA_MAX_LOADED_MODELS=1这样同一时间最多处理两条请求,也不会因为同时加载多个模型把显存打爆。单机部署不用追求大模型,先把并发和稳定性控住,体验才会在线。
4. 踩坑实录与常见问题排查
4.1 飞书事件订阅一直验证失败
我最开始卡得最久的问题,就是飞书事件订阅验证失败。反复核对 App ID 和 App Secret,确认没填错,才意识到问题出在两个地方。第一,应用还没有真正发布上线,事件根本没有推送到服务;第二,加签配置没有对应上,飞书要求必须用加密密钥对事件内容做校验,而我最初只填了 Secret,把加密密钥留空了。
排查时有一个很顺手的方法:飞书开发者后台的事件调试区,能看到每条请求的推送记录和返回内容。订阅报错时,那里会给出具体错误码。另外,如果用的是 Webhook 回调模式,服务端必须正确回传 challenge 字段原文,很多人在这一步栽跟头。
4.2 机器人收不到消息,或者不回复
事件调试区显示推送正常,但机器人就是不回话,这种情况要开始分层排查。我的顺序是固定的:先看 OpenClaw 的日志文件,确认有没有收到事件;再手动用 curl 调一下 Ollama 接口,确认模型能不能正常出内容;最后看 OpenClaw 有没有把回复发出。
实际排查中,有相当比例的问题出在模型侧。Ollama 在无人调用时进入空闲,第二天模型被自动卸载,第一条消息会被迫唤醒加载,耗时几十秒甚至更久。而 OpenClaw 的请求超时机制一旦触发,整条消息就直接丢了。解决办法是调整 Ollama 的 keep_alive 参数,让模型常驻内存,或者用系统服务托管进程,保证模型启动后一直处于加载状态。
我当时是在配置里加了:
OLLAMA_KEEP_ALIVE=-1这个参数的意思是模型加载后不自动卸载。运维上更稳妥的方案是把服务和这个环境变量一起托管给 systemd,这样即使机器重启,也会带着常驻配置自动拉起。
4.3 回复越来越慢:哪一层在拖后腿
群里最常见的反馈是“机器人是不是卡死了”。真正原因往往是上下文太长。OpenClaw 会默认把同一会话的历史消息全部发给模型,随着群聊推进,prompt 越来越长,生成速度肉眼可见地下降。我的处理办法是在配置里限制上下文轮数,超出就截断,只保留最近几轮对话。
如果截断之后仍然慢,就是纯算力问题。一是换更小的量化版本,二是关掉其他占用显存的应用。对于纯 CPU 跑 7B 模型的机器,我不建议接入实时群聊,一次回复动辄几十秒,体验很难救回来。这种场景更适合做异步任务,比如用户提交问题后稍后给结果。
4.4 显存溢出和偶发崩溃
有一段时间我在不同模型之间反复切换测试,结果 Ollama 突然报显存不足,进程直接退出。后来查日志才发现,它默认会同时保留多个已经加载的模型,切换时不会立刻释放显存。把 OLLAMA_MAX_LOADED_MODELS 设置成 1 之后,这个问题再也没有出现过。
Ollama 的日志位置在 ~/.ollama/logs/server.log,进程一崩溃先来这里找线索。很多问题不需要急着去社区提问,日志第一行往往就把原因写得明明白白。
4.5 中文回答质量忽高忽低
中文场景下,回答风格不稳定通常不是模型能力问题,而是提示词没有把输出语言约束住。跨语种模型有时会跟着用户消息里的关键词切换语言,甚至夹杂中英文混排。我在系统提示词里明确写了“一律使用简体中文回答”,并统一用中文语境测试,效果立刻稳定。
如果换了提示词还是不行,那基本就是模型本身中文语料不够,直接换 qwen2.5 这类针对中文优化过的模型,不要在原模型上硬调。
5. 跑通之后:从“能聊天”到“有手有脚”
5.1 给机器人接一个本地知识库
基础聊天通了之后,我做的第一件事是给机器人加知识库。Ollama 本身可以拉一个 embedding 模型,比如 nomic-embed-text,把本地文档切片向量化后放进向量库。用户提问时先做召回,把最相关的片段拼到 prompt 里,再让模型回答。
这一套做完,机器人就不再是“只会聊天”了,它能回答“公司报销流程是什么”“这个项目的上线文档在哪”这类具体问题。对团队来说,这个能力比通用闲聊有用得多。
5.2 定时任务与主动推送
OpenClaw 支持定时触发任务,我利用它做了一个每天早上九点的群推送:汇总当天待办、值班安排和最近更新的文档。这个功能非常适合团队早会场景,比“等人问才回答”的被动模式更有存在感。
做定时任务要留意一点:主动推送走的是创建消息接口,不依赖用户消息事件,所以调用链和普通问答不同。调试时建议先在单聊里验证推送,再投到群里。
5.3 多机器人分工协作
再往后,我拆了第二个机器人,让两个机器人各管一块:一个负责知识库问答,一个负责闲聊和脑暴。群里的 @ 目标不同,调用模型不同,系统提示词也不一样,互不干扰。实际效果比一个机器人干所有事好很多,因为系统提示词一旦塞太多职责,模型容易在长上下文里“角色混乱”。
多机器人的成本增加的只是配置,OpenClaw 本身支持多实例接入,显存够就各跑各的模型,显存紧张就共享一个 Ollama 服务。
我个人实际跑下来的体会,openclaw + ollama + 飞书这套组合,真正把“本地模型”从一个命令行玩具,变成了团队日常里随时可用的助手。做这个项目最耗费精力的不是模型本身,而是链路每一环的稳定性。如果重新来一遍,我会第一时间把日志、事件调试和模型常驻配置先弄好,再去折腾 prompt 和角色设定。
最后分享一个小技巧:群聊场景下,给机器人加一个“仅被 @ 时才响应”的开关,能有效避免它对每条群消息都插嘴刷屏。这个小细节做好,同事对机器人的好感度会直接翻倍。