note/app_prd/知识增强服务KES.md

187 lines
7.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# 产品需求文档:知识增强服务 (KES)
**Knowledge Enrichment Service - Backend**
| 文档版本 | V1.0 |
| :--- | :--- |
| **依赖模块** | UDC-M (模块一), QPES (模块二) |
| **最后更新** | 2025-12-09 |
| **状态** | 待开发 |
| **涉及端** | 后端 API, 异步 Worker, 外部 API 交互 |
---
## 1. 项目背景与目标
### 1.1 背景
模块二QPES已经完成了“文档 -> 题目”的物理拆解,数据库中已经有了干净的题干、答案和图片。
但此时的题目是“孤立”的,无法支持“查找所有关于‘勾股定理’的题”或“生成一份‘三角函数’的试卷”等业务场景。我们需要为题目注入**元数据Metadata**。
### 1.2 目标
构建一个**异步的知识增强与人工审核服务**。
* **自动打标**:监控未处理的题目,调用外部 `summary_api` 自动提取知识点和方法。
* **人工介入 (HITL)**:提供接口,允许教研人员对 AI 提取的标签进行审核、修改和确认。
* **数据回填**:将处理结果结构化地更新回主数据库。
---
## 2. 系统架构设计
系统设计为 **“生产者-消费者”** 模式,以解耦数据库读取与外部 API 调用(防止外部 API 阻塞系统)。
### 2.1 核心组件
1. **Enrichment Scheduler (调度器)**:
* 定时任务 (Celery Beat) 或 事件触发。
* 扫描 `questions` 表中 `enrich_status = 'pending'` 的记录。
* 将任务推送到 Redis 队列。
2. **API Client Worker (执行器)**:
* 消费队列。
* 调用外部 `summary_api`
* **关键特性**: 实现流控 (Rate Limiting)、重试 (Retry) 和熔断机制。
3. **Review API (审核接口)**:
* 提供给前端/教研后台,用于人工修改知识点。
### 2.2 外部接口定义 (Mock Summary API)
假设外部接口契约如下(开发时需对接真实接口):
* **Input**: `{"question_text": "...", "answer": "..."}`
* **Output**:
```json
{
"summary": "一道关于利用勾股定理求解直角三角形斜边的应用题",
"knowledges": ["勾股定理", "直角三角形性质"],
"methods": ["数形结合", "方程思想"]
}
```
---
## 3. 功能需求详细说明
### 3.1 自动打标流程
1. **任务获取**: 查询 `questions` 表,条件:`enrich_status='pending'`。
2. Write-Protect (写保护)。IF question.is_reviewed == True: UPDATE ONLY raw_fields; ELSE: UPDATE raw_fields AND updated_fields;
3. **构建 Payload**: 拼接 `ocr_text` (含公式/图片链接) 和 `answer_md`
4. **调用 API**: 发送 HTTP POST 请求给 `summary_api`
5. **结果处理**:
* **成功**:
* 将返回的 JSON 填入 `knowledges`, `methods`, `problem_summary` 字段。
* 同时将这些值 **Copy** 一份给 `updated_knowledges`, `updated_methods` (作为人工审核的默认值)。
* 更新状态 `enrich_status = 'done'`
* **失败 (5xx/Timeout)**:
* 触发重试(指数退避,最多 3 次)。
* 若最终失败,更新状态 `enrich_status = 'failed'`,并记录 `error_msg`
### 3.2 人工审核 (Human-in-the-Loop)
* **审核逻辑**: AI 的提取结果并不总是 100% 准确。系统信任链为:**人工数据 > AI 数据**。
* **数据流**:
1. 前端展示 `updated_knowledges` (初始值等于 AI 提取值)。
2. 人工修改(增删改)。
3. 调用 `PUT /questions/{id}/review` 接口保存。
4. 系统更新 `updated_at``reviewer_id`
### 3.3 知识库一致性 (Optional Advanced)
* *需求*: 虽然初期可以存自由文本的 Tag但为了检索准确建议引入“标准知识点树”。
* *逻辑*: 在保存 Tag 前,检查 Tag 是否在系统的 `knowledge_tree` 表中。如果不在,标记为“新词”,提示管理员审核。
---
## 4. 数据库设计 (PostgreSQL)
沿用模块二的 `questions` 表,本模块主要负责 **UPDATE** 操作。
### **4.1 Table: questions (字段更新)**
本模块负责该表的 **更新 (UPDATE)** 操作。
- **读取条件**: WHERE enrich_status = 'pending'
- **更新字段 (AI)**: knowledges, methods, problem_summary, enrich_status。
- **更新字段 (人工)**: updated_knowledges, updated_methods, is_reviewed。
- (完整表结构定义请参考“统一数据库设计规范”文档)
---
## 5. API 接口定义 (RESTful)
**Base URL**: `/api/v1/enrichments`
### 5.1 触发/重试打标
* **POST** `/trigger`
* **Description**: 手动触发一次批量打标(通常由定时任务调用,也可以人工触发重试失败任务)。
* **Body**: `{"retry_failed": true}`
* **Response**: `{"triggered_count": 50}`
### 5.2 提交人工审核结果
* **PUT** `/questions/{question_id}/review`
* **Description**: 教研人员提交修正后的知识点。
* **Body**:
```json
{
"knowledges": ["修正后的知识点1", "修正后的知识点2"],
"methods": ["方法1"],
"confirm": true // 标记 is_reviewed = true
}
```
* **Response**: `200 OK`
### 5.3 获取待审核题目列表
* **GET** `/questions/review-queue`
* **Query**:
* `status`: `done` (已AI打标等待人工)
* `is_reviewed`: `false`
* **Response**: 题目列表 (含 AI 提取的 Tag)。
---
## 6. 技术选型 (Vibe Coding Stack)
### 6.1 核心技术
* **HTTP Client**: **`httpx`** (异步) 或 **`aiohttp`**。
* *理由*: 相比 `requests`,异步客户端在 Celery Worker 中能支持更高的并发Event Loop适合 I/O 密集型任务。
* **Resilience (弹性)**: **`tenacity`**。
* *理由*: Python 最好的重试库。用装饰器 `@retry` 就能实现指数退避,代码极简。
* **Rate Limiting**: **`Redis` + `Lua Script`** 或 Celery 自带的 rate limit。
* *理由*: 防止把外部 `summary_api` 打挂。
### 6.2 代码结构示例 (Service Layer)
```python
# services/enrichment_service.py
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential
class SummaryAPIClient:
def __init__(self, base_url: str, api_key: str):
self.client = httpx.AsyncClient(base_url=base_url, headers={"Authorization": api_key})
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
async def get_summary(self, text: str):
response = await self.client.post("/summarize", json={"text": text})
response.raise_for_status()
return response.json()
```
---
## 7. 模块间联动总结
到此为止,三个模块已经形成了一个完美的闭环:
1. **UDC-M (文档与转换)**:
* **Input**: 用户上传 PDF/Docx。
* **Output**: 永久存储原始文件 + 标准 Markdown (含 MinIO 图片链)。
* **Data**: `documents` 表。
2. **QPES (题目解析)**:
* **Input**: 读取 `documents` 里的 Markdown。
* **Action**: 调用 DeepSeek 切分题目。
* **Output**: 结构化题目。
* **Data**: `questions` 表 (基础字段)。
3. **KES (知识增强)**:
* **Input**: 读取 `questions` (Pending 状态)。
* **Action**: 调用 Summary API + 人工审核。
* **Output**: 完整的、带标签的题库。
* **Data**: `questions` 表 (Tag 字段)。
**部署建议**
这三个模块可以部署在**同一个代码仓库 (Monorepo)** 中,共享数据库 Model 定义,但通过**Docker Compose** 拆分为不同的服务容器运行以便根据负载独立扩容例如UDC 扩容 GPU 节点KES 扩容 IO 密集型节点)。