文档: 提交重整处方与在飞收尾

This commit is contained in:
lxy
2026-10-04 16:31:17 +08:00
parent b994cf2c54
commit 91773da602
3 changed files with 186 additions and 0 deletions
+1
View File
@@ -90,6 +90,7 @@
| [多Agent并行执行与仲裁合并设计-2026-07-01.md](./专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md) | 📐 设计 | 混合数据模型(messages加FK列+Plan/SubTask/Conflict独立表)、Git worktree隔离、JoinSet层内并行、四层冲突防线、Reviewer仲裁、事件协议、UI交互 | | [多Agent并行执行与仲裁合并设计-2026-07-01.md](./专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md) | 📐 设计 | 混合数据模型(messages加FK列+Plan/SubTask/Conflict独立表)、Git worktree隔离、JoinSet层内并行、四层冲突防线、Reviewer仲裁、事件协议、UI交互 |
| [后续批次测试用例设计-2026-07-01.md](./专项设计/后续批次测试用例设计-2026-07-01.md) | 📐 测试 | 多Agent并行/worktree隔离/仲裁合并/模板系统/Git-CI/审批政策 的单元+集成+端到端测试用例 | | [后续批次测试用例设计-2026-07-01.md](./专项设计/后续批次测试用例设计-2026-07-01.md) | 📐 测试 | 多Agent并行/worktree隔离/仲裁合并/模板系统/Git-CI/审批政策 的单元+集成+端到端测试用例 |
| [测试落地实施方案-2026-07-01.md](./专项设计/测试落地实施方案-2026-07-01.md) | 📐 测试 | 各测试用例的落地方式(Rust 单元/集成/vitest/E2E 手动)、文件位置、Mock 策略、CI 自动化路径 | | [测试落地实施方案-2026-07-01.md](./专项设计/测试落地实施方案-2026-07-01.md) | 📐 测试 | 各测试用例的落地方式(Rust 单元/集成/vitest/E2E 手动)、文件位置、Mock 策略、CI 自动化路径 |
| [devflow集成三方IM-飞书企微钉钉Web-规划设计-2026-10-04.md](./专项设计/devflow集成三方IM-飞书企微钉钉Web-规划设计-2026-10-04.md) | 📐 规划(待评审) | 飞书/企微/钉钉/自定义Web 远程接入 AI Chat:新增 df-im-gateway(WS Commander)复用 u-relay+df-tunnel,桌面端零改动。含必要性分析(§三A)、破坏性分析(§三B)、演进预留(§十 S1-S4:多人/引擎上云/新端)。P0网关→P1 Web→P2飞书→P3钉钉→P4企微 |
--- ---
@@ -0,0 +1,154 @@
# DevFlow 集成三方 IM + 自定义 Web:AI Chat 远程接入规划
> 创建: 2026-10-04 | 状态: 📐 规划设计(待评审)
> 上级索引: [../INDEX.md](../INDEX.md) | 姊妹篇: [F-260620-01-跨端AIChat-微信小程序](../已编号方案/F-260620-01-跨端AIChat-微信小程序-2026-06-20.md)
## 一、目标与范围
在**飞书、企业微信、钉钉**三个 IM 内以及**自定义 Web 页面**中远程使用 DevFlow AI Chat:发消息、停止、重新生成、审批工具调用、切换会话——体验对齐桌面端。
**范围外**(本期不做):IM 内直接查看项目/任务列表等富 UI(依赖对话即入口,由 AI 工具调用返回文本结果);多人协作/团队版。
## 二、现状盘点(可复用的基础设施)
| 组件 | 现状 | 复用方式 |
|------|------|----------|
| `u-relay`(E:/wk-lab/u-relay) | 生产运行(u-relay.1216.top:9180,nginx+systemd),channel_id 配对点对点转发,payload 透传零业务耦合,25 项测试 | 直接复用,IM 网关作为新 Commander 接入 |
| `df-tunnel`(devflow crate) | 桌面端出站 WS 隧道(Agent 角色),已实现 TunnelCommand 五指令路由(Send/Stop/Approve/Regenerate/Switch)+ TunnelEvent 四事件透传(TextDelta/ToolCall/Approval/Completed)+ 指数退避重连 | **零改动**,桌面端不感知控制端是小程序还是 IM 机器人 |
| `df-miniapp`(小程序端) | F-260620-01 方案先行(Commander 模式先例) | 自定义 Web 端直接套用该模式 |
| AI Chat 引擎 | Agentic Loop + 工具审批,多会话 conv_id 路由(F-09) | 不动,仅靠隧道透传 |
**核心洞察**:三方 IM 机器人 + 自定义 Web = 新增的 **Commander 端**。桌面端(Agent)与 AI 引擎完全无感,全部新增工作收敛在「网关层」。
## 三、总体架构:IM 网关(df-im-gateway)
```
飞书 ─┐ ┌─ DevFlow 桌面端 (Agent)
企微 ─┼─► df-im-gateway ──WS Commander──► u-relay ──WS Agent ──┤ df-tunnel + AI Chat 引擎
钉钉 ─┤ (新增,Rust 独立服务) (生产已有,零改动) │ (零改动)
Web ──┘ 协议转换: IM API/回调 ↔ TunnelCommand/TunnelEvent └─ 多桌面端=多 channel_id
```
**df-im-gateway 职责**(唯一新增组件):
1. 以 WS Commander 身份连 u-relay(每条 channel 绑一个 DevFlow 桌面端)
2. 接收 IM 平台事件(回调 Webhook 或长连接推送),转 `TunnelCommand::Send/Stop/Approve`
3. 接收 `TunnelEvent`,聚合节流后调各 IM 平台**消息 API** 回复(流式 → 卡片刷新或一次性回复)
4. `Approval` 事件 → 发交互卡片(同意/拒绝按钮)→ 点击回填 `TunnelCommand::Approve`
5. IM 用户白名单 + channel_id 路由管理
**为什么独立服务而不并入 u-relay**:u-relay 的设计原则是「纯转发、零业务耦合、无外部依赖」。IM 对接需要凭证管理、回调验签、卡片模板、节流聚合等大量业务逻辑,塞进去会让中继失控。独立部署同机即可。
**语言选型 Rust**:直接 path 引用 df-tunnel 的 `TunnelCommand/TunnelEvent` 类型(同 workspace 或 git 依赖),编译时保证协议类型一致——这正是 F-260620-01 已论证的 Rust 中继优势。三方 IM SDK 均为 HTTP API,reqwest 直调即可,无 SDK 依赖硬伤。
## 三A、新组件必要性分析(df-im-gateway 为什么必须存在)
新增组件的正当性须逐一排除所有替代方案,全部不成立才立得住:
| 替代方案 | 排除理由 |
|---------|---------|
| **并入 u-relay** | ① u-relay 设计原则是「纯转发、payload 透传、零业务耦合、无外部依赖」,IM 对接需引入各平台 HTTP 客户端/AES 加解密/卡片模板/SQLite/节流器,塞入即毁掉其小审计面与高可用定位;② 故障域耦合:u-relay 是全局单点(小程序+IM+未来端全挂它),IM 平台 API 迭代快(钉钉卡片版本频繁),会让生产中继被迫高频重启;③ 二进制膨胀:3.6MB musl 单二进制的部署优势丧失 |
| **做进桌面端(df-tunnel/src-tauri)** | ① NAT 硬伤:企微回调必须公网 URL+可信 IP/域名,桌面端在内网/笔记本无法满足;飞书/钉钉长连接虽是出站,但桌面端休眠/离线时连「桌面端离线」提示都发不出(只有云端网关能兜底回复);② 桌面端会变成三套 IM 协议怪兽,Tauri 依赖拖重;③ 桌面端 IP 不固定、生命周期随人,不适合承载对外服务 |
| **Go/Node 跨语言独立服务** | 违背 F-260620-01 已论证的选型结论:TunnelCommand/TunnelEvent 跨语言镜像必然漂移,运行时消息丢失;Rust git 依赖 df-tunnel 类型 = 编译期协议一致 + 复用 publish-df-relay 同款 musl→scp→systemd 发布流水线。诚实 trade-off:飞书/钉钉官方 SDK 无 Rust 版需自写 HTTP 客户端,但均为标准 REST+签名协议,工作量可控 |
| **现成开源桥接器(onebot/matrix bridge 等)** | ① 三家 IM 官方机器人协议均非 onebot 标准,桥接器面向「自建聊天服务」场景,与「驱动本机 AI 引擎+工具审批」语义不匹配;② 审批按钮/卡片流式深度交互现成方案覆盖不了;③ 徒增第三方供应链风险 |
| **不做(维持现状)** | 需求价值真实:手机端随时驱动工作机 AI、审批卡片当场点掉无需回工位——是「桌面 AI 使用场景从工位扩展到任何地方」的产品能力增量,非技术炫技 |
**结论**:df-im-gateway 是「协议转换 + 凭证管理 + 公网可达性」三个约束的唯一交汇落点,必要性成立。
## 三B、破坏性分析(对既有系统的侵入面)
零改动承诺(桌面端/u-relay/AI 引擎)逐项压力测试,暴露真实破坏点:
| 受影响面 | 破坏性 | 等级 | 缓解/收敛策略 |
|---------|--------|------|--------------|
| **u-relay 双 Commander 并存语义** | 网关与 df-miniapp 同 channel 时:TunnelEvent 广播给两个 Commander → 双端重复回复用户;审批卡片双消费(小程序已点同意,IM 端卡片仍挂起可再点 → 重复 Approve) | 🔴 唯一高危点 | P0 实测 u-relay 多 Commander 投递行为;桌面端 Approve 处理按 approval_id 状态机幂等(pending→approved,二次点击无效——**待 P0 验证,若无则补**);过渡期运营约定同 channel 单活跃控制端;长期可演进「每端独立 channel + 桌面端多连接」(代价是破坏桌面端零改动,仅双端并存真实痛点出现时再议) |
| **df-tunnel 协议扩展压力** | IM 场景或需新指令/事件变体(如列会话、选择会话),触发桌面端升级 | 🟡 低 | 「新增变体只加不减」契约已内建向后兼容(serde `#[serde(other)]` 兜底);u-relay payload 透传对新变体天然无感;版本错配窗口仅存在于桌面端未升级期间 |
| **桌面端资源与连接** | 无新增常驻负担(仍是一条出站 WS,连接数不变) | 🟢 无 | — |
| **公网暴露面** | 攻击面从「u-relay 一个 WS 服务」扩大到「+网关 HTTP/WS(企微回调、Web Chat 端点)」 | 🟡 中 | 网关自身不执行任何命令/写盘(纯转发,真正工具执行仍在桌面端审批门禁之后);IM 用户白名单默认拒绝;审批分级(IM 端仅低风险工具) |
| **密钥面** | 三家 IM app_secret 新增落地,泄漏面 +1 | 🟡 中 | 网关 env/600 权限配置文件,不进 git;泄漏即换 secret 的应急预案 |
| **运维面** | 同机新增 systemd 服务(Rust 常驻 ~10-30MB)+ nginx +1 路由 | 🟢 低 | 发布节奏与 u-relay 解耦,互不牵连 |
| **数据一致性** | chat_id↔conv_id 映射漂移(桌面端删会话后悬空);IM 卡片状态与桌面端真实状态漂移(审批后卡片未刷新) | 🟡 低 | 映射悬空时网关回复「会话不存在」并自动清理重映射;卡片带状态版本号 + 过期失效文案 |
**总结论**:破坏性集中收敛于「双 Commander 并存」单点(🔴→🟡 可收敛),其余均为低危可控。零改动承诺成立——不需要为接入 IM 而改动任何现有生产组件;仅当未来「多控制端并存成常态」时才需重审 channel 架构。
## 四、四端集成模式对比
| 维度 | 飞书 | 企微 | 钉钉 | 自定义 Web |
|------|------|------|------|-----------|
| 应用形态 | 企业自建应用 | 企业自建应用 | 企业内部应用 + 机器人 | 网关托管静态页或桌面端内嵌页 |
| 事件接收 | **长连接模式**(官方 WS 推送,免公网回调)✅ | HTTP 回调(GET 验签 + POST AES 加密解密,需公网 URL) | **Stream Mode**(官方 WS 推送,免公网回调)✅ | 用户浏览器直连网关 HTTP/WS |
| 主动回复 | im/v1/messages(卡片消息) | 应用消息 send(Markdown 卡片) | 机器人发送 + 卡片 Stream 更新 | WS 推流(复用 df-miniapp 模式) |
| 流式体验 | 卡片流式更新(官方支持) | 消息可编辑(弱流式,节流刷新) | 卡片 AI 流式更新(官方支持) | 原生流式,体验最佳 |
| 审批按钮 | 交互卡片(最完善) | 按钮交互卡片(支持但样式受限) | 卡片回调按钮(支持) | 页面按钮(自由发挥) |
| 接入复杂度 | 中(长连接最省事) | 高(回调验签/AES/IP 白名单/可信域名) | 中 | 低(无三方审核) |
| 前置条件 | 管理员后台建应用+开权限 | 管理员后台建应用+配置可信 IP | 开放平台建应用+Stream 开关 | 无 |
**接入顺序建议**:Web(0 审核成本,先打通网关全链路)→ 飞书(长连接,免公网回调)→ 钉钉(Stream,同免公网)→ 企微(回调配置最繁琐,放最后)。
## 五、消息协议映射
```
IM 用户 @机器人 "把登录任务推进到 in_review"
→ 网关识别平台+用户+群聊 chat_id → 映射 conv_id(chat_id ↔ conv_id 持久化映射表)
→ TunnelCommand::Send { conv_id, content }
→ [桌面端 AI 引擎执行,ToolCall 需审批时回 TunnelEvent::Approval]
→ 网关发交互卡片 "[审批] advance_task(id=xxx, in_review) [同意] [拒绝]"
→ 用户点同意 → TunnelCommand::Approve { conv_id, approval_id, accepted: true }
→ TunnelEvent::TextDelta(节流聚合) / Completed
→ 网关更新卡片 / 发最终回复 + 来源标注("由 DevFlow AI 生成")
```
**关键设计点**:
1. **流式节流**:IM 平台消息 API 有频控(飞书 50 QPS/应用级、企微 200 次/分钟级),TextDelta 需聚合(如 800ms 窗口批量刷卡片);P1 可先非流式(进行中卡片 → Completed 后一次性回复)
2. **会话映射**:IM chat_id(单聊/群聊)↔ conv_id 一对一映射存网关侧 SQLite;群聊内仅 @机器人 时响应
3. **多桌面端路由**:网关支持配多 channel_id(如 `chan-work`→工作机、`chan-home`→家用机),IM 指令默认路由或按前缀路由(`/dev2 任务描述`)
4. **离线兜底**:Agent 不在线时网关直接回「桌面端未连接」(u-relay 有 PresenceState 可查询)+ 可选指令缓存重发
5. **消息长度**:IM 单条上限(飞书卡片较大、企微 Markdown 4096 字节),超长回复分段或转摘要+附件
## 六、安全设计
1. **双因子**:u-relay 侧 channel_id + token 配对(已有,常量时间比较);IM 侧回调验签(飞书 encrypt key/verification token、企微 AES+签名、钉钉 Stream 免验签)
2. **用户白名单**:企业成员 user_id 白名单表(默认拒绝所有),防止应用可见范围内任何人都能驱动桌面端 AI(高危:AI 可执行命令/改数据)
3. **审批降权**:IM 端默认只允许 `Approve` 低风险审批(只读工具);高风险(run_command/生产写入)强制回桌面端确认——网关侧按工具风险等级过滤
4. **凭证管理**:各平台 app_id/secret 存网关本地 env/配置文件(600 权限),不进 git;token 自动续期(企微 access_token 2h 缓存)
5. **审计**:网关侧记录 IM 消息 ↔ TunnelCommand 全量日志(谁在何时通过哪个平台驱动了什么指令)
## 七、实施分阶段
| Phase | 内容 | 产出 | 预估工作量 | 依赖 |
|-------|------|------|-----------|------|
| **P0 网关骨架** | df-im-gateway Rust 项目:WS Commander 连 u-relay(复用 df-tunnel 类型)、会话映射表、节流聚合器、配置管理、白名单框架 | 可连通桌面端收发消息的骨架 + 单测 | 2-3 天 | u-relay 生产实例(已有) |
| **P1 Web 端** | 自定义 Web Chat 页(复用 df-miniapp 交互模式:流式渲染/审批按钮/会话切换)+ 网关托管 | 浏览器/手机浏览器可用完整 AI Chat | 2-3 天 | P0 |
| **P2 飞书** | 长连接事件订阅 + 消息卡片(流式更新)+ 交互卡片审批 + 群聊 @识别 | 飞书内完整可用 | 3-4 天 | P0;管理员开应用权限 |
| **P3 钉钉** | Stream Mode + 卡片流式 + 按钮回调 | 钉钉内完整可用 | 3-4 天 | P0;开放平台建应用 |
| **P4 企微** | 回调 URL 验签 + AES 解密 + IP 白名单 + Markdown 卡片(节流伪流式)+ 按钮审批 | 企微内完整可用 | 3-4 天 | P0;管理员后台配置 |
| **P5 收尾** | 审批分级(IM 低风险白名单)、全平台 E2E 联调、运维脚本(复用 publish-df-relay 模式发布网关)、文档 | 生产上线 | 2 天 | P1-P4 |
总计约 **15-20 人天**。里程碑切法:P0+P1 完成即有「自定义 Web 远程 AI Chat」可日常自用(最快见效);P2/P3 并行推进;P4 视需求紧迫度排后。
## 八、风险与对策
| 风险 | 影响 | 对策 |
|------|------|------|
| IM 平台 API 频控/卡片更新限制 | 流式体验降级 | 节流聚合 + 降级为「进行中→完成」两段式 |
| 企微回调配置(可信域名/IP 白名单/AES) | 接入周期拉长 | 放 P4;提前准备备案域名与出口固定 IP |
| IM 端误触高危操作(命令执行/生产写入) | 安全事故 | 审批分级:IM 端仅放行低风险工具,高危强制桌面端确认 |
| 桌面端离线/休眠 | IM 无响应 | 离线提示 + PresenceState 感知 + 桌面端防休眠提醒 |
| u-relay 单 token 全局配对粒度粗 | 多渠道管理乱 | 网关侧单连接多路复用(channel 维度由网关统一持有);若需多 token 再扩 u-relay |
| 三平台 API 版本迭代(钉钉旧版机器人已停更) | 维护成本 | 统一走各家「新版卡片 + Stream/长连接」官方推荐路径,不碰 legacy |
## 九、待决策项
| # | 决策点 | 选项 | 建议 |
|---|--------|------|------|
| D1 | 网关部署位置 | a) 与 u-relay 同机部署 b) 独立小鸡 | a(省成本,nginx 加路由即可) |
| D2 | df-im-gateway 与 df-tunnel 类型复用方式 | a) git 依赖 df-tunnel crate b) 复制镜像类型 | a(编译期类型一致,协议演进单点维护) |
| D3 | Web 端形态 | a) 独立静态页托管在网关 b) 复用 df-miniapp 代码库分支 | a(小程序与 Web 场景差异渐大) |
| D4 | IM 审批放权策略 | a) 全审批 IM 可批 b) 低风险白名单 | b(安全优先) |
| D5 | 飞书/钉钉/企微三个应用是否现在就申请 | a) 立即申请配权限 b) 到对应 Phase 再申请 | b 中的 a:**飞书立即申请**(管理员审批周期不可控,先启动) |
## 十、与现有架构关系
- **F-260620-01 跨端 AI Chat**:本规划是其横向扩展(Commander 端从「微信小程序」扩展到「IM 机器人 + Web」),协议与中继完全复用
- **df-mcp**:对外 stdio 暴露数据层(本地进程级);本规划是远程人类入口(IM 级),互补不重叠
- **u-relay**:零改动(除非 D5 触发多 token 需求)
- **df-tunnel / AI 引擎**:零改动
+31
View File
@@ -1003,3 +1003,34 @@ graph TD
- [ ] P3 单共享 token 可冒充任意 channel_id(§8 自述):补 token 轮换 runbook(/etc/u-relay.env 改+重启+四方客户端同步换,锁步成本需写明) - [ ] P3 单共享 token 可冒充任意 channel_id(§8 自述):补 token 轮换 runbook(/etc/u-relay.env 改+重启+四方客户端同步换,锁步成本需写明)
- [ ] P3 心跳间隔未定值:nginx proxy_read_timeout=300s,间隔须 <300s,文档补建议值(30-60s) - [ ] P3 心跳间隔未定值:nginx proxy_read_timeout=300s,间隔须 <300s,文档补建议值(30-60s)
- [ ] P3 同 channel_id 多 agent 并存全投递(§3.3):双 devflow 实例共享通道=指令重复执行,补「一通道一 agent」运维纪律 - [ ] P3 同 channel_id 多 agent 并存全投递(§3.3):双 devflow 实例共享通道=指令重复执行,补「一通道一 agent」运维纪律
# 提交历史重整(2026-10-04 用户令,交 DevFlow agent 执行)
> 现状:main ahead 6(本地未推送),六笔零 body/一笔主行超长/文档笔类型误标。**执行前置:自身无在飞任务+git status 干净**(历史重放期间不得并行改码)。
## 步骤(非交互,全程可脚本化)
1. `OLD=$(git rev-parse HEAD)` 记录现 HEAD(396f74d)
2. `git reset --hard origin/main`
3. 按原序 cherry-pick 六笔:3dfa45d → f90ff80 → 737cc1f → 8dd756c → d5d9d9a → 396f74d,每笔 pick 后 `git commit --amend -F <消息文件>` 换用下方草案
4. 校验:`git diff $OLD HEAD --stat` 必须为空(树逐字节一致)+ `git status` 干净 + `git log --format="%h %s"` 六笔齐
## 六笔消息草案(subject 全部 ≤50 字;body 每行一事项;可按你对实际改动的了解细化,但不得添加 diff 中不存在的说法)
1. `新增: 无人值守P0任务边界全链`
body: 任务级授权边界判定与审批旁路单点插桩 / boundary_json 随会话落库(V45 可逆迁移) / 六路非正常终局统一安全停靠与托盘通知 / 每五轮进度事件与会话头部进度条 / 前端边界配置卡侧栏徽标及 UX 校验补齐(每条一行)
2. `优化: 子代理体验与纪律注入`
body: 工具纪律段抽共享同源注入 / 子代理轨迹浮层与完成卡身份 / 分离窗会话切换修复 / 960s 统一出口报告不再蒸发
3. `修复: 协议层与体验缺陷六件`
body: temperature 按模型适配仅收 1 的模型不再 400 / 流式 error 帧不再被 choices 必填整帧丢弃 / 只读缓存写后失效 / git diff 中文截断撞 UTF-8 边界 panic / 非视觉模型纯图片直接拒绝 / 全局快捷键补输入焦点守卫
4. `优化: 跨端链路协议对齐`
body: miniapp 配置域旧端点强制重置 / df-tunnel 隧道协议与 relay 现网对齐 / relay e2e 例程入 examples
5. `优化: 子代理截断信号与缓存失效`
body: max_tokens 截断标记穿透到完成卡 / 缓存写后失效补测试锁定 / 派发参数卡头信息补全
6. `文档: 设计定稿与评估纪律登记`(类型由「优化」改「文档」,文件面全在 docs/)
body: 无人值守长任务设计定稿含效率与可观测补遗 / u-relay wire 协议规格与五项评估结论 / 新能力引入评估纪律五项清单 / todo 销账与狗粮短板分析登记
## 提交重整补充(防坑,必读)
- **reset --hard 前工作区必须干净**:当前存在未提交改动(含本节处方)。执行顺序=①先收尾在飞工作,连同本节处方一并提交为第 7 笔(消息如 `文档: 提交重整处方与在飞收尾`)②然后 reset --hard origin/main ③按原序 cherry-pick 前六笔并逐笔 amend 换消息 ④第 7 笔原样 cherry-pick 不改消息 ⑤树一致性校验(git diff 原HEAD 为空)
- 重放期间禁止并行改码;校验不过立即 `git reset --hard $OLD` 回滚到重整前