飞书 / Lark 设置

Hermes Agent 以功能完备的机器人形式集成飞书和 Lark。连接后,您可以在私聊或群聊中与代理对话,在家聊中接收定时任务结果,并通过标准网关流程发送文本、图片、音频和文件附件。

集成支持两种连接模式:

  • websocket — 推荐;Hermes 发起出站连接,无需公共 webhook 端点
  • webhook — 当您希望飞书/Lark 通过 HTTP 推送事件到网关时使用

Hermes 的行为

上下文行为
私聊Hermes 回复每一条消息。
群聊仅在群聊中 @提及 机器人时回复。
共享群聊默认情况下,共享群聊内按用户隔离会话历史。

共享群聊行为通过 config.yaml 控制:

group_sessions_per_user: true

仅当您明确希望每个群共享一个对话时,将其设置为 false

第一步:创建飞书/Lark 应用

推荐:扫码创建(一条命令)

hermes gateway setup

选择 飞书 / Lark 并使用飞书或 Lark 手机应用扫描二维码。Hermes 将自动创建一个具有正确权限的机器人应用并保存凭证。

备选:手动设置

如果扫码创建不可用,向导会回退到手动输入:

  1. 打开飞书或 Lark 开发者控制台:
  2. 创建新应用。
  3. 凭证与基础信息 中,复制 App IDApp Secret
  4. 为应用启用 机器人 能力。
  5. 运行 hermes gateway setup,选择 飞书 / Lark,按提示输入凭证。

:::warning 保持 App Secret 私密。任何人拥有它都可以冒充您的应用。 :::

第二步:选择连接模式

推荐:WebSocket 模式

当 Hermes 运行在笔记本电脑、工作站或私有服务器上时,使用 WebSocket 模式。无需公共 URL。官方的 Lark SDK 打开并维护一个持久的出站 WebSocket 连接,具有自动重连功能。

FEISHU_CONNECTION_MODE=websocket

要求: 必须安装 websockets Python 包。SDK 内部处理连接生命周期、心跳和自动重连。

工作原理: 适配器在后台执行器线程中运行 Lark SDK 的 WebSocket 客户端。入站事件(消息、反应、卡片操作)被分发到主 asyncio 循环。断开连接时,SDK 将自动尝试重连。

可选:Webhook 模式

仅当您已经在可访问的 HTTP 端点后面运行 Hermes 时,使用 webhook 模式。

FEISHU_CONNECTION_MODE=webhook

在 webhook 模式下,Hermes 启动一个 HTTP 服务器(通过 aiohttp)并在以下地址提供飞书端点:

/feishu/webhook

要求: 必须安装 aiohttp Python 包。

您可以自定义 webhook 服务器的绑定地址和路径:

FEISHU_WEBHOOK_HOST=127.0.0.1   # 默认:127.0.0.1
FEISHU_WEBHOOK_PORT=8765         # 默认:8765
FEISHU_WEBHOOK_PATH=/feishu/webhook  # 默认:/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
 
# 可选但强烈推荐
FEISHU_ALLOWED_USERS=ou_xxx,ou_yyy
FEISHU_HOME_CHANNEL=oc_xxx

FEISHU_DOMAIN 可接受:

  • feishu 用于飞书中国版
  • lark 用于 Lark 国际版

第四步:启动网关

hermes gateway

然后从飞书/Lark 给机器人发送消息以确认连接正常。

家聊

在飞书/Lark 聊天中使用 /set-home 将其标记为定时任务结果和跨平台通知的家聊频道。

您也可以预先配置:

FEISHU_HOME_CHANNEL=oc_xxx

安全

用户白名单

生产环境中,设置飞书 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。

:::tip 在 WebSocket 模式下,签名验证由 SDK 本身处理,因此 FEISHU_ENCRYPT_KEY 是可选的。在 webhook 模式下,强烈建议生产环境中使用。 :::

验证令牌

另一层身份验证,检查 webhook 负载中的 token 字段:

FEISHU_VERIFICATION_TOKEN=your-verification-token

该令牌同样在飞书应用的 事件订阅 部分找到。设置后,每个入站 webhook 负载必须在其 header 对象中包含匹配的 token。不匹配的令牌将被拒绝,返回 HTTP 401。

FEISHU_ENCRYPT_KEYFEISHU_VERIFICATION_TOKEN 可以同时使用,实现纵深防御。

群消息策略

FEISHU_GROUP_POLICY 环境变量控制 Hermes 在群聊中是否以及如何回复:

FEISHU_GROUP_POLICY=allowlist   # 默认
行为
openHermes 响应任何群中任何用户的 @提及。
allowlistHermes 仅响应 FEISHU_ALLOWED_USERS 中列出的用户的 @提及。
disabledHermes 完全忽略所有群消息。

在所有模式下,消息处理前必须显式 @提及(或 @all)机器人。私聊始终绕过此限制。

设置 FEISHU_REQUIRE_MENTION=false 让 Hermes 读取所有群消息而不要求 @提及:

FEISHU_REQUIRE_MENTION=false

如需按聊天控制,在 group_rules 条目上设置 require_mention——请参见下文 按群访问控制

机器人身份

Hermes 在启动时自动检测机器人的 open_id 和显示名称。仅当自动检测无法访问飞书 API,或您的应用使用租户范围的用户 ID 时,才需要手动设置:

FEISHU_BOT_OPEN_ID=ou_xxx     # 仅在自动检测失败时
FEISHU_BOT_USER_ID=xxx        # 如果您的应用使用 sender_id_type=user_id 则需要
FEISHU_BOT_NAME=MyBot         # 仅在自动检测失败时

机器人与机器人消息

默认情况下,Hermes 忽略其他机器人发送的消息。当您希望 Hermes 参与 A2A 编排或接收同一群中其他机器人的通知时,启用机器人与机器人消息。

FEISHU_ALLOW_BOTS=mentions   # 默认:none
行为
none忽略所有来自其他机器人的消息(默认)。
mentions仅当对方机器人 @提及 Hermes 时接受。
all接受所有对方机器人的消息。

也可在 config.yaml 中配置为 feishu.allow_bots(同时设置时环境变量优先)。

对方机器人无需添加到 FEISHU_ALLOWED_USERS——该白名单仅适用于人类发送者。

授予 application:bot.basic_info:read 权限范围以显示对方机器人名称;没有此权限,对方机器人仍能正确路由,但会显示为其 open_id

交互式卡片操作

当用户点击机器人发送的交互式卡片上的按钮时,适配器将这些操作路由为合成 /card 命令事件:

  • 按钮点击变为:/card button {"key": "value", ...}
  • 卡片定义中的操作 value 负载以 JSON 形式包含
  • 卡片操作在 15 分钟窗口内去重,防止重复处理

网关驱动的更新提示使用原生飞书 / 卡片,而不是回退到纯文本回复。当 hermes update --gateway 需要确认时,适配器记录选中的答案到 Hermes 的 .update_response 文件中,并以内联方式将卡片替换为已解决状态。

卡片操作事件以 MessageType.COMMAND 分发,因此它们流经正常的命令处理管道。

这也是命令审批的工作方式——当代理需要运行危险命令时,它会发送一个带有”允许一次”/“会话”/“始终允许”/“拒绝”按钮的交互式卡片。用户点击按钮,卡片操作回调将审批决定返回给代理。

必需的飞书应用配置

交互式卡片需要在飞书开发者控制台中执行三个配置步骤。缺少任何一个都会在用户点击卡片按钮时导致错误 200340

  1. 订阅卡片操作事件:事件订阅 中,添加 card.action.trigger 到您订阅的事件。

  2. 启用交互式卡片能力:应用功能 > 机器人 中,确保 交互式卡片 开关已启用。这告诉飞书您的应用可以接收卡片操作回调。

  3. 配置卡片请求 URL(仅 webhook 模式):应用功能 > 机器人 > 消息卡片请求网址 中,将 URL 设置为与事件 webhook 相同的端点(例如 https://your-server:8765/feishu/webhook)。在 WebSocket 模式下,SDK 自动处理此设置。

:::warning 缺少所有三个步骤,飞书可以成功发送交互式卡片(发送仅需要 im:message:send 权限),但点击任何按钮都会返回错误 200340。卡片看起来正常——错误仅在用户与之交互时才会出现。 :::

文档评论智能回复

除了聊天,适配器还可以回答在飞书/Lark 文档上留下的 @ 提及评论。当用户在文档上评论(选择本地文本或整篇文档评论)并 @提及 机器人时,Hermes 会读取文档及周围的评论线程,并在该线程内联发布 LLM 回复。

drive.notice.comment_add_v1 事件驱动,处理程序:

  • 并行获取文档内容和评论时间线(整篇文档线程 20 条消息,本地选择线程 12 条)
  • 使用限定于该单一评论会话的 feishu_doc + feishu_drive 工具集运行代理
  • 将回复以 4000 字符分块,并以线程回复形式发布
  • 每文档会话缓存 1 小时,上限 50 条消息,以便同一文档上的后续评论保持上下文

3 层访问控制

文档评论回复为显式授权模式——没有隐式的允许所有模式。权限按此顺序解析(按字段优先,先匹配者胜出):

  1. 精确文档 — 限定于特定文档 token 的规则。
  2. 通配符 — 匹配一组文档模式的规则。
  3. 顶层 — 工作区的默认规则。

每个规则有两种策略可用:

  • allowlist — 静态的用户/租户列表。
  • pairing — 静态列表 ∪ 运行时批准的存储。适用于版主可以实时授予访问权限的推广场景。

规则保存在 ~/.hermes/feishu_comment_rules.json 中(配对授权保存在 ~/.hermes/feishu_comment_pairing.json),具有 mtime 缓存热重载——编辑后在下一次评论事件时生效,无需重启网关。

CLI:

# 查看当前规则和配对状态
python -m gateway.platforms.feishu_comment_rules status
 
# 模拟特定文档 + 用户的访问检查
python -m gateway.platforms.feishu_comment_rules check <fileType:fileToken> <user_open_id>
 
# 运行时管理配对授权
python -m gateway.platforms.feishu_comment_rules pairing list
python -m gateway.platforms.feishu_comment_rules pairing add <user_open_id>
python -m gateway.platforms.feishu_comment_rules pairing remove <user_open_id>

必需的飞书应用配置

在已授予的聊天/卡片权限基础上,添加文档评论事件:

  • 事件订阅 中订阅 drive.notice.comment_add_v1
  • 授予 docs:doc:readonlydrive:drive:readonly 权限范围,以便处理程序读取文档内容。

媒体支持

入站(接收)

适配器接收并缓存来自用户的以下媒体类型:

类型扩展名处理方式
图片.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 等下载并作为文档缓存

来自富文本(post)消息的媒体,包括内联图片和文件附件,也会被提取和缓存。

对于小型基于文本的文档(.txt, .md),文件内容会自动注入到消息文本中,以便代理无需工具即可直接阅读。

出站(发送)

方法发送内容
send文本或富文本 post 消息(基于 markdown 内容自动检测)
send_image / send_image_file上传图片到飞书,然后作为原生图片气泡发送(可选带标题)
send_document上传文件到飞书 API,然后作为文件附件发送
send_voice上传音频文件作为飞书文件附件
send_video上传视频并作为原生媒体消息发送
send_animationGIF 降级为文件附件(飞书没有原生 GIF 气泡)

文件上传路由基于扩展名自动处理:

  • .ogg, .opus → 作为 opus 音频上传
  • .mp4, .mov, .avi, .m4v → 作为 mp4 媒体上传
  • .pdf, .doc(x), .xls(x), .ppt(x) → 按其文档类型上传
  • 其他所有内容 → 作为通用流文件上传

Markdown 渲染与 Post 回退

当出站文本包含 markdown 格式(标题、粗体、列表、代码块、链接等)时,适配器自动将其作为飞书 post 消息发送,其中包含嵌入的 md 标签,而不是纯文本。这使得在飞书客户端中实现富文本渲染。

如果飞书 API 拒绝 post 负载(例如由于不支持的 markdown 构造),适配器会自动回退到以纯文本形式发送(去除 markdown)。这种两阶段回退确保消息始终能够送达。

纯文本消息(未检测到 markdown)以简单的 text 消息类型发送。

处理状态反应

代理工作时,机器人会在您的消息上显示一个 Typing 反应。回复到达时清除,如果处理失败则替换为 CrossMark

设置 FEISHU_REACTIONS=false 可关闭此功能。

突发保护与批处理

适配器包括针对快速消息突发的去抖处理,以避免压垮代理:

文本批处理

当用户快速连续发送多条文本消息时,它们会在分发前合并为单个事件:

设置环境变量默认值
静默期HERMES_FEISHU_TEXT_BATCH_DELAY_SECONDS0.6秒
每批最大消息数HERMES_FEISHU_TEXT_BATCH_MAX_MESSAGES8
每批最大字符数HERMES_FEISHU_TEXT_BATCH_MAX_CHARS4000

媒体批处理

快速连续发送的多个媒体附件(例如拖入多张图片)会合并为单个事件:

设置环境变量默认值
静默期HERMES_FEISHU_MEDIA_BATCH_DELAY_SECONDS0.8秒

按聊天串行化

同一聊天内的消息按顺序处理(一次一条)以保持对话连贯性。每个聊天有自己的锁,因此不同聊天的消息可以并发处理。

速率限制(Webhook 模式)

在 webhook 模式下,适配器实施按 IP 的速率限制以防止滥用:

  • 窗口: 60 秒滑动窗口
  • 限制: 每个窗口每 (app_id, path, IP) 三元组 120 个请求
  • 跟踪上限: 最多跟踪 4096 个唯一键(防止无限制的内存增长)

超过限制的请求会收到 HTTP 429(请求过多)。

Webhook 异常跟踪

适配器跟踪每个 IP 地址的连续错误响应。在 6 小时窗口内同一 IP 出现 25 次连续错误后,会记录警告。这有助于发现配置错误的客户端或探测尝试。

其他 webhook 保护:

  • 正文大小限制: 最大 1 MB
  • 正文读取超时: 30 秒
  • Content-Type 强制: 仅接受 application/json

WebSocket 调优

使用 websocket 模式时,您可以自定义重连和心跳行为:

platforms:
  feishu:
    extra:
      ws_reconnect_interval: 120   # 重连尝试之间的秒数(默认:120)
      ws_ping_interval: 30         # WebSocket 心跳 ping 之间的秒数(可选;未设置时使用 SDK 默认值)
设置配置键默认值描述
重连间隔ws_reconnect_interval120秒重连尝试之间的等待时间
Ping 间隔ws_ping_interval(SDK 默认值)WebSocket 保活 ping 的频率

按群访问控制

除了全局的 FEISHU_GROUP_POLICY,您还可以使用 config.yaml 中的 group_rules 为每个群聊设置细粒度规则:

platforms:
  feishu:
    extra:
      default_group_policy: "open"     # 未在 group_rules 中的群的默认值
      admins:                          # 可管理机器人设置的用户
        - "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"
        "oc_free_chat":
          policy: "open"
          require_mention: false       # 为此聊天覆盖 FEISHU_REQUIRE_MENTION
策略描述
open群内任何人都可以使用机器人
allowlist仅在群 allowlist 中的用户可以使用机器人
blacklist除了群 blacklist 中的用户外,其他人都可以使用机器人
admin_only仅在全局 admins 列表中的用户可以在该群使用机器人
disabled机器人忽略此群中的所有消息

group_rules 条目上设置 require_mention: false 以跳过该特定聊天的 @提及 要求。省略时,该聊天继承全局 FEISHU_REQUIRE_MENTION 值。

未在 group_rules 中列出的群回退到 default_group_policy(默认为 FEISHU_GROUP_POLICY 的值)。

去重

入站消息使用消息 ID 去重,TTL 为 24 小时。去重状态在重启后持久化到 ~/.hermes/feishu_seen_message_ids.json

设置环境变量默认值
缓存大小HERMES_FEISHU_DEDUP_CACHE_SIZE2048 条

所有环境变量

变量必填默认值描述
FEISHU_APP_ID飞书/Lark App ID
FEISHU_APP_SECRET飞书/Lark App Secret
FEISHU_DOMAINfeishufeishu(中国版)或 lark(国际版)
FEISHU_CONNECTION_MODEwebsocketwebsocketwebhook
FEISHU_ALLOWED_USERS(空)逗号分隔的 open_id 用户白名单
FEISHU_ALLOW_BOTSnone接受来自其他机器人的消息:nonementionsall
FEISHU_REQUIRE_MENTIONtrue群消息是否需要 @提及 机器人
FEISHU_HOME_CHANNEL定时任务/通知输出的聊天 ID
FEISHU_ENCRYPT_KEY(空)webhook 签名验证的加密密钥
FEISHU_VERIFICATION_TOKEN(空)webhook 负载认证的验证令牌
FEISHU_GROUP_POLICYallowlist群消息策略:openallowlistdisabled
FEISHU_BOT_OPEN_ID(空)机器人的 open_id(用于 @提及 检测)
FEISHU_BOT_USER_ID(空)机器人的 user_id(用于 @提及 检测)
FEISHU_BOT_NAME(空)机器人的显示名称(用于 @提及 检测)
FEISHU_WEBHOOK_HOST127.0.0.1Webhook 服务器绑定地址
FEISHU_WEBHOOK_PORT8765Webhook 服务器端口
FEISHU_WEBHOOK_PATH/feishu/webhookWebhook 端点路径
HERMES_FEISHU_DEDUP_CACHE_SIZE2048最大去重消息 ID 跟踪数
HERMES_FEISHU_TEXT_BATCH_DELAY_SECONDS0.6文本突发去抖静默期
HERMES_FEISHU_TEXT_BATCH_MAX_MESSAGES8每文本批最大合并消息数
HERMES_FEISHU_TEXT_BATCH_MAX_CHARS4000每文本批最大合并字符数
HERMES_FEISHU_MEDIA_BATCH_DELAY_SECONDS0.8媒体突发去抖静默期

WebSocket 和按群 ACL 设置通过 config.yamlplatforms.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同一时间只有一个 Hermes 实例可以使用同一个 app_id。先停止另一个网关。
机器人在群中不回复确保 @提及 了机器人,检查 FEISHU_GROUP_POLICY,如果策略为 allowlist 则确认发送者在 FEISHU_ALLOWED_USERS
Webhook rejected: invalid verification token确保 FEISHU_VERIFICATION_TOKEN 与飞书应用事件订阅配置中的令牌匹配
Webhook rejected: invalid signature确保 FEISHU_ENCRYPT_KEY 与飞书应用配置中的加密密钥匹配
Post 消息显示为纯文本飞书 API 拒绝了 post 负载;这是正常的回退行为。查看日志了解详情。
机器人未收到图片/文件在飞书应用中授予 im:messageim:resource 权限范围
机器人身份未自动检测通常是访问飞书机器人信息端点的临时网络问题。手动设置 FEISHU_BOT_OPEN_IDFEISHU_BOT_NAME 作为临时解决方案。
启用 FEISHU_ALLOW_BOTS 后仍忽略对方机器人消息Hermes 尚无法识别自身——设置 FEISHU_BOT_OPEN_ID(如果您的应用使用 sender_id_type=user_id,还需设置 FEISHU_BOT_USER_ID)。
对方机器人显示为 ou_xxxxxx 而非名称授予 application:bot.basic_info:read 权限范围。
点击审批按钮时出现错误 200340在飞书开发者控制台中启用 交互式卡片 能力并配置 卡片请求 URL。请参见上文 必需的飞书应用配置
Webhook rate limit exceeded来自同一 IP 的请求超过 120 次/分钟。这通常是配置错误或循环。

工具集

飞书 / Lark 使用 hermes-feishu 平台预设,其中包含与 Telegram 和其他基于网关的消息平台相同的核心工具。