# PRD - H5 智能推荐重构 > **REQ 编号**: REQ-用户-006 > **版本**: v1.0-Frozen(**§4.7 已冻结为最终版**;§1~§8 扩展列入 §13 分阶段交付计划) > **日期**: 2026-07-28 > **作者**: 宋献 (Simon) + Duckula > **状态**: ✅ §4.7 已冻结(决策 ① A / ② B / ③ B / ④ B / ⑤ B 宋献拍板);🟡 §1~§8 扩展按 §13 计划分阶段交付 > **关联**: > - 评估文档:`docs/02-技术文档/前端改造/前端设计-H5右侧栏动态推送-v1.0.md` > - 实现概览:`docs/02-技术文档/前端改造/设计-H5用户端实现概览-v1.0.md` > - 改造实施:`docs/02-技术文档/实现配置/AI对话链路全栈改造实施计划-v1.0.md` > - 来源标识:`docs/01-产品文档/03-AI服务/PRD-REQ-AI-004-AI回复来源标识-v1.0.md` > - 代码真相:`src/backend/app/services/asset_recommend_service.py` + `src/backend/app/config/assets.yaml` + `src/backend/app/tasks/h5_ai_task.py` --- ## 一、问题陈述(简述,待扩) H5 员工端当前"智能推荐"功能存在 5 类问题: 1. **L1 关键词匹配太硬**:`if keyword in message_lower` 纯字符串包含,无语义理解 2. **L2 画像依赖外部 API**:终端安全画像拿不到时 5 个 if 全部跳过 3. **L3 角色推荐不工作**:`assets.yaml` 是英文 key(developer/finance/manager),`profile.position` 是中文,精确匹配永远失败 4. **双轨运行**:`dynamic_recommend` 与 `asset_recommend` 两条 WS 并行,无去重、无排序 5. **审批类卡片 v2.3 后完全不出现在右侧**:用户发起的审批进度无法跨会话回看 ## 二、范围(简述,待扩) - **In-scope**:5 类卡片位置归属 + UI 规范 + 触发来源与逻辑(§4.7)+ 审批进度回流 - **Out-of-scope**:智能推荐算法升级(语义匹配/向量召回)、坐席端 AI 辅助、多模态推荐 --- ## §4 功能需求 ### 4.1 卡片位置归属决策矩阵(已审定,见 §11.1 决策记录) ### 4.2 右侧栏生命周期(B2:跨会话 + 状态完结即消 + 30 天过期)(待 §4.7 审核通过后补) ### 4.3 双发策略(C4:智能切换规则)(待 §4.7 审核通过后补) ### 4.4 审批进度回流机制(待 §4.7 审核通过后补) ### 4.5 右侧栏 UI 规范(待 §4.7 审核通过后补) ### 4.6 新卡片类型扩展(待 §4.7 审核通过后补) ### **4.7 触发来源与触发逻辑** ⭐ **本草案核心,已冻结(v1.0-Frozen,2026-07-28)** > 本章节是 PRD 的"心脏"——回答 **"卡片从哪里来、什么时机来、来了怎么合、没来怎么办"**。 #### 4.7.1 4 类触发来源(权威定义) H5 智能推荐的卡片**只能**来自以下 4 类来源。任何新增来源必须经过 PRD 变更审批,不得私下接入。 | 来源 ID | 名称 | 触发主体 | 数据源 | 触发条件 | 输出位置(按 §11.1 决策) | |--------|------|---------|--------|---------|---------------------------| | **A** | **Dify action**(dynamic_recommend) | Dify 主推理(itdesk_main 工作流) | Dify 返回的 `action` 字段(非空且非审批类) | AI 回复生成的同一时刻 | 左侧气泡(动作类)+ 右侧栏(步骤/操作类) | | **B** | **L1 关键词匹配** | 后端 `_push_asset_recommends` | `assets.yaml::keyword_assets`(10+ 个中文关键词 + alias) | 用户消息包含配置关键词(substring 匹配) | 左侧气泡(仅作为对话补充) | | **C** | **L2 画像触发** | 后端 `_push_asset_recommends` | `employee_profile_service` 画像字段(火绒版本/病毒库/离线天数/补丁缺失/违规项) | 画像字段非空且满足阈值(见 4.7.5) | 右侧栏 | | **D** | **L3 角色匹配** | 后端 `_push_asset_recommends` | `assets.yaml::role_assets` + `profile.position` | 角色 key 匹配(中文岗位名子串匹配,见 4.7.5) | 左侧气泡 | **关键约束**: - 4 类来源**必须全部登记**,代码里的任何新增触发点必须先更新本表 - 来源 A 走 `dynamic_recommend` WS(type=dynamic_recommend),来源 B/C/D 走 `asset_recommend` WS(type=asset_recommend) - 前端按 source 字段区分渲染入口(DifyActionCard vs DynamicRecommend) #### 4.7.2 3 种触发时机 | 时机 ID | 名称 | 触发点 | 典型来源 | 延迟要求 | |--------|------|--------|---------|---------| | **T0** | **同步触发**(与气泡同帧) | Dify 主推理返回瞬间 | A(Dify action) | **零延迟**,与气泡同 WS 包发出 | | **T1** | **异步触发**(AI 回复后独立步骤) | 后台任务 `_step_assets` | B(C 关键词)/ C(L2 画像)/ D(L3 角色) | **可容忍 0-3s 延迟**,失败不阻断主对话 | | **T2** | **事件触发**(状态变化驱动) | 企微审批 webhook / ITSM 工单状态变更回调 | 审批进度回流 | **可容忍 5-30s 延迟**,走 60s 轮询兜底 | **关键约束**: - T0 用于"用户在主动对话"场景,与 AI 文字强耦合 - T1 用于"补充信息"场景,独立于对话节奏 - T2 用于"异步通知"场景,必须支持跨会话持久化 #### 4.7.3 多源合并规则 当多个来源在同一时刻产生推荐时,按以下规则合并: | 规则 | 规则描述 | 备注 | |------|---------|------| | **去重规则** | 同一卡片(按 `recommend_id` 或 `card_key`)出现 2 次以上时保留 confidence 最高的 | 避免双源重复推送 | | **排序规则** | 同一时刻多卡:左侧按 layer 优先级(L1>L2>L3);右侧按"操作步骤 > 审批进度 > 运维提醒" | 用户视觉焦点固定 | | **上限规则** | 左侧气泡:每条 AI 消息最多 1 张操作卡;右侧栏:跨所有来源最多 3 张 | 避免堆叠 | | **同源抑制** | 同一会话内,L1/L2 重复触发同一关键词的同一资源卡片时,30 分钟内不再推送 | 避免噪音 | **与决策 ② 多源合并 关联**:本节是决策 ② 选项 B("同卡片去重 + layer 排序")的产品化展开。 #### 4.7.4 冷启动策略 用户进入会话但**没说话**或**刚发首条消息还没收到 AI 回复**时,右侧栏**保持空白**,不强求兜底内容。 | 场景 | 触发条件 | 显示内容 | 来源 | |------|---------|---------|------| | **场景 1:会话首次打开** | `conversation.created_at < 5s` 且无任何消息 | **右侧栏完全空白** | 无 | | **场景 2:首条消息刚发出** | 已发消息但 AI 还未回复 | **右侧栏完全空白** | 无(按 §4.7.5 触发失败降级走) | | **场景 3:AI 回复到达** | AI 已生成至少一条回复 | 按 §4.7.3 合并规则填充真实推荐 | A/B/C/D | | **场景 4:完全无数据** | 所有来源都无匹配 | **右侧栏完全空白** | 无(兜底即"不显示") | **关键约束**: - 冷启动遵循 **"有则显,无则隐"** 原则,**不强求兜底**(避免冷启动内容与 AI 回复后的真实推荐冲突造成堆叠) - 一旦 AI 回复到达(来源 A 卡片生成),立即按 §4.7.3 合并规则填充 - 冷启动状态的"空白" ≠ 异常/错误状态,前端无需展示"加载中"或"暂无数据"提示(避免视觉噪音) **与决策 ① 冷启动 关联**:本节是决策 ① 选项 A("进会话无内容,右侧栏空")的产品化展开——**宁可空,也不堆叠**。 #### 4.7.5 触发失败与降级策略 | 失败场景 | 降级策略 | 兜底内容 | |---------|---------|---------| | **来源 A 失败**:Dify 返回非 JSON / action 为空 | 跳过来源 A,仅走 B/C/D | 无 | | **来源 B 失败**:assets.yaml 配置缺失 | 跳过 B,走 C/D | 无 | | **来源 C 失败**:employee_profile_service 拿不到画像 | 跳过 C,走 B/D | 无(关键!必须降级到 D,不能空) | | **来源 D 失败**:profile.position 为 None 或空字符串 | 跳过 D | 来源 B + C(如果有) | | **全部失败** | 按 §4.7.4 冷启动策略走"右侧栏空"(保持一致性,宁可空也不堆叠) | 无 | **关键约束**: - 来源 C 失败时**必须降级到 D**(保证右侧栏有内容,不能直接空)—— 这是决策 ③ 选项 B("降级为 L3 角色")的产品化展开 - 来源 D 失败时**降级到 B + C**(保证左侧有内容)—— 这是新加的兜底 #### 4.7.6 话题切换检测(决策 ④ 落地) 会话话题切换时,**自动清空旧的同会话推荐**,避免推荐堆叠。 | 检测信号 | 检测方法 | 触发动作 | |---------|---------|---------| | **关键词突变** | 新消息与最近 3 条消息的关键词相似度 < 0.3(用 Jaccard 系数) | 清空所有 L1 推荐 | | **意图突变** | Dify 返回的 `intent_type` 与上一条不同时 | 清空对应 layer 的推荐 | | **会话分隔** | 用户点"结束会话"或新建会话 | 清空所有跨会话推荐 | **关键约束**: - L2/L3 推荐**不清空**(它们与当前话题无关,是画像/角色通用) - L1 推荐**按层清除**(关键词命中失效就清除) - 审批进度 T2 回流**不清空**(跨会话持久) #### 4.7.7 跨会话持久化规则(决策 ⑤ 落地) | 推荐类型 | 持久化策略 | 过期规则 | |---------|----------|---------| | **L1 关键词推荐** | **不持久化**,仅当前会话有效 | 话题切换或会话结束即清空 | | **L2 画像提醒** | **持久化 30 天**,跨会话可见 | 30 天后自动过期,或画像数据更新后清除 | | **L3 角色资源** | **持久化**,跨会话可见 | 角色变更时清除(极少发生) | | **来源 A 步骤卡** | **不持久化**,仅当前会话 | 话题切换或会话结束即清空 | | **审批进度 T2 回流** | **持久化直到完结**,跨会话可见 | 审批结束/已读/已完成时清除 | **关键约束**: - L1/A 不持久 → 避免"上周聊过 VPN 这周还推 VPN"的尴尬 - L2/L3/T2 持久 → 保证"运维提醒"和"审批进度"跨会话可查 - 持久化数据**存储在客户端**(localStorage),后端不持久化推荐状态 --- > **🟢 §4.7 已冻结(v1.0-Frozen,2026-07-28)** > > 本章节自 2026-07-28 起作为最终版冻结,任何修改必须经过 PRD 变更审批流程。 > > **5 个核心决策**(宋献 2026-07-28 拍板): > - **决策 ① 冷启动策略** → A(右侧栏空,宁可空也不堆叠) > - **决策 ② 多源合并规则** → B(同卡片去重 + layer 排序 + 上限 3 张) > - **决策 ③ 触发失败降级** → B(降级为下一优先级来源) > - **决策 ④ 话题切换检测** → B(检测话题切换后清空旧推荐) > - **决策 ⑤ 跨会话持久化** → B(按 layer 分级持久化) > > **约束声明**:后续扩展(§1~§8)必须遵守以上决策约束,**不得反向修改**。 > 如需调整任一决策,必须走 PRD 变更流程,并更新本章节 + §9 决策清单 + §11 变更日志。 --- ## §5 非功能需求(待 §13 扩展计划 v1.3 补充) ## §6 接口需求(待 §13 扩展计划 v1.3 补充) ## §7 验收标准(待 §13 扩展计划 v1.3 补充) ## §8 风险与降级(待 §13 扩展计划 v1.3 补充) --- ## §9 决策待审清单 > 本节明确列出本草案中 **5 个待审决策**,请宋献逐项确认或修改。 ### 决策 ① 冷启动策略(§4.7.4) | 选项 | 含义 | 我的建议 | 宋献决策 | |------|------|---------|----------| | **A** ✅ | **进会话无内容(右侧栏空)** | | ✅ **宋献 2026-07-28 选定 A** | | B | 默认显示 L3 角色通用 + 历史高频资源 | 避免首屏空 | 未选 | ### 决策 ② 多源合并规则(§4.7.3) | 选项 | 含义 | 我的建议 | |------|------|---------| | A | 不合并,各推各的 | | | **B** | **同卡片去重 + layer 排序 + 上限 3 张** | ✅ 建议 B(避免重复) | ### 决策 ③ 触发失败降级(§4.7.5) | 选项 | 含义 | 我的建议 | |------|------|---------| | A | 静默失败(不推) | | | **B** | **降级为下一优先级来源** | ✅ 建议 B(保证有内容) | ### 决策 ④ 话题切换检测(§4.7.6) | 选项 | 含义 | 我的建议 | |------|------|---------| | A | 不检测(推荐持续堆叠) | | | **B** | **检测话题切换后清空旧推荐** | ✅ 建议 B(避免堆叠) | ### 决策 ⑤ 跨会话持久化(§4.7.7) | 选项 | 含义 | 我的建议 | |------|------|---------| | A | 全局持久化 | | | **B** | **按 layer 分级持久化** | ✅ 建议 B(L1/A 不持久,L2/L3/T2 持久) | --- ## §10 关联文档(同抬头所列) --- ## §11 变更日志 | 版本 | 日期 | 变更内容 | 作者 | |------|------|---------|------| | v1.0a | 2026-07-28 18:59 | 草案:仅完成 §4.7 触发来源与逻辑章节 | Duckula | | v1.0b | 2026-07-28 19:06 | 宋献审核 §4.7 决策:① A / ② B / ③ B / ④ B / ⑤ B;同步调整 §4.7.4 冷启动策略、§4.7.5 全部失败兜底、§9 决策① | Duckula + 宋献 | | v1.0-Frozen | 2026-07-28 19:09 | §4.7 冻结为最终版(决策锚点);新增 §13 §1~§8 扩展计划(v1.1/v1.2/v1.3 分阶段交付);§5~§8 占位标记改为"待 §13 计划补充";§12 待办标记完成项 | Duckula + 宋献 | --- ## §12 待办(v1.0-Frozen 阶段) - [x] §4.7 触发来源与逻辑章节完成(v1.0a,2026-07-28) - [x] 宋献审核 §4.7 决策(v1.0b,2026-07-28,①~⑤ 拍板) - [x] §4.7 冻结为最终版(v1.0-Frozen,2026-07-28) - [ ] 扩展按 §13 计划分阶段交付(v1.1 → v1.2 → v1.3) - [ ] 配套技术方案 / 原型图 / 任务说明书 / 测试用例(详见 §13.4) --- ## §13 §1~§8 扩展计划(分阶段交付) > §4.7 已冻结为最终版(v1.0-Frozen),§1~§8 扩展必须遵守 §4.7 决策约束。 ### 13.1 扩展原则 1. **遵守 §4.7**:所有扩展章节的逻辑不得与 §4.7 冲突 2. **决策不反转**:5 个已审定决策(① A / ② B / ③ B / ④ B / ⑤ B)不得反向修改 3. **增量交付**:每个章节单独 PR / 单独 review,避免大爆炸 4. **依赖排序**:先扩 §1~§3(背景/范围/故事),再扩 §4.1~4.6(功能),最后扩 §5~§8(非功能/接口/验收/风险) ### 13.2 扩展任务清单 | # | 章节 | 扩展要点 | 依赖 | 估时 | 优先级 | 交付版本 | |---|------|---------|------|------|--------|---------| | 1 | §1 问题陈述 | 基于 5 类问题(L1/L2/L3/双轨/v2.3)展开详细描述 | 无 | 0.5h | P0 | v1.1 | | 2 | §2 详细范围 | In-scope(5 类卡片归属 + UI + §4.7 + 审批回流)/ Out-of-scope | §1 | 0.5h | P0 | v1.1 | | 3 | §3 用户故事 | 员工/坐席/管理员 3 个角色视角 | §1 | 1h | P0 | v1.1 | | 4 | §4.1 卡片归属矩阵 | 把先前对话中已审定的归属决策(A2/B2/C4 + L3/联系窗口/联系人/下载只放左边)整理为完整矩阵 | §4.7 | 0.5h | P1 | v1.1 | | 5 | §4.2 右侧栏生命周期 | B2 跨会话 + 状态完结即消 + 30 天过期 | §4.7 | 0.5h | P1 | v1.2 | | 6 | §4.3 双发策略 | C4 智能切换规则(按内容性质决定位置) | §4.7 | 0.5h | P1 | v1.2 | | 7 | §4.4 审批进度回流 | T2 事件触发 + 60s 轮询兜底 | §4.7 | 1h | P1 | v1.2 | | 8 | §4.5 右侧栏 UI 规范 | 无标题 + FIFO 插入 + 4 类卡片样式 | §4.7 | 1h | P1 | v1.2 | | 9 | §4.6 新卡片类型 | 操作步骤(可展开)/ 联系窗口 / 联系人 / 下载 | §4.7 | 1h | P1 | v1.2 | | 10 | §5 非功能需求 | 性能(<200ms 渲染)+ 兼容(v2.3 平滑过渡) | §4.7 | 0.5h | P2 | v1.3 | | 11 | §6 接口需求 | WS 新增 type=recommend_update + 订阅 API | §4.7 | 1h | P1 | v1.3 | | 12 | §7 验收标准 | 点击率>15% / 自助解决率>10% / 右侧栏 ≤3 张 | §4.7 | 0.5h | P0 | v1.3 | | 13 | §8 风险与降级 | Dify 不可用 / WS 断连 / 画像 API 不可用 | §4.7 | 0.5h | P1 | v1.3 | ### 13.3 交付节奏建议 | 阶段 | 范围 | 估时 | 触发条件 | |------|------|------|---------| | **v1.1 立即扩** | §1 / §2 / §3 / §4.1 | 2.5h | §4.7 冻结后立即启动 | | **v1.2 一周内扩** | §4.2 ~ §4.6 | 3.5h | v1.1 完成 + 原型图设计启动 | | **v1.3 两周内扩** | §5 / §6 / §7 / §8 | 2.5h | v1.2 完成 + 技术方案评审通过 | ### 13.4 关联配套交付物 | 类型 | 路径 | 状态 | 依赖 | |------|------|------|------| | 技术方案 | `docs/02-技术文档/技术架构/技术方案-REQ-用户-006-智能推荐重构-v1.0.md` | 🟡 待启动 | §4.7 + §6 接口需求 | | 原型图 | `docs/01-产品文档/05-用户端H5/原型-REQ-用户-006-智能推荐重构-v1.0.html` | 🟡 待启动 | §4.5 UI 规范 | | 任务说明书 | `docs/07-项目管理/任务说明书/任务说明书-REQ-用户-006-智能推荐重构.md` | 🟡 待启动 | 技术方案 | | 测试用例 | `docs/03-测试文档/03-功能测试用例/TC-用户-006-智能推荐重构.md` | 🟡 待启动 | §7 验收标准 | | BUG 单模板 | `docs/03-测试文档/05-缺陷单/BUG-用户-006-xxx.md` | ⚪ 按需 | 上线后 | ### 13.5 冻结约束声明 - §4.7 已冻结,任何修改必须走 PRD 变更流程(更新 §4.7 + §9 决策清单 + §11 变更日志 + 本节) - 扩展章节(§1~§8)的逻辑**不得与 §4.7 冲突**,如有冲突以 §4.7 为准 - 5 个核心决策(① A / ② B / ③ B / ④ B / ⑤ B)**不得反向修改**,如需调整必须升级文档版本号(v1.0-Frozen → v2.0)