14 KiB
后端 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 |
practice 或 teaching |
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_base、traditional_case、teaching_case、case_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当前使用practice或teaching。- 创建会话时初始化短期 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_done 或 error 后必须结束 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.score、ReportAgent |
| 表 | scoring_rule、knowledge_chunks、training_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_id、case_id、case_title、created_at、pdf_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_sources、knowledge_documents、knowledge_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_base、traditional_case、teaching_case、scoring_rule。 - 预检接口不执行源 SQL,不写入数据库。
- 源 SQL 中出现
DROP TABLE、CREATE TABLE、ALTER TABLE等语句时只作为警告展示,导入器不会执行这些语句。 - 字段数量不匹配、非法字符串、JSON 字段非法时返回
can_import=false和errors。
20. 病例 SQL 确认导入
| 项 | 内容 |
|---|---|
| Method | POST |
| Path | /imports/case-sql/apply |
| Router | imports.apply_case_sql |
| Service | CaseSqlImportService.apply |
| 用途 | 预检通过后,将 SQL 中的病例源表数据映射写入当前数据库 |
| 表 | case_base、traditional_case、teaching_case、scoring_rule、case_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_base按id更新或插入。traditional_case和teaching_case按case_id更新或插入。scoring_rule按case_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 测试。