# 前端 API 对接文档 本文档面向 Vue 前端与后续正式前端开发,描述当前第一版 Demo 已实现的后端接口、请求头、状态流转、字段结构和错误处理规则。 ## 1. 通用约定 ### 1.1 Base URL 本地开发默认地址: ```text http://127.0.0.1:8000/api/v1 ``` 前端默认配置: ```text 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 流式接口外,后端统一返回: ```json { "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. 前端主流程 ```text 入口页 -> 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 ``` 训练会话状态流转: ```text inquiry -> diagnosis -> treatment -> evaluating -> evaluated ``` 前端按钮启用规则: | 阶段 | 允许操作 | ---|---| | `inquiry` | 问诊、查看提示、申请检查、完成问诊 | | `diagnosis` | 提交诊断 | | `treatment` | 提交治疗方案 | | `evaluating` | 生成评价报告 | | `evaluated` | 查看报告、导出 PDF、查看历史 | ## 3. Agent Hello ### `GET /agent/hello` 用途:检查后端连接,返回当前用户上下文和 Demo 能力开关。 Response `data`: ```json { "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`: ```json { "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`: ```json { "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`: ```json { "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: ```json { "confirm": true, "delete_training_data": true } ``` Response `data`: ```json { "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: ```json { "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`: ```json { "session_id": 10, "session_code": "sess_20260528100000_abcd1234", "status": "inquiry", "patient_opening": "家长:医生,孩子发热咳嗽好几天了,昨天开始喘得厉害,精神也不太好。" } ``` ### `POST /sessions/{session_id}/chat` 用途:普通非流式问诊。 Request: ```json { "message": "孩子发热几天了?最高体温多少?" } ``` Response `data`: ```json { "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 事件: ```text 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: ```json { "last_user_message": "孩子发热几天了?最高体温多少?", "scope": "current_conversation" } ``` Response `data`: ```json { "hints": [ "可以继续追问最高体温、热型和退热药反应。" ], "missing_dimensions": [ "既往史", "严重程度评估" ], "next_questions": [ "孩子以前有没有喘息、哮喘或过敏史?", "现在血氧是多少?有没有呼吸困难?" ], "recommended_orders": [ { "item_code": "oxygen_saturation", "reason": "用于判断低氧和病情严重程度" } ] } ``` 前端处理规则: - 提示不自动弹出。 - 只在练习模式中显示“查看提示”按钮。 - 练习模式中是否点击提示不影响评分链路。 - 教学互动模式当前不显示提示入口。 ## 6. 检查/检验接口 ### `GET /sessions/{session_id}/order-items` 用途:获取当前病例可申请的检查项目。只返回名称和类型,不返回检查结果。 Response `data`: ```json { "items": [ { "item_code": "complete_blood_count", "item_name": "血常规", "item_type": "lab" } ] } ``` ### `POST /sessions/{session_id}/orders` 用途:申请检查/检验,结果必须来自数据库 `case_exam_item`,不允许 LLM 编造。 Request: ```json { "item_code": "complete_blood_count" } ``` Response `data`: ```json { "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`: ```json { "session_id": 10, "status": "diagnosis" } ``` 校验:至少存在一轮医生提问。 ### `POST /sessions/{session_id}/diagnosis` 用途:提交诊断。 Request: ```json { "primary_diagnosis": "支气管肺炎", "differential_diagnoses": ["毛细支气管炎", "支气管哮喘急性发作", "上呼吸道感染"], "diagnosis_basis": "结合发热、咳嗽、喘息、肺部体征、炎症指标升高、胸片异常和血氧情况,符合儿童支气管肺炎表现。" } ``` Response `data`: ```json { "status": "treatment" } ``` ### `POST /sessions/{session_id}/treatment` 用途:提交治疗方案。 Request: ```json { "treatment_principle": "抗感染、止咳平喘、改善氧合、严密观察病情变化。", "treatment_measures": "根据病情选择抗感染治疗,必要时雾化吸入缓解喘息,监测体温、呼吸、血氧和精神反应。", "risk_plan": "关注低氧、呼吸困难加重、持续高热、精神反应差、脱水等情况。", "communication": "向家属说明肺炎病情、用药注意事项、观察指标和复诊/住院指征。", "follow_up": "治疗后复查体温、呼吸、血氧和必要炎症指标,症状加重时及时就诊。" } ``` Response `data`: ```json { "status": "evaluating" } ``` ## 8. 评价与报告接口 ### `POST /sessions/{session_id}/evaluation` 用途:生成 AI 评价报告。后端读取评分规则、知识检索结果、检查申请、问诊过程和提交内容后调用 Scoring Agent。 Request: ```json { "score_type": "percentage" } ``` Response `data`: ```json { "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`: ```json { "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`:继承评价报告字段,并额外包含: ```json { "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`: ```json { "export_id": 1, "file_path": "storage/reports/training_record_1_percentage_xxx.pdf" } ``` ## 9. 病例 SQL 导入接口 ### `POST /imports/case-sql/preview` 用途:上传接口解析后的 SQL 文件,只解析和校验,不写入数据库。 Request: ```text Content-Type: multipart/form-data file: case.sql ``` Response `data`: ```json { "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`: ```json { "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`: ```json { "matched_chunks": [], "source_refs": [], "no_match": true } ``` ## 11. LLM 测试接口 ### `POST /llm/test/deepseek-fast` 用途:测试快速模型耗时。 Request: ```json { "message": "请用一句话说明医疗问诊训练 Demo 的用途。" } ``` Response `data`: ```json { "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. 前端联调注意事项 1. 所有请求必须带 `X-User-Id`,否则后端返回 `USER_ID_REQUIRED`。 2. 当前 Demo 不做登录注册,`user_id` 由宿主系统或测试页传入。 3. 病例详情不返回标准答案,避免前端泄露训练答案。 4. 检查结果只来自数据库,不来自 LLM。 5. 聊天记录只在 runtime memory 中短期保存,评价完成后释放。 6. 历史页读取的是 `training_record`,只展示完整训练结束后的评价。 7. 删除病例会级联删除该病例训练数据,前端必须保留二次确认。 8. `.env` 不进入 Git,前端不能写死 API Key。