飞书 / Lark 集成设置
Hermes Agent 与飞书和 Lark 完全集成,作为功能完整的机器人。连接成功后,您可以在私聊或群聊中与该代理对话,通过主聊天接收定时任务结果,并通过标准网关流程发送文本、图片、音频及文件附件。
该集成支持两种连接模式:
websocket— 推荐使用;Hermes 主动发起出站连接,无需公开的 Webhook 端点webhook— 当您希望飞书/Lark 通过 HTTP 将事件推送到您的网关时非常有用
Hermes 的行为表现
| 上下文 | 行为 |
|---|---|
| 私聊 | Hermes 对每条消息均作出响应。 |
| 群聊 | Hermes 仅在被 @ 提及(@mentioned)时才响应。 |
| 共享群聊 | 默认情况下,共享群聊中的会话历史按用户隔离。 |
此共享聊天行为由 config.yaml 控制:
group_sessions_per_user: true
仅当您明确希望每个聊天室拥有一个共享对话时,才将其设为 false。
第一步:创建飞书 / Lark 应用
推荐方式:扫码快速创建(一条命令)
hermes gateway setup
选择 飞书 / Lark,使用飞书或 Lark 手机 App 扫描二维码。Hermes 将自动创建具备正确权限的机器人应用并保存凭证。
替代方案:手动配置
若扫码创建不可用,向导将降级为手动输入:
- 打开飞书或 Lark 开发者控制台:
- 创建新应用。
- 在 凭证与基本信息 中,复制 App ID 和 App Secret。
- 为应用启用 机器人 功能。
- 运行
hermes gateway setup,选择 飞书 / Lark,并在提示时输入凭证。
请妥善保管 App Secret。任何获取该密钥的人都可冒充您的应用。
第二步:选择连接模式
推荐:WebSocket 模式
适用于 Hermes 运行在您的笔记本电脑、工作站或私有服务器上。无需公网 URL。官方 Lark SDK 会打开并维护持久的出站 WebSocket 连接,并具备自动重连机制。
FEISHU_CONNECTION_MODE=websocket
要求: 必须安装 websockets Python 包。SDK 内部处理连接生命周期、心跳检测和自动重连。
工作原理: 适配器在后台执行线程中运行 Lark SDK 的 WebSocket 客户端。入站事件(消息、点赞、卡片操作等)会被分发到主 asyncio 循环。断开连接后,SDK 会尝试自动重新连接。
可选:Webhook 模式
仅当您已将 Hermes 部署在可访问的 HTTP 端点后方可使用。
FEISHU_CONNECTION_MODE=webhook
在 Webhook 模式下,Hermes 启动一个 HTTP 服务(通过 aiohttp),并在以下路径提供飞书端点:
/feishu/webhook
要求: 必须安装 aiohttp Python 包。
您可以自定义 Webhook 服务器绑定地址和路径:
FEISHU_WEBHOOK_HOST=127.0.0.1 # default: 127.0.0.1
FEISHU_WEBHOOK_PORT=8765 # default: 8765
FEISHU_WEBHOOK_PATH=/feishu/webhook # default: /feishu/webhook
当飞书发送 URL 验证挑战(type: url_verification)时,Webhook 会自动响应,帮助您在飞书开发者控制台完成订阅设置。
第三步:配置 Hermes
选项 A:交互式设置
hermes gateway setup
选择 飞书 / Lark 并填写提示信息。
选项 B:手动配置
将以下内容添加至 ~/.hermes/.env:
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=secret_xxx
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE=websocket
# Optional but strongly recommended
FEISHU_ALLOWED_USERS=ou_xxx,ou_yyy
FEISHU_HOME_CHANNEL=oc_xxx
FEISHU_DOMAIN 接受:
feishu用于飞书中国版lark用于 Lark 国际版
第四步:启动网关
hermes gateway
然后从飞书/Lark 向机器人发送消息,确认连接是否正常。
主聊天(Home Chat)
在飞书/Lark 聊天中使用 /set-home 来标记该聊天为定时任务结果和跨平台通知的主频道。
您也可以预先配置:
FEISHU_HOME_CHANNEL=oc_xxx
安全性
用户白名单(Allowlist)
生产环境中,请设置允许使用的飞书 Open ID 列表:
FEISHU_ALLOWED_USERS=ou_xxx,ou_yyy
如果留空,任何能联系到机器人的用户都可能使用它。在群聊中,系统会在处理消息前检查发送者的 open_id 是否在白名单中。
Webhook 加密密钥
在 Webhook 模式下,设置加密密钥以启用对入站 Webhook 数据包的签名验证:
FEISHU_ENCRYPT_KEY=your-encrypt-key
该密钥可在飞书应用配置的 事件订阅 部分找到。设置后,适配器将使用如下算法验证每个 Webhook 请求:
SHA256(timestamp + nonce + encrypt_key + body)
计算出的哈希值将与 x-lark-signature 头部进行时间安全比较。签名无效或缺失的请求将被拒绝,返回 HTTP 401。
在 WebSocket 模式下,签名验证由 SDK 自行处理,因此 FEISHU_ENCRYPT_KEY 为可选。但在 Webhook 模式下,强烈建议用于生产环境。
验证令牌(Verification Token)
额外的身份验证层,用于检查 Webhook 数据包内的 token 字段:
FEISHU_VERIFICATION_TOKEN=your-verification-token
该令牌同样位于飞书应用的 事件订阅 部分。设置后,所有入站 Webhook 数据包必须在其 header 对象中包含匹配的 token。不匹配的令牌将被拒绝,返回 HTTP 401。
FEISHU_ENCRYPT_KEY 和 FEISHU_VERIFICATION_TOKEN 可同时使用,实现纵深防御。
群聊消息策略
FEISHU_GROUP_POLICY 环境变量控制 Hermes 在群聊中的响应规则:
FEISHU_GROUP_POLICY=allowlist # default
| 值 | 行为 |
|---|---|
open | Hermes 响应来自任意群组中任何用户的 @ 提及。 |
allowlist | Hermes 仅响应来自 FEISHU_ALLOWED_USERS 列表中用户的 @ 提及。 |
disabled | Hermes 完全忽略所有群聊消息。 |
在所有模式下,机器人必须被显式 @ 提及(或 @all)后才会处理消息。私聊消息不受此限制。
@提及过滤的机器人身份
为了精确识别群聊中的 @ 提及,适配器需要知道机器人的身份。可通过以下方式显式指定:
FEISHU_BOT_OPEN_ID=ou_xxx
FEISHU_BOT_USER_ID=xxx
FEISHU_BOT_NAME=MyBot
若未设置以上任一参数,适配器将在启动时尝试通过 应用信息 API 自动发现机器人名称。为此,请授予 admin:app.info:readonly 或 application:application:self_manage 权限范围。
交互式卡片操作
当用户点击按钮或与机器人发送的交互式卡片互动时,适配器会将这些操作转换为合成的 /card 命令事件:
- 按钮点击 →
/card button {"key": "value", ...} - 卡片定义中的
value有效载荷以 JSON 形式包含在内 - 卡片操作采用 15 分钟窗口去重,防止重复处理
卡片操作事件通过 MessageType.COMMAND 分发,因此它们会进入正常的命令处理流程。
这也正是 命令审批机制 的工作原理——当代理需要执行危险命令时,会发送带有“允许一次”、“会话内允许”、“始终允许”、“拒绝”按钮的交互式卡片。用户点击按钮后,卡片回调将审批结果传回给代理。
必需的飞书应用配置
交互式卡片需要在飞书开发者控制台完成 三项 配置。缺少任一项都会导致用户点击卡片按钮时出现错误 200340。
-
订阅卡片操作事件: 在 事件订阅 中,添加
card.action.trigger到已订阅事件列表。 -
启用交互式卡片功能: 在 应用功能 > 机器人 中,确保 交互式卡片 开关已开启。这告知飞书:您的应用可接收卡片操作回调。
-
配置卡片请求 URL(仅 Webhook 模式): 在 应用功能 > 机器人 > 消息卡片请求 URL 中,将 URL 设置为与事件 Webhook 相同的端点(例如:
https://your-server:8765/feishu/webhook``)。在 WebSocket 模式下,此步骤由 SDK 自动处理。:::warning 若未完成全部三个步骤,飞书将成功 *发送* 交互式卡片(发送仅需im:message:send` 权限),但点击任意按钮时会返回错误码 200340。卡片外观正常——问题仅在用户与之交互时才显现。 :::
媒体支持
入站(接收)
适配器可接收并缓存来自用户的以下媒体类型:
| 类型 | 文件扩展名 | 处理方式 |
|---|---|---|
| 图片 | .jpg, .jpeg, .png, .gif, .webp, .bmp | 通过飞书 API 下载并本地缓存 |
| 音频 | .ogg, .mp3, .wav, .m4a, .aac, .flac, .opus, .webm | 下载并缓存;小体积文本文件会自动提取内容 |
| 视频 | .mp4, .mov, .avi, .mkv, .webm, .m4v, .3gp | 下载并缓存为文档 |
| 文件 | .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx 等 | 下载并缓存为文档 |
来自富文本(帖子)消息中的内联图片和附件文件也一并被提取并缓存。
对于小型文本类文档(如 .txt、.md),其内容会自动注入到消息正文,使代理可直接读取,无需调用工具。
出站(发送)
| 方法 | 发送内容 |
|---|---|
send | 文本或富文本帖子消息(根据 Markdown 内容自动识别) |
send_image / send_image_file | 将图片上传至飞书,再以原生图片气泡形式发送(可选添加说明文字) |
send_document | 将文件上传至飞书 API,再作为附件发送 |
send_voice | 将音频文件作为飞书附件上传 |
send_video | 上传视频并以原生媒体消息形式发送 |
send_animation | GIF 被降级为文件附件(飞书无原生 GIF 气泡支持) |
文件上传路径根据扩展名自动路由:
.ogg,.opus→ 作为opus音频上传.mp4,.mov,.avi,.m4v→ 作为mp4媒体上传.pdf,.doc(x),.xls(x),.ppt(x)→ 按其文档类型上传- 其余所有类型 → 作为通用流文件上传
Markdown 渲染与帖子回退机制
当出站消息包含 Markdown 格式(如标题、加粗、列表、代码块、链接等)时,适配器会自动将其作为飞书 帖子消息 发送,并嵌入 md 标签,而非纯文本。这可在飞书客户端中实现丰富渲染效果。
若飞书 API 拒绝帖子负载(例如因不支持某些 Markdown 结构),适配器将自动回退为发送纯文本并移除 Markdown 格式。这种双阶段回退机制确保消息始终能送达。
未检测到 Markdown 的纯文本消息将以最简单的 text 消息类型发送。
ACK Emoji 反馈
当适配器接收到入站消息时,会立即添加 ✅(OK)emoji 反馈,以表明消息已被接收并正在处理。这为用户提供即时视觉反馈,直到代理完成响应。
该反馈是持久的——即使响应发出后,✅ 仍保留在原消息上,作为已接收的凭证标记。
用户对机器人消息的 emoji 反馈也会被追踪。若用户在机器人发送的消息上添加或移除 emoji 反馈,系统会将其转换为合成文本事件(reaction:added:EMOJI_TYPE 或 reaction:removed:EMOJI_TYPE),以便代理能够响应用户反馈。
抗突发与批量处理
适配器内置防突发机制,防止短时间内大量消息冲击代理:
文本批量处理
当用户连续快速发送多条文本消息时,这些消息会被合并为单个事件后再分发:
| 设置 | 环境变量 | 默认值 |
|---|---|---|
| 静默期 | HERMES_FEISHU_TEXT_BATCH_DELAY_SECONDS | 0.6s |
| 单批次最大消息数 | HERMES_FEISHU_TEXT_BATCH_MAX_MESSAGES | 8 |
| 单批次最大字符数 | HERMES_FEISHU_TEXT_BATCH_MAX_CHARS | 4000 |
媒体批量处理
短时间内连续发送多个媒体附件(如拖拽多张图片)时,也将合并为一个事件处理:
| 设置 | 环境变量 | 默认值 |
|---|---|---|
| 静默期 | HERMES_FEISHU_MEDIA_BATCH_DELAY_SECONDS | 0.8s |
按聊天序列化处理
同一聊天内的消息按顺序逐条处理(一次只处理一条),以保证对话连贯性。每个聊天拥有独立锁,因此不同聊天的消息可并发处理。
速率限制(Webhook 模式)
在 Webhook 模式下,适配器对每 IP 地址实施速率限制,防止滥用:
- 窗口:60 秒滑动窗口
- 限制:每窗口内每个 (app_id, path, IP) 组合最多 120 次请求
- 追踪上限:最多记录 4096 个唯一键(防止内存无限增长)
超出限制的请求将返回 HTTP 429(Too Many Requests)状态码。
Webhook 异常行为追踪
适配器会追踪每个 IP 地址的连续错误响应。若同一 IP 在 6 小时内连续出现 25 次错误,将触发警告日志。此举有助于识别配置错误的客户端或探测行为。
其他 Webhook 保护措施:
- 请求体大小限制:最大 1 MB
- 读取超时:30 秒
- Content-Type 强制校验:仅接受
application/json
WebSocket 调优
使用 websocket 模式时,可自定义重连与心跳行为:
platforms:
feishu:
extra:
ws_reconnect_interval: 120 # Seconds between reconnect attempts (default: 120)
ws_ping_interval: 30 # Seconds between WebSocket pings (optional; SDK default if unset)
| 设置 | 配置项 | 默认值 | 说明 |
|---|---|---|---|
| 重连间隔 | ws_reconnect_interval | 120s | 重连尝试之间的等待时间 |
| 心跳间隔 | ws_ping_interval | (SDK 默认值) | WebSocket 保持连接的心跳频率 |
按群组访问控制
除了全局设置的 FEISHU_GROUP_POLICY 外,您还可以通过 config.yaml 中的 group_rules 设置更细粒度的群组规则:
platforms:
feishu:
extra:
default_group_policy: "open" # Default for groups not in group_rules
admins: # Users who can manage bot settings
- "ou_admin_open_id"
group_rules:
"oc_group_chat_id_1":
policy: "allowlist" # open | allowlist | blacklist | admin_only | disabled
allowlist:
- "ou_user_open_id_1"
- "ou_user_open_id_2"
"oc_group_chat_id_2":
policy: "admin_only"
"oc_group_chat_id_3":
policy: "blacklist"
blacklist:
- "ou_blocked_user"
| 策略 | 说明 |
|---|---|
open | 群组内任何人均可使用机器人 |
allowlist | 仅群组内 allowlist 成员可使用机器人 |
blacklist | 除群组 blacklist 成员外,其余人皆可使用 |
admin_only | 仅全局 admins 列表中的用户可在本群使用机器人 |
disabled | 机器人忽略此群组的所有消息 |
未在 group_rules 中列出的群组将回退至 default_group_policy(默认值为 FEISHU_GROUP_POLICY)。
去重机制
入站消息通过消息 ID 进行去重,有效期为 24 小时。去重状态会在重启之间持久化至 ~/.hermes/feishu_seen_message_ids.json。
| 设置 | 环境变量 | 默认值 |
|---|---|---|
| 缓存大小 | HERMES_FEISHU_DEDUP_CACHE_SIZE | 2048 条记录 |
所有环境变量| 变量 | 必填 | 默认值 | 说明 |
|------|------|--------|------|
| FEISHU_APP_ID | ✅ | — | 飞书/飞书Lark 应用 ID |
| FEISHU_APP_SECRET | ✅ | — | 飞书/飞书Lark 应用密钥 |
| FEISHU_DOMAIN | — | feishu | feishu(中国区)或 lark(国际版) |
| FEISHU_CONNECTION_MODE | — | websocket | websocket 或 webhook |
| FEISHU_ALLOWED_USERS | — | (空) | 以逗号分隔的允许用户 open_id 列表(白名单) |
| FEISHU_HOME_CHANNEL | — | — | 定时任务/通知输出的聊天 ID |
| FEISHU_ENCRYPT_KEY | — | (空) | Webhook 签名验证的加密密钥 |
| FEISHU_VERIFICATION_TOKEN | — | (空) | Webhook 请求体认证的验证令牌 |
| FEISHU_GROUP_POLICY | — | allowlist | 群组消息策略:open、allowlist、disabled |
| FEISHU_BOT_OPEN_ID | — | (空) | 机器人的 open_id(用于 @提及检测) |
| FEISHU_BOT_USER_ID | — | (空) | 机器人的 user_id(用于 @提及检测) |
| FEISHU_BOT_NAME | — | (空) | 机器人的显示名称(用于 @提及检测) |
| FEISHU_WEBHOOK_HOST | — | 127.0.0.1 | Webhook 服务器绑定地址 |
| FEISHU_WEBHOOK_PORT | — | 8765 | Webhook 服务器端口 |
| FEISHU_WEBHOOK_PATH | — | /feishu/webhook | Webhook 接收路径 |
| HERMES_FEISHU_DEDUP_CACHE_SIZE | — | 2048 | 跟踪去重消息 ID 的最大数量 |
| HERMES_FEISHU_TEXT_BATCH_DELAY_SECONDS | — | 0.6 | 文本消息合并的去抖静默期 |
| HERMES_FEISHU_TEXT_BATCH_MAX_MESSAGES | — | 8 | 单次文本批次最多合并的消息数 |
| HERMES_FEISHU_TEXT_BATCH_MAX_CHARS | — | 4000 | 单次文本批次最多合并的字符数 |
| HERMES_FEISHU_MEDIA_BATCH_DELAY_SECONDS | — | 0.8 | 媒体消息合并的去抖静默期 |
WebSocket 及按群组访问控制(ACL)设置通过在 config.yaml 下配置 platforms.feishu.extra 实现(详见 WebSocket 调优 和 按群组访问控制 部分)。
故障排查
| 问题 | 解决方法 |
|---|---|
lark-oapi not installed | 安装 SDK:pip install lark-oapi |
websockets not installed; websocket mode unavailable | 安装 websockets:pip install websockets |
aiohttp not installed; webhook mode unavailable | 安装 aiohttp:pip install aiohttp |
FEISHU_APP_ID or FEISHU_APP_SECRET not set | 同时设置两个环境变量,或通过 hermes gateway setup 配置 |
Another local Hermes gateway is already using this Feishu app_id | 同一 app_id 只能有一个 Hermes 实例运行。请先停止其他网关实例。 |
| 机器人在群组中无响应 | 确保机器人被 @ 提及,检查 FEISHU_GROUP_POLICY,并确认发送者在 FEISHU_ALLOWED_USERS 白名单中(若策略为 allowlist) |
Webhook rejected: invalid verification token | 确保 FEISHU_VERIFICATION_TOKEN 与飞书应用“事件订阅”配置中的令牌一致 |
Webhook rejected: invalid signature | 确保 FEISHU_ENCRYPT_KEY 与飞书应用配置中的加密密钥一致 |
| 发送消息显示为纯文本 | 飞书 API 拒绝了消息内容;这是正常降级行为。请查看日志获取详细信息。 |
| 图片/文件未被机器人接收 | 为飞书应用授予 im:message 和 im:resource 权限范围 |
| 机器人身份无法自动识别 | 授予 admin:app.info:readonly 权限范围,或手动设置 FEISHU_BOT_OPEN_ID / FEISHU_BOT_NAME |
| 点击审批按钮时报错 200340 | 在飞书开发者控制台启用 交互卡片 功能,并配置 卡片请求 URL。参见上方 飞书应用必要配置 |
Webhook rate limit exceeded | 同一 IP 地址每分钟超过 120 次请求。通常为配置错误或循环调用所致。 |
工具集
飞书 / Lark 使用 hermes-feishu 平台预设,包含与 Telegram 等基于网关的消息平台相同的底层工具集。