Files
wecom_it_smart_desk/docs/03-测试文档/03-功能测试用例/TC-用户-006-智能推荐重构.md
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交
(5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。

一、docs 结构整改(整改 #14)
根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入,
随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录
树并存于 docs/,共 791 文件、双分类体系冲突。

修复动作:
- b2 同名异主题文件改名迁移保全 9 个
- C 类 39 个孤立文件按主题正确归类
- A/B1 类 222 个重复文件删除(新结构已有内容副本)
- 9 个旧独有空目录删除
- 270 处内部引用按 verified 映射改写
- 整改记录 #14 登记于 04-运维文档/部署运维

结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。
残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。

二、compose 双目录对齐(消除踩坑 A)
- docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist
  改为 src/frontend-*/dist(h5 / agent / admin / terminal)
- docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/
- 效果:本地 docker compose up 不再把根目录 stale dist 挂回,
  与线上一致,分叉隐患消除(已 docker compose config 校验通过)

防复发铁律:
- 重构须提交;仓库修复须 git stash -u 或先 commit
- 新结构须 git add 并提交,避免再次 untracked 复活
- H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2026-08-07 22:31:32 +08:00

32 KiB
Raw Permalink Blame History

测试用例 - 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.pyT2 webhook + 轮询)
  • 后端新增 topic_detector.pyJaccard 相似度)
  • 后端 _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-browserPlaywright
数据库 PostgreSQL 16 + Redis 7
外部 mock Dify 推理 / 企微审批 webhook / 火绒 API
环境 dev → staging → 生产灰度

四、用例分类规则

前缀 模块 用例数
TC-001 来源 ADify actionT0 同步) 8
TC-002 来源 BL1 关键词(T1 异步) 10
TC-003 来源 CL2 画像(T1 异步) 10
TC-004 来源 DL3 角色(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 actionT0 同步)

TC-001-1 [P0] 来源 AAI 返回 action 后立即同步推送到左侧气泡

  • 前置条件:用户进入新会话,员工端 WS 已连接
  • 测试步骤
    1. 用户发送"我要申请 VPN"
    2. 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 同步推送到右侧栏

  • 前置条件:同上
  • 测试步骤
    1. 用户发送"VPN 连不上怎么办"
    2. Dify 返回 {text: "请重连", action: {type: "step_card", steps: [...]}}
  • 预期结果
    • 左侧气泡显示文字 + 来源图标
    • 右侧栏顶部插入操作步骤卡(蓝色边框,可展开)
  • 关联PRD §4.5 / §4.7.1 A

TC-001-3 [P1] 来源 Aaction 为空时不推送右侧栏

  • 前置条件Dify 返回 {text: "你好", action: null}
  • 测试步骤:触发 AI 回复
  • 预期结果
    • 左侧气泡显示文字
    • 右侧栏 不增加 任何卡片
    • 不出现"暂无推荐"提示
  • 关联:技术方案 §4.1

TC-001-4 [P1] 来源 Arecommend_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"
  • 测试步骤
    1. 用户点击气泡中的"申请"
    2. 跳转企微审批表单
    3. 用户提交审批
  • 预期结果
    • 提交瞬间右侧栏顶部插入审批进度占位卡(紫色边框,状态"pending"
    • 显示"VPN 申请 已发起,等待审批"
  • 关联:技术方案 §5.3 T2 / PRD §4.7.2

TC-001-6 [P2] 来源 Aaction.type 包含 contact_window 时只推左侧

  • 前置条件Dify 返回 action.type = "contact_window"
  • 测试步骤:触发 AI 回复
  • 预期结果
    • 左侧气泡显示联系窗口按钮
    • 右侧栏 不出现 该卡(PRD §4.7.1 A 限制)
  • 关联PRD §4.7.1 来源 A 补充决策

TC-001-7 [P2] 来源 Aaction.type 包含 contact_card 时只推左侧

  • 前置条件Dify 返回 action.type = "contact_card"
  • 测试步骤:同上
  • 预期结果
    • 左侧气泡显示联系人名片
    • 右侧栏不出现
  • 关联PRD §4.7.1 来源 A 补充决策

TC-001-8 [P2] 来源 Aaction.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] 来源 Bexclude_keywords 排除规则生效

  • 前置条件:配置 exclude_keywords: ["邮箱"]
  • 测试步骤:用户发送"我的收件箱打不开,邮箱登不上"
  • 预期结果
    • L1 邮箱卡 不出现(被排除)
    • 仅出现其他来源推荐
  • 关联:技术方案 §4.2 排除关键词

TC-002-6 [P1] 来源 B30 分钟同源抑制

  • 前置条件5 分钟前已推送过 L1 VPN 卡
  • 测试步骤:用户再次发送"VPN 又连不上了"
  • 预期结果
    • L1 VPN 卡 不重复推送30 分钟内同关键词抑制)
    • Redis 中存在 suppress:{employee_id}:vpn 键(TTL ≤ 30 分钟)
  • 关联PRD §4.7.3 同源抑制 / 技术方案 §6.4

TC-002-7 [P2] 来源 B30 分钟后可再次推送

  • 前置条件: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] 来源 BDify 同步识别意图时,来源 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 都无)

  • 前置条件:新员工,无任何画像数据
  • 测试步骤:同上
  • 预期结果
    • 来源 C 返回空
    • 走来源 D 降级(C → D
  • 关联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] 来源 CT1 异步触发 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] 来源 Dprofile.position 为 None 时跳过

  • 前置条件:新员工未填写岗位
  • 测试步骤:同上
  • 预期结果
    • 来源 D 返回空
    • 走来源 B + C 降级(D 失败 → B + C)
  • 关联:技术方案 §4.4

TC-004-5 [P1] 来源 D:英文 position 也能命中英文 key(兼容)

  • 前置条件profile.position = "developer"
  • 测试步骤:同上
  • 预期结果:精确匹配 developerconfidence = 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),但配置也有 "财务开发"
  • 测试步骤:同上
  • 预期结果
    • 多张 L3 卡
    • 按 confidence 排序
  • 关联:技术方案 §4.4 / §6.1

TC-004-8 [P2] 来源 Drole_assets 配置变更热重载

  • 前置条件:调用 asset_service.reload()
  • 测试步骤:修改 assets.yaml 后调用 reload
  • 预期结果
    • 配置生效,无需重启服务
    • 日志输出"配置热重载完成"
  • 关联:技术方案 §4.4 reload()

TC-005:多源合并规则(决策 ② B)

TC-005-1 [P0] 合并:同 recommend_id 去重,保留高 confidence

  • 前置条件A 来源产生 rec_001confidence=0.85+ B 来源也产生 rec_001confidence=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 回复
  • 预期结果
    • 右侧栏仅 3 张
    • 超出 2 张按排序丢弃
  • 关联PRD §4.7.3 上限规则

TC-005-4 [P1] 合并:同 layer 内按 confidence DESC

  • 前置条件L1 VPN0.85+ L1 邮箱(0.7
  • 测试步骤:触发 AI 回复
  • 预期结果
    • L1 VPN 在 L1 邮箱上方
  • 关联:技术方案 §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 推理完成
  • 测试步骤:观察右侧栏变化
  • 预期结果
    • 按 §4.7.3 合并规则填充
    • 顶部插入新卡
  • 关联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 从 emptypopulated
    • visibleCards 非空
  • 关联:技术方案 §7.1

TC-006-6 [P2] 冷启动:清空后 state 回到 empty

  • 前置条件:已有卡,用户清空
  • 测试步骤:调用 store.clearAll()
  • 预期结果state 回到 emptyvisibleCards = []
  • 关联:技术方案 §7.1

TC-007:触发失败降级(决策 ③ B)

TC-007-1 [P0] 降级:A 失败 → B + C + D

  • 前置条件Dify 返回非 JSON 或 action 为空
  • 测试步骤:触发 AI 回复
  • 预期结果
    • 来源 A 跳过
    • 来源 B/C/D 正常执行
  • 关联PRD §4.7.5

TC-007-2 [P0] 降级:B 失败 → C + D

  • 前置条件:用户消息不包含任何关键词(来源 B 返回空)
  • 测试步骤:触发 AI 回复
  • 预期结果
    • 来源 B 跳过
    • 来源 C/D 正常执行
  • 关联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 全部响应缓慢
  • 测试步骤:模拟慢响应
  • 预期结果
    • 3s 超时触发
    • 不阻塞主对话
    • 右侧栏空
  • 关联:技术方案 §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 卡插入
  • 测试步骤
    1. 关闭浏览器,重新打开
    2. 企微审批 webhook 推送 status="completed"
  • 预期结果
    • 关闭前 progress 卡仍在
    • webhook 后 progress 卡标记"已完成"
    • 后续不再显示(已完结)
  • 关联PRD §4.7.7 / 技术方案 §5.3

TC-009-5 [P1] 持久化:localStorage 配额超限降级

  • 前置条件localStorage 写入失败(QuotaExceededError
  • 测试步骤mock QuotaExceededError
  • 预期结果
    • 捕获异常
    • LRU 淘汰最旧数据
    • 新数据正常写入
  • 关联:技术方案 §10.1 / §15 R3

TC-009-6 [P2] 持久化:profile.position 变更时清空 L3

  • 前置条件:用户从"开发"调到"财务"
  • 测试步骤:修改 profile.position + 触发 AI 回复
  • 预期结果:原 L3 开发者资源清空,命中新 L3 财务资源
  • 关联PRD §4.7.7

TC-010E2E 集成 + UI 行为

TC-010-1 [P0] E2E:员工发"VPN 申请"完整链路

  • 前置条件agent-browser + dev 环境
  • 测试步骤
    1. 打开 H5 员工端
    2. 发送"我要申请 VPN"
    3. 观察 AI 回复 + 右侧栏
    4. 点击"申请"
  • 预期结果
    • 左侧气泡显示"VPN 申请"操作卡
    • 右侧栏顶部插入审批进度占位卡
    • 跳转企微审批表单
  • 关联:技术方案 §3.2 时序图 / 端到端

TC-010-2 [P0] E2E:话题切换 + 持久化组合

  • 前置条件:已有 L1/L2/progress 卡
  • 测试步骤
    1. 用户切换话题
    2. 验证 L1 清空
    3. 验证 L2/progress 保留
    4. 关闭浏览器重新打开
    5. 验证 L2/progress 仍在
  • 预期结果:所有规则同时生效
  • 关联:综合

TC-010-3 [P0] UI:右侧栏无标题

  • 前置条件:任意场景
  • 测试步骤:观察右侧栏
  • 预期结果
    • 顶部无" 智能推荐"标题
    • 顶部无"相关推荐"/"运维提醒"/"常用资源"分组标题
    • 仅卡片内容
  • 关联PRD §4.5

TC-010-4 [P0] UIFIFO 插入验证

  • 前置条件:先产生卡 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
  • 测试步骤
    1. 断开 WS
    2. 触发 AI 回复
    3. 重连 WS
  • 预期结果
    • 断连期间 store 保持现有卡
    • 重连后增量同步
  • 关联:技术方案 §14.2

六、验收标准对照(PRD §4.7 5 个决策)

决策 测试用例覆盖 状态
① 冷启动 A TC-0066 条) 100%
② 多源合并 B TC-0058 条) 100%
③ 触发失败降级 B TC-0078 条) 100%
④ 话题切换检测 B TC-0088 条) 100%
⑤ 跨会话持久化 B TC-0096 条) 100%
§4.7.1 4 类触发源 TC-001~00436 条) 100%
§4.7.2 3 种触发时机 TC-001~00328 条) 100%
§4.7.5 触发失败降级 TC-0078 条) 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 种时机 + 多源合并 + 冷启动 + 降级 + 话题切换 + 持久化 + E2E100% 覆盖 PRD §4.7 5 个决策 Duckula + 宋献