docs: update project docs and evaluation history pagination

This commit is contained in:
刘金宝
2026-06-11 10:15:06 +08:00
parent 6b40ba1079
commit a54c2d1c85
17 changed files with 607 additions and 211 deletions
+8 -5
View File
@@ -76,7 +76,7 @@ fastapi/
│ ├── schemas/ # Pydantic 入参/出参 │ ├── schemas/ # Pydantic 入参/出参
│ ├── services/ # 业务服务 │ ├── services/ # 业务服务
│ └── tasks/ # Celery 异步任务预留 │ └── tasks/ # Celery 异步任务预留
├── docs/ # API、架构、数据库、部署和交接文档 ├── docs/ # API、架构、数据库、部署和项目文档
├── scripts/ # 初始化和维护脚本 ├── scripts/ # 初始化和维护脚本
├── tests/ # 自动化测试 ├── tests/ # 自动化测试
├── Dockerfile ├── Dockerfile
@@ -90,8 +90,8 @@ fastapi/
```powershell ```powershell
cd D:\Code\newfounder\medical-consultation-agent cd D:\Code\newfounder\medical-consultation-agent
python -m venv .venv python -m venv backend\.venv
.\.venv\Scripts\activate .\backend\.venv\Scripts\activate
pip install -r requirements.txt pip install -r requirements.txt
copy .env.example .env copy .env.example .env
uvicorn app.main:app --host 127.0.0.1 --port 9000 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 .\backend\.venv\Scripts\python.exe tests\test_api_contract.py
``` ```
## 9. 交接文档 ## 9. 项目文档
| 文档 | 用途 | | 文档 | 用途 |
|---|---| |---|---|
| `docs/00_project_overview.md` | 项目总览和功能讲解顺序 |
| `docs/01_architecture.md` | 系统架构、调用链路和模块边界 | | `docs/01_architecture.md` | 系统架构、调用链路和模块边界 |
| `docs/02_database.md` | 核心数据库表和读写边界 | | `docs/02_database.md` | 核心数据库表和读写边界 |
| `docs/03_api_design.md` | 前端联调 API 文档 | | `docs/03_api_design.md` | 前端联调 API 文档 |
| `docs/04_deployment.md` | 云服务器部署、更新和回滚 | | `docs/04_deployment.md` | 云服务器部署、更新和回滚 |
| `docs/05_modules.md` | 功能模块说明 | | `docs/05_modules.md` | 功能模块说明 |
| `docs/06_handover.md` | 离职交接说明和风险清单 | | `docs/06_maintenance_guide.md` | 开发维护说明和风险清单 |
| `docs/07_troubleshooting.md` | 常见故障排查 | | `docs/07_troubleshooting.md` | 常见故障排查 |
| `docs/08_feature_code_map.md` | 功能到接口、代码和数据表的映射表 |
| `docs/09_prompt_template_catalog.md` | 提示词模板目录和调用说明 |
## 10. 重要约定 ## 10. 重要约定
+8 -3
View File
@@ -1,6 +1,6 @@
from pathlib import Path from pathlib import Path
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends, Query
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -15,9 +15,14 @@ router = APIRouter()
@router.get("", response_model=ApiResponse[EvaluationListResponse]) @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 查询完整训练后的评价记录。""" """历史评价:基于 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]) @router.get("/{evaluation_id}", response_model=ApiResponse[EvaluationDetailResponse])
+9 -2
View File
@@ -1,4 +1,4 @@
from sqlalchemy import delete, select from sqlalchemy import delete, func, select
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.models.training_record import TrainingRecord, TrainingScoreDetail from app.models.training_record import TrainingRecord, TrainingScoreDetail
@@ -46,12 +46,19 @@ class EvaluationRepository:
) )
return self.db.scalar(stmt) 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 查询完整训练后的评价记录。""" """历史评价:按外部 user_id 查询完整训练后的评价记录。"""
stmt = ( stmt = (
select(TrainingRecord) select(TrainingRecord)
.where(TrainingRecord.external_user_id == user_id) .where(TrainingRecord.external_user_id == user_id)
.order_by(TrainingRecord.created_at.desc()) .order_by(TrainingRecord.created_at.desc())
.limit(limit)
.offset(offset)
) )
return list(self.db.scalars(stmt).all()) return list(self.db.scalars(stmt).all())
+12
View File
@@ -61,10 +61,22 @@ class EvaluationListItem(BaseModel):
pdf_exported: bool 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): class EvaluationListResponse(BaseModel):
"""历史评价列表响应。""" """历史评价列表响应。"""
items: list[EvaluationListItem] items: list[EvaluationListItem]
pagination: PaginationMeta
class ExportPdfResponse(BaseModel): class ExportPdfResponse(BaseModel):
+15 -3
View File
@@ -19,6 +19,7 @@ from app.schemas.evaluation import (
EvaluationListItem, EvaluationListItem,
EvaluationListResponse, EvaluationListResponse,
EvaluationResponse, EvaluationResponse,
PaginationMeta,
ScoreDetailItem, ScoreDetailItem,
) )
from app.services.audit_service import AuditService from app.services.audit_service import AuditService
@@ -235,9 +236,12 @@ class EvaluationService:
"""用户 ID 兼容:Django 返回的 id 写入 external_user_id,纯数字时同步写入源库 user_id。""" """用户 ID 兼容:Django 返回的 id 写入 external_user_id,纯数字时同步写入源库 user_id。"""
return int(user_id) if str(user_id).isdigit() else None 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。""" """历史评价:按 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( return EvaluationListResponse(
items=[ items=[
EvaluationListItem( EvaluationListItem(
@@ -249,7 +253,15 @@ class EvaluationService:
pdf_exported=bool(record.pdf_file_path), pdf_exported=bool(record.pdf_file_path),
) )
for record in records 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: def get_detail(self, evaluation_id: int, user_id: str) -> EvaluationDetailResponse:
+135
View File
@@ -0,0 +1,135 @@
# 项目总览
本文档用于快速说明医疗问诊 Agent FastAPI 后端的项目边界、功能现状、代码入口、部署方式、测试方法和后续维护重点。团队成员优先阅读本文,再按链接进入详细文档。
## 1. 项目定位
本项目是医疗教学平台中的 FastAPI 后端子服务,负责医疗问诊训练、教学互动、AI 评价、PDF 报告、AI 学习助手和机构知识库预留能力。
本项目不负责:
- 用户注册登录
- 用户管理后台
- 病例 PDF 解析入库
- 病例增删改后台
- 多租户权限后台
- HIS/LIS/PACS 对接
- 前端最终 UI
用户身份来自 Django 用户中心。前端携带 `Authorization: Bearer <access_token>` 调用 FastAPIFastAPI 转发 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 -1
View File
@@ -1,6 +1,6 @@
# 系统架构说明 # 系统架构说明
本文档用于交接医疗问诊 Agent FastAPI 后端的系统边界、核心链路和外部依赖。 本文档用于说明医疗问诊 Agent FastAPI 后端的系统边界、核心链路和外部依赖。
## 1. 项目定位 ## 1. 项目定位
+7 -7
View File
@@ -1,6 +1,6 @@
# 数据库说明 # 数据库说明
本文档说明医疗问诊 Agent FastAPI 后端依赖的核心数据表、读写边界和交接注意事项。 本文档说明医疗问诊 Agent FastAPI 后端依赖的核心数据表、读写边界和维护注意事项。
## 1. 数据库边界 ## 1. 数据库边界
@@ -156,35 +156,35 @@ FastAPI 使用 Django 返回的 `id` 作为业务 `user_id`。
## 5. 知识库预留表 ## 5. 知识库预留表
### `kb_knowledge_space` ### `kb_spaces`
| 项 | 说明 | | 项 | 说明 |
|---|---| |---|---|
| 用途 | 机构知识空间和 Milvus collection 映射 | | 用途 | 机构知识空间和 Milvus collection 映射 |
| 关键字段 | `institution_id``collection_name``embedding_model``embedding_dim``status` | | 关键字段 | `institution_id``collection_name``embedding_model``embedding_dim``status` |
### `kb_knowledge_document` ### `kb_documents`
| 项 | 说明 | | 项 | 说明 |
|---|---| |---|---|
| 用途 | 内容管理员上传 PDF 的元数据 | | 用途 | 内容管理员上传 PDF 的元数据 |
| 关键字段 | `institution_id``uploaded_by``file_name``file_sha256``status``parse_status``embedding_status``chunk_count` | | 关键字段 | `institution_id``uploaded_by``file_name``file_sha256``status``parse_status``embedding_status``chunk_count` |
### `kb_knowledge_chunk` ### `kb_chunks`
| 项 | 说明 | | 项 | 说明 |
|---|---| |---|---|
| 用途 | PDF 分片文本和页码来源 | | 用途 | PDF 分片文本和页码来源 |
| 关键字段 | `document_id``institution_id``chunk_uid``page_start``page_end``chunk_text` | | 关键字段 | `document_id``institution_id``chunk_uid``page_start``page_end``chunk_text` |
### `kb_knowledge_ingestion_task` ### `kb_ingestion_tasks`
| 项 | 说明 | | 项 | 说明 |
|---|---| |---|---|
| 用途 | PDF 入库任务进度 | | 用途 | PDF 入库任务进度 |
| 关键字段 | `document_id``institution_id``status``progress``current_step``error_message` | | 关键字段 | `document_id``institution_id``status``progress``current_step``error_message` |
### `kb_knowledge_query_log` ### `kb_query_logs`
| 项 | 说明 | | 项 | 说明 |
|---|---| |---|---|
@@ -204,7 +204,7 @@ Redis 用于短期会话 memory
Redis 不作为长期训练历史存储。 Redis 不作为长期训练历史存储。
## 7. 数据库交接注意事项 ## 7. 数据库维护注意事项
- FastAPI 不维护用户注册登录。 - FastAPI 不维护用户注册登录。
- FastAPI 不直接修改病例基础数据。 - FastAPI 不直接修改病例基础数据。
+1 -1
View File
@@ -201,7 +201,7 @@ data: {"latency_ms":1200,"first_token_ms":300,"model":"deepseek-chat","fallback_
| 接口名称 | url | api | methods | params(入参) | response(返回参数) | | 接口名称 | 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` 必填 | 完整评价详情,训练和教学互动共用 | | 训练记录详情 / 评价详情 | `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}/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` 文件流,浏览器可直接下载 | | 下载 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 -1
View File
@@ -1,6 +1,6 @@
# 部署说明 # 部署说明
本文档用于交接云服务器部署、更新、回滚和验证流程。 本文档用于说明云服务器部署、更新、回滚和验证流程。
## 1. 服务器目录 ## 1. 服务器目录
+4 -4
View File
@@ -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` | | 相关代码 | `app/api/evaluations.py``app/services/evaluation_service.py` |
| 相关表 | `training_record``training_score_detail` | | 相关表 | `training_record``training_score_detail` |
| 重要规则 | 必须按 `user_id` 隔离 | | 重要规则 | 必须按 `user_id` 隔离 |
| 后续优化 | 增加分页筛选、统计图表和能力画像 | | 后续优化 | 增加筛选条件、统计图表和能力画像 |
## 11. AI 学习助手模块 ## 11. AI 学习助手模块
@@ -125,7 +125,7 @@
| 当前状态 | 已实现正式流式接口;无知识库时自动降级为通用 LLM 回答 | | 当前状态 | 已实现正式流式接口;无知识库时自动降级为通用 LLM 回答 |
| 相关接口 | `POST /api/v1/learning-assistant/chat/stream` | | 相关接口 | `POST /api/v1/learning-assistant/chat/stream` |
| 相关代码 | `app/api/learning_assistant.py``app/services/learning_assistant_service.py``app/agents/learning_assistant_agent.py` | | 相关代码 | `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 | | 外部依赖 | LLM、Embedding、Milvus |
| 后续优化 | 查询改写、rerank、多轮记忆、来源引用格式优化、成本统计 | | 后续优化 | 查询改写、rerank、多轮记忆、来源引用格式优化、成本统计 |
@@ -137,6 +137,6 @@
| 当前状态 | 接口和数据结构已预留,生产级大规模入库仍需压测 | | 当前状态 | 接口和数据结构已预留,生产级大规模入库仍需压测 |
| 相关接口 | `POST /api/v1/knowledge-admin/documents/upload`、文档列表、文档详情 | | 相关接口 | `POST /api/v1/knowledge-admin/documents/upload`、文档列表、文档详情 |
| 相关代码 | `app/api/knowledge_admin.py``app/services/document_ingestion_service.py``app/integrations/*` | | 相关代码 | `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 | | 外部依赖 | Milvus、Embedding 服务、Celery |
| 后续优化 | 任务队列监控、失败重试、分片策略、文件去重、权限后台 | | 后续优化 | 任务队列监控、失败重试、分片策略、文件去重、权限后台 |
-182
View File
@@ -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 学习助手流式可用
+125
View File
@@ -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`
+2 -2
View File
@@ -1,6 +1,6 @@
# 常见故障排查 # 常见故障排查
本文档用于接手人快速定位本地和云服务器常见问题。 本文档用于开发人员快速定位本地和云服务器常见问题。
## 1. `/fastapi/docs` 打不开 ## 1. `/fastapi/docs` 打不开
@@ -155,7 +155,7 @@ retrieval_error=当前机构知识库暂未初始化或检索不可用...
排查知识库: 排查知识库:
- 用户是否有 `institution_id` - 用户是否有 `institution_id`
- 是否已有 `kb_knowledge_space` - 是否已有 `kb_spaces`
- Milvus 是否运行 - Milvus 是否运行
- Embedding 是否配置 - Embedding 是否配置
+99
View File
@@ -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 下载、个人中心记录列表。
- 知识库上传是内容管理员能力,学生端不展示入口。
+161
View File
@@ -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 单元测试。
+19
View File
@@ -362,6 +362,25 @@ def run_api_contract_tests() -> None:
assert detail.status_code == 200 assert detail.status_code == 200
assert detail.json()["data"]["evaluation_id"] == evaluation_id 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( cross_user_detail = client.get(
f"/api/v1/evaluations/{evaluation_id}", f"/api/v1/evaluations/{evaluation_id}",
headers={"Authorization": "Bearer api_user_002_token", "X-Entry-Scene": "api_test"}, headers={"Authorization": "Bearer api_user_002_token", "X-Entry-Scene": "api_test"},