# 测试用例 — AI自进化功能模块 ## 1. 需求依据 - **PRD路径**:`/data/share/project/docs/PRD-self-evolution.md` - **文档版本**:v1.0(2026-05-26) - **功能概述**:Qihu-AIFlow平台AI自进化功能。每个用户的AI在对话中持续学习进化,前端通过「AI进化驾驶舱」展示进化过程。深度整合xSkill开源框架,实现对话轨迹→原子任务→技能聚类→技能生成→灰度验证的完整流水线。 ### 需求侧功能模块(共6大模块) | 编号 | 需求模块 | PRD章节 | 功能点数 | |------|----------|---------|----------| | R1 | 默认全局持续进化 | 7.2-功能一 | 5 | | R2 | 对话自动分析(xSkill流水线) | 7.2-功能二 | 7 | | R3 | 技能库管理 | 7.2-功能三 | 6 | | R4 | AI进化驾驶舱(4个子面板) | 7.2-功能四 | 14 | | R5 | 与AI聊天无缝衔接 | 7.2-功能五 | 5 | | R6 | 数据隔离(用户级别) | 7.2-功能六 | 6 | --- ## 2. 代码功能模块概览 ### 2.1 后端代码模块 | 模块 | 说明 | 主要代码位置 | |------|------|-------------| | 技能管理API | 技能CRUD、冻结/解冻、历史/轨迹查询 | `backend/python/app/api/evolution.py:33-139` | | 进化事件API | 进化事件列表查询 | `backend/python/app/api/evolution.py:143-157` | | 驾驶舱数据API | 技能树/时间线/统计/画像4面板数据 | `backend/python/app/api/evolution.py:160-202` | | 轨迹提交API | 对话轨迹提交入口 | `backend/python/app/api/evolution.py:205-214` | | EvolutionService | 核心业务逻辑层,12个公开方法 | `backend/python/app/services/evolution_service.py` | | 数据模型(ORM) | 4张表定义 | `backend/python/app/models.py:741-792` | | 路由注册 | prefix="/app/api/evolution" | `backend/python/main.py:140` | ### 2.2 前端代码模块 | 模块 | 说明 | 主要代码位置 | |------|------|-------------| | AI进化驾驶舱页面 | 主页面组件(4面板切换+数据加载) | `frontend/src/pages/front/EvolutionDashboard.tsx` (631行) | | 驾驶舱样式 | 完整CSS样式 | `frontend/src/pages/front/EvolutionDashboard.css` (1019行) | | 技能图谱面板 | Panel A:按分类分组展示技能节点 | `EvolutionDashboard.tsx:48-152` | | 进化时间线面板 | Panel B:垂直时间线+事件筛选 | `EvolutionDashboard.tsx:155-201` | | 技能使用统计面板 | Panel C:排行+趋势图+饼图+提醒 | `EvolutionDashboard.tsx:205-340` | | AI能力画像面板 | Panel D:等级环+雷达图+标签云+建议 | `EvolutionDashboard.tsx:344-500` | | evolutionAPI | 前端API调用定义(15个方法) | `frontend/src/api/index.ts:415-455` | | 类型定义 | TypeScript interfaces | `frontend/src/types/index.ts:381-478` | | 路由配置 | `#/evolution` | `frontend/src/App.tsx:98` | | 导航入口 | 侧边栏"AI进化" | `frontend/src/components/layout/FrontLayout.tsx:14` | --- ## 3. 需求与代码差异说明 ### 3.1 PRD中未在代码中体现的内容 | 编号 | PRD功能点 | 状态 | 说明 | |------|-----------|------|------| | GAP-01 | **技能回滚**:POST /skills/{name}/rollback/{version} | ❌ 未实现 | PRD明确要求回滚到历史版本,但API中无此端点,前端无回滚UI | | GAP-02 | **对话溯源跳转**:点击来源对话可跳转到原始对话记录 | ❌ 未实现 | PRD要求"点击可跳转到原始对话记录",前端技能详情弹窗中有来源轨迹按钮但仅调用API(`evolutionAPI.getSkillTrajectories`),后端 `get_skill_trajectories` 返回的是用户最近20条轨迹而非该技能的关联轨迹 | | GAP-03 | **新技能萌芽动画** | ❌ 未实现 | PRD面板A中要求"新技能生成时,技能树上有「萌芽」动画效果",前端代码中未找到相关CSS动画 | | GAP-04 | **时间线导出** | ❌ 未实现 | PRD面板B要求"支持将进化时间线导出为图片或PDF分享",前端代码中无导出功能 | | GAP-05 | **画像分享卡片** | ❌ 未实现 | PRD面板D要求"支持将AI能力画像生成为分享卡片",前端代码中无此功能 | | GAP-06 | **Skill加载提示标签** | ❌ 未实现 | PRD功能五要求"在消息下方显示小标签:🚀 使用了你的专属技能:XXX",代码中未见此实现 | | GAP-07 | **对话结束钩子(自动提交轨迹)** | ❌ 未自动触发 | PRD要求对话结束时自动提交轨迹,但当前仅提供手动API入口 `/trajectory/submit`,前端ChatPage中未见对话结束自动调用的钩子 | | GAP-08 | **Watcher线程管理** | ❌ 未实现 | PRD要求用户注册后自动启动watcher线程持续进化,`UserEvolutionConfig`模型已定义但服务层无读写该表的代码,watcher状态管理未实现 | | GAP-09 | **xSkill管线自动调度** | ❌ 未实现 | PRD要求轨迹进入xSkill流水线自动处理,但后端仅实现轨迹落盘(status=discovered),后续状态流转(splitting→...→done)依赖外部xSkill进程 | | GAP-10 | **统计图表的交互联动** | ❌ 未实现 | PRD面板C要求"点击统计图表中的任意项可跳转到对应技能详情",前端StatisticsPanel中无此交互 | ### 3.2 PRD中未覆盖但代码中存在的功能模块 | 编号 | 代码模块 | 位置 | 说明 | 建议产品确认 | |------|----------|------|------|-------------| | EXTRA-01 | **evolutionAPI.submitTrajectory** 提供独立的手动轨迹提交入口 | `api/index.ts:453` | 前端API层暴露了轨迹提交方法,但在当前驾驶舱页面中未被任何组件调用 | 是否需要在驾驶舱中增加手动提交轨迹的入口? | | EXTRA-02 | **能力维度雷达图使用内联SVG实现** | `EvolutionDashboard.tsx:398-466` | 前端用内联SVG而非第三方图表库绘制雷达图,包含5层参考多边形、轴线、数据多边形 | 技术决策,无需产品确认 | --- ## 4. 测试用例 ### 4.1 技能管理 API #### TC-SKILL-01 [P0] 验证获取当前用户技能列表 - **前置条件**:用户已登录;数据库中存在该用户的技能数据 - **步骤**: [1] 使用有效JWT Token调用 `GET /app/api/evolution/skills` [2] 检查响应状态码和结构 - **预期结果**: - HTTP 200,响应包含 `code: 0` - `data` 为数组,每项包含 `id, skill_name, description, tags, category, state, use_count, version, created_at, updated_at` - 仅返回当前用户的技能数据,不包含其他用户的技能 - **备注**:默认按 `updated_at` 降序排列 #### TC-SKILL-02 [P0] 验证按状态过滤技能 - **前置条件**:数据库中存在不同状态的技能 - **步骤**: [1] 调用 `GET /app/api/evolution/skills?state=baby` [2] 调用 `GET /app/api/evolution/skills?state=main` [3] 调用 `GET /app/api/evolution/skills?state=frozen` [4] 调用 `GET /app/api/evolution/skills?state=staging` - **预期结果**: - 每次返回的技能 `state` 字段均匹配查询参数 - 传入无效状态值时系统行为一致(返回空列表或400错误) - **备注**:P0 覆盖核心过滤逻辑 #### TC-SKILL-03 [P0] 验证按关键词搜索技能 - **前置条件**:数据库中存在技能名包含"python"和"写作"的技能 - **步骤**: [1] 调用 `GET /app/api/evolution/skills?keyword=python` [2] 调用 `GET /app/api/evolution/skills?keyword=写作` [3] 调用 `GET /app/api/evolution/skills?keyword=不存在的关键词` - **预期结果**: - [1][2] 返回 `skill_name` 包含关键词的技能 - [3] 返回空列表 - **备注**:模糊匹配 #### TC-SKILL-04 [P1] 验证技能列表排序功能 - **前置条件**:数据库中存在多条技能记录 - **步骤**: [1] 调用 `GET /app/api/evolution/skills?sort_by=use_count&order=desc` [2] 调用 `GET /app/api/evolution/skills?sort_by=created_at&order=asc` [3] 调用 `GET /app/api/evolution/skills?sort_by=invalid_field` - **预期结果**: - [1] 按使用次数降序排列 - [2] 按创建时间升序排列 - [3] 返回错误或默认排序回退 #### TC-SKILL-05 [P0] 验证获取技能详情 - **前置条件**:数据库中存在技能名为"fix_python_bug"的技能 - **步骤**: [1] 调用 `GET /app/api/evolution/skills/fix_python_bug` [2] 调用 `GET /app/api/evolution/skills/不存在的技能名` - **预期结果**: - [1] HTTP 200,返回完整技能信息(含 `skill_md_content` 字段) - [2] HTTP 404,提示技能不存在 - **备注**:如果 `skill_md_path` 文件存在,`skill_md_content` 应包含文件内容 #### TC-SKILL-06 [P0] 验证编辑技能元数据 - **前置条件**:存在可编辑的技能 - **步骤**: [1] 调用 `PUT /app/api/evolution/skills/{skill_name}`,body: `{"description": "新描述", "tags": ["新标签"], "category": "新分类"}` [2] 再次获取该技能详情,检查变更 [3] 检查进化事件表中是否记录了编辑事件 - **预期结果**: - [1] HTTP 200,返回更新后的技能对象,`version` 字段 +1 - [2] 技能详情反映变更 - [3] `evolution_events` 表中新增一条 event_type="edited" 的记录,含 version_before/version_after - **备注**:仅可编辑 description, tags, category #### TC-SKILL-07 [P0] 验证删除技能 - **前置条件**:存在可删除的技能 - **步骤**: [1] 记录删除前的技能列表总数 N [2] 调用 `DELETE /app/api/evolution/skills/{skill_name}` [3] 调用 `GET /app/api/evolution/skills` 检查技能列表 [4] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认已不存在 [5] 检查进化事件表中是否记录了删除事件 - **预期结果**: - [2] HTTP 200 - [3] 技能列表总数为 N-1 - [4] HTTP 404 - [5] `evolution_events` 表中新增 event_type="deleted" 的记录 - **备注**:删除后事件表仍保留历史记录 #### TC-SKILL-08 [P0] 验证冻结技能 - **前置条件**:存在一个 state 为 "main" 的技能 - **步骤**: [1] 调用 `POST /app/api/evolution/skills/{skill_name}/freeze` [2] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认状态 [3] 对已冻结的技能再次调用 freeze - **预期结果**: - [1] HTTP 200,state 变为 "frozen" - [2] state 为 "frozen" - [3] 幂等操作,不报错(state 保持 "frozen") - 事件表中新增 event_type="frozen" 的记录 #### TC-SKILL-09 [P0] 验证解冻技能 - **前置条件**:存在一个 state 为 "frozen" 的技能 - **步骤**: [1] 调用 `POST /app/api/evolution/skills/{skill_name}/unfreeze` [2] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认状态 - **预期结果**: - [1] HTTP 200,state 变为 "main" - [2] state 为 "main" - 事件表中新增 event_type="unfrozen" 的记录 #### TC-SKILL-10 [P1] 验证技能版本历史查询 - **前置条件**:某技能经历多次编辑/冻结/解冻操作 - **步骤**: [1] 调用 `GET /app/api/evolution/skills/{skill_name}/history` [2] 检查返回的事件列表 - **预期结果**: - HTTP 200,返回按照 `created_at` 排序的事件列表 - 每项包含 event_type, description, version_before, version_after, created_at - 支持未操作过的技能(返回空数组) #### TC-SKILL-11 [P1] 验证技能来源轨迹查询 - **前置条件**:存在技能和对应的轨迹数据 - **步骤**: [1] 调用 `GET /app/api/evolution/skills/{skill_name}/trajectories` - **预期结果**: - HTTP 200 - 返回该技能的关联轨迹列表(最多20条) - **备注**:后端 `get_skill_trajectories` 当前仅按 user_id 过滤,未按 skill_name 过滤——此为缺陷,已记录在 3.1 GAP-02 --- ### 4.2 进化事件 API #### TC-EVENT-01 [P0] 验证获取进化事件列表 - **前置条件**:数据库中已有多条进化事件记录 - **步骤**: [1] 调用 `GET /app/api/evolution/events` [2] 检查返回的事件列表 - **预期结果**: - HTTP 200,最多返回50条(默认 limit) - 每项包含 id, skill_name, event_type, description, version_before, version_after, created_at - 仅返回当前用户的进化事件 #### TC-EVENT-02 [P1] 验证按事件类型筛选 - **前置条件**:数据库中有不同类型的进化事件 - **步骤**: [1] 调用 `GET /app/api/evolution/events?event_type=created` [2] 调用 `GET /app/api/evolution/events?event_type=frozen` [3] 调用 `GET /app/api/evolution/events?event_type=edited` - **预期结果**:每次返回的事件类型均匹配筛选条件 #### TC-EVENT-03 [P1] 验证按技能名筛选事件 - **前置条件**:某技能有多个关联事件 - **步骤**: [1] 调用 `GET /app/api/evolution/events?skill_name={skill_name}` - **预期结果**:仅返回该技能相关的进化事件 #### TC-EVENT-04 [P2] 验证limit参数边界 - **前置条件**:数据库中有大量事件记录 - **步骤**: [1] 调用 `GET /app/api/evolution/events?limit=1` [2] 调用 `GET /app/api/evolution/events?limit=200` [3] 调用 `GET /app/api/evolution/events?limit=201` [4] 调用 `GET /app/api/evolution/events?limit=0` - **预期结果**: - [1] 返回1条 - [2] 返回最多200条 - [3] 返回错误或限制到200 - [4] 返回错误或默认50条 --- ### 4.3 驾驶舱面板 API #### TC-DASH-01 [P0] 验证技能图谱数据 (dashboard/skill-tree) - **前置条件**:用户拥有多个分类的技能 - **步骤**: [1] 调用 `GET /app/api/evolution/dashboard/skill-tree` [2] 检查返回结构 - **预期结果**: - HTTP 200 - `data.categories` 为数组,每组包含 `name` 和 `skills[]` - `data` 包含统计字段:`total_count, main_count, baby_count, staging_count, frozen_count` - 技能数据仅限当前用户 #### TC-DASH-02 [P0] 验证进化时间线数据 (dashboard/timeline) - **前置条件**:用户有进化事件记录 - **步骤**: [1] 调用 `GET /app/api/evolution/dashboard/timeline` [2] 检查返回数据 - **预期结果**: - HTTP 200 - 返回事件列表,按 created_at 降序 - 支持 `event_type` 筛选参数 - 无事件时返回空数组 #### TC-DASH-03 [P0] 验证技能使用统计 (dashboard/statistics) - **前置条件**:用户有使用统计的历史数据 - **步骤**: [1] 调用 `GET /app/api/evolution/dashboard/statistics` [2] 检查返回数据结构 - **预期结果**: - HTTP 200 - `data` 包含字段:`ranking[]`(TOP N排行)、`total_use_count`、`category_distribution[]`、`daily_trend[]`、`low_use_skills[]` - `ranking` 中每项含 `skill_name, category, use_count, state, last_used_at` - `daily_trend` 数据点含 `date, count` #### TC-DASH-04 [P0] 验证AI能力画像 (dashboard/profile) - **前置条件**:用户有足够的技能数据支撑画像计算 - **步骤**: [1] 调用 `GET /app/api/evolution/dashboard/profile` [2] 检查返回结构 - **预期结果**: - HTTP 200 - `data` 包含字段:`level`(1-10的等级)、`level_title`(等级称号)、`total_skills`、`active_skills`、`staging_skills`、`baby_skills`、`total_use_count` - `data.dimensions` 为数组,每项含 `label, value, maxValue` - `data.tags` 为能力标签数组 - `data.growth_suggestions` 为成长建议数组 #### TC-DASH-05 [P1] 验证驾驶舱数据空态响应 - **前置条件**:用户为新用户,无任何进化数据 - **步骤**: [1] 分别调用4个驾驶舱API端点 [2] 检查响应 - **预期结果**:均返回 HTTP 200,数据字段为空数组或零值,不报错 --- ### 4.4 轨迹提交 API #### TC-TRAJ-01 [P0] 验证提交对话轨迹 - **前置条件**:用户已登录 - **步骤**: [1] 调用 `POST /app/api/evolution/trajectory/submit` body: `{"conversation_id": "conv-001", "messages": [{"role": "user", "content": "帮我写一个Python函数"}, {"role": "assistant", "content": "好的..."}]}` [2] 检查响应 [3] 检查数据库 `evolution_trajectories` 表中新增记录 [4] 检查文件系统中轨迹文件是否生成 - **预期结果**: - [1] HTTP 200,`message` 为"轨迹已提交" - [2] `data` 包含 id, conversation_id, file_path, status="discovered", atom_count=0 - [3] 数据库中有新记录,`user_id` 为当前用户 - [4] 轨迹文件存在于 `/data/share/project/data/users/{user_id}/trajectories/traj_{id}/traj_{id}.md` #### TC-TRAJ-02 [P1] 验证提交轨迹消息格式兼容性 - **前置条件**:用户已登录 - **步骤**: [1] 提交包含多条轮次对话的轨迹 [2] 读取生成的轨迹文件内容 - **预期结果**: - 轨迹文件格式为xSkill兼容的Markdown:`# Conversation Trajectory` + `## User` / `## Assistant` 交替分段 - `token_used` 正确累计所有消息的 tokens 字段 #### TC-TRAJ-03 [P1] 验证轨迹提交数据隔离 - **前置条件**:两个不同用户(userA 和 userB) - **步骤**: [1] userA 提交一个轨迹 [2] userB 调用 `GET /app/api/evolution/events` 查询事件 [3] userB 调用 `GET /app/api/evolution/skills` 查询技能 - **预期结果**: - [2] userB 看不到 userA 的轨迹数据 - [3] userB 的技能数据不包含 userA 的技能 #### TC-TRAJ-04 [P2] 验证提交空消息列表 - **前置条件**:用户已登录 - **步骤**: [1] 调用 `POST /app/api/evolution/trajectory/submit`,body: `{"conversation_id": "conv-empty", "messages": []}` - **预期结果**: - 返回成功(或合理的错误提示"消息列表不能为空") - 轨迹状态正确记录 --- ### 4.5 数据隔离 #### TC-ISOL-01 [P0] 验证用户A不能访问用户B的技能 - **前置条件**:userA 和 userB 各自有技能数据 - **步骤**: [1] 使用 userA 的Token调用 `GET /app/api/evolution/skills` [2] 使用 userB 的Token调用 `GET /app/api/evolution/skills` [3] 使用 userA 的Token调用 `GET /app/api/evolution/skills/{userB的skill_name}` - **预期结果**: - [1] 仅返回 userA 的技能 - [2] 仅返回 userB 的技能 - [3] HTTP 404,userA 无法通过猜解技能名获取 userB 的数据 #### TC-ISOL-02 [P0] 验证用户A不能操作用户B的技能 - **前置条件**:userA 和 userB 各自有技能 - **步骤**: [1] 使用 userA 的Token调用 `PUT /app/api/evolution/skills/{userB的skill_name}` 尝试编辑 [2] 使用 userA 的Token调用 `DELETE /app/api/evolution/skills/{userB的skill_name}` 尝试删除 [3] 使用 userA 的Token调用 `POST /app/api/evolution/skills/{userB的skill_name}/freeze` 尝试冻结 - **预期结果**:所有操作返回 HTTP 404(技能不存在),不修改 userB 的数据 #### TC-ISOL-03 [P1] 验证用户A不能查看用户B的进化事件 - **前置条件**:两个用户都有进化事件 - **步骤**: [1] 使用 userA 的Token调用 `GET /app/api/evolution/events` [2] 检查返回列表中是否出现 userB 的技能名 - **预期结果**:不包含任何 userB 相关的事件 #### TC-ISOL-04 [P1] 验证用户A不能查看用户B的驾驶舱数据 - **前置条件**:两个用户都有进化数据 - **步骤**: [1] 使用 userA 的Token分别调用4个驾驶舱API [2] 检查返回数据中是否包含 userB 的技能/事件信息 - **预期结果**:所有驾驶舱API仅返回当前用户的数据 --- ### 4.6 前端—AI进化驾驶舱页面 #### TC-FE-01 [P0] 验证驾驶舱页面加载 - **前置条件**:用户已登录(admin账号) - **步骤**: [1] 导航到 `#/evolution` [2] 观察页面加载过程 [3] 检查页面标题和统计摘要 - **预期结果**: - 页面正常渲染,显示"AI进化驾驶舱"标题 - 加载过程中显示 loading spinner + "正在加载进化数据..." 文字 - 加载完成后显示统计数字(技能总数/已成熟/萌芽中) - Console 无JS错误 #### TC-FE-02 [P0] 验证技能图谱面板(Panel A) - **前置条件**:用户有技能数据 - **步骤**: [1] 切换到"技能图谱"面板 [2] 检查技能节点展示 [3] 鼠标悬停在技能节点上 [4] 点击某个技能节点 - **预期结果**: - 技能按 category 分组展示,不同状态用不同颜色标识(baby=粉色/main=绿色/staging=橙色/frozen=灰色) - hover 显示 tooltip(技能名+描述+版本+更新时间) - 点击弹出详情弹窗(名称/状态/版本/使用次数/分类/标签/操作按钮) - 底部有状态色标图例 - 无技能时显示空态 #### TC-FE-03 [P0] 验证进化时间线面板(Panel B) - **前置条件**:用户有进化事件数据 - **步骤**: [1] 切换到"进化时间线"面板 [2] 检查时间线布局 [3] 点击不同的筛选按钮(全部/诞生/晋升/里程碑/更新/冻结/退回) [4] 检查事件卡片内容 - **预期结果**: - 垂直时间线展示,左侧圆点+连接线,右侧卡片 - 卡片显示:事件类型+技能名+描述+时间戳 - 筛选按钮正常工作,筛选结果正确 - 无事件时显示空态 #### TC-FE-04 [P0] 验证技能使用统计面板(Panel C) - **前置条件**:用户有使用统计数据 - **步骤**: [1] 切换到"技能使用统计"面板 [2] 检查技能使用排行 [3] 检查调用趋势图 [4] 检查类别分布饼图 [5] 检查低使用技能提醒(如有) - **预期结果**: - 排行条形图正常渲染,Top 3 带紫色渐变标记 - 趋势柱状图显示 Top 4 技能 - 饼图中心显示总调用次数,图例显示各分类占比 - 超过30天未使用的技能显示黄色警告提醒 - 无数据时显示"暂无数据" - Panel切换时按需加载统计数据 #### TC-FE-05 [P0] 验证AI能力画像面板(Panel D) - **前置条件**:用户有足够的技能数据 - **步骤**: [1] 切换到"AI能力画像"面板 [2] 检查等级卡片 [3] 检查能力雷达图 [4] 检查能力标签云 [5] 检查成长建议 - **预期结果**: - 等级卡片显示环形进度条(level/10)+ 等级数字 + 称号 + 四项统计 - 雷达图显示能力维度(文字创作/数据分析/代码能力/知识问答/流程自动化/创意生成等) - 标签云有4级尺寸和6种颜色循环 - 成长建议列表以黄色星标开头 - 无画像数据时显示空态 #### TC-FE-06 [P1] 验证面板切换 - **前置条件**:页面已加载 - **步骤**: [1] 依次点击4个面板切换按钮 [2] 来回切换 panels [3] 切换过程中检查加载状态 - **预期结果**: - 面板切换流畅,当前面板高亮 - statistics 和 profile 面板首次进入时显示"加载中..." - 返回已加载过的面板不重新请求数据 #### TC-FE-07 [P1] 验证错误状态和重试 - **前置条件**:页面已加载 - **步骤**: [1] 模拟后端API返回错误(或断开网络) [2] 观察页面反应 [3] 点击"重试"按钮 - **预期结果**: - 页面显示错误消息 - "重试"按钮可见且可用 - 点击"重试"重新发起API请求 #### TC-FE-08 [P1] 验证未登录状态 - **前置条件**:用户未登录 - **步骤**: [1] 清除 localStorage 中的 token [2] 导航到 `#/evolution` - **预期结果**:自动重定向到 `#/login` #### TC-FE-09 [P2] 验证CSS样式完整性 - **前置条件**:页面正常加载 - **步骤**: [1] 检查所有面板的CSS类名是否存在 [2] 检查loading spinner动画是否流畅 [3] 检查响应式布局(不同分辨率下) - **预期结果**: - 所有CSS类在 `EvolutionDashboard.css` 中有定义 - 旋转动画正常工作 - 各分辨率下布局正常 --- ### 4.7 前端—技能管理UI(技能详情弹窗中的操作) #### TC-FE-MGR-01 [P1] 验证技能详情弹窗中显示操作按钮 - **前置条件**:在技能图谱面板中点击某技能节点 - **步骤**: [1] 检查弹窗内容 [2] 确认操作按钮可见 - **预期结果**: - 弹窗显示技能完整信息 - 包含编辑/删除/冻结(或解冻)等操作按钮 - 操作按钮根据技能状态正确切换(已冻结显示"解冻",否则显示"冻结") #### TC-FE-MGR-02 [P1] 验证前端调用冻结API - **前置条件**:弹窗中显示"冻结"按钮 - **步骤**: [1] 点击"冻结"按钮 [2] 观察反馈 [3] 刷新技能列表确认状态变化 - **预期结果**: - API调用 `/app/api/evolution/skills/{name}/freeze` 成功 - 技能状态变为"frozen" - 前端显示操作成功提示 #### TC-FE-MGR-03 [P1] 验证前端调用删除API - **前置条件**:弹窗中显示"删除"按钮 - **步骤**: [1] 点击"删除"按钮 [2] 确认删除(如有确认弹窗) [3] 观察技能列表变化 - **预期结果**: - API调用 `DELETE /app/api/evolution/skills/{name}` 成功 - 技能从列表中移除 - 前端显示删除成功提示 --- ### 4.8 数据库表结构验证 #### TC-DB-01 [P0] 验证 evolution_skills 表结构 - **前置条件**:数据库连接正常 - **步骤**: [1] 查询表结构 [2] 验证所有字段存在且类型正确 - **预期结果**:表包含字段: id(PK), user_id(FK+INDEX), skill_name, description, tags(JSON), category, state, use_count, version, skill_md_path, git_commit_sha, last_used_at, created_at, updated_at #### TC-DB-02 [P0] 验证 evolution_events 表结构 - **前置条件**:数据库连接正常 - **步骤**: [1] 查询表结构 - **预期结果**:表包含字段: id(PK), user_id(FK+INDEX), skill_name, event_type, description, version_before, version_after, created_at #### TC-DB-03 [P0] 验证 evolution_trajectories 表结构 - **前置条件**:数据库连接正常 - **步骤**: [1] 查询表结构 - **预期结果**:表包含字段: id(PK), user_id(FK+INDEX), conversation_id, file_path, status, atom_count, token_used, created_at, processed_at #### TC-DB-04 [P0] 验证 user_evolution_config 表结构 - **前置条件**:数据库连接正常 - **步骤**: [1] 查询表结构 - **预期结果**:表包含字段: id(PK), user_id(FK+UNIQUE+INDEX), skill_dir_path, trajectory_dir_path, watcher_status, created_at, updated_at --- ### 4.9 技能状态流转验证 #### TC-STATE-01 [P0] 验证技能状态 baby → main - **前置条件**:存在 state="baby" 的技能 - **步骤**: [1] 通过数据层直接更新该技能 state="main" [2] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认状态 - **预期结果**:状态成功变更为 main #### TC-STATE-02 [P0] 验证技能状态 main → staging → main - **前置条件**:存在 state="main" 的技能 - **步骤**: [1] 更新 state="staging" [2] 查询确认 [3] 更新 state="main" [4] 查询确认 - **预期结果**:状态变更成功 #### TC-STATE-03 [P0] 验证技能状态 main → frozen → main - **前置条件**:存在 state="main" 的技能 - **步骤**: [1] 调用 freeze API [2] 确认 state="frozen" [3] 调用 unfreeze API [4] 确认 state="main" - **预期结果**:完整走通 freeze→unfreeze 循环,事件表记录完整 --- ## 5. 测试用例统计 | 类别 | P0 | P1 | P2 | 合计 | |------|----|----|----|------| | 技能管理 API | 7 | 2 | 0 | 9 | | 进化事件 API | 1 | 2 | 1 | 4 | | 驾驶舱面板 API | 4 | 1 | 0 | 5 | | 轨迹提交 API | 1 | 2 | 1 | 4 | | 数据隔离 | 2 | 2 | 0 | 4 | | 前端驾驶舱页面 | 4 | 3 | 1 | 8 | | 前端技能管理UI | 0 | 3 | 0 | 3 | | 数据库表结构 | 4 | 0 | 0 | 4 | | 技能状态流转 | 3 | 0 | 0 | 3 | | **合计** | **26** | **15** | **3** | **44** | --- ## 6. PRD未覆盖的代码功能模块(需产品确认) | 编号 | 模块 | 代码位置 | 建议确认项 | |------|------|----------|-----------| | EXTRA-01 | 独立轨迹提交API | `api/index.ts:453` | 驾驶舱页面是否需要手动轨迹提交入口? | | EXTRA-02 | SVG内联雷达图 | `EvolutionDashboard.tsx:398-466` | 技术决策,无需产品确认 | --- ## 7. 测试环境要求 - **后端服务**:Python FastAPI 服务运行于 localhost:18080 - **前端服务**:React 应用通过 Nginx 代理运行于 8080 端口 - **数据库**:MySQL 8 (localhost:3306, root/pwd2026) - **认证方式**:JWT Bearer Token,通过 POST /app/api/auth/login 获取 - **测试用户**:admin (管理员), demo_user (普通用户) --- > **文档生成时间**:2026-05-29 > **文档版本**:v1.0 > **基于代码版本**:evolution.py (215行) + evolution_service.py (473行) + EvolutionDashboard.tsx (631行) > **PRD版本**:v1.0 (2026-05-26)