0a9588abb7
- Add pagination support to findAll (page, limit query params) - Add findByTemplateId method to service - Add GET /by-template/:templateId endpoint to controller - Service already includes CRUD for QuestionBank and QuestionBankItem
19 KiB
19 KiB
AuraK 评估系统完整实施计划
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: 构建完整的AI人才评估系统,包含题库管理、维度均衡抽取、审核流程、评估统计
Architecture:
- 题库通过模板间接关联知识库分组
- 评估时从题库维度均衡抽取,不足时实时生成备用
- 管理员通过独立页面管理题库和查看统计
Tech Stack: NestJS + TypeORM + LangGraph + React + TypeScript
一、问题与方案对照表
| # | 待修复问题 | 解决思路 | 对应Task |
|---|---|---|---|
| 1 | 评分计算错误 | 已修复 | ✅ |
| 2 | 题目维度分配不均 | 已修复 | ✅ |
| 3 | 多轮对话中断 | 已修复 | ✅ |
| 4 | 计数器显示错误 | 已修复 | ✅ |
| 5 | 历史问答查询 | 统计页面 | Task 4 |
| 6 | 知识覆盖度来源 | 用户不 care | - |
| 7 | 实时反馈无内容 | 用户确认已有内容 | - |
| 8 | 预生成题目功能 | 题库+抽取 | Task 1,2,3 |
| 9 | 题目生成不稳定 | 题库前置 | Task 1,7 |
| 10 | 题目来源不是知识库 | 题库+范围控制 | Task 1,3 |
| 11 | 选择题实际无选项 | 题库管理 | Task 1,5 |
二、系统架构
2.1 数据层级
KnowledgeGroup(知识库分组)
↓
AssessmentTemplate(模板)→ 题目数量、知识库配置
↓
QuestionBank(题库)→ 审核状态
↓
QuestionBankItem(题目)→ 维度/难度/答案
↓
评估抽取使用
2.2 评估流程
开始评估
↓
1. 加载模板配置(题目数量、维度配置)
↓
2. 检查已发布题库题目数量
↓
充足 → 维度均衡随机抽取 → 进入答题
不足 → 实时生成题目(备用) → 进入答题
↓
3. 用户答题 → 即时评分 → 实时反馈
↓
4. 追问(如Grader判断需要)
↓
5. 答题完成 → 生成报告 + 记录统计
三、数据模型
3.1 QuestionBank(题库)
// server/src/assessment/entities/question-bank.entity.ts
@Entity('question_banks')
export class QuestionBank {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'template_id' })
templateId: string;
@ManyToOne(() => AssessmentTemplate)
@JoinColumn({ name: 'template_id' })
template: AssessmentTemplate;
@Column({ name: 'name' })
name: string; // 题库名称
@Column({ type: 'text', description: '题库描述' })
description: string;
@Column({ type: 'enum', enum: QuestionBankStatus, default: QuestionBankStatus.DRAFT })
status: QuestionBankStatus; // DRAFT | PENDING_REVIEW | PUBLISHED
@Column({ name: 'created_by' })
createdBy: string;
@Column({ name: 'reviewed_by', nullable: true })
reviewedBy: string;
@Column({ name: 'reviewed_at', nullable: true })
reviewedAt: Date;
@Column({ name: 'review_comment', nullable: true })
reviewComment: string; // 审核意见
@OneToMany(() => QuestionBankItem, item => item.bank)
items: QuestionBankItem[];
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
enum QuestionBankStatus {
DRAFT = 'DRAFT', // 草稿
PENDING_REVIEW = 'PENDING_REVIEW', // 待审核
PUBLISHED = 'PUBLISHED', // 已发布
REJECTED = 'REJECTED', // 审核拒绝
}
3.2 QuestionBankItem(题目)
// server/src/assessment/entities/question-bank-item.entity.ts
@Entity('question_bank_items')
export class QuestionBankItem {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ name: 'bank_id' })
bankId: string;
@ManyToOne(() => QuestionBank, bank => bank.items)
@JoinColumn({ name: 'bank_id' })
bank: QuestionBank;
@Column({ type: 'text', name: 'question_text' })
questionText: string;
@Column({ type: 'enum', enum: QuestionType })
questionType: QuestionType; // SHORT_ANSWER | MULTIPLE_CHOICE | TRUE_FALSE
@Column({ type: 'simple-json', nullable: true })
options: string[]; // 选择题选项 ["A. xxx", "B. xxx", ...]
@Column({ type: 'text', nullable: true })
correctAnswer: string; // 正确答案
@Column({ type: 'simple-json', name: 'key_points' })
keyPoints: string[]; // 关键点 ["point1", "point2"]
@Column({ type: 'enum', enum: QuestionDifficulty })
difficulty: QuestionDifficulty; // STANDARD | ADVANCED | SPECIALIST
@Column({ type: 'enum', enum: QuestionDimension })
dimension: QuestionDimension; // PROMPT | LLM | IDE | DEV_PATTERN | WORK_CAPABILITY
@Column({ type: 'text', name: ' basis', nullable: true })
basis: string; // 出题依据
@Column({ name: 'created_by' })
createdBy: string;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
}
enum QuestionType {
SHORT_ANSWER = 'SHORT_ANSWER', // 简答题
MULTIPLE_CHOICE = 'MULTIPLE_CHOICE', // 选择题
TRUE_FALSE = 'TRUE_FALSE', // 判断题
}
enum QuestionDifficulty {
STANDARD = 'STANDARD', // 标准
ADVANCED = 'ADVANCED', // 进阶
SPECIALIST = 'SPECIALIST', // 专家
}
enum QuestionDimension {
PROMPT = 'PROMPT', // 提示词
LLM = 'LLM', // LLM原理
IDE = 'IDE', // IDE协作
DEV_PATTERN = 'DEV_PATTERN', // 开发范式
WORK_CAPABILITY = 'WORK_CAPABILITY', // 工作能力
}
3.3 评估统计
// API返回结构
interface AssessmentStats {
// 统计卡片
totalAttempts: number; // 总考核次数
highestScore: number; // 最高分
averageScore: number; // 平均分
completionRate: number; // 完成率
// 得分趋势(可选用于图表)
scoreTrend: { date: string; score: number }[];
// 历史记录
recentRecords: {
id: string;
knowledgeBase: string;
template: string;
score: number;
status: 'IN_PROGRESS' | 'COMPLETED';
createdAt: string;
}[];
}
四、API设计
4.1 题库管理API
// 题库CRUD
POST /api/question-banks // 创建题库
GET /api/question-banks // 列表(带分页)
GET /api/question-banks/:id // 详情(含题目)
PUT /api/question-banks/:id // 更新题库信息
DELETE /api/question-banks/:id // 删除题库
// 题目管理
POST /api/question-banks/:bankId/items // 添加单题
PUT /api/question-banks/:bankId/items/:id // 更新题目
DELETE /api/question-banks/:bankId/items/:id // 删除题目
// 批量操作
POST /api/question-banks/:bankId/batch-add // 批量添加题目(AI生成或Excel导入)
POST /api/question-banks/:bankId/generate // AI批量生成待审核
// 审核流程
PUT /api/question-banks/:id/submit // 提交审核(草稿→待审核)
PUT /api/question-banks/:id/review // 审核(通过/拒绝,附带意见)
PUT /api/question-banks/:id/publish // 发布(审核通过→已发布)
PUT /api/question-banks/:id/unpublish // 下架
// 模板关联
GET /api/question-banks/by-template/:templateId // 按模板查询题库
4.2 统计API
// 评估统计
GET /api/assessment/stats // 当前用户统计
GET /api/assessment/stats/admin // 管理员统计(所有用户)
Query: startDate, endDate, templateId, knowledgeGroupId
五、前端页面设计
5.1 题库管理页面(QuestionBankView)
┌──────────────────────────────────────────────────────────────────────────┐
│ 题库管理 [新建题库] │
├────────────┬─────────────────────────────────────────────────────┤
│ 我的题库 │ 筛选: [模板▼] [状态▼] [维度▼] [难度▼] [搜索...] │
│ ├─────────────────────────────────────────────────────┤
│ □ AI开发 │ ┌────┬────────┬────────┬──────┬────────────┐ │
│ □ Python │ │选择│ 题目内容│ 题型 │ 维度 │ 难度 │ 操作│ │
│ │ ├────┼────────┼────────┼──────┼────────────┤ │
│ │ │ ○ │xxx │ 简答 │ llm │ 标准 │编辑│ │
│ │ │ ○ │xxx │ 选择 │ ide │ 进阶 │编辑│ │
│ │ │ ○ │xxx │ 判断 │ Work │ 专家 │删除│ │
│ │ └────┴────────┴────────┴──────┴────────────┘ │
│ │ [批量导入] │
│ ├─────────────────────────────────────────────────────┤
│ │ [AI批量生成] [提交审核] [全选] [取消选择] │
└────────────┴─────────────────────────────────────────────────────┘
5.2 题库详情/编辑面板
┌────────────────────────────────────┐
│ 编辑题目 [保存] │
├────────────────────────────────────┤
│ 题目内容 │
│ ┌──────────────────────────────┐ │
│ │ │ │
│ └────────────────────────────┘ │
│ │
│ 题型: ●简答 ○选择 ○判断 │
│ │
│ [选择题时显示] │
│ 选项: │
│ A. ___________________ │
│ B. ___________________ │
│ C. ___________________ │
│ D. ___________________ │
│ │
│ 正确答案: ________________ │
│ │
│ 关键点: │
│ _________________________ │
│ _________________________ │
│ │
│ 维度: [prompt▼] 难度: [标准▼] │
│ │
│ 出题依据: │
│ _________________________ │
└────────────────────────────────────┘
5.3 统计页面(AssessmentStatsView)
┌─────────────────────────────────────────────────────────────────┐
│ 评估统计 [导出] │
├─────────────────────────────────────────────────────────────────┤
│ 筛选: [时间范围▼] [知识库▼] [重置] │
├─────────────────────────────────────────────────────────────────┤
│ 总考核 │ 最高分 │ 平均分 │ 完成率 │
│ 15 │ 9.2 │ 7.8 │ 80% │
├─────────────────────────────────────────────────────────────────┤
│ 得分趋势(折线图 - 可选) │
│ 10 ____ │
│ 8 ____▓▓▓____▓▓ │
│ 6 ____▓▓▓▓▓____▓▓▓▓___ │
│ 4 _______________________________________ │
│ 2 ____________________________________________│
│ 04/10 04/12 04/14 04/16 04/18 │
├─────────────────────────────────────────────────────────────────┤
│ 历史记录 │
│ 日期 知识库 模板 得分 状态 操作│
│ 04/18 AI开发 AI基础 9.2 完成 查看 │
│ 04/15 Python 编程基础 7.5 完成 查看 │
│ 04/12 AI开发 AI基础 8.1 完成 查看 │
│ 04/10 - LLM原理 - 进行中 查看 │
└─────────────────────────────────────────────────────────────────┘
六、实施计划
Task 1: 题库管理功能(核心)
Files:
- Create:
server/src/assessment/entities/question-bank.entity.ts - Create:
server/src/assessment/entities/question-bank-item.entity.ts - Create:
server/src/assessment/question-bank.service.ts - Create:
server/src/assessment/question-bank.controller.ts - Modify:
server/src/assessment/assessment.module.ts(import) - Create: 迁移文件
add_question_banks.sql
实施步骤:
- 创建 QuestionBank 实体 + 迁移
- 创建 QuestionBankItem 实体 + 迁移
- 实现 QuestionBankService(CRUD)
- 实现 QuestionBankController(API)
- 注册模块
验收标准:
- 可以创建题库
- 可以添加/编辑/删除题目
- 可以设置题目维度/难度/答案
- 支持审核流程(草稿→待审核→发布)
Task 2: AI批量生成
目标: 调用AI批量生成题目,待人工审核
Files:
- Modify:
server/src/assessment/question-bank.service.ts(generate) - Modify:
server/src/assessment/graph/nodes/generator.node.ts(复用)
实施步骤:
- 实现批量生成逻辑
- 调用generator node生成题目
- 保存为草稿状态
- 提供审核界面
验收标准:
- 点击生成按钮,调用AI生成题目
- 生成的题目进入草稿状态
- 可以批量审核通过
Task 3: 题目抽取逻��
目标: 评估时从题库维度均衡随机抽取
Files:
- Modify:
server/src/assessment/question-bank.service.ts(selectQuestions)
实施步骤:
- 实现维度均衡抽取算法
- 处理题目不足情况
- 单元测试
验收标准:
- 抽取的题目维度大致均衡
- 不重复抽取同一题目
- 数量不足时有补充逻辑
Task 4: 评估接入题库
目标: 评估优先使用题库题目
Files:
- Modify:
server/src/assessment/assessment.service.ts(startSession)
实施步骤:
- 修改startSession逻辑
- 先查询题库
- 题库不足时使用实时生成
- 测试完整流程
验收标准:
- 有题库时优先从题库抽取
- 题库不足时使用实时生成
- 两者都可正常工作
Task 5: 统计页面
目标: 独立统计页面
Files:
- Create:
server/src/assessment/assessment.controller.ts(stats API) - Create:
web/src/services/assessmentStatsService.ts - Create:
web/components/views/AssessmentStatsView.tsx - Modify:
web/index.tsx(路由) - Modify:
web/components/layouts/WorkspaceLayout.tsx(侧边栏)
验收标准:
- 统计卡片显示正确
- 支持时间筛选
- 管理员可查看所有用户
- 历史记录表格完整
Task 6: 选择题渲染
目标: 前端支持选择题渲染
Files:
- Modify:
web/components/views/AssessmentView.tsx
验收标准:
- 选择题显示选项按钮
- 点击选项提交答案
Task 7: 判断题渲染
目标: 前端支持判断题渲染
Files:
- Modify:
web/components/views/AssessmentView.tsx
验收标准:
- 判断题显示True/False按钮
- 点击提交答案
Task 8: 稳定性优化
目标: 提高AI生成稳定性
Files:
- Modify:
server/src/assessment/graph/nodes/generator.node.ts
实施步骤:
- 添加重试逻辑
- 优化prompt
- 错误处理
七、执行顺序
Task 1 (题库管理)
↓
Task 2 (AI批量生成)
↓
Task 3 (抽取逻辑)
↓
Task 4 (评估接入)
↓
Task 5 (统计页面)
↓
Task 6 (选择题)
↓
Task 7 (判断题)
↓
Task 8 (稳定性)
八、技术要点
8.1 维度均衡算法
// 伪代码
function selectQuestions(bankId: string, count: number): Question[] {
const allItems = getPublishedItems(bankId);
const dimensions = ['prompt', 'llm', 'ide', 'devPattern', 'workCapability'];
const selected: Question[] = [];
const usedIds = new Set<string>();
// 轮询从各维度选取
let dimIdx = 0;
while (selected.length < count && dimIdx < count * dimensions.length) {
const dim = dimensions[dimIdx % dimensions.length];
const available = allItems.filter(
(i) => i.dimension === dim && !usedIds.has(i.id)
);
if (available.length > 0) {
const random = available[Math.floor(Math.random() * available.length)];
selected.push(random);
usedIds.add(random.id);
}
dimIdx++;
}
// 补充不足的题目(随机)
if (selected.length < count) {
const remaining = allItems.filter((i) => !usedIds.has(i.id));
// ... 随机补充
}
return selected;
}
8.2 审核工作流
草稿(DRAFT) → 提交审核 → 待审核(PENDING_REVIEW)
↓
审核通过 → 已发布(PUBLISHED)
↓
审核拒绝 → 草稿(DRAFT) + 意见
九、注意事项
- 权限控制:题库管理、统计只对管理员开放
- 数据隔离:用户只能看到自己的评估记录,管理员可见所有
- 维度映射:确保题目维度与评估维度一致
- 题库状态:只有已发布的题目才能被抽取
- 回退机制:题库不足时使用实时生成作为备用
Plan Complete
Two execution options:
1. Subagent-Driven (this session) - 继续在此会话,使用 subagent 逐个执行任务
2. Parallel Session (separate) - 开新会话使用 executing-plans,分批执行
Which approach?