# routers/exam.py 接口测试文档 ## 文件功能概述 该文件提供考试相关的接口,包括: - 生成考试提示词(批量 / 单题) - 修改考试题目内容 - 重新生成单道题目 所有接口均需要 Token 认证。 路由前缀:`/apiv1`(以 `routers/__init__.py` 中注册为准) --- ## 接口列表 --- ### 1. POST `/apiv1/exam/build_prompt` — 生成考试提示词 **功能说明:** 根据考试类型、主题、难度和题目数量,拼接生成用于 AI 出题的提示词字符串。不调用 AI,仅返回 prompt 文本。 **是否需要认证:** 是 **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | exam_type | string | 是 | 考试类型(如 "单选题"、"判断题"、"填空题") | | topic | string | 是 | 考试主题 | | difficulty | string | 是 | 难度等级(如 "简单"、"中等"、"困难") | | question_count | int | 是 | 题目数量 | **测试用例:** #### 用例 1:正常生成提示词 ```json // 请求 POST /apiv1/exam/build_prompt token: <有效Token> Content-Type: application/json { "exam_type": "单选题", "topic": "隧道施工安全", "difficulty": "中等", "question_count": 10 } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "prompt": "请生成10道关于隧道施工安全的单选题,难度为中等。" } } ``` #### 用例 2:不同参数组合 ```json // 请求 POST /apiv1/exam/build_prompt token: <有效Token> Content-Type: application/json { "exam_type": "判断题", "topic": "桥梁工程", "difficulty": "简单", "question_count": 5 } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "prompt": "请生成5道关于桥梁工程的判断题,难度为简单。" } } ``` #### 用例 3:未认证 ```json // 请求(不带 Token) POST /apiv1/exam/build_prompt Content-Type: application/json { "exam_type": "单选题", "topic": "测试", "difficulty": "简单", "question_count": 1 } // 预期响应 (HTTP 401) { "statusCode": 401, "msg": "未提供认证Token" } ``` #### 用例 4:缺少必填字段(由 Pydantic 校验) ```json // 请求 POST /apiv1/exam/build_prompt token: <有效Token> Content-Type: application/json { "exam_type": "单选题", "topic": "隧道施工安全" } // 预期响应 (HTTP 422) { "detail": [ { "loc": ["body", "difficulty"], "msg": "field required", "type": "value_error.missing" }, { "loc": ["body", "question_count"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 2. POST `/apiv1/exam/build_single_prompt` — 生成单题提示词 **功能说明:** 根据题目类型、主题和难度,拼接生成用于 AI 出单道题的提示词字符串。不调用 AI,仅返回 prompt 文本。 **是否需要认证:** 是 **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | question_type | string | 是 | 题目类型(如 "单选题"、"多选题") | | topic | string | 是 | 题目主题 | | difficulty | string | 是 | 难度等级 | **测试用例:** #### 用例 1:正常生成单题提示词 ```json // 请求 POST /apiv1/exam/build_single_prompt token: <有效Token> Content-Type: application/json { "question_type": "多选题", "topic": "路基施工规范", "difficulty": "困难" } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "prompt": "请生成1道关于路基施工规范的多选题,难度为困难。" } } ``` #### 用例 2:未认证 ```json // 请求 POST /apiv1/exam/build_single_prompt // 预期响应 (HTTP 401) { "statusCode": 401, "msg": "未提供认证Token" } ``` #### 用例 3:缺少必填字段 ```json // 请求 POST /apiv1/exam/build_single_prompt token: <有效Token> Content-Type: application/json { "question_type": "单选题" } // 预期响应 (HTTP 422) { "detail": [ { "loc": ["body", "topic"], "msg": "field required", "type": "value_error.missing" }, { "loc": ["body", "difficulty"], "msg": "field required", "type": "value_error.missing" } ] } ``` --- ### 3. POST `/apiv1/re_modify_question` — 修改考试题目 **功能说明:** 修改指定对话下 `type='ai'` 的 AI 消息内容。用于用户手动编辑/修正 AI 生成的考试题目。 **是否需要认证:** 是 **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_conversation_id | int | 是 | 对话 ID | | content | string | 是 | 修改后的题目内容 | **业务逻辑:** - 通过 `ai_conversation_id` + `type='ai'` 条件查找 `AIMessage` 记录 - 直接 `update` 匹配到的所有记录的 `content` 字段 - 若无匹配记录则返回 404 **测试用例:** #### 用例 1:正常修改 ```json // 请求 POST /apiv1/re_modify_question token: <有效Token> Content-Type: application/json { "ai_conversation_id": 4, "content": "[{\"question\": \"修改后的题目\", \"options\": [\"A\", \"B\", \"C\", \"D\"], \"answer\": \"A\"}]" } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success" } ``` #### 用例 2:对话不存在或无 AI 消息 ```json // 请求 POST /apiv1/re_modify_question token: <有效Token> Content-Type: application/json { "ai_conversation_id": 99999, "content": "测试内容" } // 预期响应 (HTTP 200, 业务码 404) { "statusCode": 404, "msg": "消息不存在" } ``` #### 用例 3:未认证 ```json // 请求 POST /apiv1/re_modify_question // 预期响应 (HTTP 401) { "statusCode": 401, "msg": "未提供认证Token" } ``` --- ### 4. POST `/apiv1/re_produce_single_question` — 重新生成单题 **功能说明:** 基于原对话中的 AI 消息和给出的重新生成原因,返回重新生成的题目。 > **注意:** 当前代码实际未调用 AI 服务进行重新生成,仅返回一个包含 `regenerate_reason` 的占位文本。 **是否需要认证:** 是 **请求方式:** POST **请求体(JSON):** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_conversation_id | int | 是 | 对话 ID | | regenerate_reason | string | 是 | 重新生成的原因 | **业务逻辑:** - 查找 `ai_conversation_id` + `type='ai'` 的消息 - 若不存在返回 404 - 若存在,返回重新生成的题目文本(当前为占位实现) **测试用例:** #### 用例 1:正常重新生成 ```json // 请求 POST /apiv1/re_produce_single_question token: <有效Token> Content-Type: application/json { "ai_conversation_id": 4, "regenerate_reason": "题目难度过低" } // 预期响应 (HTTP 200) { "statusCode": 200, "msg": "success", "data": { "ai_conversation_id": 4, "new_question": "重新生成的题目(原因:题目难度过低)" } } ``` #### 用例 2:对话不存在或无 AI 消息 ```json // 请求 POST /apiv1/re_produce_single_question token: <有效Token> Content-Type: application/json { "ai_conversation_id": 99999, "regenerate_reason": "测试" } // 预期响应 (HTTP 200, 业务码 404) { "statusCode": 404, "msg": "消息不存在" } ``` #### 用例 3:未认证 ```json // 请求 POST /apiv1/re_produce_single_question // 预期响应 (HTTP 401) { "statusCode": 401, "msg": "未提供认证Token" } ``` --- ## 依赖说明 | 依赖项 | 说明 | |--------|------| | `database.get_db` | SQLAlchemy 数据库会话 | | `models.chat.AIMessage` | AI 消息模型(字段:id, ai_conversation_id, type, content 等) | | `services.qwen_service` | Qwen AI 服务(已导入但当前代码中未实际调用) | | `request.state.user` | 从中间件注入的用户信息 | ## 代码备注 1. `build_prompt` 和 `build_single_prompt` 仅做字符串拼接,不调用 AI 服务,实际 AI 调用由前端拿到 prompt 后通过 chat 接口完成。 2. `re_modify_question` 使用 `update` 批量更新所有匹配 `ai_conversation_id + type='ai'` 的记录——如果同一对话有多条 AI 消息,会全部被覆盖。 3. `re_produce_single_question` 当前为占位实现,`new_question` 只是拼接字符串,未真正调用 AI 重新生成。