引言
"临床数据永不离开设备。"
这是"每日一个开源项目"系列的第129篇文章 。今天的主角是 OpenMed------一个本地优先的医疗 AI 库,由 HuggingFace 研究员 Maziyar Panahi 开发,专门解决医疗场景下的隐私问题。
医疗 AI 的现状:绝大多数工具需要把患者数据发送到云端,换回结构化结果。这在合规层面是个持续的风险点------HIPAA、GDPR、各国的数据保护法规对患者数据的处理方式有明确约束,而"数据上云"本身就已经触碰了很多医疗机构的红线。
OpenMed 的设计方向是把处理能力搬到本地:1000 多个生物医学 NLP 模型,全部在设备上跑,不发出任何网络请求,支持从 Python 服务到 iOS App 的多种部署场景。
你将学到什么
- OpenMed 的核心架构:为什么选择编码器 Transformer,而非生成式模型
- 13 个临床 NLP 域:从疾病到基因组的 NER 覆盖
- PII 脱敏的工程设计:如何覆盖全部 18 个 HIPAA Safe Harbor 标识符
- 多平台支持:Python/MLX、Swift/OpenMedKit、Docker/FastAPI
- v1.2.0 引入的零样本能力:ZeroShot NER 和关系抽取
- 在 Apple Silicon 上的性能表现
前置知识
- 了解基本的 NLP 概念(命名实体识别、Transformer)
- 有 Python 使用经验
- 对医疗数据隐私合规有基本了解(HIPAA、数据脱敏的背景)
项目背景
项目简介
OpenMed 是一套本地优先的医疗 AI 工具库,定位是"把临床文本变成结构化洞察,且数据全程不离开安全环境"。
它的核心不是生成式 AI,而是用编码器 Transformer(BERT、ELECTRA、DeBERTa 系列)做提取和分类。这个技术选型背后有具体原因:医疗场景里最常见的任务是"从文本里找到什么",而不是"生成新的文本"------识别病名、提取药物、定位患者 ID,这些任务用分类模型做更精准、更可控、也更容易审计。
arXiv 论文(2508.01630)报告在 12 个生物医学 NER 基准测试中 10 个达到 SOTA。
作者/团队介绍
- 作者: Maziyar Panahi
- 背景: HuggingFace 研究员,生物医学 NLP 领域,SpaCy 和 HuggingFace Transformers 社区贡献者
- License: Apache-2.0
- 最新版本: v1.5.5(2026年6月)
项目数据
- ⭐ GitHub Stars: 2,800+
- 🍴 Forks: 274+
- 📦 HuggingFace 模型: 1,000+
- 🌍 支持语言: 12 种
- 📄 License: Apache-2.0
主要功能
核心作用
OpenMed 的工作流很直接:
markdown
临床文本输入
↓
本地模型推理(BERT/ELECTRA/DeBERTa)
↓
┌─────────────────────────────────┐
│ NER:识别疾病、药物、基因等实体 │
│ PII 脱敏:检测并处理患者标识符 │
│ 关系抽取:实体间的语义关系 │
└─────────────────────────────────┘
↓
结构化输出(数据全程不离开本地)
使用场景
-
临床文本结构化
- 从病历、出院记录中抽取疾病名称、药物、解剖位置
- 支持 13 个生物医学 NER 域:化学品、疾病、基因、蛋白质、物种、解剖、肿瘤学等
-
患者数据脱敏
- 覆盖全部 18 个 HIPAA Safe Harbor 标识符
- 支持遮蔽(
[NAME])、替换(Faker 合成假数据)、哈希、日期偏移四种处理方式
-
iOS/macOS 医疗 App 开发
- OpenMedKit Swift 包提供原生接口,PHI 数据不离开设备
- v1.2.0 内置的 iOS Scan Demo:扫描 → OCR 审查 → 脱敏 → 临床抽取 → 导出,五步完整工作流
-
企业级医疗系统集成
- Docker/FastAPI REST API,方便嵌入现有工作流
- AWS SageMaker Marketplace 托管版本,sub-100ms 延迟端点
快速开始
安装:
bash
# CPU 版本
pip install openmed
# Apple Silicon(MLX 加速)
pip install openmed[mlx]
# CUDA GPU
pip install openmed[cuda]
基础 NER:
python
from openmed import analyze_text
# 疾病识别
result = analyze_text(
"Patient started on imatinib for CML.",
model_name="disease_detection_superclinical"
)
# 输出:{entities: [{text: "CML", label: "DISEASE", start: 30, end: 33}], ...}
# 药物识别
result = analyze_text(
"Prescribed metformin 500mg twice daily for type 2 diabetes.",
model_name="pharma_detection_superclinical"
)
PII 脱敏:
python
from openmed import deidentify
text = "Patient John Smith (DOB: 1985-03-15, SSN: 123-45-6789) was admitted..."
# 遮蔽模式
result = deidentify(text, method="mask")
# "Patient [NAME] (DOB: [DATE], SSN: [SSN]) was admitted..."
# Faker 替换(保持文本可读性,同时完全匿名化)
result = deidentify(text, method="replace")
# "Patient Michael Johnson (DOB: 1972-08-22, SSN: 987-65-4321) was admitted..."
批量处理:
python
from openmed import BatchProcessor
texts = [record1, record2, record3, ...]
processor = BatchProcessor(
operation="extract_pii",
model_name="pii_superclinical_large",
on_progress=lambda p: print(f"{p:.0%} complete")
)
results = processor.run(texts)
Swift/iOS:
swift
import OpenMedKit
let analyzer = OpenMedNER(model: .diseaseDetectionSuperClinical)
let result = try await analyzer.analyze("Patient presents with hypertension and T2DM")
// result.entities: [{text: "hypertension", label: "DISEASE"}, {text: "T2DM", label: "DISEASE"}]
支持的 NER 模型
| 模型 | 检测域 | 参数量 | HuggingFace 下载量 |
|---|---|---|---|
disease_detection_superclinical |
疾病/症状 | 434M | 104K |
pharma_detection_superclinical |
药物/化合物 | 434M | --- |
pii_superclinical_large |
PII 标识符 | 434M | --- |
chemical_detection_electramed |
化学品 | 33M | 117K |
anatomy_detection_electramed |
解剖部位 | 109M | --- |
genomic_detection_pubmed |
基因/基因组 | 109M | 103K |
oncology_detection_multimed |
肿瘤学实体 | 568M | 102K |
项目详细剖析
架构设计:为什么是编码器,不是生成式 LLM
这是 OpenMed 最值得关注的技术选择。
生成式 LLM(GPT-4、Claude 等)在医疗文本问题上有一个根本性的问题:输出不可控。让生成式模型做 PII 检测,它可能会在某些情况下把患者姓名"生成"到输出里,或者幻觉出不存在的药物名称。
OpenMed 选择编码器 Transformer 做命名实体识别,本质上是一个分类问题:对每个 token 判断它属于什么类别。这类模型:
- 输出是确定性的(给定输入,输出固定)
- 不会幻觉(只做分类,不生成新 token)
- 参数量小(33M-568M),本地推理可行
- 可以精确审计(每个实体都有来源位置)
对医疗场景来说,这些特性比"能生成流畅文本"重要得多。
Privacy Filter 架构
OpenMed 的 PII 检测不只是跑一个 NER 模型,还有几层工程处理:
上下文感知检测 :在实体前后 100 个字符范围内做关键词增强。SSN: 后面跟着数字序列,置信度比单纯的数字序列高得多。
校验和验证:减少误报。
- 美国社保号(SSN):格式验证
- 印度 Aadhaar:Verhoeff 校验算法
- 巴西 CPF/CNPJ:Luhn 校验
- 意大利 Codice Fiscale:格式 + 字母校验
- 德国 Steuer-ID:格式验证
Smart Entity Merging:解决子词分词器的分片问题。BERT 类模型会把 "O'Brien" 切成 "O", "'", "Brien",实体合并逻辑把这些片段重新拼回完整实体,避免输出残缺的 PII 检测结果。
三种 Privacy Filter 变体:
- 基础版:通用 PII 检测
- Nemotron 微调版:更高精度
- 多语言版(v1.4.0):支持 16 种语言的统一模型
多平台运行时
bash
┌─────────────────────────────────────────────────┐
│ OpenMed 运行时 │
├──────────────┬──────────────┬───────────────────┤
│ Python/MLX │ Swift │ Docker/FastAPI │
│ │ OpenMedKit │ │
│ • CPU │ • macOS │ • REST API │
│ • CUDA │ • iOS │ • 批量处理端点 │
│ • Apple MLX │ • iPadOS │ • 模型生命周期管理│
│ │ │ /models/loaded │
│ 24-33x │ PHI 不离 │ /models/unload │
│ vs CPU PyTorch│ 开设备 │ keep_alive 控制 │
└──────────────┴──────────────┴───────────────────┘
↑ ↑
共享 MLX 模型文件(含 8-bit 量化版)
Swift 和 Python 路径共享同一套 MLX 模型文件,这意味着同一个医院系统可以用 Python 服务跑服务端推理,同时用 OpenMedKit 在 iPad 上跑本地推理,模型文件不需要维护两套。
零样本能力(v1.2.0)
v1.2.0 版本引入了零样本接口,不再要求用预定义的实体类别:
python
from openmed import zero_shot_ner
# 不用预训练的医疗 NER 模型,用自定义的类别标签
result = zero_shot_ner(
text="The patient's creatinine level was 2.3 mg/dL, suggesting CKD.",
labels=["LAB_VALUE", "UNIT", "CONDITION"]
)
# 能识别 "2.3 mg/dL" 为 LAB_VALUE,"CKD" 为 CONDITION
python
from openmed import extract_relations
# 抽取实体间的语义关系
relations = extract_relations(
text="Metformin was prescribed for type 2 diabetes.",
entity_pairs=[("DRUG", "DISEASE")]
)
# [{drug: "Metformin", relation: "prescribed_for", disease: "type 2 diabetes"}]
对于不在预定义 NER 模型覆盖范围内的临床实体,零样本接口提供了一个灵活的出口。
微调设计
OpenMed 的模型训练用了领域自适应预训练(DAPT)加 LoRA 微调:
- 预训练数据:350K 段落的生物医学语料库
- LoRA 微调:只更新不到 1.5% 的参数
- 训练时间:单块 GPU,12 小时内完成
- 碳排放:整个训练过程低于 1.2 kg CO₂e
这个数据对想在自己数据集上微调的用户有参考意义:不需要多卡集群,一块消费级 GPU 加几个小时就能完成。
版本演进
| 版本 | 时间 | 核心变化 |
|---|---|---|
| v0.x | 2025年下半年 | 初期开发,基础 NER |
| v1.0.0 | 2026年4月 | 首个稳定版,MLX 后端,Swift 包 |
| v1.2.0 | 2026年4月 | 零样本 NER/分类/关系抽取,iOS Scan Demo |
| v1.4.0 | 2026年5月 | 多语言 Privacy Filter,16 种语言 |
| v1.5.0 | 2026年5月 | 阿拉伯语/日语/土耳其语 PII,247 个模型 |
| v1.5.2 | 2026年5月 | 安全加固,trust_remote_code 默认 False |
| v1.5.5 | 2026年6月 | 批量 PII,REST 生命周期管理,13 个 README 翻译 |
项目地址与资源
官方资源
- 🌟 GitHub : maziyarpanahi/openmed
- 🚀 入门教程 : maziyarpanahi/openmed-starter
- 🌐 官网 : openmed.life
- 🤖 Agent 工具 (预览): agent.openmed.life
- 📄 论文: arXiv:2508.01630
- ☁️ AWS SageMaker: Marketplace 托管版本
参考标准
- HIPAA Safe Harbor(18 个患者标识符)
- OWASP 医疗数据安全
- STRIDE 威胁建模(Privacy Filter 安全设计)
总结
OpenMed 解决的问题有明确的边界:医疗 NLP,且数据不能离开本地。
这个约束在很多行业是选择,在医疗行业经常是法规要求。OpenMed 把解法做成了库------编码器模型做分类、MLX 做本地加速、Swift 包做移动端原生集成、校验和逻辑减少误报、Smart Entity Merging 处理分词碎片。每一层都在处理医疗场景里真实存在的工程问题。
对于在做医疗 AI 应用的开发者,或者在研究临床文本处理的研究者,OpenMed 是目前开源生态里覆盖最全的本地化方案之一。即使不是医疗场景,它的 PII 脱敏能力和多语言支持,在金融、法律等同样有数据敏感性要求的领域也有直接的参考价值。
探索 PrimeSkills ------ 精选 AI Agent 与技能的市场,每一个都经过真实企业工作流验证,去掉浮夸,留下真正有用的。
欢迎访问我的个人主页,发现更多有价值的见解和有趣的产品。