diff --git a/docs/出题批题后端对接指南.md b/docs/出题批题后端对接指南.md index 5ac2337..5134d0b 100644 --- a/docs/出题批题后端对接指南.md +++ b/docs/出题批题后端对接指南.md @@ -8,6 +8,11 @@ | `/exam/generate-smart` | POST | 生成题目(AI 自动分析文档结构出题) | 120秒 | | `/exam/grade` | POST | 批阅答案 | 60秒 | +> **2026-07-03 变更**: +> 1. 移除出题总题数 20 道上限,超过 50 道时返回警告(不影响出题) +> 2. 填空题批阅增加 `student_answer` 格式校验(必须为字符串列表) +> 3. 认证错误状态码修正(仅 `DEV_MODE=true` 时生效,见 [认证说明](#认证模式说明)) +> > **2026-06-05 变更**:`/exam/grade` 请求字段 `question_content` 已重命名为 `content`(破坏性变更)。详见 [出题批阅接口变更说明(2026-06-05)](出题批阅接口变更说明(2026-06-05).md)。 --- @@ -27,9 +32,10 @@ Content-Type: application/json |------|------|------|------| | `file_path` | string | ✅ | 文档路径(相对于 documents 目录) | | `collection` | string 或 string[] | ✅ | 向量库名称,支持数组(按优先级顺序检索,找到文件即停止) | -| `question_types` | object | ✅ | 题型及数量 | +| `question_types` | object | ✅ | 题型及数量,**无上限**(超过 50 道时服务端返回警告但仍正常出题) | | `difficulty` | int | ❌ | 难度等级 1-5,默认 3 | | `request_id` | string | ❌ | 请求ID,相同ID返回缓存结果(幂等性) | +| `exclude_stems` | string[] | ❌ | 排除已有题目的题干列表,避免重复出题(最多 100 条) | **请求示例:** @@ -64,12 +70,15 @@ Content-Type: application/json { "success": true, "status": "success", - "status_code": 2011, - "message": "出题完成", + "status_code": 2020, + "message": "出题成功", "data": { "request_id": "uuid-xxx", "total": 10, "source_chunks_used": 25, + "requested_types": {"single_choice": 3, "fill_blank": 2}, + "actual_types": {"single_choice": 3, "fill_blank": 2}, + "warnings": [], "questions": [ { "question_type": "single_choice", @@ -89,7 +98,8 @@ Content-Type: application/json }, "source_trace": { "document_name": "薪酬制度.docx", - "chunks_count": 3 + "page_numbers": [1], + "sources": [{"chunk_id": "...", "page": 1, "section": "...", "snippet": "..."}] } } ] @@ -97,17 +107,30 @@ Content-Type: application/json } ``` -**失败响应:** +**⚠️ 文件/向量库不存在时的响应:** + +当 `file_path` 在指定 `collection` 中找不到,或 `collection` 不存在时,接口**不会返回错误**,而是返回空结果: ```json { - "success": false, - "status": "failed", - "error_code": "FILE_NOT_FOUND", - "message": "文件不存在" + "success": true, + "status": "success", + "status_code": 2020, + "message": "出题成功", + "data": { + "request_id": null, + "total": 0, + "questions": [], + "requested_types": {"single_choice": 1}, + "actual_types": {}, + "warnings": ["single_choice: 请求 1 道,实际生成 0 道"] + } } ``` +> **后端注意**:必须检查 `data.total` 是否 > 0 来判断出题是否成功,不能仅依赖 `success` 字段。 +``` + ### 2.3 返回字段说明 **RAG 服务返回的字段(后端需存储):** @@ -148,11 +171,63 @@ Content-Type: application/json | 错误码 | HTTP | 说明 | |--------|------|------| -| `FILE_NOT_FOUND` | 404 | 指定文件不存在 | -| `COLLECTION_NOT_FOUND` | 404 | 指定向量库不存在 | -| `NO_CONTENT` | 400 | 文件内容为空,无法出题 | -| `LLM_ERROR` | 500 | LLM 调用失败 | -| `PARSE_ERROR` | 500 | 解析失败 | +| `MISSING_PARAMS` | 400 | 缺少必填参数(file_path / collection / question_types) | +| `INVALID_PARAMS` | 400 | 参数校验失败(题型无效、难度越界、总题数≤0 等) | +| `EXAM_ERROR` | 500 | 出题过程异常(LLM 调用失败、解析错误等) | + +> **注意**:文件不存在或向量库不存在时,不会返回错误码,而是返回 `success=true` + `total=0` + `warnings`(见上方说明)。后端应检查 `total > 0`。 + +### 2.6 智能出题接口(/exam/generate-smart) + +与 `/exam/generate` 的区别:不需要传 `question_types`,AI 自动分析文档后决定题型和数量。 + +``` +POST /exam/generate-smart +Content-Type: application/json +``` + +**请求体字段说明:** + +| 字段 | 类型 | 必需 | 说明 | +|------|------|------|------| +| `file_path` | string | ✅ | 文档路径 | +| `collection` | string 或 string[] | ✅ | 向量库名称 | +| `difficulty` | int | ❌ | 难度等级 1-5,默认 3 | +| `max_total` | int | ❌ | AI 出题总数上限,不传则不限制 | +| `exclude_stems` | string[] | ❌ | 排除已有题目的题干列表 | +| `request_id` | string | ❌ | 请求ID | + +**请求示例:** + +```json +{ + "file_path": "111/卷烟货源组织管理办法.docx", + "collection": "111", + "difficulty": 3, + "max_total": 10, + "request_id": "smart-uuid-xxx" +} +``` + +**响应:** 与 `/exam/generate` 格式相同,额外包含 `ai_analysis` 字段(AI 分析结果)。 + +--- + +### 认证模式说明 + +RAG 服务支持两种认证模式,由环境变量 `DEV_MODE` 控制: + +| 模式 | DEV_MODE | 认证行为 | +|------|----------|----------| +| **生产模式** | `false` | 认证网关**直接放行**,不校验 Header。权限由后端服务完全控制 | +| **开发模式** | `true` | 支持 `Authorization: Bearer mock-token-admin` 模拟登录,无 Header 时使用默认测试用户 | + +**当前服务器为生产模式**(`DEV_MODE=false`),因此: +- `Authorization` Header 会被忽略 +- 不会返回 `401 UNAUTHORIZED` 或 `403 FORBIDDEN` +- 后端服务应自行完成用户认证和权限校验,再调用 RAG 出题/批阅接口 + +> 开发模式下,认证错误会返回正确的业务状态码(`UNAUTHORIZED=4001`、`FORBIDDEN=4002`),HTTP 状态码分别为 401/403。 --- @@ -182,6 +257,12 @@ Content-Type: application/json | `student_answer` | any | ✅ | 学生答案 | 学生提交 | | `max_score` | number | ✅ | 满分 | 后端数据库 | +> **填空题 `student_answer` 格式要求**(2026-07-03 新增校验): +> - 必须为 **字符串数组**,如 `["答案1", "答案2"]` +> - 不是列表(如传了字符串 `"答案1"`)→ 该题直接得 0 分,`grading_status` 为 `"failed"` +> - 列表中某项不是字符串(如传了数字 `123`)→ 该题直接得 0 分 +> - 校验失败不影响其他题目的正常批阅 + **请求示例:** ```json @@ -366,8 +447,11 @@ Content-Type: application/json | 错误码 | HTTP | 说明 | |--------|------|------| -| `INVALID_ANSWER_FORMAT` | 400 | 答案格式不正确 | -| `GRADING_ERROR` | 500 | 批阅过程出错 | +| `MISSING_PARAMS` | 400 | 缺少 answers 字段 | +| `INVALID_PARAMS` | 400 | answers 非数组、question_type 无效等 | +| `GRADE_ERROR` | 500 | 批阅过程出错 | + +> **填空题格式错误不返回错误码**:当 `student_answer` 格式不合法时,该题返回 `grading_status: "failed"` + `score: 0`,但接口整体仍返回 `success: true`。后端应检查每道题的 `grading_status` 字段。 --- @@ -464,8 +548,23 @@ Content-Type: application/json - 设置 60 秒超时 - 主观题较多时适当延长 +### Q5: 出题数量有上限吗? + +2026-07-03 起,出题接口**不再限制总题数**。服务端会在请求数超过 50 道时记录警告日志,但不影响出题。建议: +- 单次出题不超过 30 道(LLM 生成耗时与题数成正比,30 道约需 5-8 分钟) +- 超过 30 道建议分批调用 +- 设置 120 秒以上超时 + +### Q6: 填空题学生答案传错了会怎样? + +2026-07-03 起,填空题增加了格式校验: +- `student_answer` 不是列表 → 该题得 0 分,`grading_status = "failed"` +- 列表中某项不是字符串 → 该题得 0 分 +- 校验失败不影响同一请求中其他题目的批阅 +- 接口整体仍返回 `success: true`,需检查每道题的 `grading_status` + --- -**文档版本**: v1.1 -**更新时间**: 2026-05-17 +**文档版本**: v1.2 +**更新时间**: 2026-07-03 **相关文档**: [后端对接规范.md](./后端对接规范.md)