Files
fastapi/docs/03_api_design.md
T
2026-06-01 09:25:26 +08:00

14 KiB
Raw Blame History

后端 API 对接文档

1. 通用约定

Base URL

http://127.0.0.1:8000/api/v1

必传 Header

Header 说明
X-User-Id 宿主系统传入的用户 ID,所有业务隔离依据
X-Entry-Scene 入口场景,前端 Demo 默认 vue_demo

可传 Header

Header 说明
X-Tenant-Id 宿主系统租户/机构 ID
X-Class-Id 教学班级 ID
X-Role 用户角色

统一响应:

{
  "code": "OK",
  "message": "success",
  "data": {}
}

常见错误码:

code 含义
USER_ID_REQUIRED 缺少 X-User-Id
CASE_NOT_FOUND 病例不存在或未启用
SESSION_NOT_FOUND 会话不存在或不属于当前用户
SESSION_STATUS_INVALID 当前阶段不允许该操作
INQUIRY_REQUIRED 完成问诊前至少需要一轮医生提问
DIAGNOSIS_REQUIRED 提交治疗前需要先提交诊断
TREATMENT_REQUIRED 生成评价前需要先提交治疗
ORDER_ITEM_NOT_FOUND 检查项目不存在
LLM_CALL_TIMEOUT LLM 普通调用超时
LLM_STREAM_TIMEOUT LLM 流式调用超时
LLM_STREAM_FAILED LLM 流式调用失败
CASE_SQL_FILE_INVALID 上传文件不是 .sql
CASE_SQL_FILE_EMPTY 上传 SQL 文件为空
CASE_SQL_FILE_TOO_LARGE 上传 SQL 文件超过 5MB
CASE_SQL_IMPORT_INVALID SQL 解析或字段映射校验失败

2. Agent Hello

内容
Method GET
Path /agent/hello
Router agent.hello
用途 校验后端连接,返回当前用户上下文和功能开关

Response data

{
  "user": {
    "user_id": "demo_user_001",
    "tenant_id": null,
    "role": null
  },
  "features": {
    "stream_chat": true,
    "score_types": ["percentage", "five_point"],
    "pdf_export": true,
    "knowledge_search": true,
    "llm_mock_enabled": false,
    "llm_fallback_to_mock": false
  }
}

3. 病例列表

内容
Method GET
Path /cases
Router cases.list_cases
Service CaseService.list_cases
case_base

Query

参数 说明
department_id 科室筛选
training_type 训练类型筛选
mode practiceteaching

Response data

{
  "items": [
    {
      "id": 1,
      "title": "支气管肺炎 - 6岁男性患儿",
      "department_id": 1,
      "department_name": "儿科",
      "difficulty": "medium",
      "chief_complaint": "发热、咳嗽4天,喘息1天。",
      "patient_age": 6,
      "patient_gender": "male",
      "training_type": "case_analysis",
      "supported_modes": ["practice", "teaching"],
      "has_teaching_video": false,
      "has_knowledge_points": true
    }
  ]
}

4. 病例详情

内容
Method GET
Path /cases/{case_id}
Router cases.get_case_detail
Service CaseService.get_case_detail
case_basetraditional_caseteaching_casecase_exam_item

Response data

{
  "id": 1,
  "title": "支气管肺炎 - 6岁男性患儿",
  "department_name": "儿科",
  "chief_complaint": "发热、咳嗽4天,喘息1天。",
  "patient_age": 6,
  "patient_gender": "male",
  "supported_modes": ["practice", "teaching"],
  "exam_item_count": 5,
  "has_knowledge_points": true
}

病例详情不返回标准答案、隐藏病史和完整评分细则。

5. 创建训练会话

内容
Method POST
Path /sessions
Router sessions.create_session
Service SessionService.create_session
training_session

Request

{
  "case_id": 1,
  "training_type": "case_analysis",
  "mode": "practice",
  "score_type": "percentage"
}

Response data

{
  "session_id": 10,
  "session_code": "sess_20260528100000_abcd1234",
  "status": "inquiry",
  "patient_opening": "家长:医生,孩子发烧咳嗽好几天了..."
}

校验:

  • case_id 必须存在并启用。
  • mode 当前使用 practiceteaching
  • 创建会话时初始化短期 memory。

6. 普通问诊

内容
Method POST
Path /sessions/{session_id}/chat
Router sessions.chat
Service SessionService.chat
Agent PatientAgent.reply

Request

{
  "message": "孩子发热几天了?最高体温多少?"
}

Response data

{
  "reply": "发热有4天了,最高烧到39度多。",
  "latency_ms": 2500,
  "model": "deepseek-v4-pro",
  "fallback_used": false
}

校验:会话必须属于当前 X-User-Id,且状态为 inquiry

7. 流式问诊

内容
Method POST
Path /sessions/{session_id}/chat/stream
Router sessions.chat_stream
Service SessionService.stream_chat
Agent PatientAgent.stream_reply

Request 同普通问诊。

SSE 事件:

event: message_delta
data: {"delta":"发热有"}

event: message_done
data: {"latency_ms":3200,"first_token_ms":800,"model":"deepseek-v4-pro","fallback_used":false}

event: error
data: {"code":"LLM_STREAM_TIMEOUT","message":"AI 病人回复超时,请重试"}

前端收到 message_doneerror 后必须结束 pending。

8. 查看提示

内容
Method POST
Path /sessions/{session_id}/hints
Router sessions.generate_hints
Service SessionService.generate_hints
Agent HintAgent.generate

Request

{
  "last_user_message": "孩子发热几天了?",
  "scope": "current_conversation"
}

Response data

{
  "hints": ["可以继续追问最高体温、热型和退热药反应。"],
  "missing_dimensions": ["既往史", "严重程度评估"],
  "next_questions": ["孩子以前有没有喘息或哮喘史?"],
  "recommended_orders": [
    {"item_code": "oxygen_saturation", "reason": "用于判断缺氧和病情严重程度"}
  ]
}

校验:当前仅允许 practice 模式且会话状态为 inquiry

9. 检查项目列表

内容
Method GET
Path /sessions/{session_id}/order-items
Router sessions.list_order_items
Service OrderService.list_order_items
case_exam_item

Response data

{
  "items": [
    {
      "item_code": "complete_blood_count",
      "item_name": "血常规",
      "item_type": "lab",
      "category": "实验室检查",
      "ordered": false
    }
  ]
}

10. 申请检查

内容
Method POST
Path /sessions/{session_id}/orders
Router sessions.create_order
Service OrderService.create_order
training_order

Request

{
  "item_code": "complete_blood_count"
}

Response data

{
  "order_id": 1,
  "item_code": "complete_blood_count",
  "item_name": "血常规",
  "result_text": "WBC 12.4×10^9/L,中性粒细胞72%。",
  "result_structured": {},
  "already_ordered": false,
  "context_written": true
}

同一 session_id + item_code 幂等,重复申请返回已有记录,不重复写入 memory。

11. 完成问诊

内容
Method POST
Path /sessions/{session_id}/complete-inquiry
Router sessions.complete_inquiry
Service SessionService.complete_inquiry

Response data

{
  "session_id": 10,
  "status": "diagnosis"
}

校验:至少存在一轮医生提问。

12. 提交诊断

内容
Method POST
Path /sessions/{session_id}/diagnosis
Router sessions.submit_diagnosis
Service SessionService.submit_diagnosis
training_submission

Request

{
  "primary_diagnosis": "支气管肺炎",
  "differential_diagnoses": ["毛细支气管炎", "哮喘急性发作"],
  "diagnosis_basis": "发热、咳嗽、喘息,结合肺部体征、炎症指标、胸片和血氧情况。"
}

Response data

{
  "status": "treatment"
}

13. 提交治疗

内容
Method POST
Path /sessions/{session_id}/treatment
Router sessions.submit_treatment
Service SessionService.submit_treatment
training_submission

Request

{
  "treatment_principle": "抗感染、平喘、改善氧合、严密观察。",
  "treatment_measures": "根据病情选择抗感染治疗,必要时雾化吸入,监测体温、呼吸和血氧。",
  "risk_plan": "关注低氧、呼吸困难加重、持续高热、精神反应差。",
  "communication": "向家属说明病情、用药注意事项和复诊/住院指征。",
  "follow_up": "治疗后复查体温、呼吸、血氧和炎症指标。"
}

Response data

{
  "status": "evaluating"
}

14. 生成评价

内容
Method POST
Path /sessions/{session_id}/evaluation
Router sessions.create_evaluation
Service EvaluationService.create_evaluation
Agent ScoringAgent.scoreReportAgent
scoring_ruleknowledge_chunkstraining_record

Request

{
  "score_type": "percentage"
}

Response data

{
  "evaluation_id": 1,
  "score_type": "percentage",
  "total_score": 82,
  "dimension_scores": [],
  "errors": [],
  "improvement_plan": [],
  "evidence_summary": [],
  "guideline_refs": [],
  "overall_comment": "完成了主要诊断链路,但检查利用和沟通细节仍需加强。"
}

评价完成后释放短期 memory,并写入 training_record

15. 历史评价列表

内容
Method GET
Path /evaluations
Router evaluations.list_evaluations
Service EvaluationService.list_history
training_record

Response data

{
  "items": [
    {
      "evaluation_id": 1,
      "case_title": "支气管肺炎 - 6岁男性患儿",
      "score_type": "percentage",
      "total_score": 82,
      "created_at": "2026-05-28T10:00:00",
      "pdf_exported": true
    }
  ]
}

16. 评价详情

内容
Method GET
Path /evaluations/{evaluation_id}
Router evaluations.get_evaluation_detail
Service EvaluationService.get_detail
training_record

Response data 为完整评价报告,并包含 session_idcase_idcase_titlecreated_atpdf_file_path

17. 导出 PDF

内容
Method POST
Path /evaluations/{evaluation_id}/export-pdf
Router evaluations.export_pdf
Service PdfExportService.export
training_record

Response data

{
  "export_id": 1,
  "file_path": "storage/reports/training_record_1_percentage_xxx.pdf"
}

18. 知识检索

内容
Method GET
Path /knowledge/search
Router knowledge.search_knowledge
Service KnowledgeService.search_guidelines
knowledge_sourcesknowledge_documentsknowledge_chunks

Query

参数 说明
department_id 科室 ID
training_type 训练类型
q 关键词,逗号分隔

用途:评价生成前检索科室/类型下的评分指南。前端第一版不需要主动调用。

19. 病例 SQL 导入预检

内容
Method POST
Path /imports/case-sql/preview
Router imports.preview_case_sql
Service CaseSqlImportService.preview
用途 前端上传接口解析后的 SQL 文件,后端只解析并校验,不写入数据库

Request

Content-Type: multipart/form-data
file: case.sql

Response data

{
  "file_name": "case.sql",
  "encoding": "utf-8",
  "tables": {
    "case_base": 1,
    "traditional_case": 1,
    "teaching_case": 1,
    "scoring_rule": 5
  },
  "can_import": true,
  "warnings": [],
  "errors": [],
  "preview_cases": [
    {
      "id": 1001,
      "title": "儿童支气管肺炎",
      "case_type": "diagnosis_treatment",
      "difficulty": "medium"
    }
  ]
}

校验逻辑:

  • 必须携带 X-User-Id
  • 文件后缀必须为 .sql,大小不超过 5MB。
  • 只解析源 SQL 中的 case_basetraditional_caseteaching_casescoring_rule
  • 预检接口不执行源 SQL,不写入数据库。
  • 源 SQL 中出现 DROP TABLECREATE TABLEALTER TABLE 等语句时只作为警告展示,导入器不会执行这些语句。
  • 字段数量不匹配、非法字符串、JSON 字段非法时返回 can_import=falseerrors

20. 病例 SQL 确认导入

内容
Method POST
Path /imports/case-sql/apply
Router imports.apply_case_sql
Service CaseSqlImportService.apply
用途 预检通过后,将 SQL 中的病例源表数据映射写入当前数据库
case_basetraditional_caseteaching_casescoring_rulecase_exam_item

Request

Content-Type: multipart/form-data
file: case.sql

Response data

{
  "imported": true,
  "file_name": "case.sql",
  "encoding": "utf-8",
  "inserted_or_updated_cases": 1,
  "imported_traditional_cases": 1,
  "imported_teaching_cases": 1,
  "imported_scoring_rules": 5,
  "generated_exam_items": 4,
  "warnings": []
}

校验逻辑:

  • 必须携带 X-User-Id
  • 导入过程使用事务,任意表映射失败则整体回滚。
  • case_baseid 更新或插入。
  • traditional_caseteaching_casecase_id 更新或插入。
  • scoring_rulecase_id 先删除旧规则再写入源规则。
  • 源 SQL 缺少 case_exam_item 时,由后端根据病例文本生成基础检查项目,保障问诊训练链路可继续使用。
  • 导入成功后前端刷新 /cases,新增病例即可进入训练。

21. LLM Fast 测试

内容
Method POST
Path /llm/test/deepseek-fast
Router llm_test.test_deepseek_fast
Service OpenAICompatibleLLMClient.chat

Request

{
  "message": "请用一句话说明医疗问诊训练 Demo 的用途。"
}

Response data

{
  "model": "deepseek-v4-pro",
  "first_token_ms": null,
  "total_latency_ms": 3000,
  "stream": false,
  "mock_mode": false,
  "fallback_used": false,
  "thinking_enabled": false,
  "reasoning_effort": null
}

22. LLM Reason 测试

内容
Method POST
Path /llm/test/deepseek-reason
Router llm_test.test_deepseek_reason
Service OpenAICompatibleLLMClient.stream_chat,流式不兼容时降级到 chat

Request 同 Fast 测试。Response 字段同 Fast 测试。