测试用例 - H5 智能推荐重构
REQ 编号: REQ-用户-006
版本: v1.0
日期: 2026-07-28
作者: 宋献 (Simon) + Duckula
状态: 🟡 待评审(基于 PRD v1.0-Frozen + 技术方案 v1.0)
关联文档:
- PRD(冻结):
docs/01-产品文档/05-用户端H5/PRD-REQ-用户-006-智能推荐重构-v1.0-Frozen.md
- 技术方案:
docs/02-技术文档/技术架构/技术方案-REQ-用户-006-智能推荐重构-v1.0.md
- 任务说明书:
docs/07-项目管理/任务说明书/任务说明书-REQ-用户-006-智能推荐重构.md
- 原型图:
docs/01-产品文档/05-用户端H5/原型-REQ-用户-006-智能推荐重构-v1.0.html
一、基本信息
| 项目 |
内容 |
| 用例集名称 |
TC-用户-006 H5 智能推荐重构 |
| 关联 PRD |
REQ-用户-006 v1.0-Frozen(§4.7 已冻结) |
| 用例总数 |
76 条(10 大类) |
| 优先级分布 |
P0 28 条 / P1 32 条 / P2 16 条 |
| 关联决策 |
必须 100% 覆盖 PRD §4.7 5 个核心决策(① A / ② B / ③ B / ④ B / ⑤ B) |
| 自动化目标 |
单元测试 100% 自动化 / E2E 关键路径自动化 / 灰度指标由数据埋点验证 |
二、测试范围
2.1 In-scope
- 后端
asset_recommend_service.py 重构(L1/L2/L3 + 中文匹配)
- 后端新增
recommend_progress_service.py(T2 webhook + 轮询)
- 后端新增
topic_detector.py(Jaccard 相似度)
- 后端
_step_assets 改造(3s 超时 + 降级链路)
- 前端
recommendStore.ts 状态机
- 前端
DynamicRecommend.vue 重构(无标题 + FIFO + 4 类卡片)
- 前端
RightPanel.vue 适配
- WS 协议扩展(dynamic_recommend / asset_recommend / recommend_update)
- localStorage 持久化
- 数据模型(recommend_progress + recommend_event)
2.2 Out-of-scope
- 智能推荐算法升级(语义匹配/向量召回)→ v1.4+ 单独测
- 坐席端 AI 辅助 → 不在本次范围
- 多模态推荐 → PRD-REQ-AI-003 单独测
三、测试环境
| 项 |
配置 |
| 后端 |
Python 3.13 / FastAPI / pytest |
| 前端 |
Vue 3 / TypeScript / Vitest |
| E2E |
agent-browser(Playwright) |
| 数据库 |
PostgreSQL 16 + Redis 7 |
| 外部 mock |
Dify 推理 / 企微审批 webhook / 火绒 API |
| 环境 |
dev → staging → 生产灰度 |
四、用例分类规则
| 前缀 |
模块 |
用例数 |
| TC-001 |
来源 A:Dify action(T0 同步) |
8 |
| TC-002 |
来源 B:L1 关键词(T1 异步) |
10 |
| TC-003 |
来源 C:L2 画像(T1 异步) |
10 |
| TC-004 |
来源 D:L3 角色(T1 异步) |
8 |
| TC-005 |
多源合并规则(决策 ② B) |
8 |
| TC-006 |
冷启动策略(决策 ① A) |
6 |
| TC-007 |
触发失败降级(决策 ③ B) |
8 |
| TC-008 |
话题切换检测(决策 ④ B) |
8 |
| TC-009 |
跨会话持久化(决策 ⑤ B) |
6 |
| TC-010 |
E2E 集成 + UI 行为 |
4 |
| 合计 |
|
76 |
五、详细用例
TC-001:来源 A - Dify action(T0 同步)
TC-001-1 [P0] 来源 A:AI 返回 action 后立即同步推送到左侧气泡
- 前置条件:用户进入新会话,员工端 WS 已连接
- 测试步骤:
- 用户发送"我要申请 VPN"
- Dify 返回
{text: "好的", action: {approval_type: "vpn_access", title: "VPN 申请"}}
- 预期结果:
- WS
ai_reply 立即到达(含文字 + action)
- 左侧气泡显示"VPN 申请"操作卡(v2.3 后审批类只放左边)
- 右侧栏 不出现 该审批卡(v2.3 决策)
- 关联:PRD §4.7.1 来源 A / 技术方案 §5.1 T0
TC-001-2 [P0] 来源 A:非审批类 action 同步推送到右侧栏
- 前置条件:同上
- 测试步骤:
- 用户发送"VPN 连不上怎么办"
- Dify 返回
{text: "请重连", action: {type: "step_card", steps: [...]}}
- 预期结果:
- 左侧气泡显示文字 + 来源图标
- 右侧栏顶部插入操作步骤卡(蓝色边框,可展开)
- 关联:PRD §4.5 / §4.7.1 A
TC-001-3 [P1] 来源 A:action 为空时不推送右侧栏
- 前置条件:Dify 返回
{text: "你好", action: null}
- 测试步骤:触发 AI 回复
- 预期结果:
- 左侧气泡显示文字
- 右侧栏 不增加 任何卡片
- 不出现"暂无推荐"提示
- 关联:技术方案 §4.1
TC-001-4 [P1] 来源 A:recommend_data 包含 source/trigger_timing/layer 字段
- 前置条件:触发 AI 回复(Dify 返回非空 action)
- 测试步骤:检查 WS 数据包
- 预期结果:
recommend_data.source = "dify_action"
recommend_data.trigger_timing = "T0"
recommend_data.layer = "A"
- 关联:技术方案 §5.1
TC-001-5 [P1] 来源 A:审批发起后立即在右侧栏顶部插入占位卡
- 前置条件:用户发起 VPN 审批(action.approval_type = "vpn_access")
- 测试步骤:
- 用户点击气泡中的"申请"
- 跳转企微审批表单
- 用户提交审批
- 预期结果:
- 提交瞬间右侧栏顶部插入审批进度占位卡(紫色边框,状态"pending")
- 显示"VPN 申请 已发起,等待审批"
- 关联:技术方案 §5.3 T2 / PRD §4.7.2
TC-001-6 [P2] 来源 A:action.type 包含 contact_window 时只推左侧
- 前置条件:Dify 返回
action.type = "contact_window"
- 测试步骤:触发 AI 回复
- 预期结果:
- 左侧气泡显示联系窗口按钮
- 右侧栏 不出现 该卡(PRD §4.7.1 A 限制)
- 关联:PRD §4.7.1 来源 A 补充决策
TC-001-7 [P2] 来源 A:action.type 包含 contact_card 时只推左侧
- 前置条件:Dify 返回
action.type = "contact_card"
- 测试步骤:同上
- 预期结果:
- 关联:PRD §4.7.1 来源 A 补充决策
TC-001-8 [P2] 来源 A:action.type 包含 download 时只推左侧
- 前置条件:Dify 返回
action.type = "download"
- 测试步骤:同上
- 预期结果:
- 关联:PRD §4.7.1 来源 A 补充决策
TC-002:来源 B - L1 关键词匹配(T1 异步)
TC-002-1 [P0] 来源 B:用户消息包含精确关键词时命中
- 前置条件:assets.yaml 配置
vpn 关键词
- 测试步骤:用户发送"VPN 连不上"
- 预期结果:
- 右侧栏插入 L1 卡片(绿色边框)
- 标题为"VPN 相关信息"
- 置信度反映词频权重(≥ 0.5)
- 关联:PRD §4.7.1 来源 B / 技术方案 §4.2
TC-002-2 [P0] 来源 B:用户消息包含别名时也命中
- 前置条件:配置 alias "虚拟专用网络" → "vpn"
- 测试步骤:用户发送"虚拟专用网络怎么用"
- 预期结果:右侧栏插入 L1 VPN 卡片
- 关联:技术方案 §4.2 同义词表
TC-002-3 [P1] 来源 B:词频权重(短消息 + 高频词)
- 前置条件:用户发送"VPN"(仅 3 字)
- 测试步骤:触发 AI 回复
- 预期结果:
- L1 VPN 卡插入
- 置信度 = min(1.0, 1 × (3/3) × 10) = 1.0(短消息高权重)
- 关联:技术方案 §4.2 词频权重公式
TC-002-4 [P1] 来源 B:长消息中关键词被稀释
- 前置条件:用户发送长消息(> 50 字),仅 1 次包含 "VPN"
- 测试步骤:触发 AI 回复
- 预期结果:
- L1 VPN 卡插入
- 置信度较低(< 0.5),优先级低于其他高权重推荐
- 关联:技术方案 §4.2 长度归一化
TC-002-5 [P1] 来源 B:exclude_keywords 排除规则生效
- 前置条件:配置
exclude_keywords: ["邮箱"]
- 测试步骤:用户发送"我的收件箱打不开,邮箱登不上"
- 预期结果:
- L1 邮箱卡 不出现(被排除)
- 仅出现其他来源推荐
- 关联:技术方案 §4.2 排除关键词
TC-002-6 [P1] 来源 B:30 分钟同源抑制
- 前置条件:5 分钟前已推送过 L1 VPN 卡
- 测试步骤:用户再次发送"VPN 又连不上了"
- 预期结果:
- L1 VPN 卡 不重复推送(30 分钟内同关键词抑制)
- Redis 中存在
suppress:{employee_id}:vpn 键(TTL ≤ 30 分钟)
- 关联:PRD §4.7.3 同源抑制 / 技术方案 §6.4
TC-002-7 [P2] 来源 B:30 分钟后可再次推送
- 前置条件:30 分钟前推送过 L1 VPN 卡,Redis 键已过期
- 测试步骤:用户再次发送"VPN 连不上"
- 预期结果:L1 VPN 卡正常推送
- 关联:技术方案 §6.4
TC-002-8 [P1] 来源 B:用户消息包含多个关键词时多卡
- 前置条件:用户发送"VPN 连不上,邮箱也登不上"
- 测试步骤:触发 AI 回复
- 预期结果:
- 右侧栏插入 L1 VPN 卡 + L1 邮箱卡(2 张)
- 按 layer 优先级 + confidence 排序
- 总数 ≤ 3 张
- 关联:PRD §4.7.3 / 技术方案 §6.1
TC-002-9 [P2] 来源 B:消息完全不包含任何关键词时无 L1
- 前置条件:用户发送"今天天气真好"
- 测试步骤:触发 AI 回复
- 预期结果:
- 来源 B 返回空列表
- 继续走来源 C/D 降级链路
- 关联:技术方案 §4.2 / §6.1
TC-002-10 [P2] 来源 B:Dify 同步识别意图时,来源 B 可与 A 互补
- 前置条件:Dify 返回 action(来源 A),同时用户消息包含关键词
- 测试步骤:触发 AI 回复
- 预期结果:
- 左侧气泡显示 A 来源卡片
- 右侧栏同时显示 A 步骤卡 + B 关键词卡(不重复)
- 关联:技术方案 §6.1 去重
TC-003:来源 C - L2 画像触发(T1 异步)
TC-003-1 [P0] 来源 C:火绒病毒库过期触发提醒
- 前置条件:员工画像
huorong_virusdb_date 距今 10 天
- 测试步骤:用户发送任意消息
- 预期结果:
- 右侧栏插入 L2 提醒卡(橙色边框)
- 标题"火绒病毒库过期"
- 描述包含"已 N 天未更新"
- 关联:PRD §4.7.1 来源 C / 技术方案 §4.3
TC-003-2 [P0] 来源 C:火绒终端版本过旧触发提醒
- 前置条件:画像
huorong_version = "5.0.50"(< 5.0.73)
- 测试步骤:同上
- 预期结果:
- L2 提醒卡插入
- 描述"您的版本为 5.0.50,最新版本为 5.0.73"
- 关联:技术方案 §4.3
TC-003-3 [P0] 来源 C:终端防护离线触发最高优先级提醒
- 前置条件:画像
huorong_offline_days = 5
- 测试步骤:同上
- 预期结果:
- L2 提醒卡插入
- priority = 100(最高)
- 关联:技术方案 §4.3
TC-003-4 [P1] 来源 C:联软违规项触发
- 前置条件:画像
unionsoft_violations = ["禁用软件", "未安装补丁"]
- 测试步骤:同上
- 预期结果:
- L2 提醒卡插入
- extra.violations 包含违规项列表
- 关联:技术方案 §4.3
TC-003-5 [P1] 来源 C:系统补丁缺失触发
- 前置条件:画像
unionsoft_patches_missing = 12
- 测试步骤:同上
- 预期结果:L2 提醒卡"系统补丁缺失"
- 关联:技术方案 §4.3
TC-003-6 [P0] 来源 C:画像 API 不可用时降级到 DB 缓存
- 前置条件:
employee_profile_service.get_profile() 超时/异常
- 测试步骤:触发 AI 回复
- 预期结果:
- 调用
_get_cached_profile_from_db(employee_id) 兜底
- 如 DB 有缓存画像,按缓存触发 L2
- 如 DB 也无,走来源 D 降级
- 关联:技术方案 §4.3 缓存画像 / PRD §4.7.5 决策 ③ B
TC-003-7 [P1] 来源 C:画像完全为空时(API + DB 都无)
- 前置条件:新员工,无任何画像数据
- 测试步骤:同上
- 预期结果:
- 关联:PRD §4.7.5 / 技术方案 §4.3
TC-003-8 [P2] 来源 C:多个画像字段同时满足触发多张卡
- 前置条件:病毒库过期 + 版本过旧 + 离线 5 天
- 测试步骤:触发 AI 回复
- 预期结果:
- 3 张 L2 提醒卡(按 priority 排序:离线 > 版本 > 病毒库)
- 总数 + 其他来源 ≤ 3 张
- 关联:技术方案 §4.3 / §6.1
TC-003-9 [P2] 来源 C:画像字段格式异常时优雅跳过
- 前置条件:
huorong_version = ""(空字符串)
- 测试步骤:同上
- 预期结果:
- try-except 捕获 AttributeError/ValueError
- 该字段跳过,其他字段继续判定
- 关联:技术方案 §4.3 try-except
TC-003-10 [P1] 来源 C:T1 异步触发 3s 超时保护
- 前置条件:画像 API 响应缓慢(> 3s)
- 测试步骤:触发 AI 回复
- 预期结果:
asyncio.timeout(3.0) 触发超时
- 跳过来源 C,走来源 D
- 不阻塞主对话流程
- 关联:技术方案 §5.2 / PRD §4.7.5
TC-004:来源 D - L3 角色匹配(T1 异步)
TC-004-1 [P0] 来源 D:中文岗位名命中英文 role_assets key(精确)
- 前置条件:
profile.position = "开发工程师" + 配置 开发工程师: alias_of: developer
- 测试步骤:触发 AI 回复
- 预期结果:
- 来源 D 命中 developer 资源
- L3 卡插入右侧栏(实际:按 v1.0 用户决策移到左侧)
- 关联:PRD §4.7.1 来源 D / 技术方案 §4.4 / §11 卡片归属
TC-004-2 [P0] 来源 D:中文岗位子串匹配
- 前置条件:
profile.position = "前端开发工程师"
- 测试步骤:同上
- 预期结果:
- 子串匹配命中 "developer"
- confidence = 0.7(子串匹配置信度低)
- 关联:技术方案 §4.4 子串匹配
TC-004-3 [P1] 来源 D:别名匹配(如 "研发" → "developer")
- 前置条件:
profile.position = "研发" + 配置 role_aliases.developer: ["研发", ...]
- 测试步骤:同上
- 预期结果:
- 命中 developer 资源
- confidence = 0.85
- 关联:技术方案 §4.4 role_aliases
TC-004-4 [P1] 来源 D:profile.position 为 None 时跳过
- 前置条件:新员工未填写岗位
- 测试步骤:同上
- 预期结果:
- 来源 D 返回空
- 走来源 B + C 降级(D 失败 → B + C)
- 关联:技术方案 §4.4
TC-004-5 [P1] 来源 D:英文 position 也能命中英文 key(兼容)
- 前置条件:
profile.position = "developer"
- 测试步骤:同上
- 预期结果:精确匹配 developer,confidence = 1.0
- 关联:技术方案 §4.4
TC-004-6 [P2] 来源 D:双向子串匹配(key 包含 position)
- 前置条件:
profile.position = "开发" + key = "developer"
- 测试步骤:同上
- 预期结果:
- "开发" 在 "developer" 里?否(中文不在英文里)
- "developer" 在 "开发" 里?否
- 来源 D 返回空(无命中)
- 关联:技术方案 §4.4 双向子串
TC-004-7 [P2] 来源 D:多个角色同时命中
- 前置条件:position = "开发"(命中 developer),但配置也有 "财务开发"
- 测试步骤:同上
- 预期结果:
- 关联:技术方案 §4.4 / §6.1
TC-004-8 [P2] 来源 D:role_assets 配置变更热重载
- 前置条件:调用
asset_service.reload()
- 测试步骤:修改 assets.yaml 后调用 reload
- 预期结果:
- 配置生效,无需重启服务
- 日志输出"配置热重载完成"
- 关联:技术方案 §4.4 reload()
TC-005:多源合并规则(决策 ② B)
TC-005-1 [P0] 合并:同 recommend_id 去重,保留高 confidence
- 前置条件:A 来源产生 rec_001(confidence=0.85)+ B 来源也产生 rec_001(confidence=0.7)
- 测试步骤:触发 AI 回复
- 预期结果:
- 右侧栏仅 1 张 rec_001(保留 A 的 0.85)
- 关联:PRD §4.7.3 / 技术方案 §6.1
TC-005-2 [P0] 合并:layer 优先级排序 L1 > L2 > L3
- 前置条件:A 步骤卡(layer A)+ L1 关键词卡 + L2 画像卡 + L3 角色卡
- 测试步骤:触发 AI 回复
- 预期结果:
- 排序:A > L1 > L2 > L3
- 右侧栏显示:A 在最上
- 关联:技术方案 §6.2
TC-005-3 [P0] 合并:上限 3 张
- 前置条件:同时有 5 张推荐卡(A + 2 × L1 + L2 + L3)
- 测试步骤:触发 AI 回复
- 预期结果:
- 关联:PRD §4.7.3 上限规则
TC-005-4 [P1] 合并:同 layer 内按 confidence DESC
- 前置条件:L1 VPN(0.85)+ L1 邮箱(0.7)
- 测试步骤:触发 AI 回复
- 预期结果:
- 关联:技术方案 §6.1
TC-005-5 [P1] 合并:A 来源步骤卡优先级最高(layer A)
- 前置条件:A 步骤卡(layer A)+ L1 关键词卡
- 测试步骤:触发 AI 回复
- 预期结果:A 步骤卡在最上方(即使 confidence 较低)
- 关联:技术方案 §6.2 layer_priority
TC-005-6 [P1] 合并:进度回流卡插入最上方
- 前置条件:已有 2 张卡,审批状态变化触发 T2
- 测试步骤:企微审批 webhook 推送 status="approved"
- 预期结果:
- 进度卡插入最上方(FIFO)
- 已有的 2 张卡往下排
- 超出上限时最旧的被丢弃
- 关联:PRD §4.7.7 / 技术方案 §5.3
TC-005-7 [P2] 合并:merge_recommends 算法纯函数测试
- 前置条件:单元测试
- 测试步骤:mock 4 个来源各返回 N 张卡
- 预期结果:
- 总数 ≤ 3
- 排序符合 layer 优先级 + confidence
- 同 ID 不重复
- 关联:技术方案 §6.1
TC-005-8 [P2] 合并:空输入返回空列表
- 前置条件:所有来源都返回空
- 测试步骤:调用
merge_recommends([], [], [], [])
- 预期结果:返回
[]
- 关联:技术方案 §6.1
TC-006:冷启动策略(决策 ① A)
TC-006-1 [P0] 冷启动:进会话 5s 内无消息 → 右侧栏完全空白
- 前置条件:用户进入新会话
- 测试步骤:观察右侧栏 5 秒
- 预期结果:
- 右侧栏 完全空白
- 不显示"暂无推荐"提示
- 不显示"试试问 XXX"引导
- 关联:PRD §4.7.4 决策 ① A
TC-006-2 [P0] 冷启动:首条消息发出但 AI 未回复 → 右侧栏空白
- 前置条件:用户已发消息,AI 推理中
- 测试步骤:观察右侧栏
- 预期结果:右侧栏空白(与决策 ① A 一致)
- 关联:PRD §4.7.4
TC-006-3 [P0] 冷启动:AI 回复到达瞬间 → 真实推荐填充
- 前置条件:AI 推理完成
- 测试步骤:观察右侧栏变化
- 预期结果:
- 关联:PRD §4.7.4 场景 3
TC-006-4 [P0] 冷启动:完全不显示任何兜底
- 前置条件:所有来源都失败(L3 失败 + 无画像 + 无历史)
- 测试步骤:触发 AI 回复
- 预期结果:
- 右侧栏 完全空白
- 不显示"暂无推荐,试试问 'VPN 怎么连'"提示
- 关联:PRD §4.7.4 决策 ① A + §4.7.5 全部失败
TC-006-5 [P1] 冷启动:store 状态机从 empty → populated
- 前置条件:前端 recommendStore 初始化
- 测试步骤:触发 AI 回复(A/B/C/D 任一产生卡)
- 预期结果:
- state 从
empty → populated
- visibleCards 非空
- 关联:技术方案 §7.1
TC-006-6 [P2] 冷启动:清空后 state 回到 empty
- 前置条件:已有卡,用户清空
- 测试步骤:调用
store.clearAll()
- 预期结果:state 回到
empty,visibleCards = []
- 关联:技术方案 §7.1
TC-007:触发失败降级(决策 ③ B)
TC-007-1 [P0] 降级:A 失败 → B + C + D
- 前置条件:Dify 返回非 JSON 或 action 为空
- 测试步骤:触发 AI 回复
- 预期结果:
- 关联:PRD §4.7.5
TC-007-2 [P0] 降级:B 失败 → C + D
- 前置条件:用户消息不包含任何关键词(来源 B 返回空)
- 测试步骤:触发 AI 回复
- 预期结果:
- 关联:PRD §4.7.5
TC-007-3 [P0] 降级:C 失败 → D(关键降级)
- 前置条件:画像 API 不可用 + DB 无缓存
- 测试步骤:触发 AI 回复
- 预期结果:
- 来源 C 跳过
- 来源 D 命中(如果有中文岗位)
- 至少能展示 1 张卡(保证有内容)
- 关联:PRD §4.7.5 / 技术方案 §4.3
TC-007-4 [P0] 降级:D 失败 → 空
- 前置条件:profile.position 为 None + 用户消息无关键词 + 无画像
- 测试步骤:触发 AI 回复
- 预期结果:
- 所有来源失败
- 右侧栏空(按决策 ① A 走空状态)
- 关联:PRD §4.7.5
TC-007-5 [P0] 降级:全部失败 → 右侧栏空(与决策 ① 一致)
- 前置条件:所有来源都失败
- 测试步骤:触发 AI 回复
- 预期结果:
- 关联:PRD §4.7.4 + §4.7.5
TC-007-6 [P1] 降级:T1 异步触发 3s 超时
- 前置条件:来源 B/C/D 全部响应缓慢
- 测试步骤:模拟慢响应
- 预期结果:
- 关联:技术方案 §5.2
TC-007-7 [P2] 降级:降级路径日志完整
- 前置条件:触发降级(C → D)
- 测试步骤:检查后端日志
- 预期结果:日志包含
[AssetRecommend] 画像获取失败/超时(C → D 降级)
- 关联:技术方案 §5.2 日志
TC-007-8 [P2] 降级:recommend_event 埋点记录降级触发次数
- 前置条件:降级发生时
- 测试步骤:检查 recommend_event 表
- 预期结果:
- 存在
event_type='degraded' 记录
- 包含降级链路信息(C→D / 全部失败)
- 关联:技术方案 §11.2 埋点
TC-008:话题切换检测(决策 ④ B)
TC-008-1 [P0] 话题切换:Jaccard 相似度 < 0.3 触发清空
- 前置条件:最近 3 条消息关键词集合 = {VPN, 重连, aTrust},新消息 = {会议室, 预定, 时间}
- 测试步骤:用户发送"帮我预定会议室"
- 预期结果:
- Jaccard = 0/6 = 0 < 0.3
- 触发话题切换
- L1 推荐清空(按 layer 清除)
- 关联:PRD §4.7.6 / 技术方案 §9.1
TC-008-2 [P0] 话题切换:Jaccard 相似度 ≥ 0.3 不触发清空
- 前置条件:最近 3 条 = {VPN, 重连, aTrust},新消息 = {VPN, 又连不上}
- 测试步骤:用户发送"VPN 又连不上了"
- 预期结果:
- Jaccard = 1/5 = 0.2 < 0.3(边界)
- L1 保留(VPN 关键词继续命中)
- 关联:技术方案 §9.1
TC-008-3 [P1] 话题切换:意图突变触发清空
- 前置条件:Dify 上次返回 intent_type="vpn_query",本次 "meeting_book"
- 测试步骤:触发 AI 回复
- 预期结果:清空对应 layer 的推荐
- 关联:PRD §4.7.6 / 技术方案 §9.2
TC-008-4 [P1] 话题切换:会话分隔清空所有跨会话推荐
- 前置条件:用户点"结束会话"或新建会话
- 测试步骤:用户新建会话
- 预期结果:
- 所有跨会话推荐清空
- L2/L3/progress 也清(按"会话分隔"规则)
- 关联:PRD §4.7.6
TC-008-5 [P1] 话题切换:L2/L3/progress 不被 L1 清空影响
- 前置条件:已有 L1 VPN + L2 病毒库 + progress VPN 申请
- 测试步骤:用户切换话题到"会议室"
- 预期结果:
- L1 VPN 清空
- L2 病毒库保留(与话题无关)
- progress VPN 申请保留(跨会话持久)
- 关联:PRD §4.7.6
TC-008-6 [P2] 话题切换:算法纯函数测试
- 前置条件:单元测试
- 测试步骤:构造边界用例
- 预期结果:
- 空集合相似度 = 1.0
- 完全相同相似度 = 1.0
- 完全不同相似度 = 0
- 关联:技术方案 §9.1
TC-008-7 [P2] 话题切换:阈值为 0.3 边界测试
- 前置条件:Jaccard = 0.29 和 0.31
- 测试步骤:分别测试
- 预期结果:
- 0.29 < 0.3 → 触发
- 0.31 ≥ 0.3 → 不触发
- 关联:技术方案 §9.1
TC-008-8 [P2] 话题切换:检测失败时静默跳过(不阻塞主流程)
- 前置条件:
extract_keywords 抛异常
- 测试步骤:mock 异常
- 预期结果:
- 异常被捕获
- 主对话正常进行
- 不触发清空(保守处理)
- 关联:技术方案 §9.1 try-except
TC-009:跨会话持久化(决策 ⑤ B)
TC-009-1 [P0] 持久化:L1 关键词推荐不持久化
- 前置条件:用户会话 1 产生 L1 VPN 卡
- 测试步骤:关闭浏览器,重新打开
- 预期结果:
- L1 VPN 卡 不出现(localStorage 无记录)
- 关联:PRD §4.7.7 / 技术方案 §10.2
TC-009-2 [P0] 持久化:L2 画像提醒持久化 30 天
- 前置条件:用户会话 1 产生 L2 火绒过期提醒
- 测试步骤:关闭浏览器,重新打开
- 预期结果:
- L2 提醒卡 仍在(localStorage 有记录)
- 数据包含
ttl_days: 30
- 关联:PRD §4.7.7 / 技术方案 §10.2
TC-009-3 [P0] 持久化:L3 角色资源持久化
- 前置条件:用户会话 1 产生 L3 开发者资源
- 测试步骤:关闭浏览器,重新打开
- 预期结果:L3 卡仍在
- 关联:PRD §4.7.7
TC-009-4 [P0] 持久化:审批进度持久化直到完结
- 前置条件:用户发起 VPN 审批,progress 卡插入
- 测试步骤:
- 关闭浏览器,重新打开
- 企微审批 webhook 推送 status="completed"
- 预期结果:
- 关闭前 progress 卡仍在
- webhook 后 progress 卡标记"已完成"
- 后续不再显示(已完结)
- 关联:PRD §4.7.7 / 技术方案 §5.3
TC-009-5 [P1] 持久化:localStorage 配额超限降级
- 前置条件:localStorage 写入失败(QuotaExceededError)
- 测试步骤:mock QuotaExceededError
- 预期结果:
- 关联:技术方案 §10.1 / §15 R3
TC-009-6 [P2] 持久化:profile.position 变更时清空 L3
- 前置条件:用户从"开发"调到"财务"
- 测试步骤:修改 profile.position + 触发 AI 回复
- 预期结果:原 L3 开发者资源清空,命中新 L3 财务资源
- 关联:PRD §4.7.7
TC-010:E2E 集成 + UI 行为
TC-010-1 [P0] E2E:员工发"VPN 申请"完整链路
- 前置条件:agent-browser + dev 环境
- 测试步骤:
- 打开 H5 员工端
- 发送"我要申请 VPN"
- 观察 AI 回复 + 右侧栏
- 点击"申请"
- 预期结果:
- 左侧气泡显示"VPN 申请"操作卡
- 右侧栏顶部插入审批进度占位卡
- 跳转企微审批表单
- 关联:技术方案 §3.2 时序图 / 端到端
TC-010-2 [P0] E2E:话题切换 + 持久化组合
- 前置条件:已有 L1/L2/progress 卡
- 测试步骤:
- 用户切换话题
- 验证 L1 清空
- 验证 L2/progress 保留
- 关闭浏览器重新打开
- 验证 L2/progress 仍在
- 预期结果:所有规则同时生效
- 关联:综合
TC-010-3 [P0] UI:右侧栏无标题
- 前置条件:任意场景
- 测试步骤:观察右侧栏
- 预期结果:
- 顶部无"⚡ 智能推荐"标题
- 顶部无"相关推荐"/"运维提醒"/"常用资源"分组标题
- 仅卡片内容
- 关联:PRD §4.5
TC-010-4 [P0] UI:FIFO 插入验证
- 前置条件:先产生卡 A,再产生卡 B
- 测试步骤:观察卡片顺序
- 预期结果:B 在 A 上方(最新优先)
- 关联:PRD §4.5 / §4.7.3
TC-010-5 [P0] UI:边框颜色区分 layer
- 前置条件:同时有 L1/L2/L3 卡
- 测试步骤:观察每张卡左边框
- 预期结果:
- L1 = 绿色
- L2 = 橙色
- L3 = 灰色
- A = 蓝色
- progress = 紫色
- 关联:PRD §4.5
TC-010-6 [P1] UI:操作步骤可展开
- 前置条件:A 来源步骤卡
- 测试步骤:点击"展开 ▼"
- 预期结果:显示完整步骤列表,按钮变"收起 ▲"
- 关联:PRD §4.6
TC-010-7 [P1] 性能:右侧栏渲染 < 200ms
- 前置条件:10 张卡准备就绪
- 测试步骤:使用浏览器 Performance API 测量
- 预期结果:render 时间 < 200ms
- 关联:技术方案 §14.1
TC-010-8 [P1] 性能:T1 异步触发 < 3s
- 前置条件:正常响应
- 测试步骤:测量从用户发消息到右侧栏出现卡的时间
- 预期结果:< 3s
- 关联:技术方案 §14.1
TC-010-9 [P1] 性能:T0 同步触发零延迟
- 前置条件:Dify 返回 action
- 测试步骤:测量 ai_reply 与右侧栏卡的时间差
- 预期结果:同一 WS 包发出(0ms 延迟)
- 关联:技术方案 §14.1
TC-010-10 [P1] WS 断连降级
- 前置条件:手动断开 WS
- 测试步骤:
- 断开 WS
- 触发 AI 回复
- 重连 WS
- 预期结果:
- 关联:技术方案 §14.2
六、验收标准对照(PRD §4.7 5 个决策)
| 决策 |
测试用例覆盖 |
状态 |
| ① 冷启动 A |
TC-006(6 条) |
✅ 100% |
| ② 多源合并 B |
TC-005(8 条) |
✅ 100% |
| ③ 触发失败降级 B |
TC-007(8 条) |
✅ 100% |
| ④ 话题切换检测 B |
TC-008(8 条) |
✅ 100% |
| ⑤ 跨会话持久化 B |
TC-009(6 条) |
✅ 100% |
| §4.7.1 4 类触发源 |
TC-001~004(36 条) |
✅ 100% |
| §4.7.2 3 种触发时机 |
TC-001~003(28 条) |
✅ 100% |
| §4.7.5 触发失败降级 |
TC-007(8 条) |
✅ 100% |
七、灰度验证标准
| 阶段 |
规模 |
通过条件 |
用例支撑 |
| 1% |
10 人,1 天 |
无 P0/P1 失败 |
TC-010-1~10 全通过 |
| 10% |
100 人,2 天 |
点击率 > 5%(recommend_event 埋点) |
TC-005/TC-009 |
| 50% |
500 人,3 天 |
点击率 > 10% |
TC-005/TC-009 |
| 100% |
全量 |
点击率 > 15%,自助解决率 > 10% |
长期监控 |
八、风险与边界
| 边界场景 |
处理策略 |
| 浏览器禁用 localStorage |
持久化失效,仅当前会话有效 |
| 用户清空浏览器数据 |
所有持久化数据丢失 |
| 多设备登录同一账号 |
localStorage 仅本机生效 |
| Dify 升级改变 action 结构 |
兼容旧字段解析(向后兼容) |
| 企微 webhook 推送频率异常 |
60s 轮询兜底 |
九、关联文档
- PRD(冻结):
docs/01-产品文档/05-用户端H5/PRD-REQ-用户-006-智能推荐重构-v1.0-Frozen.md
- 技术方案:
docs/02-技术文档/技术架构/技术方案-REQ-用户-006-智能推荐重构-v1.0.md
- 任务说明书:
docs/07-项目管理/任务说明书/任务说明书-REQ-用户-006-智能推荐重构.md
- 原型图:
docs/01-产品文档/05-用户端H5/原型-REQ-用户-006-智能推荐重构-v1.0.html
- 现有代码:
src/backend/tests/services/test_asset_recommend.py(升级为 v2)
src/backend/tests/services/test_recommend_progress.py(新增)
src/backend/tests/services/test_topic_detector.py(新增)
src/frontend-h5/tests/stores/recommendStore.test.ts(新增)
十、变更日志
| 版本 |
日期 |
变更内容 |
作者 |
| v1.0 |
2026-07-28 19:31 |
初版:76 条用例覆盖 4 类触发源 + 3 种时机 + 多源合并 + 冷启动 + 降级 + 话题切换 + 持久化 + E2E;100% 覆盖 PRD §4.7 5 个决策 |
Duckula + 宋献 |