chore: finalize backend feature scope

This commit is contained in:
刘金宝
2026-06-11 16:19:07 +08:00
parent d855ecab82
commit ec515d5453
43 changed files with 680 additions and 712 deletions
+7 -7
View File
@@ -13,7 +13,7 @@
- 病例 PDF 解析入库
- 病例增删改后台
- 多租户权限后台
- HIS/LIS/PACS
- HIS/LIS/PACS
- 前端最终 UI
用户身份来自 Django 用户中心。前端携带 `Authorization: Bearer <access_token>` 调用 FastAPIFastAPI 转发 token 到 Django `/api/user/users/me/`,以 Django 返回的 `id` 作为本服务统一 `user_id`
@@ -23,7 +23,6 @@
| 模块 | 状态 | 主要入口 |
|---|---|---|
| 用户鉴权 | 已实现 | `GET /api/v1/auth/me` |
| 病例读取 | 已实现 | `GET /api/v1/cases``GET /api/v1/cases/{case_id}` |
| 训练配置 | 已实现 | `GET /api/v1/training-config/recommended``GET /api/v1/training-config/options` |
| 训练会话 | 已实现 | `POST /api/v1/sessions` |
| 流式问诊 | 已实现 | `POST /api/v1/sessions/{session_id}/chat/stream` |
@@ -34,15 +33,15 @@
| 个人中心训练记录 | 已实现,支持分页 | `GET /api/v1/evaluations?page=1&page_size=10` |
| PDF 下载 | 已实现 | `GET /api/v1/evaluations/{evaluation_id}/download-pdf` |
| 教学互动 | 已实现 | `GET /api/v1/teaching/cases/{case_id}/items``POST /api/v1/teaching/evaluation` |
| AI 学习助手 | 已实现流式问答 | `POST /api/v1/learning-assistant/chat/stream` |
| 内容管理员知识库上传 | 基础链路已实现 | `POST /api/v1/knowledge-admin/documents/upload` |
| AI 学习助手 | 已实现短期会话和流式问答 | `POST /api/v1/learning-assistant/sessions``POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` |
| 内容管理员知识库上传 | 后台预留能力,当前前端不展示 | `POST /api/v1/knowledge-admin/documents/upload` |
| 健康检查 | 已实现 | `/health/live``/health/ready` |
## 3. 逻辑顺序
1. 项目边界:FastAPI 是后端子服务,不做登录、病例管理和最终 UI。
2. 认证链路:前端 token -> FastAPI -> Django `/me` -> 统一 `user_id`
3. 训练链路:病例 -> 配置 -> 会话 -> 问诊 -> 检查 -> 诊断 -> 治疗 -> 评价 -> PDF -> 历史记录。
3. 训练链路:病例 ID -> 配置 -> 会话 -> 问诊 -> 检查 -> 诊断 -> 治疗 -> 评价 -> PDF -> 历史记录。
4. 教学互动链路:题目列表 -> 答题 -> 评价 -> PDF。
5. AI 学习助手链路:机构知识库检索 -> LLM 流式回答;无知识库时降级通用回答。
6. 数据库边界:平台基础数据由 Django/平台维护,FastAPI 主要写训练过程和训练结果。
@@ -76,13 +75,14 @@
|---|---|
| [01_architecture.md](01_architecture.md) | 系统架构、核心链路、模块边界 |
| [02_database.md](02_database.md) | 数据库表、读写边界、表含义 |
| [03_api_design.md](03_api_design.md) | 前端联调用 API 文档 |
| [03_api_design.md](03_api_design.md) | 前端 API 文档 |
| [04_deployment.md](04_deployment.md) | 云服务器部署、更新、回滚 |
| [05_modules.md](05_modules.md) | 模块职责、接口、代码入口 |
| [06_maintenance_guide.md](06_maintenance_guide.md) | 开发维护、风险、发布检查清单 |
| [07_troubleshooting.md](07_troubleshooting.md) | 常见故障排查 |
| [08_feature_code_map.md](08_feature_code_map.md) | 功能到接口、代码、数据表的映射表 |
| [09_prompt_template_catalog.md](09_prompt_template_catalog.md) | 提示词模板目录和调用说明 |
| [10_function_workflow.md](10_function_workflow.md) | 功能工作流程、接口、提示词、数据库和结果去向 |
## 6. 本地测试命令
@@ -127,7 +127,7 @@ http://8.160.178.88/fastapi/docs
- `git status --short` 无未确认改动,或已明确哪些改动尚未提交。
- `.env` 不提交 Git。
- `docs/03_api_design.md` 是前端联调依据。
- `docs/03_api_design.md` 是前端开发调用依据。
- `docs/02_database.md` 与当前 ORM 表名一致。
- 自动化测试全部通过。
- 云端 `/fastapi/docs` 可访问。
+13 -11
View File
@@ -11,7 +11,7 @@
- 训练页面:训练配置、新建会话、流式问诊、练习提示、检查申请、诊断治疗提交、AI 评价、PDF 下载
- 教学互动:题目列表、答题评价、评价详情、PDF 下载
- 个人中心:训练记录列表、训练记录详情
- AI 学习助手:流式知识问答,优先 RAG,知识库不可用时降级为通用 LLM 回答
- AI 学习助手:短期会话和流式知识问答,优先 RAG,知识库不可用时降级为通用 LLM 回答
- 后台预留:内容管理员知识库上传、PDF 解析、分片、Embedding、Milvus、Celery 异步任务
## 2. 总体架构
@@ -103,21 +103,23 @@ flowchart TD
```mermaid
flowchart TD
A["用户提问"] --> B["按 institution_id 定位知识空间"]
B --> C{"知识库可用?"}
C -- 是 --> D["Embedding 用户问题"]
D --> E["Milvus 检索 chunks"]
E --> F["拼接来源和问题"]
C -- 否 --> G["空来源降级"]
F --> H["LLM 流式回答"]
G --> H
H --> I["SSE: retrieval_done / answer_delta / answer_done"]
A["新建学习助手短期会话"] --> B["用户提问"]
B --> C["按 institution_id 定位知识空间"]
C --> D{"知识库可用?"}
D -- 是 --> E["Embedding 用户问题"]
E --> F["Milvus 检索 chunks"]
F --> G["拼接来源、问题和短期上下文"]
D -- 否 --> H["空来源降级"]
G --> I["LLM 流式回答"]
H --> I
I --> J["SSE: session_ready / retrieval_done / answer_delta / answer_done"]
```
当前正式前端接口只使用:
```text
POST /api/v1/learning-assistant/chat/stream
POST /api/v1/learning-assistant/sessions
POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream
```
知识库不可用时不会阻断回答,接口会返回 `retrieval_hit=false``retrieval_error`,随后继续输出通用 LLM 回答。
+2 -2
View File
@@ -55,7 +55,7 @@ FastAPI 使用 Django 返回的 `id` 作为业务 `user_id`。
| 项 | 说明 |
|---|---|
| 用途 | 病例主表,训练和教学互动共用 |
| 读取模块 | 病例列表、病例详情、训练会话、教学互动 |
| 读取模块 | 训练配置、训练会话、教学互动、评价 |
| 关键字段 | `id``department_id``title``difficulty``case_type``status` |
| 写入方 | 平台病例解析 / 后台维护 |
| FastAPI 是否写入 | 否 |
@@ -64,7 +64,7 @@ FastAPI 使用 Django 返回的 `id` 作为业务 `user_id`。
| 项 | 说明 |
|---|---|
| 用途 | 练习模式传统病例详情 |
| 用途 | 练习模式传统病例资料 |
| 读取模块 | 训练会话、Patient Agent、Scoring Agent |
| 关键字段 | `case_id`、主诉、现病史、既往史、查体、辅助检查、诊断、治疗 |
| 写入方 | 平台病例解析 / 后台维护 |
+57 -11
View File
@@ -1,6 +1,6 @@
# 医疗问诊 Agent API 文档
本文档面向前端联调,描述当前 FastAPI 后端可调用接口。训练模式和教学互动模式按页面模块分开书写;即使底层复用同一路由,文档中也在对应模块下分别列出,便于前端按页面开发。
本文档面向前端开发调用,描述当前 FastAPI 后端可调用接口。训练模式和教学互动模式按页面模块分开书写;即使底层复用同一路由,文档中也在对应模块下分别列出,便于前端按页面开发。
公网基础地址:
@@ -91,14 +91,11 @@ curl -X GET "http://8.160.178.88/fastapi/api/v1/auth/me" \
}
```
## 3. 病例基础接口
## 3. 病例 ID 说明
| 接口名称 | url | api | methods | params(入参) | response(返回参数) |
|---|---|---|---|---|---|
| 病例列表 | `http://8.160.178.88/fastapi/api/v1/cases` | `/api/v1/cases` | `GET` | Query`department_id` 选填,科室 ID`training_type` 选填,训练类型;`mode` 选填,交互模式 | `data.items[]` 病例列表,包含 `case_id``title``department_name``difficulty``chief_complaint` 等 |
| 病例详情 | `http://8.160.178.88/fastapi/api/v1/cases/{case_id}` | `/api/v1/cases/{case_id}` | `GET` | Path`case_id` 必填,病例 ID | `data.case_id` 病例 ID`data.title` 病例标题;`data.chief_complaint` 主诉;`data.supported_modes` 支持模式;`data.exam_item_types` 可用检查类型 |
当前 FastAPI 后端不提供病例公开查询接口。训练页面和教学互动页面需要使用的 `case_id` 由页面上下文传入,后端在各业务接口内部读取 `case_base``traditional_case``teaching_case``case_exam_item` 完成校验和业务处理。
说明:病例接口只读平台数据库中的已发布病例,不提供病例新增、删除、PDF 解析接口。
病例、教学题、检查项和评分规则由平台数据库维护。FastAPI 不提供病例新增、删除、PDF 解析入库接口。
## 4. 训练模式 API
@@ -124,7 +121,7 @@ curl -X GET "http://8.160.178.88/fastapi/api/v1/auth/me" \
| 接口名称 | url | api | methods | params(入参) | response(返回参数) |
|---|---|---|---|---|---|
| 新建会话 | `http://8.160.178.88/fastapi/api/v1/sessions` | `/api/v1/sessions` | `POST` | Body`case_id` 必填,病例 ID`training_type` 必填,当前使用 `diagnosis_treatment``mode` 必填,当前训练模式使用 `practice`,兼容旧值 `novice``score_type` 必填,`percentage``five_point``patient_config` 选填,病人初始化配置 | `data.session_id` 会话 ID`data.session_code` 会话编码;`data.status` 当前阶段;`data.patient_opening` AI 病人开场白;`data.patient_config` 实际使用配置 |
| 新建会话 | `http://8.160.178.88/fastapi/api/v1/sessions` | `/api/v1/sessions` | `POST` | Body`case_id` 必填,病例 ID`training_type` 必填,当前使用 `diagnosis_treatment``mode` 必填,当前训练模式使用 `practice``score_type` 必填,`percentage``five_point``patient_config` 选填,病人初始化配置 | `data.session_id` 会话 ID`data.session_code` 会话编码;`data.status` 当前阶段;`data.patient_opening` AI 病人开场白;`data.patient_config` 实际使用配置 |
请求示例:
@@ -367,13 +364,44 @@ async function downloadTeachingPdf(baseUrl: string, token: string, evaluationId:
## 7. AI 学习助手 API
接口用于普通用户医学知识问答。后端优先检索本机构知识库;如果机构知识库未初始化、Milvus / embedding 暂不可用或未命中来源,接口仍会继续调用 LLM,回答开头会声明“未检索到本机构知识库参考,以下为大模型通用学习回答”。
模块用于普通用户医学知识问答。前端点击 AI 学习助手入口后,先创建短期会话,再使用会话式 SSE 接口问答。后端优先检索本机构知识库;如果机构知识库未初始化、Milvus / embedding 暂不可用或未命中来源,接口仍会继续调用 LLM,回答开头会声明“未检索到本机构知识库参考,以下为大模型通用学习回答”。
学习助手会话保存在 Redis 短期缓存中,默认 TTL 为 `7200` 秒;该会话只用于当前学习问答上下文,不写入训练记录。
| 接口名称 | url | api | methods | params(入参) | response(返回参数) |
|---|---|---|---|---|---|
| AI 学习助手流式问答 | `http://8.160.178.88/fastapi/api/v1/learning-assistant/chat/stream` | `/api/v1/learning-assistant/chat/stream` | `POST` | Body`question` 必填,1-1000 字;`top_k` 选填,1-10`score_threshold` 选填,0-1 | SSE`retrieval_done` 检索状态;`answer_delta` 回答增量;`answer_done` 完成事件;`error` 错误事件 |
| AI 学习助手新建会话 | `http://8.160.178.88/fastapi/api/v1/learning-assistant/sessions` | `/api/v1/learning-assistant/sessions` | `POST` | Header`Authorization` 必填,`Bearer <access_token>``X-Entry-Scene` 建议填。Body`title` 选填,会话标题,最大 100 字 | `data.assistant_session_id` 学习助手会话 ID`data.user_id` 当前用户 ID`data.institution_id` 当前机构 ID`data.institution_name` 当前机构名称;`data.title` 会话标题;`data.status` 会话状态;`data.expires_in_seconds` 会话过期时间 |
| AI 学习助手会话式流式问答 | `http://8.160.178.88/fastapi/api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` | `/api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` | `POST` | Path`assistant_session_id` 必填,新建会话接口返回。Body`question` 必填,1-1000 字;`top_k` 选填,1-10,默认使用后端配置;`score_threshold` 选填,0-1,默认使用后端配置 | SSE:`session_ready` 会话就绪;`retrieval_done` 检索状态和来源;`answer_delta` 回答增量;`answer_done` 完成事件;`error` 错误事件 |
请求示例:
新建会话请求示例:
```json
{
"title": "儿科肺炎知识复习"
}
```
新建会话返回示例:
```json
{
"code": "OK",
"message": "success",
"data": {
"assistant_session_id": "las_2e2f4a6b8d4b4f0ba31731a814c1c5b8",
"user_id": "37",
"institution_id": 1,
"institution_name": "某医院",
"title": "儿科肺炎知识复习",
"status": "active",
"created_at": "2026-06-11T12:00:00Z",
"updated_at": "2026-06-11T12:00:00Z",
"expires_in_seconds": 7200
}
}
```
会话式流式问答请求示例:
```json
{
@@ -383,6 +411,22 @@ async function downloadTeachingPdf(baseUrl: string, token: string, evaluationId:
}
```
会话式 SSE 返回示例:
```text
event: session_ready
data: {"assistant_session_id":"las_xxx","status":"active","history_count":0}
event: retrieval_done
data: {"assistant_session_id":"las_xxx","retrieval_hit":true,"sources":[{"document_id":1,"document_title":"诊断学","file_name":"诊断学.pdf","page_start":12,"page_end":12,"chunk_uid":"chunk_001","score":0.82,"quote":"..."}],"retrieval_error":null}
event: answer_delta
data: {"assistant_session_id":"las_xxx","delta":"支气管肺炎常见表现包括..."}
event: answer_done
data: {"assistant_session_id":"las_xxx","model":"deepseek-chat","total_latency_ms":1800,"llm_latency_ms":1600}
```
## 8. 内容管理员知识库 API
该组接口是后台内容管理员能力,学生端不展示上传入口。当前阶段保留接口和数据结构,后续生产环境接入完整 PDF 解析、分片、embedding、Milvus 构建和异步任务。
@@ -414,5 +458,7 @@ async function downloadTeachingPdf(baseUrl: string, token: string, evaluationId:
| 404 | `ORDER_ITEM_NOT_FOUND` | 当前病例不存在该检查项 |
| 400 | `ORDER_ITEM_TYPE_MISMATCH` | 体格检查 / 辅助检查接口与检查项类型不匹配 |
| 404 | `EVALUATION_NOT_FOUND` | 评价不存在或不属于当前用户 |
| 404 | `LEARNING_ASSISTANT_SESSION_NOT_FOUND` | AI 学习助手会话不存在、已过期或不属于当前用户 |
| 400 | `LEARNING_ASSISTANT_SESSION_INVALID` | AI 学习助手会话状态不可用 |
| 502 | `LLM_STREAM_FAILED` | LLM 流式调用失败 |
| 503 | `AUTH_USER_CENTER_UNAVAILABLE` | Django 用户中心超时或不可达 |
+13 -2
View File
@@ -118,10 +118,20 @@ curl "http://8.160.178.88/fastapi/api/v1/auth/me" \
-H "X-Entry-Scene: production_vue"
```
AI 学习助手流式问答
AI 学习助手新建会话
```bash
curl -N -X POST "http://8.160.178.88/fastapi/api/v1/learning-assistant/chat/stream" \
curl -X POST "http://8.160.178.88/fastapi/api/v1/learning-assistant/sessions" \
-H "Authorization: Bearer <access_token>" \
-H "X-Entry-Scene: production_vue" \
-H "Content-Type: application/json" \
-d '{"title":"医学知识学习"}'
```
AI 学习助手会话式流式问答:
```bash
curl -N -X POST "http://8.160.178.88/fastapi/api/v1/learning-assistant/sessions/<assistant_session_id>/chat/stream" \
-H "Authorization: Bearer <access_token>" \
-H "X-Entry-Scene: production_vue" \
-H "Content-Type: application/json" \
@@ -131,6 +141,7 @@ curl -N -X POST "http://8.160.178.88/fastapi/api/v1/learning-assistant/chat/stre
正常应看到:
```text
event: session_ready
event: retrieval_done
event: answer_delta
event: answer_done
+8 -8
View File
@@ -45,7 +45,7 @@
| 当前状态 | 已实现,正式接口为 SSE |
| 相关接口 | `POST /api/v1/sessions/{session_id}/hints/stream` |
| 相关代码 | `app/agents/hint_agent.py``app/services/session_service.py` |
| 相关提示词 | `app/prompts/hint/novice_case_hint.md` |
| 相关提示词 | `app/prompts/hint/practice_case_hint.md` |
| 后续优化 | 增加科室主任风格模板、提示质量评估和可配置提示强度 |
## 5. 检查/检验模块
@@ -88,7 +88,7 @@
|---|---|
| 主要作用 | 生成和下载 AI 评价 PDF |
| 当前状态 | 已实现 |
| 相关接口 | `POST /api/v1/evaluations/{evaluation_id}/export-pdf``GET /api/v1/evaluations/{evaluation_id}/download-pdf` |
| 相关接口 | `GET /api/v1/evaluations/{evaluation_id}/download-pdf` |
| 相关代码 | `app/services/pdf_export_service.py` |
| 相关表 | `training_record` |
| 文件目录 | `storage/reports` |
@@ -122,19 +122,19 @@
| 项 | 内容 |
|---|---|
| 主要作用 | 普通用户提出医学学习问题,后端优先检索机构知识库并流式回答 |
| 当前状态 | 已实现式流式接口;无知识库时自动降级为通用 LLM 回答 |
| 相关接口 | `POST /api/v1/learning-assistant/chat/stream` |
| 相关代码 | `app/api/learning_assistant.py``app/services/learning_assistant_service.py``app/agents/learning_assistant_agent.py` |
| 相关表 | `kb_spaces``kb_chunks``kb_query_logs` |
| 当前状态 | 已实现新建短期会话和会话式流式接口;无知识库时自动降级为通用 LLM 回答 |
| 相关接口 | `POST /api/v1/learning-assistant/sessions``POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` |
| 相关代码 | `app/api/learning_assistant.py``app/services/learning_assistant_service.py``app/services/learning_assistant_session_store.py``app/agents/learning_assistant_agent.py` |
| 相关表 | `kb_spaces``kb_chunks``kb_query_logs`;学习助手短期会话保存在 Redis |
| 外部依赖 | LLM、Embedding、Milvus |
| 后续优化 | 查询改写、rerank、多轮记忆、来源引用格式优化、成本统计 |
| 后续优化 | 查询改写、rerank、长期学习记录、来源引用格式优化、成本统计 |
## 12. 后台知识库预留模块
| 项 | 内容 |
|---|---|
| 主要作用 | 内容管理员上传 PDF,构建机构知识库 |
| 当前状态 | 接口和数据结构已预留,生产级大规模入库仍需压测 |
| 当前状态 | 接口和数据结构保留,当前前端不展示入口,生产级大规模入库仍需压测 |
| 相关接口 | `POST /api/v1/knowledge-admin/documents/upload`、文档列表、文档详情 |
| 相关代码 | `app/api/knowledge_admin.py``app/services/document_ingestion_service.py``app/integrations/*` |
| 相关表 | `kb_spaces``kb_documents``kb_chunks``kb_ingestion_tasks` |
+1 -1
View File
@@ -135,7 +135,7 @@ REDIS_URL=redis://redis:6379/0
建议:
- 先用 `/api/v1/learning-assistant/chat/stream` 测试最简单问题
-`/api/v1/learning-assistant/sessions` 创建会话,再用 `/api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` 测试最简单问题
- 查看 FastAPI 日志
- 确认模型服务账号额度
+10 -11
View File
@@ -30,8 +30,6 @@ SSE 流式接口返回 `event + data`,不包裹上述 JSON 结构。
|---|---|---|---|---|---|---|---|
| 用户鉴权 | 当前用户信息 | `GET /api/v1/auth/me` | `app/api/auth.py::auth_me` | `app/services/external_auth_service.py::authenticate` | 无本地仓储 | Django `user``institution``department` | FastAPI 转发 token 到 Django `/api/user/users/me/`,使用 Django `id` 作为统一 `user_id` |
| Agent 状态 | Hello / 功能开关 | `GET /api/v1/agent/hello` | `app/api/agent.py::agent_hello` | `app/core/config.py::as_public_dict` | `app/services/audit_service.py` | `audit_logs` | 给前端展示当前模型、PDF、知识库等能力开关 |
| 病例读取 | 病例列表 | `GET /api/v1/cases` | `app/api/cases.py::list_cases` | `app/services/case_service.py::list_cases` | `app/repositories/case_repository.py` | `case_base``traditional_case``teaching_case` | 只读已发布启用病例,不做病例新增/删除 |
| 病例读取 | 病例详情 | `GET /api/v1/cases/{case_id}` | `app/api/cases.py::get_case_detail` | `app/services/case_service.py::get_case_detail` | `app/repositories/case_repository.py` | `case_base``traditional_case``teaching_case` | 前端展示病例基础信息,不作为病例管理后台 |
| 训练配置 | 推荐配置信息 | `GET /api/v1/training-config/recommended?case_id=1` | `app/api/training_config.py::get_recommended_training_config` | `app/services/training_config_service.py::get_recommended` | `app/repositories/case_repository.py` | `case_base``traditional_case` | 返回默认就诊环境、年龄段、文化程度、性格等病人初始化信息 |
| 训练配置 | 可选配置信息 | `GET /api/v1/training-config/options?case_id=1` | `app/api/training_config.py::get_training_config_options` | `app/services/training_config_service.py::get_options` | `app/repositories/case_repository.py` | `case_base` | 返回前端可选配置项,用于自定义病人信息 |
| 训练页面 | 新建会话 | `POST /api/v1/sessions` | `app/api/sessions.py::create_session` | `app/services/session_service.py::create_session` | `app/repositories/session_repository.py``case_repository.py` | `training_session`、Redis memory | 创建会话、写入 user_id、初始化短期 memory 和病人开场白 |
@@ -49,12 +47,11 @@ SSE 流式接口返回 `event + data`,不包裹上述 JSON 结构。
| 训练页面 | 生成评价 | `POST /api/v1/sessions/{session_id}/evaluation` | `app/api/sessions.py::create_evaluation` | `app/services/evaluation_service.py::create_evaluation` | `evaluation_repository.py``source_case_repository.py``session_repository.py` | `training_record``training_score_detail``scoring_rule` | 读取评分规则、短期 memory、诊断治疗提交内容,调用 Scoring Agent |
| 个人中心 | 训练记录列表 | `GET /api/v1/evaluations?page=1&page_size=10` | `app/api/evaluations.py::list_evaluations` | `app/services/evaluation_service.py::list_history` | `app/repositories/evaluation_repository.py` | `training_record` | 按 Django user_id 隔离,支持分页 |
| 个人中心 | 评价详情 | `GET /api/v1/evaluations/{evaluation_id}` | `app/api/evaluations.py::get_evaluation_detail` | `app/services/evaluation_service.py::get_detail` | `evaluation_repository.py` | `training_record``training_score_detail` | 训练评价和教学互动评价共用详情接口 |
| 个人中心 | 导出 PDF | `POST /api/v1/evaluations/{evaluation_id}/export-pdf` | `app/api/evaluations.py::export_pdf` | `app/services/pdf_export_service.py::export` | `evaluation_repository.py` | `training_record` | 生成本地 PDF 并写入 `pdf_file_path` |
| 个人中心 | 下载 PDF | `GET /api/v1/evaluations/{evaluation_id}/download-pdf` | `app/api/evaluations.py::download_pdf` | `app/services/pdf_export_service.py::export` | `evaluation_repository.py` | `training_record` | 校验 user_id 后返回 `application/pdf` 文件流 |
| 教学互动 | 获取教学列表 | `GET /api/v1/teaching/cases/{case_id}/items` | `app/api/teaching.py::get_teaching_items` | `app/services/teaching_service.py::list_items` | `teaching_repository.py``case_repository.py` | `case_base``teaching_case` | 返回题目、选项、答案、解析文本、视频 |
| 教学互动 | 生成评价 | `POST /api/v1/teaching/evaluation` | `app/api/teaching.py::create_teaching_evaluation` | `app/services/teaching_service.py::create_evaluation` | `evaluation_repository.py``teaching_repository.py` | `training_record``training_score_detail``teaching_case` | 根据作答结果生成教学互动评价 |
| AI 学习助手 | 流式问答 | `POST /api/v1/learning-assistant/chat/stream` | `app/api/learning_assistant.py::learning_assistant_stream_chat` | `app/services/learning_assistant_service.py::stream_chat` | `knowledge_base_repository.py` | `kb_spaces``kb_chunks``kb_query_logs` | 优先 RAG 检索;无知识库时返回 `retrieval_hit=false` 后继续 LLM 回答 |
| AI 学习助手 | 非流式调试问答 | `POST /api/v1/learning-assistant/chat` | `app/api/learning_assistant.py::learning_assistant_chat` | `app/services/learning_assistant_service.py::chat` | `knowledge_base_repository.py` | `kb_spaces``kb_chunks``kb_query_logs` | `include_in_schema=False`,正式前端不使用 |
| AI 学习助手 | 新建会话 | `POST /api/v1/learning-assistant/sessions` | `app/api/learning_assistant.py::create_learning_assistant_session` | `app/services/learning_assistant_service.py::create_session` | `learning_assistant_session_store.py` | Redis 短期缓存 | 进入 AI 学习助手页面时创建短期会话,返回 `assistant_session_id` |
| AI 学习助手 | 会话式流式问答 | `POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` | `app/api/learning_assistant.py::stream_learning_assistant_session_chat` | `app/services/learning_assistant_service.py::stream_session_chat` | `knowledge_base_repository.py``learning_assistant_session_store.py` | `kb_spaces``kb_chunks``kb_query_logs`、Redis 短期缓存 | 优先 RAG 检索;同时保存最近问答上下文;无知识库时继续 LLM 通用学习回答 |
| 知识库管理 | 上传 PDF | `POST /api/v1/knowledge-admin/documents/upload` | `app/api/knowledge_admin.py::upload_knowledge_document` | `app/services/document_ingestion_service.py::upload_pdf` | `knowledge_base_repository.py` | `kb_spaces``kb_documents``kb_ingestion_tasks``kb_chunks` | 仅内容管理员使用;学生端不展示入口 |
| 健康检查 | 存活检查 | `GET /health/live` | `app/api/health.py::live` | 无 | 无 | 无 | 检查 FastAPI 进程可响应 |
| 健康检查 | 就绪检查 | `GET /health/ready` | `app/api/health.py::ready` | `settings.deployment_config_errors` | 数据库连接 | MySQL、Redis 配置 | 用于部署验证 |
@@ -64,7 +61,7 @@ SSE 流式接口返回 `event + data`,不包裹上述 JSON 结构。
### 3.1 训练链路
1. 前端调用 `GET /api/v1/auth/me` 验证用户。
2. 前端读取病例和训练配置。
2. 前端从页面上下文获得 `case_id`,再读取训练配置。
3. 前端调用 `POST /api/v1/sessions` 创建 `training_session`,后端初始化 Redis 短期 memory。
4. 前端调用 `POST /api/v1/sessions/{session_id}/chat/stream` 进行流式问诊。
5. 用户申请体格检查或辅助检查,后端从 `case_exam_item` 返回固定结果并写入 `training_order` 和 Redis memory。
@@ -82,11 +79,13 @@ SSE 流式接口返回 `event + data`,不包裹上述 JSON 结构。
### 3.3 AI 学习助手链路
1. 前端调用 `POST /api/v1/learning-assistant/chat/stream`
2. 后端根据当前用户 `institution_id` 查找知识空间
3. 有知识库时:问题 embedding -> Milvus 检索 -> MySQL 读取 chunk 元数据 -> 拼接来源给 LLM
4. 无知识库或检索失败时:返回 `retrieval_hit=false`,继续给出通用 LLM 学习回答
5. 后端写入 `kb_query_logs`,记录命中、来源和耗时
1. 前端进入页面后调用 `POST /api/v1/learning-assistant/sessions` 创建短期会话
2. 前端携带 `assistant_session_id` 调用 `POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream`
3. 后端校验该学习助手会话属于当前 Django 用户,并读取最近问答上下文
4. 后端根据当前用户 `institution_id` 查找知识空间
5. 有知识库时:问题 embedding -> Milvus 检索 -> MySQL 读取 chunk 元数据 -> 拼接来源和会话上下文给 LLM
6. 无知识库或检索失败时:返回 `retrieval_hit=false`,继续给出通用 LLM 学习回答。
7. 后端写入 `kb_query_logs`,记录命中、来源和耗时,同时把本轮问答写回 Redis 短期会话。
## 4. 重要边界
+13 -13
View File
@@ -21,20 +21,15 @@
| 提示词模板 | 文件路径 | 使用场景 | 调用模块 | 触发接口 | 输入数据 | 输出格式 | 说明 |
|---|---|---|---|---|---|---|---|
| 新手病例提示 | `app/prompts/hint/novice_case_hint.md` | 生成结构化练习提示 | `app/agents/hint_agent.py::HintAgent.generate` | `POST /api/v1/sessions/{session_id}/hints` | 病例标题、主诉、关键症状、关键检查、当前会话 memory、已申请检查、最后一句用户问题 | JSON | 返回 `hints``missing_dimensions``next_questions``recommended_orders`LLM 失败时使用兜底提示 |
| 新手提示旧模板 | `app/prompts/hint/novice_hint.md` | 早期新手提示模板保留 | 当前主流程不直接调用 | 无主入口 | 无 | 文本 | 保留用于兼容和后续提示词对比,当前推荐使用 `novice_case_hint.md` |
| 练习病例提示 | `app/prompts/hint/practice_case_hint.md` | 生成结构化练习提示 | `app/agents/hint_agent.py::HintAgent.generate` | `POST /api/v1/sessions/{session_id}/hints` | 病例标题、主诉、关键症状、关键检查、当前会话 memory、已申请检查、最后一句用户问题 | JSON | 返回 `hints``missing_dimensions``next_questions``recommended_orders`LLM 失败时使用兜底提示 |
| AI 病人通用模板 | `app/prompts/patient/free_chat.md` | AI 病人通用问诊风格参考 | 当前 `PatientAgent` 主要在代码内拼接系统提示 | `POST /api/v1/sessions/{session_id}/chat/stream` | 病例、隐藏信息、初始化配置、短期 memory、医生问题 | 纯文本 | 文件作为模板资产保留;实际回复规则见 `PatientAgent._build_messages` |
| AI 病人新手模板 | `app/prompts/patient/novice.md` | 新手/练习模式风格参考 | 当前 `PatientAgent` 主要在代码内拼接系统提示 | `POST /api/v1/sessions/{session_id}/chat/stream` | 同上 | 纯文本 | 新手与练习模式已合并为训练模式,提示功能由王主任练习提示承担 |
| AI 病人练习模板 | `app/prompts/patient/practice.md` | 练习模式风格参考 | 当前 `PatientAgent` 主要在代码内拼接系统提示 | `POST /api/v1/sessions/{session_id}/chat/stream` | 同上 | 纯文本 | 练习时只回答被问到的信息,不主动给诊断建议 |
| AI 病人教学模板 | `app/prompts/patient/teaching.md` | 教学风格参考 | 当前 `PatientAgent` 主要在代码内拼接系统提示 | 训练流式问诊相关接口 | 同上 | 纯文本 | 用于后续教学模式对话扩展 |
| 医生问题润色 | `app/prompts/polish/doctor_question_polish.md` | 医学生提问润色能力预留 | 当前主流程不直接调用 | 无主入口 | 医生原始问题、病例场景 | JSON 或文本 | 后续用于前端输入优化时启用 |
| 百分制评分 | `app/prompts/scoring/default_percentage.md` | 训练评价百分制评分模板 | 当前 `ScoringAgent` 在代码内拼接评分系统提示,文件作为模板资产 | `POST /api/v1/sessions/{session_id}/evaluation` | 病例、问诊 memory、检查、诊断治疗、评分规则、指南引用 | JSON | 输出 `total_score``dimension_scores``score_details``errors``improvement_plan` 等 |
| 五分制评分 | `app/prompts/scoring/default_five_point.md` | 训练评价五分制评分模板 | 当前 `ScoringAgent` 支持五分制转换,文件作为模板资产 | `POST /api/v1/sessions/{session_id}/evaluation` | 同百分制 | JSON | `score_type=five_point` 时将百分制结构转换为五分制 |
| 儿科肺炎评分 | `app/prompts/scoring/pediatrics_pneumonia.md` | 儿科支气管肺炎病例评分参考 | 当前评分依赖 `scoring_rule` 和病例数据,文件作为病例专科提示资产 | `POST /api/v1/sessions/{session_id}/evaluation` | 儿科病例、检查、诊断、治疗、评分规则 | JSON | 用于病例专科评分要求维护 |
| 教学互动评分 | `app/prompts/scoring/teaching_interaction_evaluation.md` | 教学互动答题评价 | `app/agents/scoring_agent.py::ScoringAgent.score_teaching` | `POST /api/v1/teaching/evaluation` | 病例、教学题、标准答案、解析、学生作答、评分规则 | JSON | 评价答题正确率、错误原因、学习建议和教学维度表现 |
| 报告整理 | `app/prompts/report/evaluation_report.md` | 评价报告整理模板资产 | `app/agents/report_agent.py::ReportAgent.build_report` 使用代码内校验整理 | 评价生成、PDF 下载 | Scoring Agent 输出 | JSON | Report Agent 不重新评分,只补齐报告字段 |
| 学习助手命中知识库 | `app/prompts/learning_assistant/rag_answer.md` | RAG 命中时的回答模板资产 | 当前 `LearningAssistantAgent._messages` 在代码内拼接同等规则 | `POST /api/v1/learning-assistant/chat/stream` | 用户问题、知识库片段、PDF 名称、页码、chunk_uid | 流式纯文本 | 回答中必须引用来源编号,不得编造 PDF 和页码 |
| 学习助手未命中知识库 | `app/prompts/learning_assistant/no_reference_answer.md` | 未命中知识库时的回答模板资产 | 当前 `LearningAssistantAgent._messages` 在代码内拼接同等规则 | `POST /api/v1/learning-assistant/chat/stream` | 用户问题 | 流式纯文本 | 开头必须说明“未检索到本机构知识库参考” |
| 学习助手命中知识库 | `app/prompts/learning_assistant/rag_answer.md` | RAG 命中时的回答模板资产 | 当前 `LearningAssistantAgent._messages` 在代码内拼接同等规则 | `POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` | 用户问题、学习助手短期上下文、知识库片段、PDF 名称、页码、chunk_uid | 流式纯文本 | 回答中必须引用来源编号,不得编造 PDF 和页码 |
| 学习助手未命中知识库 | `app/prompts/learning_assistant/no_reference_answer.md` | 未命中知识库时的回答模板资产 | 当前 `LearningAssistantAgent._messages` 在代码内拼接同等规则 | `POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` | 用户问题、学习助手短期上下文 | 流式纯文本 | 开头必须说明“未检索到本机构知识库参考” |
## 3. 训练问诊提示词调用链
@@ -81,7 +76,7 @@ POST /api/v1/sessions/{session_id}/hints
-> app/api/sessions.py::generate_hints
-> app/services/session_service.py::generate_hints
-> app/agents/hint_agent.py::HintAgent.generate
-> app/prompts/hint/novice_case_hint.md
-> app/prompts/hint/practice_case_hint.md
```
输出字段:
@@ -130,15 +125,20 @@ POST /api/v1/teaching/evaluation
## 7. AI 学习助手提示词调用链
```text
POST /api/v1/learning-assistant/chat/stream
-> app/api/learning_assistant.py::learning_assistant_stream_chat
-> app/services/learning_assistant_service.py::stream_chat
POST /api/v1/learning-assistant/sessions
-> app/api/learning_assistant.py::create_learning_assistant_session
-> app/services/learning_assistant_service.py::create_session
-> app/services/learning_assistant_session_store.py::LearningAssistantSessionStore.create
POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream
-> app/api/learning_assistant.py::stream_learning_assistant_session_chat
-> app/services/learning_assistant_service.py::stream_session_chat
-> app/agents/learning_assistant_agent.py::LearningAssistantAgent.stream_answer
```
命中知识库时:
- 输入用户问题和检索到的知识片段。
- 输入用户问题、学习助手短期上下文和检索到的知识片段。
- 每个来源包含 PDF 名称、页码、chunk_uid、引用文本。
- 回答必须标注来源编号,例如 `【来源1】`
+96
View File
@@ -0,0 +1,96 @@
# 功能工作流说明
本文档说明当前保留功能的运行方式,重点描述接口、代码入口、提示词、数据库读写和结果去向。本文档与 `docs/03_api_design.md` 配合使用:API 文档面向前端调用,本文档面向后端维护和功能排查。
## 1. 通用链路
所有业务接口先执行用户鉴权:
```text
Authorization: Bearer <access_token>
-> app/core/user_context.py::get_user_context
-> app/services/external_auth_service.py::ExternalAuthService.get_current_user
-> Django /api/user/users/me/
-> UserContext(user_id, role, institution_id, department_id)
```
FastAPI 使用 Django 返回的 `id` 作为业务 `user_id`。训练会话、评价详情、PDF 下载、学习助手会话都按 `user_id` 做访问隔离。
## 2. 功能工作流表
| 功能 | 接口 | Router | Service / Agent | 提示词 | 数据库读取 | 数据库写入 | 结果去向 |
|---|---|---|---|---|---|---|---|
| 用户鉴权 | `GET /api/v1/auth/me` | `app/api/auth.py::auth_me` | `ExternalAuthService.get_current_user` | 无 | Django `user``institution``department` | 无 | 返回前端标准化用户信息 |
| 推荐配置信息 | `GET /api/v1/training-config/recommended` | `training_config.py::get_recommended_training_config` | `TrainingConfigService.get_recommended` | 无 | `case_base``traditional_case` | 无 | 返回前端默认病人配置 |
| 训练配置信息 | `GET /api/v1/training-config/options` | `training_config.py::get_training_config_options` | `TrainingConfigService.get_options` | 无 | `case_base` | 无 | 返回前端可选配置 |
| 新建训练会话 | `POST /api/v1/sessions` | `sessions.py::create_session` | `SessionService.create_session` | 无 | `case_base``traditional_case` | `training_sessions`Redis `mem:*` | 返回 `session_id`、开场白;初始化短期 memory |
| 流式会话 | `POST /api/v1/sessions/{session_id}/chat/stream` | `sessions.py::chat_stream` | `SessionService.stream_chat` -> `PatientAgent.stream_reply` | `PatientAgent._build_messages` 代码内提示;`app/prompts/patient/free_chat.md` 为模板资产 | `training_sessions``case_base`、Redis memory | Redis memory 追加 doctor / patient 消息 | SSE 返回 `message_delta``message_done` |
| 王主任练习提示 | `POST /api/v1/sessions/{session_id}/hints/stream` | `sessions.py::stream_hints` | `SessionService.stream_hints` -> `HintAgent.generate` | `app/prompts/hint/practice_case_hint.md` | `training_sessions``case_base``session_orders`、Redis memory | 无 | SSE 返回一句话练习提示 |
| 结构化练习提示 | `POST /api/v1/sessions/{session_id}/hints` | `sessions.py::generate_hints` | `SessionService.generate_hints` -> `HintAgent.generate` | `app/prompts/hint/practice_case_hint.md` | `training_sessions``case_base``session_orders`、Redis memory | 无 | 返回缺失维度、下一步问题、推荐检查 |
| 体格检查列表 | `GET /api/v1/sessions/{session_id}/physical-exams` | `sessions.py::list_physical_exam_items` | `OrderService.list_physical_exam_items` | 无 | `training_sessions``case_exam_item` | 无 | 返回当前病例 `item_type=physical` 的检查项 |
| 辅助检查列表 | `GET /api/v1/sessions/{session_id}/auxiliary-exams` | `sessions.py::list_auxiliary_exam_items` | `OrderService.list_auxiliary_exam_items` | 无 | `training_sessions``case_exam_item` | 无 | 返回当前病例 `item_type=auxiliary` 的检查项 |
| 体格检查结果 | `POST /api/v1/sessions/{session_id}/physical-exams/{item_code}` | `sessions.py::create_physical_exam_order` | `OrderService.create_physical_exam_order` | 无 | `training_sessions``case_exam_item` | `session_orders`Redis memory 追加 tool 消息 | 返回前端检查结果;结果写入评分依据 |
| 辅助检查结果 | `POST /api/v1/sessions/{session_id}/auxiliary-exams/{item_code}` | `sessions.py::create_auxiliary_exam_order` | `OrderService.create_auxiliary_exam_order` | 无 | `training_sessions``case_exam_item` | `session_orders`Redis memory 追加 tool 消息 | 返回前端检查结果;结果写入评分依据 |
| 完成问诊 | `POST /api/v1/sessions/{session_id}/complete-inquiry` | `sessions.py::complete_inquiry` | `SessionService.complete_inquiry` | 无 | `training_sessions`、Redis memory | `training_sessions.status=diagnosis` | 返回前端新阶段 |
| 提交诊断 | `POST /api/v1/sessions/{session_id}/diagnosis` | `sessions.py::submit_diagnosis` | `SessionService.submit_diagnosis` | 无 | `training_sessions` | `session_submissions``training_sessions.status=treatment` | 返回前端新阶段 |
| 提交治疗 | `POST /api/v1/sessions/{session_id}/treatment` | `sessions.py::submit_treatment` | `SessionService.submit_treatment` | 无 | `training_sessions``session_submissions` | `session_submissions``training_sessions.status=evaluating` | 返回前端新阶段 |
| 训练生成评价 | `POST /api/v1/sessions/{session_id}/evaluation` | `sessions.py::create_evaluation` | `EvaluationService.create_evaluation` -> `ScoringAgent.score` -> `ReportAgent.build_report` | `app/prompts/scoring/default_percentage.md``default_five_point.md``pediatrics_pneumonia.md` 为模板资产;评分系统提示在 `ScoringAgent` 中拼接 | `training_sessions``case_base``session_orders``session_submissions``scoring_rule`、Redis memory | `training_record``training_score_detail`;释放 Redis 训练 memory | 返回前端结构化评价;长期保存评价记录 |
| 获取评价详情 | `GET /api/v1/evaluations/{evaluation_id}` | `evaluations.py::get_evaluation_detail` | `EvaluationService.get_evaluation_detail` | 无 | `training_record``training_score_detail` | 无 | 返回前端评价详情 |
| 下载 PDF | `GET /api/v1/evaluations/{evaluation_id}/download-pdf` | `evaluations.py::download_pdf` | `PdfExportService.export` | 无 | `training_record``training_score_detail` | 更新 `training_record.pdf_file_path` | 浏览器直接下载 PDF 文件流 |
| 教学互动获取教学列表 | `GET /api/v1/teaching/cases/{case_id}/items` | `teaching.py::get_teaching_items` | `TeachingService.get_items` | 无 | `case_base``teaching_case` | 无 | 返回题目、选项、答案、解析文本、视频 |
| 教学互动生成评价 | `POST /api/v1/teaching/evaluation` | `teaching.py::create_teaching_evaluation` | `TeachingService.create_evaluation` -> `ScoringAgent.score_teaching` | `app/prompts/scoring/teaching_interaction_evaluation.md` | `case_base``teaching_case``scoring_rule` | `training_sessions``training_record``training_score_detail` | 返回前端教学评价;长期保存评价记录 |
| 个人中心训练记录列表 | `GET /api/v1/evaluations?page=1&page_size=10` | `evaluations.py::list_evaluations` | `EvaluationService.list_evaluations` | 无 | `training_record` | 无 | 返回前端分页记录 |
| AI 学习助手新建会话 | `POST /api/v1/learning-assistant/sessions` | `learning_assistant.py::create_learning_assistant_session` | `LearningAssistantService.create_session` -> `LearningAssistantSessionStore.create` | 无 | 用户上下文 | Redis `learning_assistant:session:*` | 返回 `assistant_session_id` |
| AI 学习助手流式会话 | `POST /api/v1/learning-assistant/sessions/{assistant_session_id}/chat/stream` | `learning_assistant.py::stream_learning_assistant_session_chat` | `LearningAssistantService.stream_session_chat` -> `VectorSearchService` -> `LearningAssistantAgent.stream_answer` | `app/prompts/learning_assistant/rag_answer.md``no_reference_answer.md` 为模板资产;实际提示在 `LearningAssistantAgent._messages` 中拼接 | `kb_spaces``kb_chunks`、Milvus、Redis 学习助手会话 | `kb_query_logs`;Redis 追加学习助手问答 | SSE 返回检索状态、来源和回答;保存查询日志 |
| 内容管理员上传知识库 | `POST /api/v1/knowledge-admin/documents/upload` | `knowledge_admin.py::upload_knowledge_document` | `DocumentIngestionService.upload_and_ingest` | 无 | 用户角色、机构知识库空间 | `kb_documents``kb_chunks``kb_ingestion_tasks`;Milvus 向量 | 后台接口保留;当前学生端不展示入口 |
## 3. 检查项处理规则
当前体格检查和辅助检查都读取 `case_exam_item`
- `item_type=physical`:体格检查。
- `item_type=auxiliary`:辅助检查。
- 列表接口只返回项目,不返回结果。
- 结果接口按 `item_code` 返回固定结果。
- 同一会话同一 `item_code` 幂等,重复申请不会重复写入 `session_orders` 和 Redis memory。
- 检查结果只来自数据库,不由 LLM 编造。
## 4. 训练评价数据去向
训练评价只在用户完成完整流程后写入长期记录:
```text
新建会话 -> 流式问诊 -> 申请检查 -> 完成问诊 -> 提交诊断 -> 提交治疗 -> 生成评价
-> training_record
-> training_score_detail
-> PDF 下载时生成 storage/reports 文件
```
中途退出、未生成评价的会话不会写入 `training_record`。问诊内容保存在 Redis 短期 memory 中,生成评价后释放。
## 5. AI 学习助手数据去向
AI 学习助手不写入训练记录:
```text
新建学习助手会话 -> Redis 短期会话
流式提问 -> RAG 检索 -> LLM 流式回答
-> kb_query_logs 保存查询、命中来源和耗时
-> Redis 保存最近问答上下文
```
命中知识库时,回答必须带来源。未命中知识库时,回答开头说明未检索到本机构知识库参考,不伪造 PDF、页码或指南名称。
## 6. 内容管理员知识库能力
内容管理员知识库接口当前保留在后端,用于后续后台页面接入。学生端不展示上传入口。
当前已保留:
- PDF 上传接口。
- 文档表、分片表、任务表。
- Embedding 适配器。
- Milvus 适配器。
- 同步构建和 Celery 异步任务扩展点。
后续生产级扩展需要重点补齐任务队列监控、失败重试、分片质量评估、文件去重和权限后台。