[Bug] 飞书定时任务通知窜台:通知始终从苹果发出而非Agent对应的机器人 #37

Closed
opened 2026-05-06 00:29:59 +08:00 by admin · 0 comments
Owner

问题描述

用户在飞书通过灵犀(或其他机器人)设置的定时任务,到时间后执行结果通知始终从「苹果」发出,而非从创建任务的机器人发出("窜台"现象)。

现象链路

  1. 用户在灵犀飞书应用中创建定时任务
  2. 定时任务到期,Agent 执行完成
  3. 通知发送时优先尝试用灵犀 App 发送 → 飞书返回 code=99992361 msg=open_id cross app → 失败
  4. 回退到苹果 App 发送 → 成功(因为 feishu_open_id 是苹果的)
  5. 用户收到的通知来自苹果,而非灵犀

根因分析

飞书 open_id 机制

飞书的 open_id 是按应用隔离的。同一个用户在不同飞书应用中拥有完全不同的 open_id。但飞书的 union_id 在同一租户下跨所有应用相同,可用于跨应用识别用户。

代码根因(两层)

第一层:存储结构缺陷

  • users 表只有一个 feishu_open_id 字段,存储的是苹果应用下的 open_id
  • 没有存储其他应用(灵犀/橙子/苏瑶/甜甜)的 open_id
  • 导致发送通知时只能用苹果的 open_id

第二层:跨应用关联缺失

  • 苹果绑定流程没有获取 union_id,导致苹果记录中 union_id=NULL
  • 用户消息灵犀后,灵犀的 open_id + union_id 被捕获,但因苹果记录无 union_id,无法跨应用匹配到同一用户
  • 灵犀记录保存为 user_id=NULL(未关联),通知时查找不到

影响范围

所有非苹果的飞书机器人(灵犀/橙子/苏瑶/甜甜)的定时任务通知都会窜台到苹果。

修复方案

1. 新建多应用 open_id 映射表

user_feishu_open_ids:
  - user_id    -- 平台用户 ID(可空,首次捕获时可能未知)
  - app_id     -- 飞书应用 app_id
  - open_id    -- 该应用下的用户 open_id
  - union_id   -- 飞书 union_id(跨应用唯一,用于关联)

2. WS Handler 自动捕获与关联

所有 5 个飞书 WS handler 收到用户消息时自动捕获 open_id + union_id,通过 resolve_user_and_save() 自动识别用户并保存关联。

3. 通知路由改用 per-app open_id

notify_schedule_result 改为先查该用户在此应用下的专属 open_id,找到则用对应应用发送;未找到则回退苹果。

4. 绑定流程增强

绑定苹果时同步调用飞书 Contact API 获取并存储 union_id,使跨应用自动关联成为可能。

涉及文件(10个)

文件 改动
app/models/user_feishu_open_id.py 新建 — 多应用 open_id 映射表模型
app/models/init.py 导入新模型
app/services/feishu_open_id_service.py 新建 — per-app open_id 管理工具函数
app/services/feishu_app_service.py 新增 lookup_union_id_by_open_id()
app/services/feishu_ws_handler.py 新增 union_id 提取 + resolve_user_and_save
app/services/lingxi_ws_handler.py 同上
app/services/orange_ws_handler.py 同上
app/services/suyao_ws_handler.py 同上
app/services/tiantian_ws_handler.py 同上
app/services/agent_schedule_service.py 通知路由改用 per-app open_id 查询
app/api/feishu_bind.py 绑定时同步获取 union_id

严重程度

中等 — 功能可用但通知来源错误,影响多机器人场景下的用户体验。

测试验证

  1. 用户分别在苹果和灵犀飞书应用中发消息
  2. 通过灵犀创建定时任务
  3. 任务到期后验证通知从灵犀发出(非苹果)
## 问题描述 用户在飞书通过灵犀(或其他机器人)设置的定时任务,到时间后执行结果通知始终从「苹果」发出,而非从创建任务的机器人发出("窜台"现象)。 ### 现象链路 1. 用户在灵犀飞书应用中创建定时任务 2. 定时任务到期,Agent 执行完成 3. 通知发送时优先尝试用灵犀 App 发送 → 飞书返回 `code=99992361 msg=open_id cross app` → 失败 4. 回退到苹果 App 发送 → 成功(因为 `feishu_open_id` 是苹果的) 5. 用户收到的通知来自苹果,而非灵犀 ## 根因分析 ### 飞书 open_id 机制 飞书的 `open_id` 是按应用隔离的。同一个用户在不同飞书应用中拥有完全不同的 open_id。但飞书的 `union_id` 在同一租户下跨所有应用相同,可用于跨应用识别用户。 ### 代码根因(两层) **第一层:存储结构缺陷** - `users` 表只有一个 `feishu_open_id` 字段,存储的是苹果应用下的 open_id - 没有存储其他应用(灵犀/橙子/苏瑶/甜甜)的 open_id - 导致发送通知时只能用苹果的 open_id **第二层:跨应用关联缺失** - 苹果绑定流程没有获取 `union_id`,导致苹果记录中 `union_id=NULL` - 用户消息灵犀后,灵犀的 open_id + union_id 被捕获,但因苹果记录无 union_id,无法跨应用匹配到同一用户 - 灵犀记录保存为 `user_id=NULL`(未关联),通知时查找不到 ### 影响范围 所有非苹果的飞书机器人(灵犀/橙子/苏瑶/甜甜)的定时任务通知都会窜台到苹果。 ## 修复方案 ### 1. 新建多应用 open_id 映射表 ``` user_feishu_open_ids: - user_id -- 平台用户 ID(可空,首次捕获时可能未知) - app_id -- 飞书应用 app_id - open_id -- 该应用下的用户 open_id - union_id -- 飞书 union_id(跨应用唯一,用于关联) ``` ### 2. WS Handler 自动捕获与关联 所有 5 个飞书 WS handler 收到用户消息时自动捕获 open_id + union_id,通过 `resolve_user_and_save()` 自动识别用户并保存关联。 ### 3. 通知路由改用 per-app open_id `notify_schedule_result` 改为先查该用户在此应用下的专属 open_id,找到则用对应应用发送;未找到则回退苹果。 ### 4. 绑定流程增强 绑定苹果时同步调用飞书 Contact API 获取并存储 `union_id`,使跨应用自动关联成为可能。 ## 涉及文件(10个) | 文件 | 改动 | |------|------| | app/models/user_feishu_open_id.py | 新建 — 多应用 open_id 映射表模型 | | app/models/__init__.py | 导入新模型 | | app/services/feishu_open_id_service.py | 新建 — per-app open_id 管理工具函数 | | app/services/feishu_app_service.py | 新增 lookup_union_id_by_open_id() | | app/services/feishu_ws_handler.py | 新增 union_id 提取 + resolve_user_and_save | | app/services/lingxi_ws_handler.py | 同上 | | app/services/orange_ws_handler.py | 同上 | | app/services/suyao_ws_handler.py | 同上 | | app/services/tiantian_ws_handler.py | 同上 | | app/services/agent_schedule_service.py | 通知路由改用 per-app open_id 查询 | | app/api/feishu_bind.py | 绑定时同步获取 union_id | ## 严重程度 中等 — 功能可用但通知来源错误,影响多机器人场景下的用户体验。 ## 测试验证 1. 用户分别在苹果和灵犀飞书应用中发消息 2. 通过灵犀创建定时任务 3. 任务到期后验证通知从灵犀发出(非苹果)
admin self-assigned this 2026-05-06 00:29:59 +08:00
admin closed this issue 2026-05-06 21:13:02 +08:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/aiagent#37