# 出题批卷系统设计 > **文档类型**: 系统设计文档 > **创建日期**: 2026-04-10 > **最后更新**: 2026-04-13 > **状态**: 已实施 --- ## 一、系统概述 ### 1.1 背景 出题批卷系统是 RAG 知识库系统的扩展模块,支持: - **按文件出题**:根据指定文档自动生成题目 - **智能批卷**:支持选择题、填空题、简答题的自动批改 - **溯源追踪**:每道题可追溯到来源文件和知识片段 ### 1.2 模块结构 ``` exam_pkg/ # 考试系统 ├── manager.py # 出题与批卷核心逻辑 ├── api.py # Flask Blueprint (exam_bp) ├── analysis.py # 考试分析 ├── local_db.py # 本地题库 (SQLite) └── question_hook.py # 题目维护钩子 ``` **认证模块**: `auth/gateway.py` - 网关认证 --- ## 二、出题系统设计 ### 2.1 按文件出题接口 **接口路径**:`POST /exam/generate-by-file` **请求参数**: ```json { "file_path": "public/产品手册.pdf", "collection": "public_kb", "choice_count": 5, "blank_count": 2, "short_answer_count": 2, "difficulty": 3, "choice_score": 2, "blank_score": 3 } ``` | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `file_path` | string | ✅ | - | 文件路径 | | `collection` | string | ✅ | - | 向量库名称 | | `choice_count` | int | ❌ | 3 | 选择题数量 | | `blank_count` | int | ❌ | 2 | 填空题数量 | | `short_answer_count` | int | ❌ | 2 | 简答题数量 | | `difficulty` | int | ❌ | 3 | 难度等级 (1-5) | | `choice_score` | int | ❌ | 2 | 每道选择题分值 | | `blank_score` | int | ❌ | 3 | 每道填空题分值 | **返回结果**: ```json { "exam_id": "uuid-xxxx-xxxx", "source_file": { "path": "public/产品手册.pdf", "collection": "public_kb" }, "choice_questions": [ { "id": "q_choice_001", "content": "根据保密制度,公司最高机密的处理原则是什么?", "options": ["A. 可向客户透露", "B. 严禁外传", "C. 部门内共享", "D. 仅领导知晓"], "answer": "B", "analysis": "根据保密制度第1条规定...", "knowledge_points": ["保密制度", "信息安全"], "difficulty": 2, "score": 2, "source_file": "public/产品手册.pdf", "source_snippet": "该题依据的知识片段..." } ], "blank_questions": [...], "short_answer_questions": [...], "total_count": 9, "total_score": 22, "generated_at": "2026-04-10T14:00:00" } ``` ### 2.2 试卷状态流程 ``` 生成试卷 → draft (草稿) ↓ 提交审核 → pending_review (待审核) ↓ 管理员审核 → approved (通过) / rejected (驳回) ↓ 学生答题 → 批阅 → 生成报告 ``` **状态说明**: | 状态 | 说明 | 可见范围 | |------|------|----------| | `draft` | 草稿,刚生成尚未提交审核 | 创建者可见 | | `pending_review` | 待审核,已提交等待管理员审核 | 管理员可见 | | `approved` | 已通过,可用于学生答题 | 所有用户可见 | | `rejected` | 已驳回,不可使用 | 创建者可见 | --- ## 三、题目格式规范 ### 3.1 选择题 ```json { "id": "q_choice_001", "content": "根据保密制度,公司最高机密的处理原则是什么?", "options": [ "A. 可向客户透露", "B. 严禁外传", "C. 部门内共享", "D. 仅领导知晓" ], "answer": "B", "analysis": "根据保密制度第1条规定,公司最高机密严禁外传,仅限特定人员知晓。", "knowledge_points": ["保密制度", "信息安全"], "difficulty": 2, "score": 2, "source_file": "public/产品手册.pdf", "source_snippet": "原文相关片段..." } ``` **字段说明**: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `id` | string | ✅ | 题目唯一标识 | | `content` | string | ✅ | 题干内容 | | `options` | array | ✅ | 选项列表,格式为 `["A. 选项内容", ...]` | | `answer` | string | ✅ | 正确答案,单个字母(如 "A", "B") | | `analysis` | string | ✅ | 答案解析 | | `knowledge_points` | array | ❌ | 知识点标签 | | `difficulty` | int | ❌ | 难度等级 1-5,默认 3 | | `score` | int | ✅ | 题目分值 | | `source_file` | string | ❌ | 来源文件路径 | | `source_snippet` | string | ❌ | 来源文本片段 | ### 3.2 填空题 ```json { "id": "q_blank_001", "content": "公司财务报表应在每季度结束后______天内提交。", "answer": "15", "analysis": "根据财务管理制度第5条规定,季度报表需在季后15天内提交。", "knowledge_points": ["财务管理"], "difficulty": 3, "score": 3 } ``` **字段说明**: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `id` | string | ✅ | 题目唯一标识 | | `content` | string | ✅ | 题干内容,空缺处用 `______` 表示 | | `answer` | string | ✅ | 正确答案 | | `analysis` | string | ✅ | 答案解析 | | `knowledge_points` | array | ❌ | 知识点标签 | | `difficulty` | int | ❌ | 难度等级 1-5 | | `score` | int | ✅ | 题目分值 | ### 3.3 简答题 ```json { "id": "q_short_001", "content": "简述公司数据安全的三道防线。", "reference_answer": { "points": [ {"point": "技术防线(防火墙、加密、访问控制等)", "score": 3}, {"point": "制度防线(安全规定、审批流程、应急预案)", "score": 3}, {"point": "人员防线(安全培训、意识教育、考核机制)", "score": 4} ], "total_score": 10 }, "analysis": "评分要点说明...", "knowledge_points": ["数据安全"], "difficulty": 4, "score": 10 } ``` **字段说明**: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `id` | string | ✅ | 题目唯一标识 | | `content` | string | ✅ | 题干内容 | | `reference_answer` | object | ✅ | 参考答案,包含评分要点 | | `reference_answer.points` | array | ✅ | 得分点列表 | | `reference_answer.points[].point` | string | ✅ | 得分点描述 | | `reference_answer.points[].score` | int | ✅ | 该得分点分值 | | `analysis` | string | ❌ | 整体解析 | | `knowledge_points` | array | ❌ | 知识点标签 | | `difficulty` | int | ❌ | 难度等级 1-5 | | `score` | int | ✅ | 题目总分值 | --- ## 四、批卷系统设计 ### 4.1 批卷输入格式 **接口路径**:`POST /exam/grade-from-mysql` **当前格式(完整字段)**: ```json { "exam_id": "uuid-xxxx-xxxx", "student_id": "STU_2023001", "student_name": "张三", "answers": [ { "question_id": "q_choice_001", "question_type": "choice", "question_content": "根据保密制度,公司最高机密的处理原则是什么?", "options": ["A. 可向客户透露", "B. 严禁外传", "C. 部门内共享", "D. 仅领导知晓"], "correct_answer": "B", "max_score": 2, "student_answer": "B" }, { "question_id": "q_blank_001", "question_type": "blank", "question_content": "公司财务报表应在每季度结束后______天内提交。", "correct_answer": "15", "max_score": 3, "student_answer": "10" }, { "question_id": "q_short_001", "question_type": "short_answer", "question_content": "简述公司数据安全的三道防线。", "correct_answer": "{\"points\":[{\"point\":\"技术防线\",\"score\":3},{\"point\":\"制度防线\",\"score\":3},{\"point\":\"人员防线\",\"score\":4}]}", "max_score": 10, "student_answer": "第一道是技术防护,包括防火墙和加密;第二道是制度管理;第三道是员工培训。" } ] } ``` **优化后格式(最小字段)**: ```json { "exam_id": "uuid", "student_id": "STU_001", "student_name": "张三", "answers": [ { "question_id": "q_choice_001", "question_type": "choice", "student_answer": "B" }, { "question_id": "q_blank_001", "question_type": "blank", "student_answer": "15" }, { "question_id": "q_short_001", "question_type": "short_answer", "student_answer": "第一道是技术防护..." } ] } ``` ### 4.2 批卷输出格式 ```json { "report_id": "report-uuid-xxxx", "exam_id": "uuid-xxxx-xxxx", "student_id": "STU_2023001", "student_name": "张三", "total_score": 12, "max_score": 15, "score_rate": 80.0, "graded_at": "2026-04-12T14:30:00", "results": [ { "question_id": "q_choice_001", "question_type": "choice", "correct": true, "score": 2, "max_score": 2, "student_answer": "B", "correct_answer": "B", "feedback": "回答正确!" }, { "question_id": "q_blank_001", "question_type": "blank", "correct": false, "score": 0, "max_score": 3, "student_answer": "10", "correct_answer": "15", "feedback": "正确答案是15天,请复习财务管理制度。" }, { "question_id": "q_short_001", "question_type": "short_answer", "score": 8, "max_score": 10, "student_answer": "第一道是技术防护...", "score_details": [ {"point": "技术防线", "earned": 3, "max": 3}, {"point": "制度防线", "earned": 2, "max": 3}, {"point": "人员防线", "earned": 3, "max": 4} ], "feedback": "整体回答较好,制度防线描述不够具体。", "highlights": ["技术防线表述准确"], "shortcomings": ["制度防线未具体说明"], "suggestions": ["建议补充具体的制度名称"] } ], "summary": { "strengths": ["选择题掌握较好", "简答题要点覆盖全面"], "weaknesses": ["填空题记忆不准确"], "recommendations": ["重点复习财务管理制度第3章"] } } ``` ### 4.3 批改流程 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 批量批改流程 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 1. 前端传入 answers (最小字段) │ │ └─ 只有 question_id + question_type + student_answer │ │ │ │ 2. 后端查询题目详情 │ │ └─ 从数据库/缓存获取 correct_answer, max_score, content │ │ │ │ 3. 按题型分组 │ │ ├─ choice 组 → 批量调用 Dify 代码执行节点 │ │ └─ blank/short_answer 组 → 批量调用 Dify LLM 节点 │ │ │ │ 4. 合并结果返回 │ │ └─ 统一格式返回所有批改结果 │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` --- ## 五、数据库设计 ### 5.1 题目表 (questions) ```sql CREATE TABLE questions ( id VARCHAR(64) PRIMARY KEY, -- 题目ID(UUID) question_type ENUM('choice', 'blank', 'short_answer') NOT NULL, content TEXT NOT NULL, -- 题干内容 options JSON, -- 选择题选项(JSON数组) correct_answer TEXT NOT NULL, -- 正确答案 analysis TEXT, -- 解析 knowledge_points JSON, -- 知识点(JSON数组) difficulty TINYINT DEFAULT 3, -- 难度(1-5) score INT NOT NULL, -- 分值 -- 溯源字段(核心) source_file VARCHAR(255) NOT NULL, -- 来源文件路径 source_collection VARCHAR(64) NOT NULL, -- 来源向量库 source_snippet TEXT, -- 来源知识片段 source_hash VARCHAR(64), -- 文件哈希(用于检测文件变更) -- 审核状态 status ENUM('pending', 'approved', 'rejected') DEFAULT 'pending', reviewed_by VARCHAR(64), reviewed_at DATETIME, -- 元数据 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_by VARCHAR(64), updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_source_file (source_file), INDEX idx_source_collection (source_collection), INDEX idx_question_type (question_type), INDEX idx_status (status) ); ``` ### 5.2 试卷表 (exams) ```sql CREATE TABLE exams ( id VARCHAR(64) PRIMARY KEY, -- 试卷ID name VARCHAR(255) NOT NULL, -- 试卷名称 description TEXT, -- 描述 total_score INT NOT NULL, -- 总分 total_count INT NOT NULL, -- 题目总数 duration INT DEFAULT 60, -- 考试时长(分钟) -- 状态 status ENUM('draft', 'pending', 'published', 'archived') DEFAULT 'draft', published_at DATETIME, -- 元数据 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_by VARCHAR(64), updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_status (status) ); ``` ### 5.3 试卷题目关联表 (exam_questions) ```sql CREATE TABLE exam_questions ( exam_id VARCHAR(64) NOT NULL, question_id VARCHAR(64) NOT NULL, question_order INT NOT NULL, -- 题目顺序 PRIMARY KEY (exam_id, question_id), FOREIGN KEY (exam_id) REFERENCES exams(id) ON DELETE CASCADE, FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE, INDEX idx_exam_id (exam_id), INDEX idx_question_id (question_id) ); ``` ### 5.4 学生答卷表 (student_answers) ```sql CREATE TABLE student_answers ( id VARCHAR(64) PRIMARY KEY, exam_id VARCHAR(64) NOT NULL, student_id VARCHAR(64) NOT NULL, student_name VARCHAR(100), question_id VARCHAR(64) NOT NULL, question_type ENUM('choice', 'blank', 'short_answer') NOT NULL, student_answer TEXT NOT NULL, -- 学生答案 -- 批阅结果 score INT DEFAULT 0, max_score INT NOT NULL, feedback TEXT, score_details JSON, -- 评分详情(JSON) -- 元数据 submitted_at DATETIME DEFAULT CURRENT_TIMESTAMP, graded_at DATETIME, FOREIGN KEY (exam_id) REFERENCES exams(id) ON DELETE CASCADE, FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE, INDEX idx_exam_student (exam_id, student_id), INDEX idx_student_id (student_id) ); ``` ### 5.5 批阅报告表 (grade_reports) ```sql CREATE TABLE grade_reports ( id VARCHAR(64) PRIMARY KEY, exam_id VARCHAR(64) NOT NULL, student_id VARCHAR(64) NOT NULL, student_name VARCHAR(100), total_score INT NOT NULL, max_score INT NOT NULL, score_rate DECIMAL(5,2), -- 整卷分析(可选) analysis JSON, -- AI生成的整卷分析 graded_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (exam_id) REFERENCES exams(id) ON DELETE CASCADE, INDEX idx_exam_id (exam_id), INDEX idx_student_id (student_id) ); ``` --- ## 六、文件修改联动 ### 6.1 触发条件 当文件被修改或删除时,通过 `source_file` 字段查找受影响的题目。 ### 6.2 联动逻辑 ```sql -- 查找受影响的题目 SELECT id, source_file, source_hash FROM questions WHERE source_file = 'public/产品手册.pdf'; -- 如果文件哈希变更,标记题目需要重新审核 UPDATE questions SET status = 'pending', source_hash = 'new_hash_value' WHERE source_file = 'public/产品手册.pdf'; ``` ### 6.3 联动接口 **接口路径**:`POST /exam/check-file-changes` **请求参数**: ```json { "file_path": "public/产品手册.pdf", "new_hash": "新的文件哈希" } ``` **返回结果**: ```json { "success": true, "file_path": "public/产品手册.pdf", "affected_questions": ["q_uuid_001", "q_uuid_002", ...], "count": 15, "recommendation": "建议重新生成该文件的题目" } ``` --- ## 七、API 接口汇总 ### 7.1 出题接口 | 接口 | 方法 | 说明 | |------|------|------| | `/exam/generate` | POST | 按主题生成试卷 | | `/exam/generate-by-file` | POST | 按文件生成题目 | | `/exam/list` | GET | 获取试卷列表 | | `/exam/` | GET | 获取试卷详情 | | `/exam/` | PUT | 更新试卷 | | `/exam/` | DELETE | 删除试卷 | | `/exam//submit` | POST | 提交审核 | | `/exam//review` | POST | 审核试卷(仅管理员) | | `/exam/by-file` | GET | 查询文件关联的题目 | ### 7.2 批卷接口 | 接口 | 方法 | 说明 | |------|------|------| | `/exam/grade-from-mysql` | POST | 基于传入题目批卷 | | `/exam//grade` | POST | 批阅试卷 | | `/exam/report/` | GET | 获取批阅报告 | | `/exam/report/list` | GET | 批阅报告列表 | ### 7.3 题库接口 | 接口 | 方法 | 说明 | |------|------|------| | `/exam/questions/search` | GET | 搜索题目 | ### 7.4 联动接口 | 接口 | 方法 | 说明 | |------|------|------| | `/exam/check-file-changes` | POST | 检查文件变更影响的题目 | --- ## 八、错误处理 ### 8.1 错误响应格式 ```json { "error": "错误类型", "message": "详细错误信息", "details": {} } ``` ### 8.2 常见错误码 | HTTP状态码 | 错误类型 | 说明 | |-----------|---------|------| | 400 | bad_request | 请求参数格式错误 | | 401 | unauthorized | 未认证 | | 403 | forbidden | 权限不足 | | 404 | not_found | 资源不存在 | | 500 | internal_error | 服务器内部错误 | --- ## 九、注意事项 1. **题目ID生成**:使用UUID,确保全局唯一 2. **文件哈希**:用于检测文件变更,建议使用MD5或SHA256 3. **批量批卷性能**:简答题批卷耗时,建议使用异步处理或并发 4. **错误处理**:批卷失败时返回默认结果,不影响整体流程 5. **认证方式**:出题系统使用 JWT Bearer Token 认证 --- ## 十、变更记录 | 日期 | 版本 | 变更内容 | |------|------|---------| | 2026-04-13 | 2.0 | 合并出题批卷功能改造计划、批卷工作流优化计划、批卷接口规范 | | 2026-04-12 | 1.2 | 新增最小字段输入格式,优化批量批改流程 | | 2026-04-10 | 1.0 | 初始版本:按文件出题功能设计 |