初始化项目代码
This commit is contained in:
468
docs/ai/出题批题后端对接指南.md
Normal file
468
docs/ai/出题批题后端对接指南.md
Normal file
@@ -0,0 +1,468 @@
|
||||
# 出题批题接口 - 后端对接指南
|
||||
|
||||
## 一、接口概览
|
||||
|
||||
| 接口 | 方法 | 功能 | 超时建议 |
|
||||
|------|------|------|----------|
|
||||
| `/exam/generate` | POST | 生成题目 | 120秒 |
|
||||
| `/exam/grade` | POST | 批阅答案 | 60秒 |
|
||||
|
||||
---
|
||||
|
||||
## 二、出题接口
|
||||
|
||||
### 2.1 请求
|
||||
|
||||
```
|
||||
POST /exam/generate
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**请求体字段说明:**
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `file_path` | string | ✅ | 文档路径(相对于 documents 目录) |
|
||||
| `collection` | string 或 string[] | ✅ | 向量库名称,支持数组(按优先级顺序检索,找到文件即停止) |
|
||||
| `question_types` | object | ✅ | 题型及数量 |
|
||||
| `difficulty` | int | ❌ | 难度等级 1-5,默认 3 |
|
||||
| `request_id` | string | ❌ | 请求ID,相同ID返回缓存结果(幂等性) |
|
||||
|
||||
**请求示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"file_path": "薪酬制度.docx",
|
||||
"collection": ["dept_hr", "public_kb"],
|
||||
"question_types": {
|
||||
"single_choice": 3,
|
||||
"multiple_choice": 2,
|
||||
"true_false": 2,
|
||||
"fill_blank": 2,
|
||||
"subjective": 1
|
||||
},
|
||||
"difficulty": 3,
|
||||
"request_id": "uuid-for-idempotency"
|
||||
}
|
||||
```
|
||||
|
||||
> **collection 检索逻辑说明**:
|
||||
> - 出题接口采用**按优先级顺序检索**策略
|
||||
> - 先在 `dept_hr` 中查找文件,找到则停止
|
||||
> - 未找到则继续在 `public_kb` 中查找
|
||||
> - 这与 RAG 问答接口的**并行检索+融合**策略不同
|
||||
> - 原因:出题需要特定文件的完整内容,而非广泛搜索
|
||||
|
||||
### 2.2 响应
|
||||
|
||||
**成功响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"status": "success",
|
||||
"status_code": 2011,
|
||||
"message": "出题完成",
|
||||
"data": {
|
||||
"request_id": "uuid-xxx",
|
||||
"total": 10,
|
||||
"source_chunks_used": 25,
|
||||
"questions": [
|
||||
{
|
||||
"question_type": "single_choice",
|
||||
"difficulty": 3,
|
||||
"content": {
|
||||
"stem": "题干内容",
|
||||
"data": {
|
||||
"options": [
|
||||
{"key": "A", "content": "选项A"},
|
||||
{"key": "B", "content": "选项B"},
|
||||
{"key": "C", "content": "选项C"},
|
||||
{"key": "D", "content": "选项D"}
|
||||
]
|
||||
},
|
||||
"answer": "B",
|
||||
"explanation": "答案解析"
|
||||
},
|
||||
"source_trace": {
|
||||
"document_name": "薪酬制度.docx",
|
||||
"chunks_count": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"status": "failed",
|
||||
"error_code": "FILE_NOT_FOUND",
|
||||
"message": "文件不存在"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 返回字段说明
|
||||
|
||||
**RAG 服务返回的字段(后端需存储):**
|
||||
|
||||
| 字段 | 类型 | 说明 | 后端是否需要存储 |
|
||||
|------|------|------|------------------|
|
||||
| `question_type` | string | 题型 | ✅ 存储 |
|
||||
| `difficulty` | int | 难度 1-5 | ✅ 存储 |
|
||||
| `content` | object | 题目内容 | ✅ 存储 |
|
||||
| `content.stem` | string | 题干 | ✅ |
|
||||
| `content.data` | object | 附加数据(选项、评分标准等) | ✅ |
|
||||
| `content.answer` | any | 正确答案 | ✅ 批阅时需要 |
|
||||
| `content.explanation` | string | 答案解析 | ✅ |
|
||||
| `source_trace` | object | 来源追踪 | ✅ 存储 |
|
||||
|
||||
**后端需要自己生成的字段:**
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `question_id` | UUID,唯一标识 |
|
||||
| `score` | 满分,根据业务需求设定 |
|
||||
| `tags` | 标签 |
|
||||
| `status` | 状态(待审核/已通过/已拒绝) |
|
||||
|
||||
> **重要**:RAG 服务不返回 `score` 字段,分值由后端在入库时指定。
|
||||
|
||||
### 2.4 题型格式对照表
|
||||
|
||||
| 题型 | question_type | content.answer 格式 | content.data |
|
||||
|------|---------------|---------------------|--------------|
|
||||
| 单选题 | `single_choice` | `"B"` | `{options: [{key, content}]}` |
|
||||
| 多选题 | `multiple_choice` | `["A", "C"]` | `{options: [{key, content}]}` |
|
||||
| 判断题 | `true_false` | `"T"` 或 `"F"` | 无 |
|
||||
| 填空题 | `fill_blank` | `[["答案1"], ["答案2", "同义词"]]` | `{blank_count: 2}` |
|
||||
| 简答题 | `subjective` | `"参考范文..."` | `{scoring_points: [...]}` |
|
||||
|
||||
### 2.5 错误码
|
||||
|
||||
| 错误码 | HTTP | 说明 |
|
||||
|--------|------|------|
|
||||
| `FILE_NOT_FOUND` | 404 | 指定文件不存在 |
|
||||
| `COLLECTION_NOT_FOUND` | 404 | 指定向量库不存在 |
|
||||
| `NO_CONTENT` | 400 | 文件内容为空,无法出题 |
|
||||
| `LLM_ERROR` | 500 | LLM 调用失败 |
|
||||
| `PARSE_ERROR` | 500 | 解析失败 |
|
||||
|
||||
---
|
||||
|
||||
## 三、批阅接口
|
||||
|
||||
### 3.1 请求
|
||||
|
||||
```
|
||||
POST /exam/grade
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**请求体字段说明:**
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `request_id` | string | ❌ | 请求ID,用于追踪 |
|
||||
| `answers` | array | ✅ | 答案列表 |
|
||||
|
||||
**answers 数组中每个对象的字段:**
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 | 来源 |
|
||||
|------|------|------|------|------|
|
||||
| `question_id` | string | ✅ | 题目ID | 后端数据库 |
|
||||
| `question_type` | string | ✅ | 题型 | 后端数据库 |
|
||||
| `question_content` | object | ✅ | 题目内容(含正确答案) | 后端数据库 |
|
||||
| `student_answer` | any | ✅ | 学生答案 | 学生提交 |
|
||||
| `max_score` | number | ✅ | 满分 | 后端数据库 |
|
||||
|
||||
**请求示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"request_id": "grade-uuid-xxx",
|
||||
"answers": [
|
||||
{
|
||||
"question_id": "q-001",
|
||||
"question_type": "single_choice",
|
||||
"question_content": {
|
||||
"stem": "根据公司规定,员工薪资由哪几部分组成?",
|
||||
"data": {
|
||||
"options": [
|
||||
{"key": "A", "content": "基本工资+奖金"},
|
||||
{"key": "B", "content": "基本工资+绩效奖金+津贴补贴"},
|
||||
{"key": "C", "content": "基本工资+加班费"},
|
||||
{"key": "D", "content": "基本工资"}
|
||||
]
|
||||
},
|
||||
"answer": "B"
|
||||
},
|
||||
"student_answer": "B",
|
||||
"max_score": 5.0
|
||||
},
|
||||
{
|
||||
"question_id": "q-002",
|
||||
"question_type": "multiple_choice",
|
||||
"question_content": {
|
||||
"stem": "以下哪些属于绩效奖金的评定因素?",
|
||||
"data": {
|
||||
"options": [
|
||||
{"key": "A", "content": "工作质量"},
|
||||
{"key": "B", "content": "工作态度"},
|
||||
{"key": "C", "content": "考勤情况"},
|
||||
{"key": "D", "content": "团队协作"}
|
||||
]
|
||||
},
|
||||
"answer": ["A", "B", "D"]
|
||||
},
|
||||
"student_answer": ["A", "B"],
|
||||
"max_score": 4.0
|
||||
},
|
||||
{
|
||||
"question_id": "q-003",
|
||||
"question_type": "true_false",
|
||||
"question_content": {
|
||||
"stem": "公司规定员工每月绩效奖金上限为工资的20%。",
|
||||
"answer": "F"
|
||||
},
|
||||
"student_answer": "T",
|
||||
"max_score": 2.0
|
||||
},
|
||||
{
|
||||
"question_id": "q-004",
|
||||
"question_type": "fill_blank",
|
||||
"question_content": {
|
||||
"stem": "员工薪资由___、___和___三部分组成。",
|
||||
"data": {"blank_count": 3},
|
||||
"answer": [["基本工资"], ["绩效奖金", "绩效"], ["津贴补贴", "补贴"]]
|
||||
},
|
||||
"student_answer": ["基本工资", "绩效奖金", "交通补贴"],
|
||||
"max_score": 6.0
|
||||
},
|
||||
{
|
||||
"question_id": "q-005",
|
||||
"question_type": "subjective",
|
||||
"question_content": {
|
||||
"stem": "请简述公司薪酬制度的核心原则。",
|
||||
"data": {
|
||||
"scoring_points": [
|
||||
{"point": "公平性", "weight": 0.3},
|
||||
{"point": "激励性", "weight": 0.3},
|
||||
{"point": "竞争力", "weight": 0.2},
|
||||
{"point": "合法性", "weight": 0.2}
|
||||
]
|
||||
},
|
||||
"answer": "公司薪酬制度遵循公平、激励、竞争、合法四大原则..."
|
||||
},
|
||||
"student_answer": "我认为公司的薪酬制度应该公平公正...",
|
||||
"max_score": 10.0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 响应
|
||||
|
||||
**成功响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"status": "success",
|
||||
"status_code": 2012,
|
||||
"message": "批阅完成",
|
||||
"data": {
|
||||
"request_id": "grade-uuid-xxx",
|
||||
"total_score": 14.0,
|
||||
"total_max_score": 27.0,
|
||||
"score_rate": 51.85,
|
||||
"results": [
|
||||
{
|
||||
"question_id": "q-001",
|
||||
"question_type": "single_choice",
|
||||
"score": 5.0,
|
||||
"max_score": 5.0,
|
||||
"is_correct": true,
|
||||
"student_answer": "B",
|
||||
"correct_answer": "B",
|
||||
"feedback": "回答正确"
|
||||
},
|
||||
{
|
||||
"question_id": "q-002",
|
||||
"question_type": "multiple_choice",
|
||||
"score": 2.0,
|
||||
"max_score": 4.0,
|
||||
"is_correct": false,
|
||||
"student_answer": ["A", "B"],
|
||||
"correct_answer": ["A", "B", "D"],
|
||||
"feedback": "少选了 D 选项,正确答案: A, B, D"
|
||||
},
|
||||
{
|
||||
"question_id": "q-003",
|
||||
"question_type": "true_false",
|
||||
"score": 0.0,
|
||||
"max_score": 2.0,
|
||||
"is_correct": false,
|
||||
"student_answer": "T",
|
||||
"correct_answer": "F",
|
||||
"feedback": "正确答案: F"
|
||||
},
|
||||
{
|
||||
"question_id": "q-004",
|
||||
"question_type": "fill_blank",
|
||||
"score": 4.0,
|
||||
"max_score": 6.0,
|
||||
"is_correct": false,
|
||||
"student_answer": ["基本工资", "绩效奖金", "交通补贴"],
|
||||
"correct_answer": [["基本工资"], ["绩效奖金", "绩效"], ["津贴补贴", "补贴"]],
|
||||
"feedback": "第1、2空正确,第3空答案应为:津贴补贴或补贴"
|
||||
},
|
||||
{
|
||||
"question_id": "q-005",
|
||||
"question_type": "subjective",
|
||||
"score": 3.0,
|
||||
"max_score": 10.0,
|
||||
"is_correct": false,
|
||||
"student_answer": "我认为公司的薪酬制度应该公平公正...",
|
||||
"correct_answer": "公司薪酬制度遵循公平、激励、竞争、合法四大原则...",
|
||||
"feedback": "得分点:提到公平性概念,但未展开说明激励性和竞争力原则"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 返回字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `total_score` | number | 总得分 |
|
||||
| `total_max_score` | number | 总满分 |
|
||||
| `score_rate` | number | 得分率(百分比) |
|
||||
| `results` | array | 每道题的批阅结果 |
|
||||
| `results[].question_id` | string | 题目ID |
|
||||
| `results[].score` | number | 该题得分 |
|
||||
| `results[].max_score` | number | 该题满分 |
|
||||
| `results[].is_correct` | boolean | 是否完全正确 |
|
||||
| `results[].feedback` | string | 批阅反馈 |
|
||||
|
||||
### 3.4 批阅规则
|
||||
|
||||
| 题型 | 批阅方式 | 得分规则 |
|
||||
|------|----------|----------|
|
||||
| 单选题 | 精确匹配 | 正确得满分,错误得 0 |
|
||||
| 多选题 | 集合比对 | 全对满分,少选得一半,错选得 0 |
|
||||
| 判断题 | 精确匹配 | 正确得满分,错误得 0 |
|
||||
| 填空题 | 多答案匹配 | 每空独立评分,支持同义词匹配 |
|
||||
| 简答题 | LLM 评分 | 根据得分点评分,不超过 `max_score` |
|
||||
|
||||
### 3.5 错误码
|
||||
|
||||
| 错误码 | HTTP | 说明 |
|
||||
|--------|------|------|
|
||||
| `INVALID_ANSWER_FORMAT` | 400 | 答案格式不正确 |
|
||||
| `GRADING_ERROR` | 500 | 批阅过程出错 |
|
||||
|
||||
---
|
||||
|
||||
## 四、完整调用流程
|
||||
|
||||
### 4.1 出题流程
|
||||
|
||||
```
|
||||
后端调用 /exam/generate
|
||||
│
|
||||
▼
|
||||
RAG 返回题目
|
||||
(question_type, difficulty, content, source_trace)
|
||||
│
|
||||
▼
|
||||
后端生成 question_id
|
||||
后端设置 score (满分)
|
||||
后端设置 status
|
||||
│
|
||||
▼
|
||||
后端存入数据库
|
||||
```
|
||||
|
||||
### 4.2 批阅流程
|
||||
|
||||
```
|
||||
学生提交答案
|
||||
│
|
||||
▼
|
||||
后端从数据库查询:
|
||||
- question_id
|
||||
- question_type
|
||||
- question_content (含正确答案)
|
||||
- score (满分)
|
||||
│
|
||||
▼
|
||||
后端组装请求调用 /exam/grade
|
||||
│
|
||||
▼
|
||||
RAG 返回批阅结果
|
||||
(score, feedback, is_correct)
|
||||
│
|
||||
▼
|
||||
后端存入成绩表
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、字段来源速查表
|
||||
|
||||
### 5.1 出题接口
|
||||
|
||||
| 字段 | 返回方 | 存储方 | 说明 |
|
||||
|------|--------|--------|------|
|
||||
| question_id | ❌ 不返回 | 后端生成 | UUID |
|
||||
| question_type | ✅ RAG | 后端存储 | 题型 |
|
||||
| difficulty | ✅ RAG | 后端存储 | 难度 1-5 |
|
||||
| content | ✅ RAG | 后端存储 | 题目内容 |
|
||||
| source_trace | ✅ RAG | 后端存储 | 来源追踪 |
|
||||
| **score** | ❌ 不返回 | **后端设定** | 满分 |
|
||||
| tags | ❌ 不返回 | 后端设定 | 标签 |
|
||||
| status | ❌ 不返回 | 后端设定 | 状态 |
|
||||
|
||||
### 5.2 批阅接口
|
||||
|
||||
| 字段 | 来源 | 说明 |
|
||||
|------|------|------|
|
||||
| question_id | 后端数据库 | 题目唯一标识 |
|
||||
| question_type | 后端数据库 | 题型 |
|
||||
| question_content | 后端数据库 | 题目内容(含正确答案) |
|
||||
| student_answer | 学生提交 | 学生作答 |
|
||||
| **max_score** | **后端数据库** | 满分(决定得分上限) |
|
||||
|
||||
---
|
||||
|
||||
## 六、常见问题
|
||||
|
||||
### Q1: 出题接口返回的题目需要审核吗?
|
||||
|
||||
建议后端设置 `status` 字段进行审核流程,审核通过后再用于组卷。
|
||||
|
||||
### Q2: 分值如何动态调整?
|
||||
|
||||
后端在入库时自由设定 `score` 字段,批阅时传入 `max_score` 即可。RAG 服务不干预分值。
|
||||
|
||||
### Q3: 填空题同义词匹配是如何实现的?
|
||||
|
||||
填空题答案格式为 `[["主答案", "同义词1", "同义词2"], ...]`,学生答案匹配任意一个即视为正确。
|
||||
|
||||
### Q4: 批阅接口超时怎么办?
|
||||
|
||||
建议:
|
||||
- 单次批阅不超过 50 道题
|
||||
- 设置 60 秒超时
|
||||
- 主观题较多时适当延长
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.1
|
||||
**更新时间**: 2026-05-17
|
||||
**相关文档**: [后端对接规范.md](./后端对接规范.md)
|
||||
Reference in New Issue
Block a user