docs: update project docs and evaluation history pagination
This commit is contained in:
@@ -76,7 +76,7 @@ fastapi/
|
||||
│ ├── schemas/ # Pydantic 入参/出参
|
||||
│ ├── services/ # 业务服务
|
||||
│ └── tasks/ # Celery 异步任务预留
|
||||
├── docs/ # API、架构、数据库、部署和交接文档
|
||||
├── docs/ # API、架构、数据库、部署和项目文档
|
||||
├── scripts/ # 初始化和维护脚本
|
||||
├── tests/ # 自动化测试
|
||||
├── Dockerfile
|
||||
@@ -90,8 +90,8 @@ fastapi/
|
||||
```powershell
|
||||
cd D:\Code\newfounder\medical-consultation-agent
|
||||
|
||||
python -m venv .venv
|
||||
.\.venv\Scripts\activate
|
||||
python -m venv backend\.venv
|
||||
.\backend\.venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
copy .env.example .env
|
||||
uvicorn app.main:app --host 127.0.0.1 --port 9000
|
||||
@@ -209,17 +209,20 @@ event: answer_done
|
||||
.\backend\.venv\Scripts\python.exe tests\test_api_contract.py
|
||||
```
|
||||
|
||||
## 9. 交接文档
|
||||
## 9. 项目文档
|
||||
|
||||
| 文档 | 用途 |
|
||||
|---|---|
|
||||
| `docs/00_project_overview.md` | 项目总览和功能讲解顺序 |
|
||||
| `docs/01_architecture.md` | 系统架构、调用链路和模块边界 |
|
||||
| `docs/02_database.md` | 核心数据库表和读写边界 |
|
||||
| `docs/03_api_design.md` | 前端联调 API 文档 |
|
||||
| `docs/04_deployment.md` | 云服务器部署、更新和回滚 |
|
||||
| `docs/05_modules.md` | 功能模块说明 |
|
||||
| `docs/06_handover.md` | 离职交接说明和风险清单 |
|
||||
| `docs/06_maintenance_guide.md` | 开发维护说明和风险清单 |
|
||||
| `docs/07_troubleshooting.md` | 常见故障排查 |
|
||||
| `docs/08_feature_code_map.md` | 功能到接口、代码和数据表的映射表 |
|
||||
| `docs/09_prompt_template_catalog.md` | 提示词模板目录和调用说明 |
|
||||
|
||||
## 10. 重要约定
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -15,9 +15,14 @@ router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=ApiResponse[EvaluationListResponse])
|
||||
def list_evaluations(ctx: UserContext = Depends(get_user_context), db: Session = Depends(get_db)):
|
||||
def list_evaluations(
|
||||
page: int = Query(default=1, ge=1, description="页码,从 1 开始"),
|
||||
page_size: int = Query(default=10, ge=1, le=100, description="每页数量,最大 100"),
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""历史评价:基于 user_id 查询完整训练后的评价记录。"""
|
||||
return ok(EvaluationService(db).list_history(ctx.user_id))
|
||||
return ok(EvaluationService(db).list_history(ctx.user_id, page=page, page_size=page_size))
|
||||
|
||||
|
||||
@router.get("/{evaluation_id}", response_model=ApiResponse[EvaluationDetailResponse])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy import delete, func, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models.training_record import TrainingRecord, TrainingScoreDetail
|
||||
@@ -46,12 +46,19 @@ class EvaluationRepository:
|
||||
)
|
||||
return self.db.scalar(stmt)
|
||||
|
||||
def list_by_user(self, user_id: str) -> list[TrainingRecord]:
|
||||
def count_by_user(self, user_id: str) -> int:
|
||||
"""历史评价计数:按外部 user_id 统计完整训练后的评价记录总数。"""
|
||||
stmt = select(func.count()).select_from(TrainingRecord).where(TrainingRecord.external_user_id == user_id)
|
||||
return int(self.db.scalar(stmt) or 0)
|
||||
|
||||
def list_by_user(self, user_id: str, limit: int, offset: int) -> list[TrainingRecord]:
|
||||
"""历史评价:按外部 user_id 查询完整训练后的评价记录。"""
|
||||
stmt = (
|
||||
select(TrainingRecord)
|
||||
.where(TrainingRecord.external_user_id == user_id)
|
||||
.order_by(TrainingRecord.created_at.desc())
|
||||
.limit(limit)
|
||||
.offset(offset)
|
||||
)
|
||||
return list(self.db.scalars(stmt).all())
|
||||
|
||||
|
||||
@@ -61,10 +61,22 @@ class EvaluationListItem(BaseModel):
|
||||
pdf_exported: bool
|
||||
|
||||
|
||||
class PaginationMeta(BaseModel):
|
||||
"""分页信息:用于历史训练记录列表的前端分页展示。"""
|
||||
|
||||
page: int
|
||||
page_size: int
|
||||
total: int
|
||||
total_pages: int
|
||||
has_next: bool
|
||||
has_prev: bool
|
||||
|
||||
|
||||
class EvaluationListResponse(BaseModel):
|
||||
"""历史评价列表响应。"""
|
||||
|
||||
items: list[EvaluationListItem]
|
||||
pagination: PaginationMeta
|
||||
|
||||
|
||||
class ExportPdfResponse(BaseModel):
|
||||
|
||||
@@ -19,6 +19,7 @@ from app.schemas.evaluation import (
|
||||
EvaluationListItem,
|
||||
EvaluationListResponse,
|
||||
EvaluationResponse,
|
||||
PaginationMeta,
|
||||
ScoreDetailItem,
|
||||
)
|
||||
from app.services.audit_service import AuditService
|
||||
@@ -235,9 +236,12 @@ class EvaluationService:
|
||||
"""用户 ID 兼容:Django 返回的 id 写入 external_user_id,纯数字时同步写入源库 user_id。"""
|
||||
return int(user_id) if str(user_id).isdigit() else None
|
||||
|
||||
def list_history(self, user_id: str) -> EvaluationListResponse:
|
||||
def list_history(self, user_id: str, page: int = 1, page_size: int = 10) -> EvaluationListResponse:
|
||||
"""历史评价:按 Django 用户中心 ID 查询完整训练后的 training_record。"""
|
||||
records = self.eval_repo.list_by_user(user_id)
|
||||
total = self.eval_repo.count_by_user(user_id)
|
||||
offset = (page - 1) * page_size
|
||||
records = self.eval_repo.list_by_user(user_id, limit=page_size, offset=offset)
|
||||
total_pages = (total + page_size - 1) // page_size if total else 0
|
||||
return EvaluationListResponse(
|
||||
items=[
|
||||
EvaluationListItem(
|
||||
@@ -249,7 +253,15 @@ class EvaluationService:
|
||||
pdf_exported=bool(record.pdf_file_path),
|
||||
)
|
||||
for record in records
|
||||
]
|
||||
],
|
||||
pagination=PaginationMeta(
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
total=total,
|
||||
total_pages=total_pages,
|
||||
has_next=page < total_pages,
|
||||
has_prev=page > 1 and total_pages > 0,
|
||||
),
|
||||
)
|
||||
|
||||
def get_detail(self, evaluation_id: int, user_id: str) -> EvaluationDetailResponse:
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# 项目总览
|
||||
|
||||
本文档用于快速说明医疗问诊 Agent FastAPI 后端的项目边界、功能现状、代码入口、部署方式、测试方法和后续维护重点。团队成员优先阅读本文,再按链接进入详细文档。
|
||||
|
||||
## 1. 项目定位
|
||||
|
||||
本项目是医疗教学平台中的 FastAPI 后端子服务,负责医疗问诊训练、教学互动、AI 评价、PDF 报告、AI 学习助手和机构知识库预留能力。
|
||||
|
||||
本项目不负责:
|
||||
|
||||
- 用户注册登录
|
||||
- 用户管理后台
|
||||
- 病例 PDF 解析入库
|
||||
- 病例增删改后台
|
||||
- 多租户权限后台
|
||||
- HIS/LIS/PACS 对接
|
||||
- 前端最终 UI
|
||||
|
||||
用户身份来自 Django 用户中心。前端携带 `Authorization: Bearer <access_token>` 调用 FastAPI,FastAPI 转发 token 到 Django `/api/user/users/me/`,以 Django 返回的 `id` 作为本服务统一 `user_id`。
|
||||
|
||||
## 2. 当前已实现功能
|
||||
|
||||
| 模块 | 状态 | 主要入口 |
|
||||
|---|---|---|
|
||||
| 用户鉴权 | 已实现 | `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` |
|
||||
| 王主任练习提示 | 已实现 | `POST /api/v1/sessions/{session_id}/hints/stream` |
|
||||
| 体格检查 / 辅助检查 | 已实现 | `physical-exams`、`auxiliary-exams` 相关接口 |
|
||||
| 诊断 / 治疗提交 | 已实现 | `complete-inquiry`、`diagnosis`、`treatment` |
|
||||
| AI 评价 | 已实现 | `POST /api/v1/sessions/{session_id}/evaluation` |
|
||||
| 个人中心训练记录 | 已实现,支持分页 | `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` |
|
||||
| 健康检查 | 已实现 | `/health/live`、`/health/ready` |
|
||||
|
||||
## 3. 推荐讲解顺序
|
||||
|
||||
1. 项目边界:FastAPI 是后端子服务,不做登录、病例管理和最终 UI。
|
||||
2. 认证链路:前端 token -> FastAPI -> Django `/me` -> 统一 `user_id`。
|
||||
3. 训练链路:病例 -> 配置 -> 会话 -> 问诊 -> 检查 -> 诊断 -> 治疗 -> 评价 -> PDF -> 历史记录。
|
||||
4. 教学互动链路:题目列表 -> 答题 -> 评价 -> PDF。
|
||||
5. AI 学习助手链路:机构知识库检索 -> LLM 流式回答;无知识库时降级通用回答。
|
||||
6. 数据库边界:平台基础数据由 Django/平台维护,FastAPI 主要写训练过程和训练结果。
|
||||
7. 部署和验证:Docker、`.env`、`/fastapi/docs`、测试命令。
|
||||
8. 后续生产化工作:索引补齐、任务队列、知识库构建、权限细化、日志监控。
|
||||
|
||||
## 4. 重点代码入口
|
||||
|
||||
| 目录/文件 | 作用 |
|
||||
|---|---|
|
||||
| `app/main.py` | FastAPI 应用工厂、CORS、路由挂载、异常处理 |
|
||||
| `app/api/router.py` | 所有业务路由聚合 |
|
||||
| `app/core/user_context.py` | 从请求中解析当前用户上下文 |
|
||||
| `app/services/external_auth_service.py` | 调用 Django 用户中心 `/me` |
|
||||
| `app/api/sessions.py` | 训练链路接口 |
|
||||
| `app/services/session_service.py` | 训练会话、问诊、诊断治疗状态流转 |
|
||||
| `app/services/order_service.py` | 体格检查和辅助检查 |
|
||||
| `app/services/evaluation_service.py` | 训练评价生成和训练记录查询 |
|
||||
| `app/services/teaching_service.py` | 教学互动题目与评价 |
|
||||
| `app/services/pdf_export_service.py` | PDF 报告生成与下载 |
|
||||
| `app/services/learning_assistant_service.py` | AI 学习助手 RAG + LLM 编排 |
|
||||
| `app/services/document_ingestion_service.py` | 内容管理员 PDF 上传入库 |
|
||||
| `app/agents` | Patient、Hint、Scoring、Report、Learning Assistant 等 LLM Agent |
|
||||
| `app/prompts` | Markdown 提示词模板 |
|
||||
|
||||
完整功能映射见 [08_feature_code_map.md](08_feature_code_map.md)。
|
||||
|
||||
## 5. 核心文档索引
|
||||
|
||||
| 文档 | 用途 |
|
||||
|---|---|
|
||||
| [01_architecture.md](01_architecture.md) | 系统架构、核心链路、模块边界 |
|
||||
| [02_database.md](02_database.md) | 数据库表、读写边界、表含义 |
|
||||
| [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) | 提示词模板目录和调用说明 |
|
||||
|
||||
## 6. 本地测试命令
|
||||
|
||||
```powershell
|
||||
cd D:\Code\newfounder\medical-consultation-agent
|
||||
|
||||
.\backend\.venv\Scripts\python.exe -m compileall app scripts tests
|
||||
.\backend\.venv\Scripts\python.exe tests\test_core_logic.py
|
||||
.\backend\.venv\Scripts\python.exe tests\test_demo_flow.py
|
||||
.\backend\.venv\Scripts\python.exe tests\test_api_contract.py
|
||||
```
|
||||
|
||||
## 7. 数据库与 Redis 检查
|
||||
|
||||
```powershell
|
||||
.\backend\.venv\Scripts\python.exe scripts\check_final_schema.py
|
||||
.\backend\.venv\Scripts\python.exe scripts\check_final_demo_readiness.py
|
||||
```
|
||||
|
||||
推荐索引缺失不会阻断当前功能,但生产并发前需要补齐。
|
||||
|
||||
## 8. 云端部署验证
|
||||
|
||||
```bash
|
||||
cd /home/code/medical-ai/fastapi
|
||||
git pull origin main
|
||||
|
||||
cd /home/code/medical-ai
|
||||
docker compose build fastapi
|
||||
docker compose up -d fastapi
|
||||
docker compose logs --tail=200 fastapi
|
||||
curl http://127.0.0.1:9000/health/ready
|
||||
```
|
||||
|
||||
公网访问:
|
||||
|
||||
```text
|
||||
http://8.160.178.88/fastapi/docs
|
||||
```
|
||||
|
||||
## 9. 发布前检查
|
||||
|
||||
- `git status --short` 无未确认改动,或已明确哪些改动尚未提交。
|
||||
- `.env` 不提交 Git。
|
||||
- `docs/03_api_design.md` 是前端联调依据。
|
||||
- `docs/02_database.md` 与当前 ORM 表名一致。
|
||||
- 自动化测试全部通过。
|
||||
- 云端 `/fastapi/docs` 可访问。
|
||||
- `GET /api/v1/auth/me` 可用。
|
||||
- 训练链路、教学互动、PDF、AI 学习助手各跑通一次。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 系统架构说明
|
||||
|
||||
本文档用于交接医疗问诊 Agent FastAPI 后端的系统边界、核心链路和外部依赖。
|
||||
本文档用于说明医疗问诊 Agent FastAPI 后端的系统边界、核心链路和外部依赖。
|
||||
|
||||
## 1. 项目定位
|
||||
|
||||
|
||||
+7
-7
@@ -1,6 +1,6 @@
|
||||
# 数据库说明
|
||||
|
||||
本文档说明医疗问诊 Agent FastAPI 后端依赖的核心数据表、读写边界和交接注意事项。
|
||||
本文档说明医疗问诊 Agent FastAPI 后端依赖的核心数据表、读写边界和维护注意事项。
|
||||
|
||||
## 1. 数据库边界
|
||||
|
||||
@@ -156,35 +156,35 @@ FastAPI 使用 Django 返回的 `id` 作为业务 `user_id`。
|
||||
|
||||
## 5. 知识库预留表
|
||||
|
||||
### `kb_knowledge_space`
|
||||
### `kb_spaces`
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 用途 | 机构知识空间和 Milvus collection 映射 |
|
||||
| 关键字段 | `institution_id`、`collection_name`、`embedding_model`、`embedding_dim`、`status` |
|
||||
|
||||
### `kb_knowledge_document`
|
||||
### `kb_documents`
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 用途 | 内容管理员上传 PDF 的元数据 |
|
||||
| 关键字段 | `institution_id`、`uploaded_by`、`file_name`、`file_sha256`、`status`、`parse_status`、`embedding_status`、`chunk_count` |
|
||||
|
||||
### `kb_knowledge_chunk`
|
||||
### `kb_chunks`
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 用途 | PDF 分片文本和页码来源 |
|
||||
| 关键字段 | `document_id`、`institution_id`、`chunk_uid`、`page_start`、`page_end`、`chunk_text` |
|
||||
|
||||
### `kb_knowledge_ingestion_task`
|
||||
### `kb_ingestion_tasks`
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 用途 | PDF 入库任务进度 |
|
||||
| 关键字段 | `document_id`、`institution_id`、`status`、`progress`、`current_step`、`error_message` |
|
||||
|
||||
### `kb_knowledge_query_log`
|
||||
### `kb_query_logs`
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
@@ -204,7 +204,7 @@ Redis 用于短期会话 memory:
|
||||
|
||||
Redis 不作为长期训练历史存储。
|
||||
|
||||
## 7. 数据库交接注意事项
|
||||
## 7. 数据库维护注意事项
|
||||
|
||||
- FastAPI 不维护用户注册登录。
|
||||
- FastAPI 不直接修改病例基础数据。
|
||||
|
||||
@@ -201,7 +201,7 @@ data: {"latency_ms":1200,"first_token_ms":300,"model":"deepseek-chat","fallback_
|
||||
|
||||
| 接口名称 | url | api | methods | params(入参) | response(返回参数) |
|
||||
|---|---|---|---|---|---|
|
||||
| 训练记录列表 | `http://8.160.178.88/fastapi/api/v1/evaluations` | `/api/v1/evaluations` | `GET` | Query:`limit` 可选,默认20;`offset` 可选,默认0 | `data.items[]` 当前用户完整训练后的评价记录 |
|
||||
| 训练记录列表 | `http://8.160.178.88/fastapi/api/v1/evaluations?page=1&page_size=10` | `/api/v1/evaluations` | `GET` | Query:`page` 选填,页码,从1开始,默认1;`page_size` 选填,每页数量,1-100,默认10 | `data.items[]` 当前用户完整训练后的评价记录;`data.pagination` 分页信息 |
|
||||
| 训练记录详情 / 评价详情 | `http://8.160.178.88/fastapi/api/v1/evaluations/{evaluation_id}` | `/api/v1/evaluations/{evaluation_id}` | `GET` | Path:`evaluation_id` 必填 | 完整评价详情,训练和教学互动共用 |
|
||||
| 导出 PDF | `http://8.160.178.88/fastapi/api/v1/evaluations/{evaluation_id}/export-pdf` | `/api/v1/evaluations/{evaluation_id}/export-pdf` | `POST` | Path:`evaluation_id` 必填 | `data.file_path`;`data.exported_at` |
|
||||
| 下载 PDF | `http://8.160.178.88/fastapi/api/v1/evaluations/{evaluation_id}/download-pdf` | `/api/v1/evaluations/{evaluation_id}/download-pdf` | `GET` | Path:`evaluation_id` 必填 | `application/pdf` 文件流,浏览器可直接下载 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 部署说明
|
||||
|
||||
本文档用于交接云服务器部署、更新、回滚和验证流程。
|
||||
本文档用于说明云服务器部署、更新、回滚和验证流程。
|
||||
|
||||
## 1. 服务器目录
|
||||
|
||||
|
||||
+4
-4
@@ -111,11 +111,11 @@
|
||||
|---|---|
|
||||
| 主要作用 | 查询当前用户训练记录和评价详情 |
|
||||
| 当前状态 | 已实现 |
|
||||
| 相关接口 | `GET /api/v1/evaluations`、`GET /api/v1/evaluations/{evaluation_id}` |
|
||||
| 相关接口 | `GET /api/v1/evaluations?page=1&page_size=10`、`GET /api/v1/evaluations/{evaluation_id}` |
|
||||
| 相关代码 | `app/api/evaluations.py`、`app/services/evaluation_service.py` |
|
||||
| 相关表 | `training_record`、`training_score_detail` |
|
||||
| 重要规则 | 必须按 `user_id` 隔离 |
|
||||
| 后续优化 | 增加分页筛选、统计图表和能力画像 |
|
||||
| 后续优化 | 增加筛选条件、统计图表和能力画像 |
|
||||
|
||||
## 11. AI 学习助手模块
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
| 当前状态 | 已实现正式流式接口;无知识库时自动降级为通用 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_knowledge_space`、`kb_knowledge_chunk`、`kb_knowledge_query_log` |
|
||||
| 相关表 | `kb_spaces`、`kb_chunks`、`kb_query_logs` |
|
||||
| 外部依赖 | LLM、Embedding、Milvus |
|
||||
| 后续优化 | 查询改写、rerank、多轮记忆、来源引用格式优化、成本统计 |
|
||||
|
||||
@@ -137,6 +137,6 @@
|
||||
| 当前状态 | 接口和数据结构已预留,生产级大规模入库仍需压测 |
|
||||
| 相关接口 | `POST /api/v1/knowledge-admin/documents/upload`、文档列表、文档详情 |
|
||||
| 相关代码 | `app/api/knowledge_admin.py`、`app/services/document_ingestion_service.py`、`app/integrations/*` |
|
||||
| 相关表 | `kb_knowledge_space`、`kb_knowledge_document`、`kb_knowledge_chunk`、`kb_knowledge_ingestion_task` |
|
||||
| 相关表 | `kb_spaces`、`kb_documents`、`kb_chunks`、`kb_ingestion_tasks` |
|
||||
| 外部依赖 | Milvus、Embedding 服务、Celery |
|
||||
| 后续优化 | 任务队列监控、失败重试、分片策略、文件去重、权限后台 |
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
# 交接文档
|
||||
|
||||
本文档用于说明医疗问诊 Agent FastAPI 后端当前状态、接手重点、风险和后续工作。
|
||||
|
||||
## 1. 当前项目状态
|
||||
|
||||
当前 FastAPI 后端已经完成第一阶段核心功能,并已接入 Django 用户中心、MySQL、Redis、LLM、PDF 下载和 AI 学习助手。
|
||||
|
||||
已完成能力:
|
||||
|
||||
- Django access token 鉴权
|
||||
- 训练配置和推荐配置
|
||||
- 新建训练会话
|
||||
- AI 病人流式问诊
|
||||
- 王主任练习提示
|
||||
- 体格检查和辅助检查
|
||||
- 完成问诊、提交诊断、提交治疗
|
||||
- AI 评价和评分明细
|
||||
- PDF 报告导出和下载
|
||||
- 教学互动题目和评价
|
||||
- 个人中心训练记录和详情
|
||||
- AI 学习助手流式问答
|
||||
- 后台知识库上传和 RAG 架构预留
|
||||
|
||||
当前不是最终生产级完整系统,后续上线后仍需要逐模块做稳定性、监控、权限、性能和运维增强。
|
||||
|
||||
## 2. 优先关注
|
||||
|
||||
接手后建议按顺序确认:
|
||||
|
||||
1. 能否本地启动 FastAPI。
|
||||
2. 能否连接云端 MySQL 和 Redis。
|
||||
3. `GET /api/v1/auth/me` 是否能通过 Django token 返回用户信息。
|
||||
4. 训练全流程是否能跑通。
|
||||
5. 教学互动是否能跑通。
|
||||
6. PDF 下载是否正常。
|
||||
7. AI 学习助手流式接口是否正常。
|
||||
8. 云服务器 `docker compose build fastapi` 是否成功。
|
||||
9. `.env` 是否与云服务器 docker-compose 服务名一致。
|
||||
|
||||
## 3. 当前重要约定
|
||||
|
||||
- FastAPI 不负责登录注册。
|
||||
- 用户身份来自 Django `/api/user/users/me/`。
|
||||
- FastAPI 使用 Django 返回的 `id` 作为 `user_id`。
|
||||
- 普通业务接口需要 `Authorization: Bearer <access_token>`。
|
||||
- 训练记录只有完整流程完成后写入。
|
||||
- 问诊过程主要存在 Redis 短期 memory。
|
||||
- 检查结果只来自数据库。
|
||||
- AI 学习助手正式接口只保留流式接口。
|
||||
- 知识库未初始化时,学习助手仍应正常回答。
|
||||
|
||||
## 4. 发布前必须检查
|
||||
|
||||
本地检查:
|
||||
|
||||
```powershell
|
||||
cd D:\Code\newfounder\medical-consultation-agent
|
||||
|
||||
.\backend\.venv\Scripts\python.exe -m compileall app scripts tests
|
||||
.\backend\.venv\Scripts\python.exe tests\test_core_logic.py
|
||||
.\backend\.venv\Scripts\python.exe tests\test_demo_flow.py
|
||||
.\backend\.venv\Scripts\python.exe tests\test_api_contract.py
|
||||
```
|
||||
|
||||
Git 检查:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git grep -n "<<<<<<<\|=======\|>>>>>>>"
|
||||
git diff --check
|
||||
```
|
||||
|
||||
敏感信息检查:
|
||||
|
||||
```bash
|
||||
git grep -n "sk-"
|
||||
git grep -n "api_key"
|
||||
git grep -n "password"
|
||||
git grep -n "access_token"
|
||||
git grep -n "secret"
|
||||
```
|
||||
|
||||
服务器检查:
|
||||
|
||||
```bash
|
||||
cd /home/code/medical-ai
|
||||
docker compose build fastapi
|
||||
docker compose up -d fastapi
|
||||
docker compose logs --tail=200 fastapi
|
||||
curl http://127.0.0.1:9000/health/ready
|
||||
```
|
||||
|
||||
## 5. 已知风险
|
||||
|
||||
| 风险 | 当前处理 | 后续建议 |
|
||||
|---|---|---|
|
||||
| LLM 调用超时或失败 | 已有异常返回和 mock/fallback 配置 | 增加限流、重试、熔断、成本统计 |
|
||||
| 知识库真实大规模入库 | 当前为生产预留能力 | 压测 PDF 解析、embedding、Milvus 写入 |
|
||||
| Celery 任务监控 | 已预留任务模块 | 增加 worker 部署、重试、任务状态看板 |
|
||||
| 部分宽异常处理 | 保证 Demo 稳定 | 逐步收窄异常类型并补充结构化日志 |
|
||||
| PDF 报告样式 | 当前可下载 | 后续按医院模板优化 |
|
||||
| 前端最终样式 | 不在本仓库维护 | 以后按 API 文档继续联调 |
|
||||
|
||||
## 6. 后续生产级优化建议
|
||||
|
||||
### 6.1 工程与质量
|
||||
|
||||
- 增加 CI/CD。
|
||||
- 增加 lint 和格式化。
|
||||
- 增加数据库 migration 管理。
|
||||
- 增加更多 service 单元测试。
|
||||
- 增加接口压测。
|
||||
|
||||
### 6.2 安全与权限
|
||||
|
||||
- 完善内容管理员角色来源。
|
||||
- 对后台知识库接口增加更细权限。
|
||||
- 增加审计日志检索。
|
||||
- 增加敏感信息脱敏。
|
||||
|
||||
### 6.3 AI 与 Agent
|
||||
|
||||
- 优化 Patient Agent 回答稳定性。
|
||||
- 优化 Scoring Agent JSON 结构校验。
|
||||
- 增加评分重试和人工复核。
|
||||
- 增加 LLM 调用耗时、token、费用统计。
|
||||
- 增加提示词版本管理。
|
||||
|
||||
### 6.4 知识库
|
||||
|
||||
- 完善 PDF 解析质量检测。
|
||||
- 优化分片策略。
|
||||
- 接入真实 embedding 批量任务。
|
||||
- 增加 Milvus collection 生命周期管理。
|
||||
- 增加 RAG 命中率和用户反馈统计。
|
||||
|
||||
## 7. 常用命令
|
||||
|
||||
本地测试:
|
||||
|
||||
```powershell
|
||||
.\backend\.venv\Scripts\python.exe tests\test_api_contract.py
|
||||
```
|
||||
|
||||
服务器日志:
|
||||
|
||||
```bash
|
||||
docker compose logs -f fastapi
|
||||
```
|
||||
|
||||
服务器重启:
|
||||
|
||||
```bash
|
||||
docker compose up -d fastapi
|
||||
```
|
||||
|
||||
拉取最新代码:
|
||||
|
||||
```bash
|
||||
cd /home/code/medical-ai/fastapi
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
## 8. 交接清单
|
||||
|
||||
- [ ] `main` 分支是最新代码
|
||||
- [ ] `git status` 干净
|
||||
- [ ] 无 Git 冲突标记
|
||||
- [ ] 无真实密钥提交
|
||||
- [ ] `.env.example` 和 `.env.production.example` 已更新
|
||||
- [ ] README 已更新
|
||||
- [ ] API 文档已更新
|
||||
- [ ] 架构、数据库、部署、模块、排障文档已补齐
|
||||
- [ ] 本地测试全部通过
|
||||
- [ ] Docker build 通过
|
||||
- [ ] 云端 `/fastapi/docs` 可访问
|
||||
- [ ] `auth/me` 可用
|
||||
- [ ] 训练链路可用
|
||||
- [ ] 教学互动可用
|
||||
- [ ] PDF 下载可用
|
||||
- [ ] AI 学习助手流式可用
|
||||
@@ -0,0 +1,125 @@
|
||||
# 开发维护指南
|
||||
|
||||
本文档面向后续开发和运维人员,说明当前 FastAPI 后端的维护重点、发布检查、风险项和排查路径。
|
||||
|
||||
## 1. 维护目标
|
||||
|
||||
当前项目已经具备训练页面、教学互动、个人中心训练记录、PDF 报告、AI 学习助手和知识库预留链路。后续维护应优先保持以下原则:
|
||||
|
||||
- 不改变已稳定 API 的语义。
|
||||
- 不把业务逻辑写入 API router。
|
||||
- 不在 FastAPI 中实现登录注册。
|
||||
- 不让 LLM 编造检查检验结果。
|
||||
- 不长期保存完整问诊聊天记录。
|
||||
- 不提交 `.env`、token、API Key、日志、PDF 生成物。
|
||||
|
||||
## 2. 重点维护模块
|
||||
|
||||
| 模块 | 代码入口 | 维护重点 |
|
||||
|---|---|---|
|
||||
| 用户鉴权 | `app/services/external_auth_service.py` | Django `/me` 地址、Authorization 透传、用户字段标准化 |
|
||||
| 训练会话 | `app/services/session_service.py` | 状态流转、Redis memory、Patient Agent 调用 |
|
||||
| 检查申请 | `app/services/order_service.py` | 数据库检查项、幂等写入、结果写入 memory |
|
||||
| 评价生成 | `app/services/evaluation_service.py` | 评分规则、评分明细、PDF 数据结构 |
|
||||
| 教学互动 | `app/services/teaching_service.py` | 教学题读取、答案评分、训练记录复用 |
|
||||
| 个人中心 | `app/api/evaluations.py` | 分页、user_id 隔离、PDF 下载 |
|
||||
| 学习助手 | `app/services/learning_assistant_service.py` | RAG 检索、来源引用、流式输出 |
|
||||
| 知识库 | `app/services/document_ingestion_service.py` | 内容管理员权限、PDF 解析、embedding、Milvus |
|
||||
|
||||
## 3. 发布前检查清单
|
||||
|
||||
```powershell
|
||||
.\backend\.venv\Scripts\python.exe -m compileall app scripts tests
|
||||
.\backend\.venv\Scripts\python.exe tests\test_core_logic.py
|
||||
.\backend\.venv\Scripts\python.exe tests\test_demo_flow.py
|
||||
.\backend\.venv\Scripts\python.exe tests\test_api_contract.py
|
||||
.\backend\.venv\Scripts\python.exe scripts\check_final_demo_readiness.py
|
||||
```
|
||||
|
||||
通过标准:
|
||||
|
||||
- Python 编译无错误。
|
||||
- 核心逻辑测试通过。
|
||||
- Demo 流程测试通过。
|
||||
- API 契约测试通过。
|
||||
- 就绪检查 `ready=true`。
|
||||
|
||||
## 4. 数据库维护说明
|
||||
|
||||
FastAPI 当前依赖平台合并后的数据库,核心表包括:
|
||||
|
||||
- `user`
|
||||
- `institution`
|
||||
- `department`
|
||||
- `case_base`
|
||||
- `traditional_case`
|
||||
- `teaching_case`
|
||||
- `case_exam_item`
|
||||
- `scoring_rule`
|
||||
- `training_session`
|
||||
- `training_order`
|
||||
- `training_submission`
|
||||
- `training_record`
|
||||
- `training_score_detail`
|
||||
- `audit_logs`
|
||||
- `prompt_templates`
|
||||
- `kb_spaces`
|
||||
- `kb_documents`
|
||||
- `kb_chunks`
|
||||
- `kb_query_logs`
|
||||
|
||||
生产并发前需要重点确认推荐索引:
|
||||
|
||||
- `case_base.case_type`
|
||||
- `case_base.difficulty`
|
||||
- `case_base.publish_status`
|
||||
- `case_base.status`
|
||||
- `scoring_rule.dimension`
|
||||
- `scoring_rule.competency_dimension`
|
||||
- `training_score_detail.dimension`
|
||||
|
||||
## 5. Redis 维护说明
|
||||
|
||||
Redis 用于训练会话短期 memory,不作为长期训练记录保存。
|
||||
|
||||
生命周期:
|
||||
|
||||
1. 创建训练会话时写入开场消息。
|
||||
2. 流式问诊时写入医生问题和 AI 病人回复。
|
||||
3. 申请检查时写入工具结果。
|
||||
4. 生成评价后释放当前会话 memory。
|
||||
5. 未完成训练依赖 TTL 自动过期。
|
||||
|
||||
## 6. LLM 和提示词维护说明
|
||||
|
||||
提示词模板说明见 [09_prompt_template_catalog.md](09_prompt_template_catalog.md)。
|
||||
|
||||
维护规则:
|
||||
|
||||
- Patient Agent 只回答患者或家属视角,不输出诊断和治疗方案。
|
||||
- Hint Agent 用于练习提示,不能直接给完整答案。
|
||||
- Scoring Agent 必须输出可解析 JSON。
|
||||
- Report Agent 只整理报告,不重新评分。
|
||||
- Learning Assistant 命中知识库时必须引用 PDF 来源和页码;未命中时必须声明未检索到机构知识库参考。
|
||||
|
||||
## 7. 常见风险
|
||||
|
||||
| 风险 | 表现 | 处理 |
|
||||
|---|---|---|
|
||||
| Django 鉴权失败 | `AUTH_CREDENTIAL_REQUIRED` 或 `AUTH_INVALID` | 检查 token、`AUTH_USER_ME_URL`、Django 服务 |
|
||||
| 问诊流式卡住 | 前端一直等待 SSE | 检查 LLM Key、Base URL、模型名、超时配置 |
|
||||
| 检查项为空 | 前端无体格/辅助检查 | 检查 `case_exam_item.case_id` 和 `item_type` |
|
||||
| 评价失败 | 无法生成报告 | 检查 `scoring_rule`、提交内容、LLM JSON 输出 |
|
||||
| PDF 下载失败 | 文件不存在或 404 | 检查 `REPORT_STORAGE_DIR` 和文件权限 |
|
||||
| 学习助手无来源 | `retrieval_hit=false` | 检查知识库表、Milvus、embedding 配置 |
|
||||
|
||||
## 8. 开发规范
|
||||
|
||||
- API 层只做参数接收、用户上下文获取和响应封装。
|
||||
- Service 层承载业务流程。
|
||||
- Repository 层只做数据库读写。
|
||||
- Agent 层只做提示词拼接、LLM 调用和输出校验。
|
||||
- Model 层只定义 ORM。
|
||||
- Schema 层只定义 Pydantic 入参/出参。
|
||||
- 新增接口必须同步更新 `docs/03_api_design.md` 和 `docs/08_feature_code_map.md`。
|
||||
- 新增提示词必须同步更新 `docs/09_prompt_template_catalog.md`。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 常见故障排查
|
||||
|
||||
本文档用于接手人快速定位本地和云服务器常见问题。
|
||||
本文档用于开发人员快速定位本地和云服务器常见问题。
|
||||
|
||||
## 1. `/fastapi/docs` 打不开
|
||||
|
||||
@@ -155,7 +155,7 @@ retrieval_error=当前机构知识库暂未初始化或检索不可用...
|
||||
排查知识库:
|
||||
|
||||
- 用户是否有 `institution_id`
|
||||
- 是否已有 `kb_knowledge_space`
|
||||
- 是否已有 `kb_spaces`
|
||||
- Milvus 是否运行
|
||||
- Embedding 是否配置
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
# 功能-接口-代码-数据表映射表
|
||||
|
||||
本文档说明每个功能对应的 API、Router、Service、Repository、Model/数据表和关键逻辑。开发人员排查问题时优先从本表定位代码入口。
|
||||
|
||||
## 1. 通用调用规则
|
||||
|
||||
除健康检查外,业务接口都需要携带:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <access_token>
|
||||
X-Entry-Scene: vue_frontend
|
||||
X-Request-Id: <可选>
|
||||
```
|
||||
|
||||
普通 JSON 接口统一返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "success",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
SSE 流式接口返回 `event + data`,不包裹上述 JSON 结构。
|
||||
|
||||
## 2. 功能映射总表
|
||||
|
||||
| 功能模块 | 功能点 | API | Router | Service | Repository | Model/表 | 关键说明 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 用户鉴权 | 当前用户信息 | `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 和病人开场白 |
|
||||
| 训练页面 | 流式问诊 | `POST /api/v1/sessions/{session_id}/chat/stream` | `app/api/sessions.py::chat_stream` | `app/services/session_service.py::stream_chat` | `session_repository.py`、`case_repository.py` | `training_session`、Redis memory | Patient Agent SSE 输出 `message_delta`、`message_done`、`error` |
|
||||
| 训练页面 | 王主任练习提示 | `POST /api/v1/sessions/{session_id}/hints/stream` | `app/api/sessions.py::stream_hints` | `app/services/session_service.py::stream_hints` | `session_repository.py`、`case_repository.py` | `training_session`、Redis memory | 根据病例和当前会话生成一句话练习提示 |
|
||||
| 训练页面 | 结构化提示 | `POST /api/v1/sessions/{session_id}/hints` | `app/api/sessions.py::generate_hints` | `app/services/session_service.py::generate_hints` | `session_repository.py`、`case_repository.py` | `training_session`、Redis memory | 返回缺失维度、下一步问题、推荐检查;当前前端主用流式提示 |
|
||||
| 训练页面 | 检查项列表 | `GET /api/v1/sessions/{session_id}/order-items` | `app/api/sessions.py::list_order_items` | `app/services/order_service.py::list_order_items` | `case_repository.py`、`session_repository.py` | `case_exam_item` | 返回当前病例全部可申请检查项,不返回结果 |
|
||||
| 训练页面 | 体格检查列表 | `GET /api/v1/sessions/{session_id}/physical-exams` | `app/api/sessions.py::list_physical_exam_items` | `app/services/order_service.py::list_physical_exam_items` | `case_repository.py`、`session_repository.py` | `case_exam_item` | 过滤 `item_type=physical_exam` |
|
||||
| 训练页面 | 辅助检查列表 | `GET /api/v1/sessions/{session_id}/auxiliary-exams` | `app/api/sessions.py::list_auxiliary_exam_items` | `app/services/order_service.py::list_auxiliary_exam_items` | `case_repository.py`、`session_repository.py` | `case_exam_item` | 过滤非体格检查项 |
|
||||
| 训练页面 | 体格检查结果 | `POST /api/v1/sessions/{session_id}/physical-exams/{item_code}` | `app/api/sessions.py::create_physical_exam_order` | `app/services/order_service.py::create_physical_exam_order` | `case_repository.py`、`session_repository.py` | `case_exam_item`、`training_order`、Redis memory | 检查结果只来自数据库;同一会话同一 `item_code` 幂等 |
|
||||
| 训练页面 | 辅助检查结果 | `POST /api/v1/sessions/{session_id}/auxiliary-exams/{item_code}` | `app/api/sessions.py::create_auxiliary_exam_order` | `app/services/order_service.py::create_auxiliary_exam_order` | `case_repository.py`、`session_repository.py` | `case_exam_item`、`training_order`、Redis memory | 检查结果写入短期 memory,供后续评价使用 |
|
||||
| 训练页面 | 完成问诊 | `POST /api/v1/sessions/{session_id}/complete-inquiry` | `app/api/sessions.py::complete_inquiry` | `app/services/session_service.py::complete_inquiry` | `session_repository.py` | `training_session`、Redis memory | 校验至少有医生问诊后进入诊断阶段 |
|
||||
| 训练页面 | 提交诊断 | `POST /api/v1/sessions/{session_id}/diagnosis` | `app/api/sessions.py::submit_diagnosis` | `app/services/session_service.py::submit_diagnosis` | `session_repository.py` | `training_submission`、`training_session` | 保存主诊断、鉴别诊断、诊断依据 |
|
||||
| 训练页面 | 提交治疗 | `POST /api/v1/sessions/{session_id}/treatment` | `app/api/sessions.py::submit_treatment` | `app/services/session_service.py::submit_treatment` | `session_repository.py` | `training_submission`、`training_session` | 保存治疗原则、措施、风险预案、沟通和随访 |
|
||||
| 训练页面 | 生成评价 | `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`,正式前端不使用 |
|
||||
| 知识库管理 | 上传 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 配置 | 用于部署验证 |
|
||||
|
||||
## 3. 核心流程说明
|
||||
|
||||
### 3.1 训练链路
|
||||
|
||||
1. 前端调用 `GET /api/v1/auth/me` 验证用户。
|
||||
2. 前端读取病例和训练配置。
|
||||
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。
|
||||
6. 用户完成问诊、提交诊断、提交治疗。
|
||||
7. 后端读取 `scoring_rule`、问诊 memory、检查结果、诊断治疗提交内容,调用 Scoring Agent。
|
||||
8. 完成评价后写入 `training_record` 和 `training_score_detail`,释放 Redis memory。
|
||||
9. 用户通过评价详情或 PDF 下载查看结果。
|
||||
|
||||
### 3.2 教学互动链路
|
||||
|
||||
1. 前端调用 `GET /api/v1/teaching/cases/{case_id}/items` 获取题目、选项、答案、解析、视频。
|
||||
2. 前端提交作答到 `POST /api/v1/teaching/evaluation`。
|
||||
3. 后端生成评价并写入 `training_record`、`training_score_detail`。
|
||||
4. 评价详情和 PDF 下载复用个人中心接口。
|
||||
|
||||
### 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`,记录命中、来源和耗时。
|
||||
|
||||
## 4. 重要边界
|
||||
|
||||
- FastAPI 不维护用户注册登录。
|
||||
- FastAPI 不负责病例 PDF 解析入库。
|
||||
- 检查结果必须来自 `case_exam_item`,不允许 LLM 编造。
|
||||
- 问诊聊天记录只作为 Redis 短期 memory,评价完成后释放。
|
||||
- 长期训练结果只写入 `training_record` 和 `training_score_detail`。
|
||||
- 教学互动评价和训练评价共用评价详情、PDF 下载、个人中心记录列表。
|
||||
- 知识库上传是内容管理员能力,学生端不展示入口。
|
||||
@@ -0,0 +1,161 @@
|
||||
# 提示词模板目录
|
||||
|
||||
本文档说明当前项目中 Markdown 提示词模板的用途、调用位置、输入数据和输出要求。新增或修改提示词时,需要同步更新本文档。
|
||||
|
||||
## 1. 提示词加载规则
|
||||
|
||||
当前提示词分为两类:
|
||||
|
||||
1. 文件模板:存放在 `app/prompts`,由对应 Agent 或服务读取。
|
||||
2. 代码内系统提示:部分 Agent 会在代码中拼接系统提示,同时结合病例、会话、检查结果和评分规则构造输入。
|
||||
|
||||
维护要求:
|
||||
|
||||
- 医疗问诊训练类提示词不得替代真实临床诊疗。
|
||||
- AI 病人不得主动泄露病例隐藏信息。
|
||||
- 检查检验结果只能来自数据库。
|
||||
- 评分提示词必须要求结构化 JSON,不能返回纯长文本。
|
||||
- 学习助手命中知识库时必须引用来源;未命中时必须说明未检索到机构知识库参考。
|
||||
|
||||
## 2. 模板清单
|
||||
|
||||
| 提示词模板 | 文件路径 | 使用场景 | 调用模块 | 触发接口 | 输入数据 | 输出格式 | 说明 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 新手病例提示 | `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` |
|
||||
| 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` | 用户问题 | 流式纯文本 | 开头必须说明“未检索到本机构知识库参考” |
|
||||
|
||||
## 3. 训练问诊提示词调用链
|
||||
|
||||
```text
|
||||
POST /api/v1/sessions/{session_id}/chat/stream
|
||||
-> app/api/sessions.py::chat_stream
|
||||
-> app/services/session_service.py::stream_chat
|
||||
-> app/agents/patient_agent.py::PatientAgent.stream_reply
|
||||
-> PatientAgent._build_messages
|
||||
-> LLM stream_chat
|
||||
```
|
||||
|
||||
输入包括:
|
||||
|
||||
- `case_base.chief_complaint`
|
||||
- `case_base.ai_patient_profile`
|
||||
- `case_base.hidden_patient_info`
|
||||
- `patient_config`
|
||||
- Redis 短期 memory
|
||||
- 医学生当前问题
|
||||
|
||||
输出要求:
|
||||
|
||||
- 纯文本
|
||||
- 1 到 3 句话
|
||||
- 患者或家属口吻
|
||||
- 不输出 JSON / Markdown / 思考过程
|
||||
- 不主动泄露隐藏信息
|
||||
- 不编造检查结果
|
||||
|
||||
## 4. 王主任练习提示调用链
|
||||
|
||||
```text
|
||||
POST /api/v1/sessions/{session_id}/hints/stream
|
||||
-> app/api/sessions.py::stream_hints
|
||||
-> app/services/session_service.py::stream_hints
|
||||
-> HintAgent 或业务兜底逻辑
|
||||
```
|
||||
|
||||
结构化提示接口:
|
||||
|
||||
```text
|
||||
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
|
||||
```
|
||||
|
||||
输出字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"hints": [],
|
||||
"missing_dimensions": [],
|
||||
"next_questions": [],
|
||||
"recommended_orders": []
|
||||
}
|
||||
```
|
||||
|
||||
LLM 输出非法 JSON 或调用失败时,`HintAgent._fallback_output` 会根据病例关键点和已申请检查生成稳定提示。
|
||||
|
||||
## 5. 训练评价提示词调用链
|
||||
|
||||
```text
|
||||
POST /api/v1/sessions/{session_id}/evaluation
|
||||
-> app/api/sessions.py::create_evaluation
|
||||
-> app/services/evaluation_service.py::create_evaluation
|
||||
-> app/agents/scoring_agent.py::ScoringAgent.score
|
||||
-> app/agents/report_agent.py::ReportAgent.build_report
|
||||
```
|
||||
|
||||
输入包括病例、Redis 问诊 memory、`training_order` 检查结果、`training_submission` 诊断治疗提交、`scoring_rule` 评分规则和预留指南引用。
|
||||
|
||||
输出必须包含 `score_type`、`total_score`、`dimension_scores`、`score_details`、`errors`、`improvement_plan`、`evidence_summary`、`guideline_refs`、`overall_comment`。
|
||||
|
||||
异常处理:
|
||||
|
||||
- LLM 异常、JSON 解析失败、字段缺失时,`ScoringAgent._fallback_score` 返回稳定结构。
|
||||
- `ReportAgent` 只整理字段,不重新评分。
|
||||
|
||||
## 6. 教学互动评价提示词调用链
|
||||
|
||||
```text
|
||||
POST /api/v1/teaching/evaluation
|
||||
-> app/api/teaching.py::create_teaching_evaluation
|
||||
-> app/services/teaching_service.py::create_evaluation
|
||||
-> app/agents/scoring_agent.py::ScoringAgent.score_teaching
|
||||
```
|
||||
|
||||
输入包括病例信息、教学题列表、标准答案、解析文本、学生作答和评分规则。输出复用训练评价结构,写入 `training_record` 和 `training_score_detail`。
|
||||
|
||||
## 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
|
||||
-> app/agents/learning_assistant_agent.py::LearningAssistantAgent.stream_answer
|
||||
```
|
||||
|
||||
命中知识库时:
|
||||
|
||||
- 输入用户问题和检索到的知识片段。
|
||||
- 每个来源包含 PDF 名称、页码、chunk_uid、引用文本。
|
||||
- 回答必须标注来源编号,例如 `【来源1】`。
|
||||
|
||||
未命中知识库时:
|
||||
|
||||
- 开头必须说明未检索到机构知识库参考。
|
||||
- 不得伪造 PDF、页码或指南名称。
|
||||
- 回答仅作为医学学习参考。
|
||||
|
||||
## 8. 后续维护规则
|
||||
|
||||
新增提示词时必须同时确认:
|
||||
|
||||
- 是否有明确调用接口。
|
||||
- 是否有明确 Agent。
|
||||
- 输入字段是否来自可信数据源。
|
||||
- 输出格式是否可被前端或服务稳定解析。
|
||||
- 是否有 fallback。
|
||||
- 是否需要同步 `prompt_templates` 元数据。
|
||||
- 是否需要新增 API 测试或 Agent 单元测试。
|
||||
@@ -362,6 +362,25 @@ def run_api_contract_tests() -> None:
|
||||
assert detail.status_code == 200
|
||||
assert detail.json()["data"]["evaluation_id"] == evaluation_id
|
||||
|
||||
history_page_one = client.get("/api/v1/evaluations?page=1&page_size=1", headers=headers)
|
||||
assert history_page_one.status_code == 200
|
||||
history_data = history_page_one.json()["data"]
|
||||
assert len(history_data["items"]) == 1
|
||||
assert history_data["pagination"]["page"] == 1
|
||||
assert history_data["pagination"]["page_size"] == 1
|
||||
assert history_data["pagination"]["total"] >= 2
|
||||
assert history_data["pagination"]["total_pages"] >= 2
|
||||
assert history_data["pagination"]["has_next"] is True
|
||||
assert history_data["pagination"]["has_prev"] is False
|
||||
|
||||
empty_cross_user_history = client.get(
|
||||
"/api/v1/evaluations?page=1&page_size=10",
|
||||
headers={"Authorization": "Bearer api_user_002_token", "X-Entry-Scene": "api_test"},
|
||||
)
|
||||
assert empty_cross_user_history.status_code == 200
|
||||
assert empty_cross_user_history.json()["data"]["items"] == []
|
||||
assert empty_cross_user_history.json()["data"]["pagination"]["total"] == 0
|
||||
|
||||
cross_user_detail = client.get(
|
||||
f"/api/v1/evaluations/{evaluation_id}",
|
||||
headers={"Authorization": "Bearer api_user_002_token", "X-Entry-Scene": "api_test"},
|
||||
|
||||
Reference in New Issue
Block a user