医疗NLP实战:从“患者:天黑了”到结构化症状的智能抽取与标准化 最近在医疗信息化项目中我遇到了一个看似简单却让团队头疼不已的问题如何让系统“理解”并准确响应“患者天黑了”这样的自然语言描述这背后远不止是文本匹配那么简单。这并非一个孤立的案例。在电子病历录入、医患沟通记录、智能分诊等场景中医护人员和患者习惯使用大量口语化、非结构化的描述。比如“患者主诉心慌感觉天要塌了”、“家属描述病人这几天没精神像霜打的茄子”。这些描述富含临床价值但传统的基于关键词或固定模板的信息系统却难以有效捕捉和处理。工程师往往需要花费大量时间在业务逻辑中硬编码各种“if-else”规则结果却是规则越叠越复杂系统越改越脆弱最终变成一个难以维护的“补丁怪兽”。“患者天黑了”这句话就是一个绝佳的切入点。它可能指向多种临床情况可能是抑郁症患者的“晨重暮轻”症状描述可能是白内障患者视物模糊的直观表达也可能是脑血管病患者的视觉障碍主诉。如果系统只能简单记录文本那么这些宝贵的诊断线索就流失了。本文要解决的正是如何利用自然语言处理技术将这类口语化、场景化的患者主诉转化为结构化、可计算、能辅助临床决策的标准化数据。我们将从一个具体的工程实践出发探讨如何构建一个轻量级、可集成、高可解释的临床文本信息抽取与标准化服务。读完本文你将能掌握从零搭建一个服务它不仅能理解“天黑了”背后的含义还能将其关联到标准的医学术语库并输出可供电子病历系统直接使用的结构化数据。更重要的是你会理解这套方法背后的设计哲学知道如何将其适配到“心慌”、“没力气”、“肚子胀”等更广泛的场景中真正提升医疗信息化系统的“智商”与实用性。1. 核心问题为什么“天黑了”难住了医疗系统在深入技术方案之前我们必须先厘清问题的本质。医疗信息系统处理自然语言主诉的难点并非技术本身不成熟而在于医疗领域的特殊性与工程落地的复杂性。1.1 医疗文本的独特性高度口语化与隐喻性患者常用生活化语言描述不适如“天黑了”视力障碍/抑郁、“心里像揣了只兔子”心悸、“头要炸了”剧烈头痛。这些表述与标准医学术语存在巨大鸿沟。一词多义与多词一义“晕”可能指头晕Dizziness、晕厥Syncope或眩晕Vertigo三者病因完全不同。反之“急性上腹痛”和“突发胃脘部疼痛”可能描述同一件事。上下文强依赖“天黑了”若出自眼科患者之口优先考虑视觉问题若出自精神科患者则更可能指向情绪或感知障碍。缺乏上下文准确解读几乎不可能。非结构化与噪声主诉文本常夹杂无关信息、语法错误、地方方言如“大夫我这两天啊就那个眼睛一到下午就看不清跟天黑了似的”。1.2 传统解决方案的瓶颈关键词匹配构建“黑-视力”的映射规则。但无法处理“看不见了”、“眼前发蒙”等同义表述且极易误判如“黑便”。正则表达式模式越写越复杂可维护性极差无法应对语言的多变性。人工模板录入强制医护人员从标准术语库中选择。这增加了操作负担且无法覆盖所有口语表达最终往往导致“模板归模板文本备注里再写一遍”的双轨制数据依然非结构化。1.3 我们需要的新方案一个理想的解决方案应该具备以下能力语义理解能抓住“天黑了”的核心是“视觉光线感知减弱”或“时间感知异常”。术语标准化能将理解的核心语义映射到如“SNOMED CT”、“ICD-10”或本地化诊断库中的标准概念如“视力模糊”、“黄昏盲症”、“抑郁情绪晨重暮轻”。上下文感知能结合患者科室、病史、性别、年龄等信息进行消歧。轻量可集成能以微服务或API形式方便地嵌入现有HIS、EMR系统而不是推翻重来。结果可解释不仅给出标准术语还能提供置信度和推理依据让医生能够审核和信任。接下来的内容我们将围绕如何构建这样一个服务展开。2. 技术选型从规则到模型的演进之路面对这个问题技术路径大致可分为三类基于规则、基于传统机器学习、基于深度学习/大语言模型。我们将分析其优劣并给出当前性价比最高的混合架构建议。2.1 方案对比方案核心思想优点缺点适用场景纯规则引擎专家编写大量“if-else”或词典规则。可解释性极强开发直接无数据依赖。维护成本高泛化能力差难以覆盖长尾表达。术语非常固定、表述极其有限的场景。传统机器学习将文本视为词袋使用SVM、CRF等模型进行分类或序列标注。有一定泛化能力比规则系统更灵活。严重依赖特征工程难以捕捉深层语义和上下文性能有瓶颈。中等规模标注数据任务相对明确如命名实体识别。深度学习/预训练模型使用BERT、RoBERTa等模型进行文本表征完成分类、NER、关系抽取。语义理解能力强泛化性能好减少特征工程。需要一定量标注数据模型有一定黑盒性计算资源要求较高。数据量较充足追求高准确率和泛化能力的场景。大语言模型提示工程直接调用GPT-4、文心一言等API通过精心设计的Prompt进行标准化。开发极快零样本或少样本能力惊人理解复杂语义。成本高响应延迟不稳定数据隐私风险结果不可控。快速原型验证处理极其复杂、开放的语义理解任务。2.2 我们的混合架构决策对于“患者主诉标准化”这个任务我们推荐“预训练模型微调 轻量规则后处理”的混合架构。这是目前平衡效果、成本、可控性和落地难度的最佳选择。核心使用一个在中文医学文本上预训练过的模型如BERT-MedBERT、RoBERTa-wwm进行微调完成主诉实体识别和意图分类。辅助构建一个轻量级的同义词词典和术语映射规则库对模型结果进行校准、纠错和标准化编码映射。为什么不是纯LLM尽管LLM能力强大但在生产环境中稳定性、成本、数据安全和结果一致性是首要考量。混合方案将LLM的“智能”固化到一个专有、可控的小模型中更适合企业级部署。3. 环境准备与工具清单在开始构建之前请确保你的开发环境已就绪。3.1 基础软件环境操作系统Linux (Ubuntu 20.04 / CentOS 7) macOS 或 Windows 10/11 (WSL2推荐)。Python版本 3.8 或 3.9。这是大多数深度学习框架的稳定支持版本。包管理使用pip和virtualenv或conda创建独立的Python环境避免依赖冲突。3.2 核心Python库我们将使用PyTorch作为深度学习框架Transformers库加载预训练模型。# 创建并激活虚拟环境 python -m venv med_ner_env source med_ner_env/bin/activate # Linux/macOS # med_ner_env\Scripts\activate # Windows # 安装PyTorch (请根据CUDA版本访问官网获取对应命令) # 例如无GPU或CUDA 11.3 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu113 # 安装Transformers和其它必要库 pip install transformers pip install datasets scikit-learn pandas tqdm3.3 模型与数据准备预训练模型我们将使用哈工大讯飞联合实验室开源的RoBERTa-wwm-ext模型它在中文通用文本上表现优异。也可以尝试BERT-base-Chinese。# 模型会在代码运行时自动从Hugging Face Hub下载 # 国内网络可能较慢可提前下载或使用镜像源术语标准库需要一份标准医学术语列表及其编码如ICD-10。可以从公开医学知识图谱如CN-DBpedia或购买专业数据服务获取。本文为演示将创建一个简易的映射文件。标注数据这是模型微调的关键。你需要一批已标注的“患者主诉-标准术语”配对数据。可以从公开医学NLP竞赛数据集如CHIP、CMeEE中抽取相关部分或进行人工标注。本文后续会提供一个模拟数据生成脚本和标注示例。4. 项目架构与核心流程拆解我们的服务将分为离线训练和在线服务两个部分。4.1 整体架构图文字描述离线训练流水线输入标注好的医疗文本数据集。过程数据预处理 - 构建标签体系 - 加载预训练模型 - 模型微调 - 模型评估 - 模型导出。输出训练好的模型文件(pytorch_model.bin)和配置文件。在线推理服务输入新的患者主诉文本如“患者天黑了”。过程文本预处理 - 模型推理实体识别分类- 规则后处理同义词校准、术语映射- 结果组装。输出结构化JSON包含原始文本、识别出的症状实体、对应的标准术语编码、置信度等。4.2 核心流程步骤详解步骤一定义标签体系。我们需要决定模型识别什么。例如定义实体标签SYMPTOM(症状)BODY(身体部位)TIME(时间)等。对于“天黑了”我们期望模型识别出SYMPTOM。步骤二准备训练数据。将标注数据转换为模型可接受的格式通常是token序列和对应的label序列。步骤三模型选择与微调。选择预训练模型在其顶层添加一个用于序列标注的分类层然后用我们的医疗数据训练这个新层及部分底层参数。步骤四构建术语映射器。建立一个从模型识别出的实体词到标准术语编码如ICD-10 R代码的映射表。这部分需要医学知识。步骤五部署推理服务。使用Flask或FastAPI将模型封装成 RESTful API供其他系统调用。5. 从零开始数据准备与模型微调实战这是最核心的部分。我们将一步步创建模拟数据、定义任务、并微调模型。5.1 创建模拟训练数据由于真实医疗标注数据获取困难我们先创建一个小的模拟数据集来演示流程。# 文件create_sample_data.py import json import random # 模拟症状和对应的标准术语编码虚构 symptom_mapping { “天黑了”: {“std_term”: “视力模糊” “code”: “H53.8”} “看不清”: {“std_term”: “视力模糊” “code”: “H53.8”} “心慌”: {“std_term”: “心悸” “code”: “R00.2”} “心跳快”: {“std_term”: “心悸” “code”: “R00.2”} “头疼”: {“std_term”: “头痛” “code”: “R51”} “头晕”: {“std_term”: “头晕” “code”: “R42”} “没力气”: {“std_term”: “乏力” “code”: “R53”} “肚子胀”: {“std_term”: “腹胀” “code”: “R14.0”} } # 模拟生成带标注的句子 def generate_annotated_sentence(symptom_key): templates [ “患者主诉{}。” “病人说{}。” “家属描述{}。” “{}” ] sentence random.choice(templates).format(symptom_key) # 简单的标注假设症状词出现在句子中且只有一个实体 start_idx sentence.find(symptom_key) end_idx start_idx len(symptom_key) return { “text”: sentence “entities”: [{ “start_idx”: start_idx “end_idx”: end_idx “entity”: symptom_key “type”: “SYMPTOM” }] } # 生成数据 data [] for symptom in symptom_mapping.keys(): for _ in range(20): # 每个症状生成20条变体 data.append(generate_annotated_sentence(symptom)) # 保存为JSONL格式每行一个JSON with open(‘train_data.jsonl’ ‘w’ encoding‘utf-8’) as f: for item in data: f.write(json.dumps(item ensure_asciiFalse) ‘\n’) print(f“已生成 {len(data)} 条模拟训练数据到 train_data.jsonl”)5.2 将数据转换为模型训练格式我们需要将JSONL数据转换为token和label的序列。这里使用BIO标注法。# 文件data_preprocess.py import json from transformers import BertTokenizerFast tokenizer BertTokenizerFast.from_pretrained(‘hfl/chinese-roberta-wwm-ext’) def convert_to_features(example): text example[‘text’] entities example[‘entities’] # 1. 对文本进行tokenization tokens tokenizer.tokenize(text) # 初始化标签为 ‘O’ (Outside) labels [‘O’] * len(tokens) # 2. 将字符级别的实体标注映射到token级别这是一个简化处理真实场景需处理word piece # 注意这是一个复杂步骤简化起见我们假设实体边界与token边界对齐。 # 实际项目应使用更精确的对齐算法。 tokenized tokenizer(text return_offsets_mappingTrue) token_offsets tokenized[‘offset_mapping’] for entity in entities: start_char end_char entity[‘start_idx’] entity[‘end_idx’] entity_type entity[‘type’] # 找到被这个实体覆盖的所有token token_indices [] for idx (token_start token_end) in enumerate(token_offsets): if token_start start_char and token_end end_char: token_indices.append(idx) elif not (token_end start_char or token_start end_char): # 部分重叠简化处理也算入实体实际应更精细 token_indices.append(idx) if token_indices: # 标注为BIO格式 labels[token_indices[0]] f‘B-{entity_type}’ for idx in token_indices[1:]: labels[idx] f‘I-{entity_type}’ return {“tokens”: tokens “ner_tags”: labels} # 读取并处理数据 processed_data [] with open(‘train_data.jsonl’ ‘r’ encoding‘utf-8’) as f: for line in f: example json.loads(line.strip()) processed_data.append(convert_to_features(example)) # 查看一个样本 print(“原始文本:” processed_data[0].get(‘text’ ‘N/A’)) print(“Tokens:” processed_data[0][‘tokens’]) print(“Labels:” processed_data[0][‘ner_tags’])5.3 定义模型与训练脚本我们将使用Transformers库的BertForTokenClassification模型。# 文件train_model.py import torch from transformers import BertForTokenClassification BertTokenizerFast Trainer TrainingArguments from datasets import Dataset import json # 1. 加载处理好的数据假设已保存为processed_train.json # 这里简化直接使用上一步的processed_data前几条 label_list [‘O’ ‘B-SYMPTOM’ ‘I-SYMPTOM’] # 我们的标签列表 label2id {label: idx for idx label in enumerate(label_list)} id2label {idx: label for idx label in enumerate(label_list)} # 模拟一个Dataset def gen(): for item in processed_data[:100]: # 用前100条做演示 # 将标签文本转为ID label_ids [label2id.get(tag 0) for tag in item[‘ner_tags’]] # Tokenizer将tokens转为input_ids encoding tokenizer(item[‘tokens’] is_split_into_wordsTrue padding‘max_length’ truncationTrue max_length128) # 对齐labels因为padding和truncation labels [-100] * 128 # -100被CrossEntropyLoss忽略 real_labels label_ids[:128] labels[:len(real_labels)] real_labels encoding[‘labels’] labels yield encoding dataset Dataset.from_generator(gen) # 2. 加载预训练模型和分词器 model_name ‘hfl/chinese-roberta-wwm-ext’ tokenizer BertTokenizerFast.from_pretrained(model_name) model BertForTokenClassification.from_pretrained(model_name num_labelslen(label_list) id2labelid2label label2idlabel2id) # 3. 设置训练参数 training_args TrainingArguments( output_dir‘./results’ # 输出目录 num_train_epochs3 # 训练轮数 per_device_train_batch_size8 # 每设备批大小 warmup_steps500 # 预热步数 weight_decay0.01 # 权重衰减 logging_dir‘./logs’ # 日志目录 logging_steps10 save_steps500 evaluation_strategy“no” # 演示用不验证 ) # 4. 创建Trainer并训练 trainer Trainer( modelmodel argstraining_args train_datasetdataset ) trainer.train() print(“训练完成”) model.save_pretrained(‘./symptom_ner_model’) tokenizer.save_pretrained(‘./symptom_ner_model’)6. 构建推理服务与规则后处理模型训练好后我们需要将其部署为服务并加入术语映射的规则层。6.1 创建推理API使用FastAPI# 文件inference_api.py from fastapi import FastAPI HTTPException from pydantic import BaseModel from transformers import BertForTokenClassification BertTokenizerFast import torch import json from typing import List app FastAPI(title“患者主诉标准化服务”) # 1. 加载模型和分词器 model_path ‘./symptom_ner_model’ tokenizer BertTokenizerFast.from_pretrained(model_path) model BertForTokenClassification.from_pretrained(model_path) model.eval() # 设置为评估模式 # 2. 加载术语映射规则示例实际应从数据库或文件加载 term_map { “视力模糊”: {“code”: “H53.8” “desc”: “其他视力障碍”} “心悸”: {“code”: “R00.2” “desc”: “心悸”} “头痛”: {“code”: “R51” “desc”: “头痛”} “头晕”: {“code”: “R42” “desc”: “头晕和眩晕”} “乏力”: {“code”: “R53” “desc”: “不适和疲劳”} “腹胀”: {“code”: “R14.0” “desc”: “腹胀感”} } # 同义词映射模型识别出的词 - 标准术语 synonym_to_std { “天黑了”: “视力模糊” “看不清”: “视力模糊” “心慌”: “心悸” “心跳快”: “心悸” “头疼”: “头痛” “头晕”: “头晕” # 本身已是标准词 “没力气”: “乏力” “肚子胀”: “腹胀” } class SymptomRequest(BaseModel): text: str patient_dept: str None # 可选患者科室用于消歧 class Entity(BaseModel): text: str start: int end: int type: str confidence: float class StandardizedResult(BaseModel): original_text: str entities: List[Entity] standardized_terms: List[dict] # 标准化后的术语列表 def predict_entities(text: str): 使用模型预测实体 inputs tokenizer(text return_tensors“pt” paddingTrue truncationTrue max_length128) with torch.no_grad(): outputs model(**inputs) predictions torch.argmax(outputs.logits dim-1)[0].tolist() tokens tokenizer.convert_ids_to_tokens(inputs[‘input_ids’][0]) labels [model.config.id2label[p] for p in predictions] # 将token序列转换回实体简化版忽略subword问题 entities [] current_entity None for i (token label) in enumerate(zip(tokens labels)): if label.startswith(‘B-’): if current_entity: entities.append(current_entity) current_entity {‘text’: token ‘start’: i ‘end’: i ‘type’: label[2:] ‘token_start’: i} elif label.startswith(‘I-’) and current_entity and label[2:] current_entity[‘type’]: current_entity[‘text’] token.replace(‘##’ ‘’) current_entity[‘end’] i elif label ‘O’ and current_entity: entities.append(current_entity) current_entity None if current_entity: entities.append(current_entity) # 将token位置转换为字符位置简化处理 char_entities [] for ent in entities: # 这里需要更精确的offset mapping为简化我们返回token位置 # 实际应用应使用tokenizer的return_offsets_mapping功能 char_entities.append(Entity( textent[‘text’] startent[‘token_start’] # 注意这里是token索引非字符索引 endent[‘end’] typeent[‘type’] confidence0.95 # 简化实际应从模型输出计算 )) return char_entities app.post(“/standardize” response_modelStandardizedResult) async def standardize_symptom(req: SymptomRequest): try: # 1. 模型推理识别实体 raw_entities predict_entities(req.text) # 2. 规则后处理同义词映射 术语标准化 standardized_terms [] for ent in raw_entities: if ent.type ‘SYMPTOM’: recognized_text ent.text # 同义词映射 std_term_text synonym_to_std.get(recognized_text recognized_text) # 术语编码映射 term_info term_map.get(std_term_text) if term_info: standardized_terms.append({ “recognized_symptom”: recognized_text “standard_term”: std_term_text “code”: term_info[“code”] “description”: term_info[“desc”] “confidence”: ent.confidence }) return StandardizedResult( original_textreq.text entitiesraw_entities standardized_termsstandardized_terms ) except Exception as e: raise HTTPException(status_code500 detailf“处理失败: {str(e)}”) if __name__ ‘__main__’: import uvicorn uvicorn.run(app host“0.0.0.0” port8000)6.2 测试API服务启动服务后我们可以使用curl或 Pythonrequests进行测试。# 启动服务 python inference_api.py# 文件test_api.py import requests import json url “http://127.0.0.1:8000/standardize” data {“text”: “患者主诉这两天一到下午就看不清感觉天黑了。”} response requests.post(url jsondata) if response.status_code 200: result response.json() print(json.dumps(result indent2 ensure_asciiFalse)) else: print(“请求失败:” response.status_code response.text)预期输出结构{ “original_text”: “患者主诉这两天一到下午就看不清感觉天黑了。” “entities”: [ { “text”: “看不清” “start”: 10 “end”: 12 “type”: “SYMPTOM” “confidence”: 0.95 } { “text”: “天黑了” “start”: 16 “end”: 18 “type”: “SYMPTOM” “confidence”: 0.96 } ] “standardized_terms”: [ { “recognized_symptom”: “看不清” “standard_term”: “视力模糊” “code”: “H53.8” “description”: “其他视力障碍” “confidence”: 0.95 } { “recognized_symptom”: “天黑了” “standard_term”: “视力模糊” “code”: “H53.8” “description”: “其他视力障碍” “confidence”: 0.96 } ] }7. 常见问题、优化策略与生产部署建议7.1 常见问题排查表问题现象可能原因排查方式解决方案模型识别不出实体1. 训练数据不足或质量差。2. 文本表述超出训练集范围。3. 预处理分词对齐错误。1. 检查输入文本是否与训练数据分布相似。2. 使用tokenizer单独分词查看token序列。3. 分析模型预测的原始logits。1. 增加相关领域的训练数据。2. 引入同义词扩充和数据增强。3. 检查并修复数据标注与tokenization的对齐代码。实体识别错误类型或边界1. 标签定义模糊。2. 实体边界在分词时被切分。3. 样本中存在嵌套实体。1. 复核错误样本的标注。2. 使用return_offsets_mapping仔细调试位置映射。1. 细化标签体系增加上下文特征。2. 采用更适应中文的模型如LERT或调整分词策略。3. 对于嵌套实体考虑使用span-based模型如SpanBERT。术语映射失败1. 同义词词典覆盖不全。2. 识别出的实体词与词典键不匹配。1. 查看recognized_symptom是否在synonym_to_std中。2. 对识别文本进行归一化如去除标点、统一简繁体。1. 持续维护和扩充同义词词典可考虑从医学知识图谱自动抽取。2. 使用编辑距离或词向量相似度进行模糊匹配。API服务响应慢1. 模型加载在每次请求时发生。2. 未使用GPU推理。3. 序列长度过长。1. 检查服务启动日志确认模型是否只加载一次。2. 监控GPU使用率。3. 分析输入文本长度。1. 确保模型在服务启动时单例加载。2. 部署时使用GPU并考虑模型量化如torch.quantization。3. 设置合理的max_length对超长文本分段处理。内存占用过高1. 模型过大。2. 批处理设置不当。使用nvidia-smi或psutil监控内存。1. 尝试使用更小的预训练模型如BERT-tiny。2. 在服务端限制并发数和批处理大小。7.2 性能与效果优化策略数据层面数据增强对已有标注数据使用同义词替换、随机插入、删除、回译等方法生成新数据。主动学习将模型预测置信度低的样本交给专家标注迭代提升模型。领域适配如果条件允许在大量医学文献、电子病历无监督文本上继续预训练Domain-Adaptive Pretraining。模型层面模型轻量化使用知识蒸馏将大模型的能力迁移到小模型或使用模型剪枝、量化技术减少部署体积和加速。集成上下文在模型输入中除了当前主诉语句还可以拼接患者基本信息如年龄、性别、科室作为辅助信息帮助消歧。尝试专用模型使用在中文医学文本上预训练的模型如MedBERT、Chinese-BERT-wwm-医学版通常比通用模型起点更高。系统层面缓存对常见的、标准化的主诉结果进行缓存避免重复模型计算。异步处理对于非实时性要求高的场景如批量病历后结构化可以采用消息队列进行异步推理。服务化与监控使用Docker容器化部署通过Kubernetes管理。集成Prometheus和Grafana监控服务QPS、延迟、错误率。7.3 生产环境部署清单[ ]环境隔离使用Docker镜像封装模型、代码和依赖。[ ]配置外化将模型路径、术语映射文件路径、服务端口等通过环境变量或配置文件管理。[ ]健康检查为FastAPI服务添加/health端点供容器编排系统探活。[ ]日志标准化集成结构化日志如JSON格式记录每一次请求的输入、输出、耗时和错误信息便于排查。[ ]限流与熔断使用API网关或FastAPI中间件实现限流防止服务被突发流量打垮。[ ]版本管理模型文件和服务代码应有明确的版本号支持灰度发布和回滚。[ ]隐私与安全患者文本数据需加密传输服务部署在内网并遵循《个人信息保护法》和医疗数据安全规范。模型文件也应视为重要资产进行保护。8. 总结与展望让系统真正“听懂”患者通过本文的实践我们成功搭建了一个能够理解“患者天黑了”并对其进行标准化的原型系统。这个过程清晰地揭示了一条路径将前沿的NLP模型能力与扎实的领域知识规则、术语库相结合是解决医疗信息化中自然语言处理难题的高效路径。我们不仅得到了一个可运行的API更重要的是掌握了一套方法论问题定义从业务痛点出发明确要抽取什么信息症状实体输出什么格式标准术语编码。技术选型根据数据、算力和精度要求选择“预训练模型微调规则后处理”的混合架构。数据工程构建高质量的标注数据是模型效果的基石仿真数据只是起点。模型迭代训练、评估、分析错误、补充数据、再训练这是一个持续的过程。系统集成模型最终要变成稳定、可扩展、易监控的服务才能产生业务价值。下一步可以深入的方向关系抽取不仅识别症状还能识别症状与身体部位“左眼视力模糊”、严重程度“轻微头晕”、时间频率“持续三天”之间的关系。多模态理解结合患者影像报告、检验数值等多源信息进行综合判断。诊断建议初筛在标准化症状的基础上结合知识图谱为医生提供可能的诊断方向参考需非常谨慎仅作为辅助。持续学习平台构建一个平台让医生可以方便地纠正系统的错误识别结果并实时反馈到模型优化流程中。技术的最终目的是服务于人。当我们的系统能够更准确地“听懂”患者那些口语化、情绪化的描述时它就在医生和患者之间架起了一座更通畅的桥梁让宝贵的临床信息得以高效、准确地流转最终助力于诊疗质量的提升。从这个角度看解决好“天黑了”这个问题意义远超技术本身。