前段时间我想做一件事: 把 Hermes Agent 从终端里"放出来",直接接进飞书。
原因很简单。
虽然 Hermes 在终端里已经很好用了,能读文件、跑命令、调工具、处理任务,但每次都得开命令行,总归还是偏开发者工作流。 如果能直接在飞书里和它说话,那使用体验会自然很多:
- 想到事情就直接发它
- 手机上也能随手用
- 不一定非得守着终端窗口
- 更像一个真正在线的 AI 助手
我一开始以为这事不算复杂: "无非就是配个机器人、填点参数、启动一下服务。"
结果真做下来才发现,最坑的不是彻底连不上,而是这种特别迷惑的状态:
- WebSocket 已经连上了
- 机器人也能主动给我发消息
- 但我给它发消息,它就是不回
这种状态最烦,因为它会给你一种错觉:
好像哪里都对了,但就是差最后一下。
这篇文章就把整个过程按"踩坑复盘"的方式整理一下,希望能帮你少走一点弯路。
先说结论:飞书"机器人"真的不是一回事
我最开始踩的第一个坑,就是把飞书里的两种机器人混在一起了。
很多人平时接触飞书机器人,第一反应都是 webhook。 因为这玩意很常见:
- 配一个 webhook 地址
- 外部系统往这个地址发请求
- 群里就能收到通知
这种方式很适合做:
- 告警推送
- 构建通知
- 定时播报
- 状态同步
但问题是,Hermes 不是这种场景。
我想要的是:
我在飞书里给 Hermes 发一句话,它收到、处理、再回我。
这就不是"通知机器人"的事了,而是一个真正的双向对话入口。
后来我才彻底想明白,飞书里至少有两种完全不同的东西:
1. 自定义机器人 / Webhook 机器人
适合推送,不适合做持续对话。
2. 企业自建应用
这才是 Hermes 该走的路径。
如果你的目标是:
- 在飞书里和 AI 聊天
- 让 AI 真正接收用户消息
- 处理后再回复
那应该做的是:
飞书企业自建应用 + WebSocket 事件模式 + Hermes Gateway
如果一开始选错路,后面再怎么折腾都会很绕。
我的实际环境
我这次跑通的环境如下:
- 系统:macOS
- Hermes:本地已安装
- 飞书侧:企业自建应用
- 连接方式:WebSocket
- 后台运行方式:launchd
整体链路大概是这样:
飞书用户
↓
飞书企业自建应用
↓(WebSocket 事件)
Hermes Gateway
↓
Hermes Agent
↓
回复消息回飞书
第二个坑:很多教程默认你是 Linux,但我其实是 macOS
我查资料的时候,看到很多文章默认环境都是 Linux。
所以中间经常会看到这些东西:
systemctlsystemd- service 配置
如果你机器本来就是 Linux,那没问题。 但我这边是 macOS,所以这套不能直接抄。
这里我后面才意识到,必须换思路:
在 macOS 上,Hermes gateway 更适合挂成 launchd 服务,而不是 systemd service。
这一步很关键。 因为如果你照着 Linux 教程硬做,后面经常会出现两类问题:
- 服务虽然能手动起,但不稳定
- 重启系统后服务没了
所以如果你也是 macOS,建议从一开始就按 launchd 这条路走。
第一步:先确认 Hermes 本体没问题
我没有一上来就折腾飞书,而是先确认 Hermes 本地本身能跑。
先执行:
css
hermes --version
如果这一步都不通,后面就不用继续了。
然后我还确认了 gateway 相关命令可用:
bash
hermes gateway --help
因为飞书接入,本质上依赖的是 Hermes 的 gateway 能力,而不是普通 CLI 聊天。
第三个坑:依赖不对,后面会一直像"玄学问题"
接飞书之前,我先补了两个依赖:
bash
cd ~/.hermes/hermes-agent
source venv/bin/activate
uv pip install lark-oapi websockets
这里核心是:
lark-oapiwebsockets
如果你本身 Hermes 是源码 / venv 方式运行,这一步最好显式做一下。 不然后面你看到报错时,很可能会误以为是配置有问题,实际上只是依赖没齐。
最核心的一步:Hermes 侧到底要配什么
我这次接飞书,主要是通过 ~/.hermes/.env 来配置的。
核心配置大概是这样:
ini
FEISHU_APP_ID=你的_APP_ID
FEISHU_APP_SECRET=你的_APP_SECRET
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE=websocket
FEISHU_ALLOWED_USERS=你的_OPEN_ID
这里最重要的是几个字段:
FEISHU_APP_ID
飞书企业自建应用的 App ID。
FEISHU_APP_SECRET
飞书企业自建应用的 App Secret。
FEISHU_DOMAIN
如果接的是飞书,一般写:
ini
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE
我这次跑通用的是:
ini
FEISHU_CONNECTION_MODE=websocket
FEISHU_ALLOWED_USERS
这个字段不是绝对必须,但我很建议一开始就加上。
因为如果你只是自己先测,限制可用用户范围会清爽很多,也更方便排查。
第四个坑:我一度以为"能主动发消息"就等于接好了
这是整个过程中最迷惑我的地方。
我当时做到一个阶段,发现下面几件事都成立了:
- WebSocket 连接成功
- gateway 状态正常
- 机器人能主动发消息给我
按直觉看,这不就算接好了吗?
结果并没有。
因为后面一试就发现:
我给它发消息,它不回。
这时候我才意识到,自己当时其实只验证了出站链路 ,并没有验证入站链路。
也就是说,我验证成功的只是:
rust
Hermes -> 飞书
但真正要跑通的,是:
rust
用户 -> 飞书 -> Hermes -> 飞书回复
这两者完全不是一回事。
这也是我这次最大的认知修正之一:
机器人能主动发消息,不代表它能收到你的消息。
这句话非常重要。
我是怎么确认 WebSocket 已经连上的
这个倒不复杂,直接看日志最靠谱。
bash
tail -f ~/.hermes/logs/gateway.log
如果接入成功,通常会看到类似这样的信息:
arduino
connected to wss://msg-frontier.feishu.cn/ws/v2/...
看到这个日志时,我当时还挺高兴,以为差不多结束了。 但现在回头看,这只能说明:
- App ID / Secret 大概率没问题
- WebSocket 连接建立成功
- Hermes gateway 和飞书事件通道至少"表面上"打通了
还是那句话:
这不等于真正接入完成。
第五个坑:最难排的不是"发不出去",而是"收不到进来"
我这次真正卡住的,就是这种情况:
- 机器人能主动发消息
- 用户也确实能在飞书里看到它
- 但用户给它回消息,Hermes 这边完全没反应
这种状态最难排,因为它不是彻底坏掉。 而是会不断给你一种错觉:
好像哪里都没问题,但就是不工作。
后来我总结,这种情况最应该先区分的是:
问题到底出在"收到消息之前",还是"收到消息之后"?
这是排查方向的分水岭。
我后来的排查顺序
如果你也遇到"能发不能回",我建议直接按下面顺序查。
1)先盯日志,看 Hermes 到底有没有收到入站消息
这一条最关键。
bash
tail -f ~/.hermes/logs/gateway.log
然后你在飞书里给机器人发一条全新的测试消息,比如:
你好
如果你是在群里测,最好显式 @机器人 再发。
这一步不是先看它回不回,而是看:
日志里有没有新的入站消息记录。
如果完全没有,那问题大概率不在模型层,也不在 Hermes 的推理逻辑,而是在更前面:
飞书根本没把消息事件送到 Hermes。
这一点特别重要。 因为很多时候大家第一反应会怀疑:
- 是不是模型挂了
- 是不是 Hermes 逻辑有 bug
- 是不是 gateway 崩了
- 是不是本地代码有问题
但如果日志里压根没有入站事件,那说明问题还没走到那一步。
2)重点检查飞书开放平台的事件订阅
如果表现是:
- 主动发消息成功
- 用户发消息却不触发回复
那飞书侧最值得重点怀疑的是:
- 消息接收事件没订阅
- 订阅了,但没发布
- 权限没配完整
- 应用没对测试用户开放
我后面重点看的就是这些:
- 是否订阅了消息接收事件
-
- 常见名字类似:
-
im.message.receive_v1p2_im_message_receive_v1
- 是否开启了机器人能力
- 是否补齐消息相关权限
- 最新配置是否已经发布
- 测试用户是否在应用可见范围里
这里面我觉得最容易被忽略的是:
你改了配置,但没有真正发布上线。
这是非常典型的坑。
3)群聊测试时,一定要记得 @机器人
这个也很容易漏掉。
很多平台适配默认不会处理所有群消息,而是只处理:
- 私聊消息
- 群里明确
@机器人的消息
所以如果你在群里只是发一句"你好",很可能 Hermes 根本不会接。
如果你在群里测试,最保险的方式就是:
python
@机器人 你好
4)别忘了看错误日志
除了普通日志,我后面也会顺手盯这个:
bash
tail -f ~/.hermes/logs/gateway.error.log
原因很简单。 如果你本地改过 Hermes 代码,或者某次更新后 gateway 某个处理环节有异常,错误日志往往比普通日志更直接。
有时候不是飞书没送到,而是送到了以后 Hermes 某段逻辑抛异常了。 这种情况只看 gateway.log 还不够。
macOS 下我最后沉淀出来的几个常用命令
到后面我基本就围着这几个命令在排:
查看 gateway 状态
lua
hermes gateway status
启动 gateway
sql
hermes gateway start
重启 gateway
hermes gateway restart
看普通日志
bash
tail -f ~/.hermes/logs/gateway.log
看错误日志
bash
tail -f ~/.hermes/logs/gateway.error.log
如果你是在 macOS 上折腾 Hermes 接飞书,我觉得这几个命令的出场频率会非常高。
回头看,这次最值得记住的其实就三件事
折腾完之后,我自己总结下来,最值得记住的是这三点。
第一,不要把 webhook 机器人和企业自建应用搞混
前者更像通知工具,后者才适合做对话式 AI Agent。
第二,不要因为"能主动发消息"就以为接入完成了
那只能证明出站链路通了,不能证明入站事件通了。
第三,真正的验收标准只有一个
不是"状态正常",不是"WebSocket 连上了",也不是"机器人能给你发一条测试消息"。
真正的完成标准是:
你给它发消息,它能收到、能处理、还能回你。
少任何一步,都不能算真的接好了。
如果你也准备接,我建议你按这个顺序来
这是我踩完坑之后,觉得最省时间的一套顺序。
第一步:确认 Hermes 本地能跑
css
hermes --version
第二步:补飞书依赖
bash
cd ~/.hermes/hermes-agent
source venv/bin/activate
uv pip install lark-oapi websockets
第三步:配置 ~/.hermes/.env
ini
FEISHU_APP_ID=...
FEISHU_APP_SECRET=...
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE=websocket
FEISHU_ALLOWED_USERS=...
第四步:在 macOS 上安装 gateway 后台服务
sql
hermes gateway install
hermes gateway start
第五步:先看 WebSocket 是否连上
bash
hermes gateway status
tail -f ~/.hermes/logs/gateway.log
第六步:先验证主动发消息
这一步只验证出站。
第七步:再验证用户回复是否能触发 Hermes
这一步才是最终验收。
写在最后
如果你只是想做一个飞书里的通知机器人,那 webhook 真的已经够用了。
但如果你想做的是:
- 在飞书里直接和 AI 聊天
- 把 Hermes 变成一个随时能叫到的助手
- 让它继续调用本地文件、命令、工具帮你做事
那正确路线应该是:
飞书企业自建应用 + Hermes Gateway + WebSocket
我这次在 macOS 上确实把它跑通了,但中间最大的问题不是"完全跑不起来",而是那种最烦的半通状态:
它已经能发消息了,但就是不回你。
如果你也卡在这一步,别急着怀疑模型,也别急着怀疑 Hermes 本体。 先回到最前面的链路去看:
飞书到底有没有把你的消息事件真正送到 Hermes。
很多时候,问题就卡在这里。
附:这次最常看的几个路径
Hermes 配置
javascript
~/.hermes/.env
~/.hermes/config.yaml
日志
javascript
~/.hermes/logs/gateway.log
~/.hermes/logs/gateway.error.log
macOS 的 launchd 配置
javascript
~/Library/LaunchAgents/ai.hermes.gateway.plist
结尾
如果你也在折腾本地 AI Agent、消息平台接入,或者想把终端里的能力"搬进聊天工具",希望这篇文章能帮你少踩一点坑。
如果这篇对你有帮助,欢迎点个赞、收藏一下。 后面如果我继续整理,也可以再写一篇:
- Hermes 接入飞书后,怎么做多平台消息联动
- Hermes Gateway 的后台运行与服务治理
- 本地 AI Agent 接入 IM 后的真实工作流怎么搭