门诊病历书写是门诊流程里最容易积压“隐性工时”的环节。医生既要面对患者、又要录入结构化病历,往往到下班还有一批病历没写完。智能生成系统如果在架构上设计得不好,就会出现“看似能生成、实际没法用”的尴尬局面:接口响应慢、字段结构不统一、数据安全过不了关、和医院 HIS 系统对接困难。
我们这次要聊的,不是某一个具体开源项目的安装教程,而是一套完整的“门诊病历智能生成系统”架构设计。主题是系统架构设计,核心落点是智能生成。简单说,就是讲清楚:医生口语输入一段病情描述后,系统如何通过大模型生成符合门诊病历规范的结构化病历,再经过人工确认,最终写入医院业务系统。这一个看似简单的过程,涉及模型服务、提示词工程、数据结构、权限审计、高并发治理、内外网隔离等多个模块,横跨“模型能不能用”和“系统能不能上线”两个层面。
本文会从业务痛点出发,拆分整体架构分层、核心生成流程、模型服务接入、数据存储设计、API 接口规范、安全合规边界、部署与性能观察、常见排障这几个角度展开。如果你是做医疗信息化、医院集成平台、AI 辅助诊断产品,或者正在设计类似的企业级 LLM 应用系统,这篇文章可以直接作为初期架构参考。
1. 核心能力速览
先给一张速览表,把“门诊病历智能生成系统”的关键维度列清楚,后面再逐层展开。
| 能力项 | 说明 |
|---|---|
| 系统定位 | 面向门诊医生的病历辅助生成系统,不替代医生决策,只负责草稿生成与结构化整理 |
| 核心能力 | 口语化描述转结构化病历、模板化生成、既往史与用药信息抽取、诊断建议知识检索、人工审核入库 |
| 输入方式 | 医生语音转写文本、键盘录入文本、HIS 系统已有患者信息 |
| 输出内容 | 主诉、现病史、既往史、体格检查、初步诊断、处理意见等结构化病历字段 |
| 模型接入方式 | 可接入本地化部署的 LLM、也可接入经审批的云端大模型 API,按数据敏感级别做路由 |
| 关键前置条件 | 需要和医院 HIS 系统做数据交互,必须走内部网络与授权接口 |
| 主要技术组件 | LLM 推理服务、提示词模板引擎、结构化数据校验模块、知识库检索模块、审计日志模块 |
| 是否支持 API | 必须支持,面向 HIS 前端或医生工作台提供 HTTP 接口 |
| 是否支持批量任务 | 支持,例如批量生成初诊草稿、批量归档历史病历,但所有结果必须进入人工复核队列 |
| 部署方式 | 建议内网私有化部署,GPU 资源按并发量评估 |
| 适合场景 | 门诊医生工作站、互联网医院在线问诊、体检报告解读辅助、基层医疗病历规范化 |
从架构角度看,这套系统和普通“对话机器人”最大的区别是:它不是给用户聊天的,而是给业务系统供数据的。所以设计重心要从“能不能生成”转移到“生成结果能不能被业务系统安全准确地消费”。
如果只看材料,没有具体的实测环境数据和代码路径,某些参数需要按实际环境测试;下面所有设计都基于常见的企业级 LLM 应用架构思路,属于通用方案模板,落地时请结合你所在项目的技术栈替换具体实现。
2. 门诊病历生成系统面临的业务与技术挑战
在展开架构设计之前,先梳理业务和技术上的关键挑战。因为这些挑战直接决定架构选型,绕过任何一个,系统上线后都会补窟窿。
2.1 病历书写场景的特殊性
门诊病历不是自由文本,它有严格的组成要素:主诉、现病史、既往史、体格检查、辅助检查、初步诊断、治疗意见。每家医院的病历规范略有差异,但整体结构高度标准化。
这意味着智能生成系统不能直接输出一大段口语文本,而必须输出“符合科室模板的、字段齐全的、没有幻觉性诊断的”结构化数据。对生成结果的约束,远比一般写作类任务严格。
2.2 实时性要求
门诊场景是实时的。患者坐在诊室里,医生不可能等模型跑 3 分钟。系统在设计上要有明确的目标:第一版草稿必须在医生可接受的等待时间内返回,通常要在几秒到十几秒的范围内完成从请求到首字返回的过程。
这对模型服务层、网络传输和流式输出都提出了要求。如果模型推理无法达到要求,架构上就要引入降级方案,比如先返回一个基于模板的极简草稿,再异步生成完整版本。
2.3 数据安全与合规边界
门诊病历包含患者身份信息、疾病信息、用药信息,属于高度敏感数据。按照医疗数据管理的一般原则,这类数据不允许直接发送到未备案的外部服务。因此在架构设计上,模型推理建议优先走内网私有化部署,如果必须使用外部模型服务,要经过数据脱敏、审批、加密传输等多层处理。
2.4 与 HIS 系统的集成难度
医院的核心业务系统通常不是开放平台,不可能为了一个新系统随意改表结构。所以门诊病历智能生成系统必须和 HIS 系统之间保留一个适配层,由适配层负责格式转换、字段映射、状态回写。
很多项目失败不是模型效果不行,而是适配层没有设计好,HIS 前端改一个字段名称,整个生成流程就崩了。架构上必须把适配层独立出来。
3. 系统整体架构设计
下面进入核心内容:门诊病历智能生成系统的架构分层。
整体采用分层架构,从下往上依次是基础设施层、模型服务层、业务服务层、接口接入层、应用展示层;横切关注点包括安全与审计、监控与告警、配置中心。分层设计是为了让不同团队可以独立迭代,模型团队只关心模型推理,业务团队只关心病历结构,前端团队只关心交互。
| 层级 | 职责 | 关键组件 |
|---|---|---|
| 应用展示层 | 医生工作台、移动端、HIS 前端插件 | Web 前端、HIS 嵌入组件 |
| 接口接入层 | 提供 HTTP API、鉴权、限流、参数校验 | API Gateway、Nginx、Spring Cloud Gateway |
| 业务服务层 | 病历生成流程编排、模板管理、人工审核、状态流转 | 病历服务、审核服务、模板服务、患者服务 |
| 模型服务层 | LLM 推理、提示词模板、知识检索、结果结构化 | 模型推理服务、向量检索服务、提示词引擎 |
| 数据层 | 结构化存储、非结构化存储、向量存储、缓存 | PostgreSQL / MySQL、对象存储、Redis、向量数据库 |
| 基础设施层 | GPU 资源、日志采集、监控告警、容器编排 | Kubernetes、Docker、Prometheus、Grafana |
下面把每一层的设计重点展开说明。
3.1 应用展示层
这一层是医生直接接触的界面,一般有两种形态:
- 独立网页,医生在浏览器中打开系统,复制或导入患者信息,生成病历草稿,复制回 HIS。
- HIS 嵌入插件,在 HIS 医生工作站里通过 iframe 或原生插件调起生成面板,生成结果一键回填到 HIS 对应字段。
第二种体验更好,但集成成本更高,需要医院信息科配合提供 HIS 的字段配置能力。架构设计上,接入层要预留两种形态都支持的接口结构。前端的核心任务是“让医生看到生成进度、可编辑、可确认、可回退”。这里尤其要设计好“流式输出展示”和“阶段进度展示”,否则医生会以为系统卡死了。
3.2 接口接入层
接入层层面的设计,不只是提供一个 REST 接口,而是要作为所有调用方的统一入口。
需要重点设计的能力包括:
- 身份认证:医生工号、科室、角色。
- 接口鉴权:调用方标识、签名校验。
- 参数校验:患者 ID、病历类型、科室模板 ID 是否合法。
- 限流控制:按医生ID、按调用方应用、按Token维度限流。
- 灰度发布:只对部分科室开放新模型策略。
推荐的网关组件可以是 Spring Cloud Gateway、APISIX 或 Nginx + Lua。如果是轻量部署,直接用 Nginx 反代加一个鉴权中间件也可以,但到生产级还是要独立的 API 网关。
3.3 业务服务层
业务服务层是整个系统的编排中枢,负责串起“请求进来 → 准备上下文 → 调用模型 → 校验结果 → 返回医生确认 → 回写 HIS”的完整链路。
建议拆成以下几个微服务:
| 服务名 | 职责 | 关键接口 |
|---|---|---|
| 病历生成服务 | 接收生成请求,编排生成流程,管理任务状态 | /api/medical-record/generate |
| 模板管理服务 | 维护各科室病历模板、字段规则 | /api/template/list |
| 审核服务 | 记录医生确认、修改、退回操作 | /api/medical-record/audit |
| 患者信息服务 | 从 HIS 或集成平台同步患者基本信息、既往病历 | /api/patient/info |
| 模型调用服务 | 封装对模型服务层的调用,处理超时重试 | /api/model/completion |
业务服务层要特别注意“状态机设计”。一份门诊病历从“草稿生成中”到“待医生确认”到“已确认待回写”到“已回写”再到“已归档”,状态不能乱。推荐引入工作流引擎,或者在代码里用显式的状态机枚举,避免出现医生已经修改保存、后台却还在执行异步生成覆盖数据的严重问题。
3.4 模型服务层
模型服务层是智能生成的核心。针对门诊病历场景,建议采用“通用大模型 + 领域知识检索 + 结构化约束”的混合架构。
从部署策略看,模型推理可以选择本地化私有部署,也可以选择经过审批的云端 API 服务,两种情况都能接入,但对应的架构处理不同:
- 本地化部署:数据不出内网,安全合规性高,但需要 GPU 资源投入,需要模型推理服务具备并发排队能力。
- 云端 API 服务:接入成本低、模型能力强,但要经过数据脱敏审批,只能用于非敏感字段或脱敏后的文本生成。
模型服务层的核心组件包括:
- Prompt 引擎:维护不同科室、不同病历类型的提示词模板,把医生输入和患者上下文拼装成完整 Prompt。
- 推理网关:负责把请求分发到具体模型服务,处理超时、重试、降级。
- 结构化输出解析:LLM 返回的内容不一定是严格 JSON,需要增加解析和纠错环节。
- 知识检索模块:从诊断知识库、用药指南、科室规范中检索相关信息,辅助模型生成更可靠的诊断建议。
- 安全过滤模块:对生成内容进行敏感信息检测,避免出现不当医疗建议和有害表述。
这里有一个关键设计点:不要直接让医生输入的文本拼成 Prompt 丢给模型。必须加入“上下文组装”动作,包括患者基本信息脱敏、历史病历摘要、科室模板约束、诊断代码提示等。没有合理的上下文,生成结果通常会模板化严重、缺乏针对性。
3.5 数据层
门诊病历智能生成系统的数据存储不是一张大表就能搞定的。按照数据类型不同,建议拆分存储组件:
| 数据类型 | 存储方案 | 说明 |
|---|---|---|
| 结构化病历数据 | PostgreSQL / MySQL | 存放病历主表、明细表、字段值、状态 |
| 生成任务日志 | PostgreSQL / MongoDB | 记录每一次生成请求、响应、耗时、状态 |
| 向量知识库 | 向量数据库 | 存放诊断指南、用药说明、科室规范 |
| 缓存数据 | Redis | 存放模板缓存、患者上下文缓存、限流计数 |
| 原始文件与音频 | 对象存储 | 语音转写的原始音频、医生确认前草稿快照 |
病历主表建议采用“主表 + 扩展字段表”的冗余设计。因为不同科室的病历字段差异较大,如果在主表固定几十个字段,后续扩展会非常痛苦。可以把公共字段放主表,科室差异化字段放 JSONB 或 text 类型的扩展字段列。
同时在设计上要避免一条巨大 JSON 塞进数据库的做法。虽然模型输出的自然是 JSON,但业务系统后续要按字段检索、按字段统计,应该把高频检索字段拆列为独立列,低频展示字段保留 JSON。
3.6 基础设施层
在企业内部署时,基础设施层推荐采用 Kubernetes 管理微服务,GPU 机器通过设备插件接入集群。如果没有 K8s 条件,也可以采用 Docker Compose 加单机部署的简化方案。
日志方面要统一采集到 Elasticsearch 或 Loki,方便排查生成链路问题。监控上要覆盖四个维度:服务存活状态、接口延迟、GPU 利用率和显存占用、队列积压量。
还需要特别设计“一键回到 N 分钟前”的能力。把每次生成前快照、生成后草稿、医生修改后版本都保存下来,一旦线上出现问题,可以回溯到底是模型的问题还是医生修改导致的数据问题。
4. 门诊病历智能生成核心流程设计
这部分把“输入口语描述”到“生成结构化病历”的内部流程设计清楚。整个流程按阶段划分,可以让系统在每一步都有清晰的判断标准。
4.1 整体流程步骤
整个生成流程建议划分为以下阶段:
- 接收请求:前端传入医生语音转写文本或键盘文本、患者 ID、科室模板 ID。
- 患者上下文装配:根据患者 ID 从 HIS 同步患者基本信息、最近就诊记录、过敏史、当前用药。
- 文本预处理:对医生输入做清洗,识别关键症状描述,去除口语噪音。
- Prompt 组装:结合科室模板、患者上下文、历史病历摘要,生成最终 Prompt。
- 模型推理:调用模型服务生成病历草稿。
- 结构化解析:将模型输出解析为 JSON,校验必填字段。
- 规则校验:进行必填项检查、诊断代码合法性检查、敏感词过滤。
- 草稿落库:生成草稿记录,状态为“待确认”。
- 返回前端:医生在界面上看到草稿,可编辑、可重新生成。
- 人工确认:医生确认或修改后,系统回写 HIS 并归档。
4.2 状态机设计
一张病历记录建议拥有如下状态:
| 状态 | 含义 | 可流转到 |
|---|---|---|
| DRAFT_GENERATING | 草稿生成中 | DRAFT_GENERATED, GENERATE_FAILED |
| DRAFT_GENERATED | 草稿已生成 | PENDING_CONFIRM, GENERATE_FAILED |
| PENDING_CONFIRM | 待医生确认 | CONFIRMED, EDITING |
| EDITING | 医生修改中 | CONFIRMED, DRAFT_GENERATED |
| CONFIRMED | 已确认待回写 | WRITE_BACK_SUCCESS, WRITE_BACK_FAILED |
| WRITE_BACK_SUCCESS | 已回写 HIS | ARCHIVED |
| WRITE_BACK_FAILED | 回写失败 | PENDING_CONFIRM |
| ARCHIVED | 已归档 | 无 |
状态机实现上,最忌讳的就是在代码里到处写 if/else 修改状态。推荐用状态机框架,例如 Spring StateMachine,或者在数据库层面用乐观锁 version 字段,避免并发修改导致状态错乱。
4.3 流式输出与任务中断处理
门诊医生对“等待时间”非常敏感。如果模型生成需要 10 秒,这 10 秒里医生看到的不应该是一个转圈动画,而是逐字出现的病历文本和阶段进度。
因此在接口设计上,推荐生成接口支持 SSE 流式输出。服务端执行流程:
- 返回 HTTP 200,Content-Type 为 text/event-stream。
- 每完成一个解析和生成阶段,推送一个进度事件。
- 生成完成时,推送完整病历 JSON。
前端收到事件后,按阶段展示。医生如果发现生成内容偏离预期,可以直接点击“停止生成”,后台收到中断请求后,取消模型调用,保留已完成的中间结果。
4.4 异步任务与人工审核队列
批量任务在门诊病历场景中不常见,但在体检报告解读、历史病历归档补录、教学科研数据整理中会用到。
异步任务的架构设计建议:
- 任务接入消息队列,例如 RabbitMQ 或 Kafka。
- 每个任务记录患者 ID、病历类型、计划生成时间、优先级。
- 模型服务按队列消费,控制并发数。
- 所有生成结果进入“待人工复核”队列,不允许自动直写 HIS。
批量任务的重点不是跑得快,而是“每一条结果都有人看过”。所以架构上一定要设置人工复核队列,并统计复核通过率、修改率,反过来指导 Prompt 优化。
5. 模型服务层设计:Prompt 引擎与结构化输出
模型服务层是整个系统能否真正好用的关键。下面展开讲三个设计重点:Prompt 引擎、结构化输出解析、知识检索增强生成。
5.1 Prompt 引擎设计
不同的科室、不同的病历类型,对应不同的 Prompt。Prompt 引擎的核心能力是“模板变量替换”和“科室规则注入”。
一个模板的抽象结构如下:
你是一名{科室}门诊医生助手。 请根据以下患者信息和医生描述,生成结构化门诊病历草稿。 【患者信息】 {患者简要信息脱敏} 【历史病历摘要】 {历史病历摘要} 【本次医生描述】 {医生输入文本} 【生成要求】 1. 按以下JSON格式输出:主诉、现病史、既往史、体格检查、诊断、处理意见。 2. 诊断必须使用规范的ICD-10编码。 3. 不得编造患者未提供的信息。 4. 处理意见中的用药建议需要参考{知识库检索结果}。 5. 输出只包含JSON,不输出解释。Prompt 模板要放在配置中心或数据库里,不能写死在代码中。因为医生和运营团队后续会不断调整 Prompt,如果每次调整都改代码,迭代效率太低。
5.2 结构化输出解析与纠错
大模型直接输出 JSON 的可能性和模型能力、Prompt 约束有关,但不能完全信任。即使模型按要求输出 JSON,也经常出现:字段名带引号差异、JSON 里混入 Markdown、中文括号和英文括号混用、字段值超出长度。
因此需要一个独立的解析模块:
- 提取模型输出中的 JSON 片段。
- 尝试 json.loads 解析;失败则进入修复流程。
- 用正则提取字段名和值。
- 必填字段缺失时,调用模型补全一次。
- 仍然失败则标记为生成失败,提示医生重试或使用模板草稿。
推荐引入 Pydantic 或 Java 的 Bean Validation 做字段校验,把模型输出映射为严格的病历结构体。这块写好后,后面所有下游任务都用结构体,不用反复解析字符串。
5.3 RAG 知识检索增强
为了让模型生成内容更贴合医院实际,建议引入向量知识库。知识库可以包含:
- 医院各科室病历书写规范。
- 常见疾病诊断要点。
- 常用药物说明与禁忌。
- 既往典型病例脱敏样本(注意隐私)。
生成请求进来后,先根据医生输入文本做向量检索,召回最相关的 3-5 条知识片段,再拼接到 Prompt 中。
检索过程放在业务服务层还是模型服务层,取决于你的团队分工。推荐把检索能力封装为独立的知识服务,既服务生成接口,也服务前端“诊断参考”功能。
一个简化版 Python 伪代码示意如下(实际实现需按项目技术栈替换):
from langchain.embeddings import OpenAIEmbeddings # 示例用法 from langchain.vectorstores import Milvus embeddings = OpenAIEmbeddings() vector_store = Milvus( embedding_function=embeddings, collection_name="clinical_knowledge", connection_args={"host": "milvus-host", "port": "19530"} ) def retrieve_knowledge(query: str, top_k: int = 3): docs = vector_store.similarity_search(query, k=top_k) return [doc.page_content for doc in docs]这里只是给出一种通用实现思路,具体的向量库选型和嵌入模型需要根据实际环境测试。
6. 接口 API 与 HIS 集成设计
接口设计是医疗系统集成中比较容易出问题的地方。前端调用、HIS 调用、内部服务调用,三者的接口风格应该统一,但权限粒度要区分。
6.1 生成病历接口
下面给出一个通用的接口设计模板,实际路径和参数名需要按项目规范调整。
POST /api/medical-record/generate Content-Type: application/json { "patientId": "P20250101001", "doctorId": "D10032", "department": "心血管内科", "templateId": "T3001", "inputText": "患者男,56岁,近一周活动后胸闷气短,休息可缓解,偶有头晕,无胸痛硝酸甘油缓解史", "useStream": true }响应采用 SSE 流式返回时,前端按事件类型解析:
event: status data: {"stage": "receiving", "message": "已接收请求"} event: status data: {"stage": "assembling_context", "message": "正在组装患者上下文"} event: status data: {"stage": "generating", "message": "正在生成病历草稿"} event: draft data: {"medicalRecordId": "MR20250101088", "content": "{...结构化病历JSON...}"}如果不用流式,可以设计为同步返回:
{ "code": 0, "message": "success", "data": { "medicalRecordId": "MR20250101088", "status": "PENDING_CONFIRM", "draft": { "chiefComplaint": "活动后胸闷气短1周", "presentIllness": "患者于1周前出现活动后胸闷气短...", "pastHistory": "既往体健,否认高血压、糖尿病史", "physicalExam": "神清,心肺腹查体未见明显异常", "diagnosis": [ {"code": "I20.9", "name": "冠心病,不稳定型心绞痛"} ], "treatmentPlan": "建议心电图、心肌酶检查,必要时冠脉CTA" } } }这里不再展开具体的 Python 代码,实际接入时建议后端使用 Spring Boot 或 FastAPI,统一封装响应体结构。
6.2 人工确认接口
医生确认或修改之后,调用确认接口:
POST /api/medical-record/confirm { "medicalRecordId": "MR20250101088", "doctorId": "D10032", "finalContent": "{...与draft结构一致...}", "auditAction": "CONFIRM" }确认接口要记录医生实际操作,包括修改了哪些字段、从哪个状态到哪个状态,方便后续审计。
6.3 HIS 集成方案
和 HIS 系统的数据交互,建议走医院集成平台或 HIS 提供的 WebService/HL7 接口。集成方案上要注意:
- 先确认 HIS 是否提供病历写入接口。如果没有,只能做“复制粘贴”模式,医生把生成内容手动粘贴到 HIS。
- 如果 HIS 有接口,适配层要负责字段映射,例如把本系统的 chiefComplaint 映射到 HIS 的主诉字段。
- 回写时要有幂等机制。同一个 medicalRecordId 不能重复插入。
- 回写失败要记录详细错误日志,保留重试队列。
架构上建议独立出hiss-adapter模块。该模块只做一件事:把本系统的标准病历结构转换为 HIS 的表结构或接口报文。HIS 字段一改,只动适配层,不牵扯生成服务。
7. 安全合规与权限设计
医疗数据安全是不可妥协的底线。下面从身份认证、数据脱敏、审计日志、合规边界四个方面展开。
7.1 身份认证与权限控制
医生登录系统后,所有操作都要绑定到具体工号。权限设计上至少要区分三层:
- 医生:只能查看和编辑自己接诊患者的病历草稿。
- 科室管理员:可以查看本科室的生成统计、修改 Prompt 模板。
- 系统管理员:可以查看全系统日志、管理模型服务配置。
患者数据按就诊关系隔离,不能出现医生 A 能查医生 B 的患者病历这种越权行为。如果基于 Spring Security,可以使用自定义 PermissionEvaluator 校验患者和医生的就诊关系。
7.2 数据脱敏
在调用外部模型服务或者做日志展示时,必须对患者身份信息脱敏。脱敏内容包括:
- 姓名:保留姓氏,名字打码。
- 身份证号:保留前 3 后 4。
- 手机号:保留前 3 后 4。
- 地址:精确到市/区。
- 住院号/门诊号:做映射替换。
脱敏动作必须在业务服务层完成,模型调用服务只接收脱敏后的文本。原始数据不能出现在模型推理日志里。
7.3 审计日志
审计日志是医疗系统上线的硬性要求。每次生成请求、确认操作、回写操作都要记录:
| 字段 | 说明 |
|---|---|
| traceId | 请求链路追踪ID |
| operatorId | 操作人ID |
| patientId | 患者ID |
| action | 操作类型:generate / confirm / delete |
| requestContent | 请求内容脱敏 |
| responseContent | 生成草稿脱敏 |
| actionTime | 操作时间 |
| ipAddress | 请求来源IP |
| resultStatus | 成功 / 失败 / 超时 |
日志建议每日归档,保留周期按医院规范执行。排查问题的时候,一条完整的 traceId 就能贯穿网关、业务服务、模型服务三条链路。
7.4 合规边界
从使用边界上看,这套系统生成的病历草稿必须经过医生确认才能写入 HIS。系统不能替代医生做最终诊断,也不能自动在病历上签名。架构上要通过状态机强制约束:只有 PENDING_CONFIRM 状态的病历才能进入确认环节,确认操作必须绑定医生 ID。
涉及语音转写、患者音频等数据,如果使用了第三方语音识别能力,需要确认授权范围和数据处理协议。模型生成内容属于辅助建议,系统界面需要展示“AI生成草稿,请医生审核”的字样。
8. 部署架构与性能观察
部署架构的目标是在满足医院安全要求的前提下,让系统稳定跑起来。这里给出一套常见的内部部署方案,具体资源规格需按实际并发测试调整。
8.1 部署拓扑
推荐结构:
客户端浏览器(医生工作台) ↓ HTTPS Nginx / API Gateway(内网入口) ↓ 业务服务集群(K8s Deployment) ↓ 模型推理服务(GPU Pod 或 独立 GPU 服务器) ↓ PostgreSQL / Redis / 向量数据库 / 对象存储在私有化部署场景下,模型推理服务建议放在独立 GPU 机器上。因为模型推理负载波动大,和其他微服务混布容易互相干扰。GPU 机器通过内部网络暴露推理接口,只允许业务服务访问,不直接暴露给前端。
8.2 性能观察指标
系统上线前,要重点观察以下指标:
| 指标 | 观察方式 | 关注原因 |
|---|---|---|
| 接口 P95 延迟 | Prometheus + Grafana | 门诊医生等待容忍度 |
| 模型首 token 延迟 | 模型服务日志 | 判断模型推理效率 |
| GPU 显存占用 | nvidia-smi / DCGM | 判断是否需要扩容 |
| GPU 利用率 | nvidia-smi | 判断资源配置合理性 |
| 并发生成任务排队数 | Redis 队列监控 | 判断是否需要横向扩容 |
| 生成失败率 | 业务日志 | 判定模型和提示词稳定性 |
| 人工确认修改率 | 业务报表 | 判定生成结果质量 |
在门诊高峰期,如果有 20 个医生同时使用,排队数会快速上升。架构上要在模型服务前加一个队列,控制同时推理的任务数量,避免 GPU 显存被打爆导致整体崩溃。
8.3 显存与并发估算思路
关于显存占用,不能一概而论。不同模型参数量、量化方式、并发数都会影响显存。在做容量规划时,建议按以下思路验证:
- 先用单卡跑通一个生成任务,用
nvidia-smi观察空闲显存、生成时峰值显存。 - 逐步增加并发数到 2、4、8,观察显存和延迟变化。
- 找到“显存不超限、延迟可接受”的最大并发数。
- 按该值设置模型推理服务的最大并发数,超出部分进队列排队。
如果并发要求高但显卡显存有限,可以降低单并发显存占用:比如加载低精度模型、减小最大输入 token 数、限制输出长度、拆分成多个小模型服务实例。
8.4 降低资源占用的实践
门诊病历生成和通用对话不同,输出长度有限,一般几百到一千字就够。因此:
- 限制 max_tokens,避免模型生成冗长内容。
- Prompt 里明确限制输出 JSON,不带解释。
- 设置合理的超时时间,例如 30 秒没有返回就标记失败。
- 对同科室、同模板的请求做缓存,如果医生输入相近,可以复用上一份草稿结构。
这些手段能明显降低单次生成耗时和显存占用。
9. 常见问题与排查方法
系统上线后,各种问题会陆续暴露。下面整理一份门诊病历智能生成系统常见问题排查表。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 生成的病历字段缺失 | Prompt 约束不足或模型能力不足 | 查看原始模型输出日志,确认是否输出了字段 | 增强 Prompt 字段约束、增加必填字段校验和补全 |
| 生成内容包含幻觉诊断 | 缺乏知识库约束或模型错误推断 | 对比知识库检索结果和生成诊断 | 增加 RAG 检索约束、在 Prompt 中强调“不得编造” |
| 接口响应超时 | 模型推理慢、队列积压或网络延迟 | 查看模型服务日志、队列长度、网关超时配置 | 调大超时、增加并发、优化模型量化、预加载模型 |
| GPU 显存溢出 | 并发任务过多或单任务输入太长 | 查看 nvidia-smi、任务并发数 | 降低并发数、限制输入长度、开启队列排队 |
| 回写 HIS 失败 | 字段映射错误、HIS 接口变更、网络不通 | 查看适配层日志、HIS 接口返回 | 修复映射关系、联系 HIS 厂商、增加重试机制 |
| 医生改了病历但被覆盖 | 并发修改冲突、状态机未加锁 | 查看状态流日志、数据库 version 字段 | 增加乐观锁、编辑时锁定任务、回写前二次确认 |
| 外部模型调用报敏感错误 | 脱敏未生效或数据未脱敏 | 检查脱敏模块日志 | 在业务服务层强制脱敏后再调用模型 |
| 生成结果反复不一致 | 模型采样参数不稳定 | 检查 temperature 参数 | 降低 temperature,设置固定随机种子 |
| 批量任务卡住 | 队列消费异常、数据库连接池耗尽 | 查看死信队列和日志 | 增加消费失败重试、告警介入 |
| 前端流式输出中断 | 网关超时、SSE 连接断开 | 查看 Nginx Proxy 配置 | 调整 proxy_read_timeout,支持长连接 |
9.1 排查思路
碰到问题,第一步不是看模型效果,而是先看链路完整度。推荐的做法是:
- 根据 traceId 把整条日志拉出来。
- 确认请求到网关 → 业务服务 → 模型服务的每一步耗时。
- 确认模型服务的响应内容是否符合预期。
- 确认结构化解析是否成功。
- 确认数据库落库是否成功。
- 确认前端展示状态是否更新。
只要链路日志完整,大部分问题都能快速定位。所以日志设计要从第一天就按 traceId 贯穿全链路。
10. 最佳实践与后续演进
最后聊聊工程落地建议和后续可以继续扩展的方向。
10.1 最佳实践
- 先小科室试点,再全院推广。选择门诊量稳定、病历模板固化的科室,跑通后再扩展。
- 模型不一定要一开始就用最好的大模型,先使用轻量化模型验证流程,再逐步更换。
- 所有生成结果先进入“草稿池”,由医生确认后落库,系统不自动写 HIS。
- 模板和 Prompt 配置化,业务人员不写代码就能调整。
- 每一次医生修改都是一次标注数据。把医生修改前后的差异保存下来,后续做模型微调或 Prompt 优化。
- 日志、审计、监控从第一天就接入,不要等项目跑半年再补。
10.2 后续演进方向
- 引入语音实时转写,医生说话过程中系统实时生成结构化内容。
- 引入患者历史病历向量化,生成现病史时自动关联历史诊断。
- 建立“修改反馈闭环”,把医生修改率高的字段作为 Prompt 优化的重点。
- 从门诊病历扩展到住院病历、出院小结、手术记录等更多文书类型。
- 在充分合规的前提下,支持科室级数据统计,帮助科室分析病历书写质量和诊断分布。
整套架构的核心并不是某个模型效果有多强,而是“AI 生成结果如何安全可靠地进入医院业务系统”。只要把分层、状态机、模型服务、适配层、审计日志这几块设计好,后续无论是换模型、改模板、加功能,都只是在局部迭代,不会推倒重来。
如果只记住一条建议:先画清楚状态机,再调模型。状态机不稳定,模型再强也落不了地。