Files
rag/docs/出题批题后端对接指南.md
lacerate551 100d1a06eb init: RAG 知识库服务初始提交
- 后端 API(Flask + Gunicorn)
- RAG 引擎(混合检索 + 云端 Reranker + 引用溯源)
- 文档解析(MinerU + 多格式支持)
- Docker 生产部署配置
- 排除前端项目、敏感配置、模型文件
2026-06-04 17:35:27 +08:00

469 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 出题批题接口 - 后端对接指南
## 一、接口概览
| 接口 | 方法 | 功能 | 超时建议 |
|------|------|------|----------|
| `/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)