
1. 先说结论个人AI助手接进飞书到底怎么玩最近我把一个开源的个人AI助手框架接进了飞书挂上免费额度的大模型API现在在群里直接机器人就能让它总结文章、写周报、查资料甚至定时推送每日待办。整套玩法的核心步骤其实只有三步在飞书开放平台创建一个带机器人能力的应用用长连接模式接收群聊消息事件再把消息转发给大模型API拿结果回传到群里。跑通之后体验确实称得上“爽用”两个字因为你日常工作的IM窗口突然变成了一个随时在线的AI入口不需要打开网页控制台不需要切窗口群里一句话就有响应。这个项目最初的代号叫Openclaw为了避免和市面上同名产品混淆下文统一用“助手框架”来称呼它。我写这篇文章的目的是把从零到一接通的完整过程、选型理由和踩坑记录一次性讲清楚。文章适合三种人看想给团队或自己搭一个飞书AI机器人的开发者正在纠结免费大模型API怎么选型的朋友以及只看过官方文档但还是不知道怎么把事件订阅跑通的新手。如果你已经有一定Python基础哪怕只是写过几个脚本跟着这篇文章走一遍基本能在一个晚上把机器人跑起来。先说它能解决什么问题。IM已经成了大多数人的办公主战场但AI能力往往停留在网页端、客户端或者命令行里和日常工作场景是割裂的。你要么把内容复制到另一个窗口要么把结果再粘贴回来这个往返过程非常消耗耐心。把助手框架接进飞书之后等于把AI能力直接嵌入了消息流群里抛一个链接机器人返回摘要问一个技术问题机器人直接给出可执行的步骤甚至定时任务也能在群里完成。这种形态最大的价值不是“有一个机器人”而是“AI离你正在做的事更近了”。不过也得说清楚它不是万能的。免费API有配额限制模型能力也有天花板复杂推理和长文档处理还是需要专业工具。如果你指望它完全替代付费方案那可能会失望。但如果只是日常问答、信息整理、轻量自动化这套组合是目前性价比最高的玩法之一。1.1 项目定位一个可扩展的消息中转中枢助手框架本质上不是一个现成的聊天机器人而是一个消息处理中枢。它做的事情很纯粹监听飞书群里的事件解析消息内容按规则分发到不同的处理模块再把结果通过飞书API发回去。这种设计的最大好处是扩展性极强。你可以在不碰消息链路的情况下往框架里加各种处理器——接大模型API只是其中的一种你还可以接定时任务、接搜索接口、接内部工具这让它从一个聊天机器人慢慢长成个人助理。我见过很多开发者一开始就把所有逻辑堆在事件回调里结果代码越写越乱。助手框架的思路是分层接入层只负责“收到消息”和“发送消息”业务层才处理“这句话该干什么”。这个设计看起来很基础但对于个人项目来说足够清晰后续加功能非常顺手。如果你准备长期维护这个机器人我强烈建议一开始就按这个思路组织代码而不是图省事把所有东西塞到一个文件里。1.2 解决的真实痛点AI能力的“最后一公里”很多AI工具的问题不是能力不够而是到达路径太长。网页端的AI助手要打开浏览器、登录账号、输入提示词本地部署的模型又要维护环境、处理依赖。这些步骤单独看都不麻烦但叠加起来就构成了使用门槛。而IM机器人把路径压缩成了一句话你在飞书里它然后等结果。这个交互模型极其自然因为它复用了一个你已经高频率使用的窗口不需要任何新的学习成本。另一个痛点是信息聚合。工作群里每天有大量链接、文件、讨论这些内容散落各处没有汇总。接入大模型API之后机器人可以做到“丢个链接给它它把网页内容读出来总结给你”“把这段会议纪要贴给它它整理成待办列表”。我在实际使用中感受最深的就是这一点以前每天要花不少时间浏览和摘录信息现在群里说一声就有人帮你处理了这种体验变化是实打实的。2. 选型思路为什么是长连接模式加免费API的组合动手之前先把选型逻辑讲透。这个组合不是随便选的每一个决定背后都有现实约束理解了这些你后续遇到问题才不会慌。2.1 飞书机器人接入模式长连接为什么更省心飞书开放平台提供两种主流的事件接收方式一种是传统的Webhook回调需要你有一个公网HTTPS地址飞书把事件POST到你的服务器另一种是长连接模式WebSocket你的服务主动连上飞书的网关事件通过长连接推下来。两种模式我用过后直接推荐长连接。原因很现实个人开发环境下公网回调要处理域名、HTTPS证书、反向代理、端口开放一堆事情任何一个环节出问题都会导致收不到消息。而长连接只需要你的服务器能主动访问飞书网关不需要任何入站端口部署起来极其简单。调试的时候也舒服本地起一个服务就能连上不依赖外网穿透。对比项Webhook回调模式长连接模式公网地址要求需要HTTPS公网回调地址不需要服务主动外连部署复杂度较高需配域名/证书/反向代理低直接运行代码即可调试体验需要外网可访问调试链路长本地即可联调微信打日志方便适用场景分布式/多实例生产环境个人服务器、小团队机器人这里有个小提醒长连接模式下你的事件订阅地址可以不用配但应用的权限和事件仍需要在后台声明好否则飞书网关不会把对应事件推给你。我在初次接入时就因为漏掉了“接收消息”的事件声明连接建立得很正常却一条消息都收不到排查了半天。2.2 免费大模型API的挑选标准不是所有“免费”都值得用市面上号称免费的大模型API不少但质量参差不齐。我的筛选标准是四条有合法合规的公开服务协议、有明确的免费额度说明、上下文长度够用、接口兼容性好。优先考虑那些云厂商提供的限时免费额度和开源模型服务商提供的免费体验资源这些都是正规渠道不需要任何特殊网络环境就能访问数据走公开接口风险可控。具体看参数的时候重点关注三个每日请求次数限制、单次请求的上下文长度、响应速度。个人聊天场景下日请求几百次基本够用上下文长度低于8K的遇到长文档总结容易截断响应速度超过20秒的飞书端体验会很差因为用户等太久会以为机器人坏了。我在选型时就淘汰过好几个看起来额度很大、但响应速度慢得离谱的接口实测下来“稳定快速”比“额度大”重要得多。2.3 整体数据流一条消息从群聊到大模型再回来的路径把整条链路拆开看消息的旅程是这样的你在飞书群里机器人并输入文字飞书服务器收到后通过长连接把一条事件推送到你的服务你的服务解析出用户ID、群ID、消息内容去掉占位符后拼成一段请求发给大模型API大模型返回文本结果后服务调用飞书消息回复接口把结果发到同一个会话里。整个过程看起来复杂但实际上就是一个“接收-处理-回复”的三段式管道。这里最关键的点是“回复”这一步。飞书的事件推送只是通知你“有人发了消息”它不要求你同步返回内容。你可以先立即给飞书返回一个空响应表示收到然后异步处理完再主动调用消息接口把结果发回去。这个设计给耗时操作留了很大空间也是长连接模式调试时最需要注意的地方如果你在事件回调里同步调用大模型API很容易超过网关的响应超时时间导致消息丢失或重复推送。3. 动手实操从创建应用到跑通第一条回复这一部分我按完整的实操顺序写你照着一步步来就行。我假设你有一台能联网的服务器或本地开发机装了Python 3.9以上版本其他依赖我们现场装。3.1 前置准备清单实际操作之前先把材料备齐能省很多来回切换的麻烦。你需要准备一个飞书账号用于登录开放平台一个能持续运行Python服务的环境本地开发可以先用电脑跑长期运行建议放到云服务器上一个可用的大模型API地址和对应的密钥先准备好一个能返回文本的接口就行后面再调优。依赖安装很简单只需要两个库飞书官方Python SDK和requests。SDK负责长连接和API调用requests用来请求大模型接口。我个人没有用第三方的消息框架因为飞书官方SDK已经足够简洁再加一层封装反而增加排查难度。pip install lark-oapi requests3.2 创建飞书应用并开启机器人能力登录飞书开放平台进入开发者后台创建一个企业自建应用。应用创建完之后在“应用能力”页面找到“机器人”并启用这一步会为你的应用生成一个机器人身份之后它就能在群里被了。然后进入“凭证与基础信息”页面记下App ID和App Secret这两个凭证是后续所有API调用的身份标识要像保管密码一样对待。接下来配置权限。在“权限管理”页面开通两个关键权限一个是“接收消息”相关的事件权限用于监听群聊消息另一个是“发送消息”或“回复消息”的权限用于把结果发回群里。不同的权限名称在后台叫法略有差异你搜索“消息”关键词把读消息、发消息相关的权限都开通即可。这一步容易踩坑的是开了权限之后需要在“事件与回调”页面重新订阅事件新权限才会生效。3.3 配置事件订阅选择长连接模式进入“事件与回调”页面在“事件订阅”区域添加事件。最关键的一个事件是接收消息对应的标识通常是im.message.receive_v1。添加完成后选择使用长连接模式接收事件。如果你在后台看到了“请求地址URL”的输入框说明当前是Webhook模式要切换成以长连接方式接收事件同时不需要再填URL。长连接模式的原理实际上是一个WebSocket客户端你的服务启动后会连上飞书网关并保持在线。SDK内部会处理心跳、重连和事件分发你不需要关心底层协议细节。但有一点要注意长连接模式下本地调试非常方便可一旦服务重启连接会断开并自动重连如果重连期间有消息进来飞书网关可能会尝试重推或直接丢弃所以长期运行一定要配合守护进程使用。3.4 消息处理核心代码从收到事件到调用大模型下面是一段简化但能跑通全流程的Python代码实现了“收到机器人的文本消息后调用大模型API把结果回复到群里”。这段代码我按最小可用原则写的没有做复杂的模块拆分方便你理解整条链路。import json import os import requests import lark_oapi as lark from lark_oapi.api.im.v1 import * APP_ID os.getenv(FEISHU_APP_ID) APP_SECRET os.getenv(FEISHU_APP_SECRET) LLM_API_URL os.getenv(LLM_API_URL) LLM_API_KEY os.getenv(LLM_API_KEY) def call_llm(prompt: str) - str: headers {Authorization: fBearer {LLM_API_KEY}, Content-Type: application/json} payload { model: your-model-id, messages: [{role: user, content: prompt}], temperature: 0.7, } resp requests.post(LLM_API_URL, jsonpayload, headersheaders, timeout30) resp.raise_for_status() data resp.json() return data[choices][0][message][content] def do_reply(tenant_access_token: str, message_id: str, content: str): client lark.Client.builder() \ .app_id(APP_ID) \ .app_secret(APP_SECRET) \ .log_level(lark.LogLevel.INFO) \ .build() request ReplyMessageRequest.builder() \ .message_id(message_id) \ .request_body(ReplyMessageRequestBody.builder() .content(json.dumps({text: content})) .msg_type(text) .build()) \ .build() response client.im.v1.message.reply(request) if not response.success(): print(f回复失败: {response.code} {response.msg}) def handle_message(event): message event.event.message if message.message_type ! text: return content json.loads(message.content) raw_text content.get(text, ) # 去掉 占位符例如 _user_1 for mention in event.event.mentions or []: key mention.key raw_text raw_text.replace(key, ).replace(_user_1, ) user_input raw_text.strip() if not user_input: return try: answer call_llm(user_input) do_reply(None, message.message_id, answer) except Exception as e: do_reply(None, message.message_id, f处理出错: {e}) def main(): client lark.Client.builder() \ .app_id(APP_ID) \ .app_secret(APP_SECRET) \ .log_level(lark.LogLevel.INFO) \ .build() handler lark.EventDispatcherHandler.builder( , ).register_p2_im_message_receive_v1(handle_message).build() client.im.v1.message.dispatcher handler client.start() if __name__ __main__: main()这段代码有几个细节值得说明。首先是消息解析飞书事件里的message.content是一个JSON字符串文本类型的消息body里有一个text字段但实际内容会包含占位符比如_user_1。如果直接用完整文本提问模型会看到一堆奇怪的占位符所以要先去掉。其次是回复消息我用了reply接口它的效果是在原消息下回复一条用户能清楚看到机器人回应的是哪条消息这个交互体验比单独发一条新消息更自然。还有一个容易被忽略的点长连接启动时事件处理器注册的写法一定要和SDK版本匹配。不同版本的lark_oapi在事件注册方式上略有差异如果你用的版本和我的不完全一样以你安装版本对应的官方示例为准。我一开始就是因为SDK版本升级后方法名变了照着老代码抄导致事件一直没注册上。3.5 大模型API接入细节请求格式和响应解析大模型API的接口格式并不统一有些是OpenAI兼容格式有些是自定义格式。我建议优先选那种兼容OpenAI的接口因为生态工具多、文档齐全、代码示例好找。OpenAI兼容格式的请求体一般是传入模型名和消息列表响应体在choices数组里取第一个元素的message.content就是生成的文本上面的代码就是按这个格式写的。实际调试中最常见的坑是鉴权头格式不对。有的服务商要求Authorization: Bearer key有的要求自定义头部还有的要在请求体里带上密钥。我建议先写一个几行的测试脚本把接口调通了再往下走不要直接集成到机器人主逻辑里。我习惯的做法是先用curl验证接口返回正常再封装成函数这样可以隔离“接口问题”和“代码问题”。另外大模型API的超时时间一定要设置。飞书场景下用户大可忍受的等待时间大概在10到30秒超过这个范围体验就很差了。我通常给请求设置30秒超时然后做一层超时重试第一次超时就重试一次如果还是失败就回复一句“当前服务繁忙”而不是让用户干等。3.6 部署到服务器用systemd保住进程本地调试跑通之后就要考虑长期运行的问题。我见过太多人用nohup python挂后台结果服务器一重启进程就没了机器人就悄悄下线。正确的做法是把服务注册成systemd服务让操作系统帮你守护进程崩溃自动拉起开机自动启动。下面是一个最简的systemd服务配置把其中路径替换成你的实际路径[Unit] DescriptionFeishu AI Bot Afternetwork.target [Service] Useryour_user WorkingDirectory/opt/feishu-bot EnvironmentFEISHU_APP_IDyour_app_id EnvironmentFEISHU_APP_SECRETyour_app_secret EnvironmentLLM_API_URLyour_llm_url EnvironmentLLM_API_KEYyour_llm_key ExecStart/usr/bin/python3 /opt/feishu-bot/main.py Restartalways RestartSec5 [Install] WantedBymulti-user.target环境变量千万要直接写在服务文件里更稳妥的做法是用EnvironmentFile指定一个权限严格的文件比如/etc/feishu-bot.env这样主服务文件不用保存敏感信息。配置好之后依次执行systemctl daemon-reload、systemctl start feishu-bot、systemctl enable feishu-bot然后看一下运行状态systemctl status feishu-bot。如果日志里显示长连接已建立那就说明部署成功了。4. 调优实测从“能回话”到“真的好用”机器人能回话只是起点实际好用才是重点。我在连续用了一周之后逐步打磨了几个细节现在把效果和做法一起分享出来。4.1 第一轮实测裸奔状态的表现刚跑起来时我用最简单的提示词让机器人回答问题。它确实能回但问题很明显回答太短没有结构你问一个开放性问题它只丢两行字让它总结会议纪要它只给你一句话概括。这种状态在群里给同事用大概率会被吐槽。所以第一件事不是调模型参数而是优化提示词。我把系统提示词改成了更具体的角色设定比如这样的模板你是一个懂技术的助手回答问题时先给结论再补充步骤如果信息不足直接说明不知道不要编造尽量用列表呈现操作步骤。这个简单的改变立竿见影回答的可用性提升了一截。这里也说明一个重要问题大模型的能力固然重要但提示词决定了它输出的格式和风格后者对用户体感的影响往往更大。4.2 上下文管理别让机器人“失忆”默认情况下每次调用大模型API都是独立的机器人没有记忆。你上一句问它“帮我梳理一下这个项目的背景”下一句问“那核心难点呢”它完全不记得。要让对话连贯就得自己维护上下文。最简单的方式是把最近的几轮问答拼进请求里一起发给模型。我在实现时给每个会话维护了一个长度为6的滑动窗口保留最近3轮用户输入和3轮机器人回复超出部分丢弃。这样既不会烧太多token又能保证短时对话的连贯性。注意这里的会话不是按群来分的而是按用户ID来分否则群里不同人聊天会串味。实现上可以用一个全局字典存会话历史进程重启后会清空对于个人机器人来说完全够用。4.3 并发、限流和错误兜底稳定性才是“爽用”的关键免费API最大的毛病就是限流一旦短时间请求过多接口会返回429或者直接拒连。我在实际使用中遇到过好几次白天用的人多请求密集时机器人突然就不回消息了。排查下来不是服务挂了而是API被限流请求全部超时。解决思路是加一个本地的请求队列把调用模型的操作变成串行的限制每秒最多1到2个请求超出就排队。这样单用户场景感受不到差异但能明显降低限流概率。问题类型表现兜底策略接口超时请求30秒无响应重试一次仍失败则回复“繁忙”限流429连续多次请求被拒本地队列滑动窗口限速模型报错返回空内容或异常捕获异常回复可理解的错误信息事件重复推送同一条消息触发两次回复对消息ID做去重缓存错误兜底还有一个容易被忽视的点大模型返回的内容里可能有换行、特殊字符直接塞进飞书文本消息里时显示格式可能乱掉。我后来发现把长回复按空行拆成段落再发阅读体验会好很多。如果内容超过飞书单条消息的长度限制就拆成多条消息依次发送。这些细节单独看都不起眼但合在一起决定了用户愿意不愿意持续使用。5. 高频问题排查机器人为什么不理我跑了一个多月我把遇到过的典型问题整理了一份排查表按“现象-原因-解法”的格式写在这里。你会发现大部分问题的根源就是身份认证、权限声明和消息格式这三个方向。5.1 机器人完全不回复先查连接和权限机器人收不到消息时先看进程是否还活着再看日志里有没有长连接建立成功的记录。如果连接没有建立大概率是App ID或App Secret不对或者后台没有启用机器人能力。如果连接是正常的但收不到消息优先检查事件订阅有没有添加接收消息事件权限是不是真的开通了。这里有个细节修改权限或事件后有时需要等待一两分钟让配置生效别急着反复重启服务。我遇到过一种很隐蔽的情况开发者在后台配置了事件但用的是旧版本SDK事件注册代码没生效服务日志里一条事件都没打印。遇到这种情况先在后台的事件订阅页面查看“事件推送调试”功能它可以手动模拟一条消息事件推给你配置的地址。如果是长连接模式SDK客户端会收到并打印日志这样就能判断消息到底有没有到达你的服务。5.2 机器人提示“无权限”或回复失败多半是密文明文问题飞书要求部分接口传的消息内容不能是明文的。很多开发者在调用发送消息接口时直接把JSON字符串作为content传进去结果报错。正确做法是看接口要求的content_type如果是text需要传一个JSON编码后的字符串例如json.dumps({text: hello})而不是直接传hello。这个错误我在刚开始接入时踩过一次飞书SDK报的错信息又不够直观排查了好一阵。另一个和权限相关的问题是机器人尝试给不是它所在群的会话发消息或者给没有加入的群发消息会被拒绝。个人使用场景下建议先把机器人拉进一个测试群用测试群跑通所有功能再考虑扩大范围。别一上来就想着全公司部署风险太大。5.3 回复很慢或超时别同步调用大模型飞书长连接模式下事件回调如果长时间不返回网关可能判定处理超时并重推事件导致你的服务重复处理同一条消息用户会看到机器人回复了两遍甚至三遍。我的做法是事件处理器里只做消息存储和快速应答把真正的大模型调用放到另一个线程或进程里去执行处理完成后再调用消息接口发出去。这样回调毫秒级返回彻底告别超时问题。如果还是觉得慢就检查大模型API的响应时间。免费接口在高负载时段反应慢是常态可以在请求里设置更高的超时容忍度同时把系统的提示词精简一些太长的Prompt会明显增加响应延迟。实测下来把系统提示词控制在100字以内比堆一大段规则要快不少。5.4 安全和合规这条必须单独说既然是接进办公IM的机器人安全这根弦得绷紧。首先不要在群聊里处理敏感数据因为你无法控制谁在群里看到了机器人的回复涉及个人信息、密钥、合同内容的对话一律不要发给外部大模型API。其次API密钥、App Secret这些凭证不要出现在代码仓库里哪怕私有仓库也不要环境变量是比较稳妥的存放方式。最后要遵守飞书开放平台和所选大模型API的服务条款只使用合法合规的渠道和权限不要试图绕过平台的限制。这个意识从第一天就要有等出了问题再补就晚了。我还建议给机器人加一层使用范围限制在代码里配一个允许使用机器人的用户ID或群ID白名单非白名单内的消息一律不处理。这样做不是为了防自己人而是防止机器人被恶意刷量导致API配额耗尽或者被人用来测试一些不合适的内容。成本几乎为零但能挡掉很多麻烦。6. 后续扩展个人助理的更多玩法基础对话跑通之后我开始往框架里加各种插件式功能。得益于前面的分层架构加功能基本不碰消息链路只在业务处理层做文章。6.1 定时消息让机器人每天主动汇报配合一个定时任务库机器人可以在每天早上固定时间往指定群里推送日报今日天气、待办提醒、昨日项目进度摘要等。实现上很简单定时触发后机器人调用大模型API生成内容再主动调用发送消息接口推送到群里。这个功能非常适合个人使用相当于给自己配了一个每天早上准时上班的助理。需要注意一点定时任务服务要和飞书长连接服务跑在同一个进程里避免出现两个进程互相抢占资源的问题。我最初把它们拆成了两个服务结果本地调试没问题部署到服务器后因为环境变量不一致定时任务老是找不到API密钥。后来合并到一个进程全局共享配置问题就消失了。6.2 知识库问答把个人笔记变成私域问答如果你积累了不少技术文档和笔记可以把它们导出成文本文件做一个最简版的知识库问答。做法是把文档切成小块建立关键词索引用户提问时先在本地用简单的文本检索把最相关的几个片段找出来然后把问题加片段拼进Prompt让大模型基于这些材料回答。这个方法不依赖向量数据库几十个文档规模下完全够用而且效果比直接让模型“硬答”好很多。我实际用下来最舒服的场景是团队内部的FAQ整理把常见问题文档喂给机器人群里有人问相关问题机器人能直接从文档里找到答案并给出来源。这比让每个新人都去翻文档高效得多。缺点是文档更新后索引也要跟着更新所以我把索引用脚本定时重建保证内容不过期。6.3 多模态输入图片理解和文件摘要如果接入的大模型API支持视觉或多模态能力还可以扩展图片理解功能。飞书的消息事件里不直接包含图片文件你需要先用消息ID调用接口获取图片资源下载到本地再转成Base64或按API要求的格式传给模型。这个链路稍微长一点但效果很惊艳拍了照片发到群里机器人能描述画面内容截图发过去它能读出里面的文字并总结要点。文件摘要功能同理先用飞书接口下载文件再用处理脚本提取文本最后交给大模型总结。不过多模态功能对免费API的消耗通常更大配额消耗速度比纯文本快很多。我的建议是先做好文本场景确认稳定够用之后再考虑多模态别一上来把免费额度全烧在图片理解上。这个项目我前后折腾了大概两个周末最值钱的经验就是先把消息链路彻底跑通再考虑花哨的功能。很多新手一上来就想着多模态、知识库、定时任务一把抓结果连基础回复都没调好最后全卡在排查环境问题上。如果你也想搞一个类似的飞书AI机器人我建议从最简版本开始先让机器人在测试群里回一句“你好”再把大模型接进来最后逐步加功能。链路通了后面的扩展都是水到渠成的事。最后再分享一个小技巧把调试群的名字设成“机器人测试群”然后把你的开发号也拉进群里调试的时候直接在群里发消息看响应比看日志直观得多。