用 Milvus 和 Unstructured.io 搭建个人 EHR RAG 系统

crumpled hospital printouts、blurry scans 和 nested PDFs 堆成山,三年前的血检结果几乎无处可寻,医生的手写体直接把 OCR 变成最终 BOSS。教程用 Milvus 向量数据库和 Unstructured.io 把这些混乱数据转成可对话的个人 EHR RAG 系统。

Unstructured.io 把医疗 PDF 和扫描件拆成可检索块

Unstructured.io 的核心能力在于文档分区。它能读取嵌套 PDF、扫描图像和包含表格的医疗报告,将它们拆解为更小的语义单元。这些单元不再是整页 PDF,而是带有上下文的文本块、表格数据和图片描述。

在处理 scanned images 时,工具会先尝试 OCR,把医生手写体和打印化验单转化为机器可读文本。尽管手写识别准确率仍不完美,但它把原本无法搜索的内容变成了可向量化的字符串。nested PDFs 里层层嵌套的检验报告、影像描述和出院小结也被逐层展开,避免了传统 PDF 解析器只抓到封面的尴尬。

这一步是整个 RAG 流程的起点。没有高质量的分块,后续的向量嵌入就缺少清晰边界,检索结果会混杂无关段落。Unstructured.io 提供的分区策略允许开发者选择按标题、段落或表格切分,医疗场景下特别适合把同一份化验单的不同项目拆成独立块,便于后续精确匹配。

实际使用中,用户只需把所有历史病历文件丢进指定文件夹,Unstructured.io 就能批量完成解析和清洗工作,输出结构化的 JSON 列表,每个元素都包含原始文本、元数据和分区类型。这些输出直接成为下一步嵌入模型的输入。

整个过程本地运行,不需要把原始医疗文件上传到云端,这为后续隐私讨论埋下伏笔。但也必须承认,目前 OCR 对潦草手写体的识别仍有明显误差,部分血检项目名称可能被错认,需要人工校对或后续提示工程弥补。

Milvus 向量数据库让医疗记录支持语义检索

Milvus 专门用来存储和检索高维向量。当 Unstructured.io 输出的文本块被送入嵌入模型(例如 sentence-transformers 或 OpenAI 的 text-embedding 系列)后,每一段医疗记录都变成一个固定维度的向量。这些向量被插入 Milvus 集合,并建立 IVF 或 HNSW 索引。

与传统关键词搜索不同,Milvus 做的是语义相似度匹配。用户输入“我三年前的血脂指标怎么样”,系统会把这句话也转为向量,然后在 Milvus 中查找余弦相似度最高的若干医疗文本块。即使原始记录里没有出现“血脂”这个词,只要上下文描述的是胆固醇、甘油三酯等项目,Milvus 仍能把它找出来。

医疗记录里充斥着同义表述、缩写和专业术语,关键词搜索很容易漏掉。Milvus 把这种模糊匹配变成了可量化、可排序的操作,大幅提升了个人健康数据的可用性。它还支持混合检索,允许同时使用向量相似度和元数据过滤,比如只看“2021 年”或“某三甲医院”的记录。

在 RAG 架构中,Milvus 扮演知识库的角色。当用户提出问题时,先从 Milvus 召回最相关的 top-k 块,再把这些块连同问题一起塞给大语言模型,让模型生成自然语言回答。这样既避免了幻觉,又把回答严格锚定在用户自己的历史记录上。

Milvus 支持本地部署,通过 Docker 或 Kubernetes 都能跑在个人电脑或 NAS 上,数据完全不离开用户设备。这一点对医疗隐私至关重要,但也带来资源消耗的现实问题——向量索引需要较多内存,普通笔记本跑几千页病历还行,超过上万页就需要考虑扩容。

个人 EHR RAG 的端到端构建流程

整个 pipeline 从数据摄取开始。用户把历年纸质报告扫描成 PDF,或直接收集医院导出的电子文件,全部放入一个目录。Unstructured.io 读取这些文件,执行分区、OCR 和元数据提取,输出干净的文档块列表。

下一步是向量化。选择一个嵌入模型,把每个文本块转为向量,同时保留原始文件名、检查日期、医院名称等元数据。这些向量和元数据一起插入 Milvus 集合,并创建合适的索引。

查询阶段,用户通过一个简单的聊天界面输入问题。问题先被同一个嵌入模型转为向量,Milvus 执行相似度搜索,返回最相关的若干块。这些块被组装成提示词,连同系统指令一起发给本地或云端的大语言模型。模型根据用户自己的医疗历史生成回答,并可引用具体出处。

整个流程可以封装成一个 Streamlit 或 Gradio 应用,也能做成桌面客户端。Milvus 提供 Python SDK,Unstructured.io 同样有现成 SDK,开发者只需几百行代码就能把两个工具串起来。教程中强调了本地运行的重要性,所有组件都可以部署在个人设备上,避免数据泄露。

当然,实际搭建时还需要处理嵌入模型的选择、索引参数调优和检索后处理的细节。不同嵌入模型对医疗术语的理解能力差异明显,需要根据中文病历特点进行测试。

本地部署仍面临医疗隐私合规风险

即使全部跑在本地,把个人医疗记录存入向量数据库仍不是零风险。Milvus 本身不提供加密存储功能,用户必须自行启用磁盘加密或容器层面的安全措施。数据库一旦被同一设备上的其他程序访问,历史病历就可能泄露。

中国《个人信息保护法》和《数据安全法》对健康数据有明确要求,个人搭建的系统很难满足医疗机构级别的访问控制、审计日志和数据最小化原则。如果未来用户想把这套系统分享给家人或医生,就涉及数据共享的合规问题。

另一个现实挑战是备份。向量数据库的索引文件和原始 PDF 需要同步备份,一旦硬盘损坏,重建索引需要重新跑一遍嵌入流程,耗时耗力。加密备份又带来密钥管理的新麻烦。

普通用户往往缺乏安全意识,可能直接把 Milvus 暴露在局域网内,或使用弱密码保护界面。这些操作都可能让精心搭建的个人 EHR 变成隐私漏洞。教程虽然强调本地部署,但并未提供完整的威胁模型和加固建议,用户需要额外补课。

目前还不清楚普通消费者级硬件上运行这类系统是否能满足未来可能出现的更严格合规要求。医疗数据一旦被认定为敏感信息,个人 RAG 系统可能需要经过第三方审计才能在某些场景下合法使用。

普通用户能用自然语言调取多年病历

对大多数人来说,最大的痛点就是找不到旧记录。体检报告、手术记录、影像报告分散在不同医院的 App、邮箱和纸质文件中,查找一次慢性病趋势往往要花几个小时。

这个个人 EHR RAG 系统让用户可以用大白话提问:“我 2022 年甲状腺功能怎么样?”“上次肺部 CT 报告里提到结节大小是多少?”系统从所有历史文件中召回相关段落,再用自然语言总结趋势,甚至可以回答“我的血糖控制是变好了还是变差了”。

这种交互方式极大降低了使用门槛。不需要学习复杂的查询语法,也不需要记住每份报告的文件名。多年积累的医疗数据终于变成一个可以对话的知识库,普通人也能快速获得连续性洞察。

举例来说,一个糖尿病患者可以问“过去五年我的 HbA1c 趋势如何”,系统会把历次化验单里的数值提取出来,生成简单的时间线描述,帮助患者判断治疗效果。这在过去几乎不可能靠人工完成。

当然,回答质量高度依赖 OCR 准确率和嵌入模型对医疗语境的理解。目前系统还不能完全替代专业医师判断,但它能把患者自己最关心的历史数据快速摆到面前,减少信息不对称。

个人 RAG 与医院官方 EHR 的互补边界

医院的官方 EHR 系统记录的是临床决策、处方和检查结果,具有法律效力。个人搭建的 RAG 系统无法替代它,也不能用于医疗纠纷举证或保险理赔。

它的价值在于填补个人访问空白。很多医院的患者端 App 只提供最近一两年的数据,旧纸质报告无法电子化检索。个人 RAG 把这些碎片全部收拢,变成统一入口。

两者边界清晰:官方 EHR 负责权威记录和医生查看,个人 RAG 负责患者自己长期跟踪和自然语言查询。患者可以在就诊前用个人系统快速整理过去五年关键指标,打印或口头告诉医生,节省沟通成本。

未来如果医院开放标准 API,个人 RAG 可以作为补充,从官方系统定期同步结构化数据,进一步提升准确性。但在现阶段,它主要解决的是“我的历史数据在哪里”这个基础问题。

这个定位决定了它的适用人群:对自身健康管理有较高主动性、积累了较多纸质或零散电子记录的用户。技术爱好者可以快速上手,而普通用户仍需面对安装、OCR 纠错和隐私管理的门槛。

总体来看,Milvus 和 Unstructured.io 的组合提供了一条可行的技术路径,让个人医疗数据从死文档变成活知识。但要真正普及,还需要在易用性、准确率和合规工具链上继续迭代。

参考来源