docs(exam): 出题批卷接口变更说明及文档同步

- 新增《出题批阅接口变更说明(2026-06-05)》面向后端的迁移指南
- 同步更新 curl测试手册 和 后端对接规范 中的出题批卷章节
This commit is contained in:
lacerate551
2026-06-05 14:06:17 +08:00
parent 3f1980ba78
commit 6f863ddfd7
3 changed files with 510 additions and 38 deletions

View File

@@ -2,9 +2,11 @@
---
## 📋 变更记录2026-05-28 更新)
## 📋 变更记录2026-06-05 更新)
> **本次更新内容**:新增 AI 智能出题端口、更新生产环境测试结果
>
> **2026-06-05 更新**:出题批卷接口格式优化与输入校验增强
### 新增端口
@@ -55,6 +57,17 @@
| `/images/list` | 200 | ✅ 正常 |
| `/documents/sync` | 200 | ✅ 正常(已修复) |
### 出题批卷接口变更2026-06-05
| 变更项 | 旧值 | 新值 | 影响 |
|--------|------|------|------|
| 批卷请求字段名 | `question_content` | `content` | ⚠️ **破坏性变更**,后端需同步修改 |
| 出题总题数上限 | 无限制 | **20 道** | 超过返回 400 |
| 批卷 question_type | 无校验 | 必须属于 5 种合法题型 | 无效值返回 400 |
| 批卷结果格式 | 各题型格式不统一 | 统一 `grading_status` + `details` | 后端需适配新格式 |
| **跨调用去重** | 无 | **`exclude_stems` 参数** | 追加出题时传入已有题干避免重复 |
| 出题结果 | 无短缺提示 | 新增 `warnings` 字段 | 可选消费 |
---
## 一、服务概述
@@ -1387,6 +1400,7 @@ POST /exam/generate
| `question_types` | object | ✅ | 题型及数量,键为题型名,值为数量 |
| `difficulty` | int | ❌ | 难度等级 1-5默认 3 |
| `request_id` | string | ❌ | 请求 ID相同 ID 返回缓存结果(幂等性) |
| `exclude_stems` | string[] | ❌ | 已有题目题干列表,用于跨调用去重(最多 100 条,传空或不传则不去重) |
**collection 参数说明:**
@@ -1394,6 +1408,15 @@ POST /exam/generate
- 单个向量库:`"dept_a_kb"`
- 多个向量库:`["dept_a_kb", "public_kb"]`(按优先级排序,优先在第一个库检索)
#### 入参校验规则2026-06-05 新增)
| 校验项 | 规则 | 失败返回 |
|--------|------|----------|
| question_types 题型 | 必须属于: single_choice, multiple_choice, true_false, fill_blank, subjective | HTTP 400 INVALID_PARAMS |
| question_types 数量 | 每种题型数量必须为非负整数 | HTTP 400 INVALID_PARAMS |
| difficulty | 必须为 1-5 的整数 | HTTP 400 INVALID_PARAMS |
| **总题数上限** | **所有题型数量之和不能超过 20** | HTTP 400 INVALID_PARAMS |
**响应:**
**完整响应格式**(包含外层包装):
@@ -1420,6 +1443,9 @@ POST /exam/generate
"request_id": "xxx",
"total": 10,
"source_chunks_used": 15,
"requested_types": {"single_choice": 3, "true_false": 2, "fill_blank": 2},
"actual_types": {"single_choice": 3, "true_false": 2, "fill_blank": 2},
"warnings": [],
"questions": [
{
"question_type": "single_choice",
@@ -1455,6 +1481,8 @@ POST /exam/generate
}
```
> **`warnings` 字段说明**:当某题型实际生成数量少于请求数量时,`warnings` 数组会返回短缺提示(如 `["single_choice: 请求 5 道,实际生成 3 道"]`)。后端可据此判断是否需要重新出题。正常情况该数组为空。
**题型与 answer 格式对照:**
| 题型 | question_type | answer 格式 | data 字段 |
@@ -1492,6 +1520,7 @@ POST /exam/generate
| `FILE_NOT_FOUND` | 404 | 指定文件不存在 |
| `COLLECTION_NOT_FOUND` | 404 | 指定向量库不存在 |
| `NO_CONTENT` | 400 | 文件内容为空,无法出题 |
| `INVALID_PARAMS` | 400 | 入参校验失败题型不合法、数量超限、difficulty 范围错误等) |
| `LLM_ERROR` | 500 | LLM 调用失败 |
| `PARSE_ERROR` | 500 | 解析 LLM 响应失败 |
@@ -1503,6 +1532,8 @@ POST /exam/generate
### 7.2 批改答案
> **⚠️ 重要变更2026-06-05**:批卷请求中的 `question_content` 字段已更名为 `content`,与出题接口返回的题目 `content` 字段保持一致。后端可直接将出题结果的 `content` 透传到批卷接口,无需额外转换。
```
POST /exam/grade
```
@@ -1516,7 +1547,7 @@ POST /exam/grade
{
"question_id": "uuid-001",
"question_type": "single_choice",
"question_content": {
"content": {
"stem": "题干内容",
"data": {"options": [{"key": "A", "content": "选项A"}, {"key": "B", "content": "选项B"}]},
"answer": "B"
@@ -1527,7 +1558,7 @@ POST /exam/grade
{
"question_id": "uuid-002",
"question_type": "multiple_choice",
"question_content": {
"content": {
"stem": "多选题题干",
"data": {"options": [...]},
"answer": ["A", "C"]
@@ -1538,7 +1569,7 @@ POST /exam/grade
{
"question_id": "uuid-003",
"question_type": "true_false",
"question_content": {
"content": {
"stem": "判断题题干",
"answer": "T"
},
@@ -1548,7 +1579,7 @@ POST /exam/grade
{
"question_id": "uuid-004",
"question_type": "fill_blank",
"question_content": {
"content": {
"stem": "填空题有___个空",
"answer": [["答案1", "同义词1"], ["答案2"]]
},
@@ -1558,7 +1589,7 @@ POST /exam/grade
{
"question_id": "uuid-005",
"question_type": "subjective",
"question_content": {
"content": {
"stem": "简答题题干",
"data": {
"scoring_points": [
@@ -1587,8 +1618,8 @@ POST /exam/grade
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `question_id` | string | **是** | 题目 ID后端生成用于匹配结果 |
| `question_type` | string | 是 | 题型single_choice/multiple_choice/true_false/fill_blank/subjective |
| `question_content` | object | 是 | 题目内容(从出题结果中获取) |
| `question_type` | string | 是 | 题型**必须属于**single_choice/multiple_choice/true_false/fill_blank/subjective,无效值返回 HTTP 400 |
| `content` | object | 是 | 题目内容(从出题结果中获取) |
| `student_answer` | any | 是 | 学生答案(格式见下表) |
| `max_score` | number | 是 | 该题满分 |
@@ -1636,36 +1667,31 @@ POST /exam/grade
"question_id": "uuid-001",
"score": 0,
"max_score": 2.0,
"correct": false,
"feedback": "正确答案: B"
},
{
"question_id": "uuid-002",
"score": 0,
"max_score": 4.0,
"correct": false,
"feedback": "正确答案: ['A', 'C']"
},
{
"question_id": "uuid-003",
"score": 0,
"max_score": 2.0,
"correct": false,
"feedback": "正确答案: T"
"grading_status": "success",
"details": {
"correct": false,
"student_answer": "A",
"correct_answer": "B",
"feedback": "正确答案: B"
}
},
{
"question_id": "uuid-004",
"score": 2.0,
"max_score": 4.0,
"grading_status": "success",
"details": {
"total_blanks": 2,
"correct_blanks": 1,
"blank_scores": [2.0, 0],
"correct_answers": [["答案1", "同义词1"], ["答案2"]]
"feedback": "2 个空中答对 1 个"
}
},
{
"question_id": "uuid-005",
"score": 7.5,
"max_score": 10.0,
"grading_status": "success",
"details": {
"scoring_breakdown": [
{"point": "要点1", "weight": 0.4, "achieved": 0.35, "comment": "部分掌握"},
@@ -1673,13 +1699,30 @@ POST /exam/grade
],
"highlights": ["思路清晰"],
"shortcomings": ["细节不够完整"],
"overall_feedback": "整体回答良好,建议补充细节。"
"overall_feedback": "整体回答良好",
"warnings": ["缺少评分标准(scoring_points),评分结果仅供参考"]
}
},
{
"question_id": "uuid-006",
"score": 0,
"max_score": 10.0,
"grading_status": "failed",
"details": {
"error": "评分结果解析失败"
}
}
]
}
```
#### grading_status 状态说明2026-06-05 新增)
| 状态 | 说明 |
|------|------|
| `success` | 评分成功score 和 details 有效 |
| `failed` | 评分失败LLM 解析失败或超时score 为 0details 包含 error 描述 |
#### 批卷逻辑说明
| 题型 | 批卷方式 | 说明 |
@@ -1766,7 +1809,7 @@ def build_grade_request(answer_list, questions_map):
grade_answers.append({
"question_id": qid,
"question_type": question.question_type,
"question_content": question.content, # 含正确答案
"content": question.content, # 含正确答案,与出题接口 content 结构一致
"student_answer": ans['answer'],
"max_score": question.score
})
@@ -1854,8 +1897,8 @@ def grade_student_exam(student_answers):
|------|------|------|
| `question_id` | 后端数据库 | 用于匹配返回结果,更新成绩 |
| `question_type` | 后端数据库 | 题型,决定批卷方式 |
| `question_content.answer` | 后端数据库 | 正确答案(客观题直接比对,主观题作为参考) |
| `question_content.data` | 后端数据库 | 题目附加数据(选项、评分标准等) |
| `content.answer` | 后端数据库 | 正确答案(客观题直接比对,主观题作为参考) |
| `content.data` | 后端数据库 | 题目附加数据(选项、评分标准等) |
| `student_answer` | 学生提交 | 学生作答内容 |
| `max_score` | 后端数据库 | 该题满分 |