20 KiB
前端 API 对接文档
本文档面向 Vue 前端与后续正式前端开发,描述当前第一版 Demo 已实现的后端接口、请求头、状态流转、字段结构和错误处理规则。
1. 通用约定
1.1 Base URL
本地开发默认地址:
http://127.0.0.1:8000/api/v1
前端默认配置:
Vite dev server: http://127.0.0.1:5173
API base: http://127.0.0.1:8000/api/v1
1.2 必传 Header
所有业务接口都必须携带以下 Header:
| Header | 类型 | 说明 |
|---|---|---|
X-User-Id |
string | 宿主系统传入的用户标识。后端按该字段隔离会话、提交、评价和历史记录。 |
X-Entry-Scene |
string | 入口场景。Demo 前端默认 vue_demo。 |
可选 Header:
| Header | 类型 | 说明 |
|---|---|---|
X-Tenant-Id |
string | 租户、机构或项目 ID。第一版只透传和审计。 |
X-User-Role |
string | 用户角色。第一版只透传和审计。 |
X-Class-Id |
string | 班级或课程 ID。第一版只透传和审计。 |
X-Request-Id |
string | 请求链路 ID。前端有链路追踪需求时传入。 |
1.3 统一响应结构
除 SSE 流式接口外,后端统一返回:
{
"code": "OK",
"message": "success",
"data": {}
}
前端处理规则:
code === "OK":读取data。code !== "OK":展示message,不要直接展示底层异常。- HTTP 401 通常表示缺少
X-User-Id。 - HTTP 404 通常表示资源不存在或不属于当前
user_id。 - HTTP 400 通常表示当前状态不允许操作或入参不合法。
1.4 常见错误码
| code | 场景 | 前端处理 |
|---|---|---|
USER_ID_REQUIRED |
缺少 X-User-Id |
回到入口设置页,提示填写 user_id。 |
CASE_NOT_FOUND |
病例不存在、未启用或已删除 | 刷新病例列表。 |
CASE_DELETE_CONFIRM_REQUIRED |
删除病例未传 confirm=true |
保持确认弹窗,不执行删除。 |
CASE_DELETE_TRAINING_DATA_EXISTS |
病例存在训练数据但未允许删除训练数据 | 当前前端固定传 delete_training_data=true。 |
SESSION_NOT_FOUND |
会话不存在或不属于当前用户 | 回到病例页重新创建会话。 |
SESSION_STATUS_INVALID |
当前阶段不允许执行该操作 | 根据 status 禁用按钮并提示原因。 |
INQUIRY_REQUIRED |
完成问诊前没有医生提问 | 提示至少完成一轮问诊。 |
DIAGNOSIS_REQUIRED |
提交治疗前未提交诊断 | 引导到诊断表单。 |
TREATMENT_REQUIRED |
生成评价前未提交治疗 | 引导到治疗表单。 |
ORDER_ITEM_NOT_FOUND |
检查项不存在 | 刷新检查项列表。 |
LLM_CALL_TIMEOUT |
非流式模型调用超时 | 提示重试。 |
LLM_STREAM_TIMEOUT |
流式模型调用超时 | 结束 pending,提示重试或关闭流式。 |
LLM_STREAM_FAILED |
流式模型调用失败 | 结束 pending,提示模型服务异常。 |
CASE_SQL_FILE_INVALID |
上传文件不是 .sql |
提示选择 SQL 文件。 |
CASE_SQL_FILE_EMPTY |
SQL 文件为空 | 提示重新导出文件。 |
CASE_SQL_FILE_TOO_LARGE |
文件超过 5MB | 提示压缩或拆分。 |
CASE_SQL_IMPORT_INVALID |
SQL 解析或字段映射失败 | 展示 errors,不允许确认导入。 |
2. 前端主流程
入口页
-> GET /agent/hello
病例页
-> GET /cases
-> GET /cases/{case_id}
-> GET /cases/{case_id}/delete-preview
-> DELETE /cases/{case_id}
训练配置页
-> POST /sessions
Chat 页
-> POST /sessions/{session_id}/chat 或 /chat/stream
-> POST /sessions/{session_id}/hints
-> GET /sessions/{session_id}/order-items
-> POST /sessions/{session_id}/orders
提交页
-> POST /sessions/{session_id}/complete-inquiry
-> POST /sessions/{session_id}/diagnosis
-> POST /sessions/{session_id}/treatment
报告页
-> POST /sessions/{session_id}/evaluation
-> POST /evaluations/{evaluation_id}/export-pdf
历史页
-> GET /evaluations
-> GET /evaluations/{evaluation_id}
导入页
-> POST /imports/case-sql/preview
-> POST /imports/case-sql/apply
LLM 测试页
-> POST /llm/test/deepseek-fast
-> POST /llm/test/deepseek-reason
训练会话状态流转:
inquiry -> diagnosis -> treatment -> evaluating -> evaluated
前端按钮启用规则:
| 阶段 | 允许操作 |
|---|---|
inquiry |
问诊、查看提示、申请检查、完成问诊 |
diagnosis |
提交诊断 |
treatment |
提交治疗方案 |
evaluating |
生成评价报告 |
evaluated |
查看报告、导出 PDF、查看历史 |
3. Agent Hello
GET /agent/hello
用途:检查后端连接,返回当前用户上下文和 Demo 能力开关。
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_mode": "real",
"llm_fallback_to_mock": false,
"llm_fast_model": "deepseek-v4-pro",
"llm_reason_model": "deepseek-v4-pro",
"runtime_memory_backend": "redis"
}
}
前端展示说明:
stream_chat:是否支持 SSE 流式问诊。score_types:评分输出类型,percentage为百分制,five_point为五分制。pdf_export:是否支持 PDF 导出。knowledge_search:是否已接入评分参考指南检索。llm_mock_enabled:是否强制使用 mock 模型。llm_fallback_to_mock:真实模型失败时是否回退 mock。runtime_memory_backend:短期记忆后端,通常为redis或memory。
4. 病例接口
GET /cases
用途:获取病例列表。不会返回标准答案、隐藏病史、评分细则。
Query:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
department_id |
number | 否 | 科室筛选。 |
training_type |
string | 否 | 训练类别筛选:case_analysis、diagnosis_treatment、consultation。 |
mode |
string | 否 | 模式筛选:practice、teaching。 |
Response data:
{
"items": [
{
"id": 2,
"case_code": "SRC_2",
"department_id": 1,
"title": "支气管肺炎 - 6岁男性患儿",
"difficulty": "medium",
"chief_complaint": "发热、咳嗽4天,喘息1天。",
"supported_training_type": "diagnosis_treatment",
"supported_mode": "free_chat",
"has_teaching_video": false,
"has_knowledge_points": true,
"has_quiz": false
}
]
}
GET /cases/{case_id}
用途:获取病例训练入口详情。不会返回标准诊断、标准治疗、隐藏病史。
Response data:
{
"id": 2,
"case_code": "SRC_2",
"title": "支气管肺炎 - 6岁男性患儿",
"department": "儿科",
"difficulty": "medium",
"patient": {
"name": null,
"age": 6,
"gender": "male",
"occupation": null
},
"chief_complaint": "发热、咳嗽4天,喘息1天。",
"supported_training_type": "diagnosis_treatment",
"supported_mode": "free_chat",
"has_teaching_video": false,
"has_knowledge_points": true,
"has_quiz": false,
"order_item_types": ["lab", "imaging", "vital_sign"]
}
GET /cases/{case_id}/delete-preview
用途:删除病例前统计影响范围。前端删除弹窗先调用该接口。
Response data:
{
"case_id": 2,
"case_title": "支气管肺炎 - 6岁男性患儿",
"can_delete": true,
"affected": {
"case_base": 1,
"traditional_case": 1,
"teaching_case": 0,
"scoring_rule": 1,
"case_exam_item": 6,
"training_session": 1,
"training_order": 6,
"training_submission": 1,
"training_record": 1
}
}
DELETE /cases/{case_id}
用途:确认后删除病例及关联业务数据。审计日志只记录删除行为,不反删。
Request:
{
"confirm": true,
"delete_training_data": true
}
Response data:
{
"deleted": true,
"case_id": 2,
"deleted_counts": {
"training_order": 6,
"training_submission": 1,
"training_record": 1,
"training_session": 1,
"case_exam_item": 6,
"scoring_rule": 1,
"traditional_case": 1,
"teaching_case": 0,
"case_base": 1
}
}
前端交互规则:
- 删除按钮只放在病例详情区,不放在病例卡片上。
- 点击删除后先调用
delete-preview。 - 弹窗展示
affected。 - 用户输入固定确认文案后再调用
DELETE。 - 删除成功后清空当前病例、会话、检查结果、报告缓存,并刷新
/cases。
5. 会话与问诊接口
POST /sessions
用途:创建训练会话,初始化短期 memory。
Request:
{
"case_id": 2,
"training_type": "diagnosis_treatment",
"mode": "practice",
"score_type": "percentage"
}
字段说明:
| 字段 | 允许值 | 说明 |
|---|---|---|
training_type |
case_analysis、diagnosis_treatment、consultation |
训练类别。 |
mode |
practice、teaching |
训练模式。后端兼容旧值 novice,会归一为 practice。 |
score_type |
percentage、five_point |
评分输出类型。 |
Response data:
{
"session_id": 10,
"session_code": "sess_20260528100000_abcd1234",
"status": "inquiry",
"patient_opening": "家长:医生,孩子发热咳嗽好几天了,昨天开始喘得厉害,精神也不太好。"
}
POST /sessions/{session_id}/chat
用途:普通非流式问诊。
Request:
{
"message": "孩子发热几天了?最高体温多少?"
}
Response data:
{
"reply": "发热有4天了,最高烧到39度多,吃了退烧药能降下来,但过几个小时又会烧。",
"latency_ms": 2500,
"model": "deepseek-v4-pro",
"fallback_used": false
}
校验:
- 会话必须属于当前
X-User-Id。 - 当前状态必须为
inquiry。 message长度 1 到 2000。
POST /sessions/{session_id}/chat/stream
用途:SSE 流式问诊。当前 Chat 页面优先使用该接口。
Request 同普通问诊。
SSE 事件:
event: message_delta
data: {"delta":"发热有4天了,"}
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_delta:追加到当前 AI 病人气泡。 - 收到
message_done:结束 pending,启用发送按钮。 - 收到
error:结束 pending,展示错误。 - fetch abort 或 reader done 但未收到
message_done:结束 pending,提示“AI 病人回复超时或失败,请重试”。
POST /sessions/{session_id}/hints
用途:练习模式下手动生成提示。提示基于病例、当前对话和已申请检查动态生成。
Request:
{
"last_user_message": "孩子发热几天了?最高体温多少?",
"scope": "current_conversation"
}
Response data:
{
"hints": [
"可以继续追问最高体温、热型和退热药反应。"
],
"missing_dimensions": [
"既往史",
"严重程度评估"
],
"next_questions": [
"孩子以前有没有喘息、哮喘或过敏史?",
"现在血氧是多少?有没有呼吸困难?"
],
"recommended_orders": [
{
"item_code": "oxygen_saturation",
"reason": "用于判断低氧和病情严重程度"
}
]
}
前端处理规则:
- 提示不自动弹出。
- 只在练习模式中显示“查看提示”按钮。
- 练习模式中是否点击提示不影响评分链路。
- 教学互动模式当前不显示提示入口。
6. 检查/检验接口
GET /sessions/{session_id}/order-items
用途:获取当前病例可申请的检查项目。只返回名称和类型,不返回检查结果。
Response data:
{
"items": [
{
"item_code": "complete_blood_count",
"item_name": "血常规",
"item_type": "lab"
}
]
}
POST /sessions/{session_id}/orders
用途:申请检查/检验,结果必须来自数据库 case_exam_item,不允许 LLM 编造。
Request:
{
"item_code": "complete_blood_count"
}
Response data:
{
"item_code": "complete_blood_count",
"item_name": "血常规",
"item_type": "lab",
"result_text": "WBC 12.4×10^9/L,中性粒细胞72%。",
"result_structured": {},
"is_key": true,
"is_abnormal": true,
"context_written": true,
"already_ordered": false
}
幂等规则:
- 同一
session_id + item_code只写入一次。 - 重复申请返回已有结果,
already_ordered=true。 - 重复申请不重复写入 runtime memory。
- 前端按
item_code去重展示。
7. 阶段提交接口
POST /sessions/{session_id}/complete-inquiry
用途:完成问诊,进入诊断阶段。
Response data:
{
"session_id": 10,
"status": "diagnosis"
}
校验:至少存在一轮医生提问。
POST /sessions/{session_id}/diagnosis
用途:提交诊断。
Request:
{
"primary_diagnosis": "支气管肺炎",
"differential_diagnoses": ["毛细支气管炎", "支气管哮喘急性发作", "上呼吸道感染"],
"diagnosis_basis": "结合发热、咳嗽、喘息、肺部体征、炎症指标升高、胸片异常和血氧情况,符合儿童支气管肺炎表现。"
}
Response data:
{
"status": "treatment"
}
POST /sessions/{session_id}/treatment
用途:提交治疗方案。
Request:
{
"treatment_principle": "抗感染、止咳平喘、改善氧合、严密观察病情变化。",
"treatment_measures": "根据病情选择抗感染治疗,必要时雾化吸入缓解喘息,监测体温、呼吸、血氧和精神反应。",
"risk_plan": "关注低氧、呼吸困难加重、持续高热、精神反应差、脱水等情况。",
"communication": "向家属说明肺炎病情、用药注意事项、观察指标和复诊/住院指征。",
"follow_up": "治疗后复查体温、呼吸、血氧和必要炎症指标,症状加重时及时就诊。"
}
Response data:
{
"status": "evaluating"
}
8. 评价与报告接口
POST /sessions/{session_id}/evaluation
用途:生成 AI 评价报告。后端读取评分规则、知识检索结果、检查申请、问诊过程和提交内容后调用 Scoring Agent。
Request:
{
"score_type": "percentage"
}
Response data:
{
"evaluation_id": 1,
"score_type": "percentage",
"total_score": 82,
"dimension_scores": [
{
"dimension": "信息采集",
"score": 18,
"max_score": 25,
"comment": "已覆盖发热和咳嗽,但既往喘息史和家族过敏史追问不足。",
"evidence": ["询问发热天数和最高体温", "申请血常规和CRP"],
"deductions": ["未充分询问既往喘息史"],
"improvement": "补充既往史、过敏史、严重程度评估相关问题。"
}
],
"errors": [],
"improvement_plan": ["加强儿童肺炎严重程度评估训练。"],
"evidence_summary": ["检查结果已写入评分依据。"],
"guideline_refs": [],
"overall_comment": "诊断方向正确,检查利用和沟通细节仍需加强。"
}
评价完成后:
- 写入
training_record。 - 释放当前会话短期 memory。
- 历史记录只保存评价报告,不长期保存完整聊天记录。
GET /evaluations
用途:按当前 X-User-Id 查询历史评价。
Response data:
{
"items": [
{
"evaluation_id": 1,
"case_title": "支气管肺炎 - 6岁男性患儿",
"score_type": "percentage",
"total_score": 82,
"created_at": "2026-05-29T10:00:00",
"pdf_exported": true
}
]
}
GET /evaluations/{evaluation_id}
用途:获取评价详情。只能读取当前用户自己的评价。
Response data:继承评价报告字段,并额外包含:
{
"session_id": 10,
"case_id": 2,
"case_title": "支气管肺炎 - 6岁男性患儿",
"created_at": "2026-05-29T10:00:00",
"pdf_file_path": "storage/reports/training_record_1_percentage_xxx.pdf"
}
POST /evaluations/{evaluation_id}/export-pdf
用途:生成本地 PDF 报告并保存文件路径。
Response data:
{
"export_id": 1,
"file_path": "storage/reports/training_record_1_percentage_xxx.pdf"
}
9. 病例 SQL 导入接口
POST /imports/case-sql/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": 0,
"scoring_rule": 1
},
"can_import": true,
"warnings": [
"源 SQL 未包含 case_exam_item,导入器会按当前业务规则处理。"
],
"errors": [],
"preview_cases": [
{
"id": 2,
"title": "支气管肺炎 - 6岁男性患儿",
"case_type": "traditional",
"difficulty": "medium"
}
]
}
规则:
- 只识别
case_base、traditional_case、teaching_case、scoring_rule。 - 不执行源 SQL 中的
DROP TABLE、CREATE TABLE、ALTER TABLE、LOCK TABLES。 - 字段数量不匹配、JSON 损坏、字符串未闭合时返回
can_import=false。 preview不写库。
POST /imports/case-sql/apply
用途:确认导入,将 SQL 中的病例源表数据映射写入当前数据库。
Request 同预检接口。
Response data:
{
"imported": true,
"file_name": "case.sql",
"encoding": "utf-8",
"inserted_or_updated_cases": 1,
"imported_traditional_cases": 1,
"imported_teaching_cases": 0,
"imported_scoring_rules": 1,
"generated_exam_items": 6,
"warnings": []
}
前端处理:
- 先调用
preview,只有can_import=true才允许点击“确认导入”。 - 导入成功后刷新病例列表。
- 如果源 SQL 缺少
case_exam_item,后端会生成基础检查项,保证新病例可训练。
10. 知识检索接口
GET /knowledge/search
用途:按科室、训练类别和关键词检索评分参考指南。第一版主要供评价链路和调试使用。
Query:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
department_id |
number | 是 | 科室 ID。 |
training_type |
string | 是 | 训练类别。 |
q |
string | 否 | 关键词,多个关键词用英文逗号分隔。 |
Response data:
{
"matched_chunks": [],
"source_refs": [],
"no_match": true
}
11. LLM 测试接口
POST /llm/test/deepseek-fast
用途:测试快速模型耗时。
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
}
POST /llm/test/deepseek-reason
用途:测试 reason 模型耗时。接口内部会优先按配置执行,流式不兼容时降级为非流式,不影响问诊主链路。
Request 同 Fast 测试。
Response 字段同 Fast 测试。
12. 前端字段枚举
| 字段 | 允许值 |
|---|---|
score_type |
percentage、five_point |
mode |
practice、teaching |
training_type |
case_analysis、diagnosis_treatment、consultation |
session.status |
inquiry、diagnosis、treatment、evaluating、evaluated |
patient.gender |
male、female、null |
13. 前端联调注意事项
- 所有请求必须带
X-User-Id,否则后端返回USER_ID_REQUIRED。 - 当前 Demo 不做登录注册,
user_id由宿主系统或测试页传入。 - 病例详情不返回标准答案,避免前端泄露训练答案。
- 检查结果只来自数据库,不来自 LLM。
- 聊天记录只在 runtime memory 中短期保存,评价完成后释放。
- 历史页读取的是
training_record,只展示完整训练结束后的评价。 - 删除病例会级联删除该病例训练数据,前端必须保留二次确认。
.env不进入 Git,前端不能写死 API Key。