OpenMed Python API 完全参考:PII 提取、去标识化、可逆重标识与结构化错误体系
【免费下载链接】openmedLocal-first healthcare AI: clinical NER & HIPAA PII de-identification that runs 100% on-device. 2,200+ medical models, 21 languages, Apple MLX + Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed
导读
本文以 OpenMed 官方 API 参考(docs/api-reference.md)为主线,结合仓库源码(openmed/core/pii.py、openmed/core/errors.py、openmed/init.py 等)逐项解读顶层公开 API。你将掌握extract_pii、deidentify、reidentify三大 PII 核心函数及analyze_text、list_models、BatchProcessor等配套能力的完整签名、参数语义与实战用法,理解从检测到脱敏、再到可审计重标识的全链路编程模型,并学会用统一的OpenMedError错误树(含 REST/MCP 映射)安全地处理失败。所有结论均可回溯到当前仓库源码,适用于在本地构建 HIPAA 合规的临床文本处理管线。
1. 快速上手与公共 API 表面
OpenMed 的顶层包openmed采用**惰性导入(lazy import)**机制:openmed/init.py 中的__getattr__会在首次访问符号时才从对应子模块加载,__dir__()则暴露全部可发现的顶层导出。这意味着import openmed本身开销极低,且只有真正用到的能力才会被加载——对端侧部署与冷启动敏感场景友好。
顶层 API 分组(见 openmed/init.py 的__all__)大致包括:
- PII 检测与去标识化:
extract_pii、deidentify、reidentify、PIIEntity、DeidentificationResult; - 通用 NER 分析:
analyze_text、AnalyzeResult; - 模型发现:
list_models、get_model_info、get_models_by_category、search_models、get_default_pii_model等; - 批处理与文档流:
BatchProcessor、process_batch、redact_dataset、deidentify_document_stream; - 结构化错误:
OpenMedError及其十个子类、ERROR_CODES、redact_detail; - PDF 处理:
openmed.multimodal下的render_redacted_pdf、verify_redacted_pdf、verify_redacted_text_removed、measure_pdf_layout_fidelity; - 可观测性:
openmed.core.telemetry.PipelineTelemetry、StageTelemetry。
一个最简的端到端示例(与源码 docstring 中reidentify的用法一致):
import openmed # 1) 检测 result = openmed.extract_pii( "Patient Casey Example called from 555-0100 on 01/15/1970.", confidence_threshold=0.5, ) # 2) 脱敏(mask 策略,默认即保留映射以支持逆向) d = openmed.deidentify( "Patient Casey Example called from 555-0100 on 01/15/1970.", method="mask", keep_mapping=True, ) print(d.deidentified_text) # 形如 'Patient [NAME] called from [PHONE] on [DATE]' # 3) 依据映射恢复 restored = openmed.reidentify(d.deidentified_text, d.mapping) print(restored) # 还原原始文本2.extract_pii:检测临床文本中的 PII 实体
定义位于 openmed/core/pii.py。它使用 token 分类模型检测姓名、邮箱、电话、地址及其他受 HIPAA 保护的标识符(模块 docstring 声称支持 18+ 实体类型),并通过**智能实体合并(smart merging)**把被模型切碎的片段(如日期01与/15/1970)依据正则语义单元重新合并为完整实体(01/15/1970),再以主导标签(dominant label)归类。
2.1 函数签名
extract_pii( text: str | bytes | bytearray | memoryview, model_name: str = "OpenMed/OpenMed-PII-SuperClinical-Small-44M-v1", confidence_threshold: float = 0.5, config: Optional[OpenMedConfig] = None, use_smart_merging: bool = True, lang: str = "en", cache_results: bool = False, max_cache_entries: int = 128, normalize_accents: Optional[bool] = None, *, preserve_whitespace: bool = False, locale: Optional[str] = None, loader: Optional[ModelLoader] = None, batch_size: Optional[int] = None, num_workers: Optional[int] = None, custom_recognizer: Any = None, abdm: Optional[bool] = None, code_mixed: bool = False, token_language_tags: Optional[Sequence[Any]] = None, lid_model: Optional[TokenLIDHook] = None, transliterated_name_config: Any = None, budget: Optional[RequestBudget] = None, ) -> PredictionResult2.2 核心参数语义
| 参数 | 默认值 | 说明 |
|---|---|---|
text | — | 支持str及bytes/bytearray/memoryview,入口先经validate_pii_input校验 |
model_name | OpenMed/OpenMed-PII-SuperClinical-Small-44M-v1 | PII 模型标识:注册表键、Hugging Face 仓库 ID 或本地路径;当lang != "en"时自动切换到对应语言的默认模型 |
confidence_threshold | 0.5 | 置信度下限(0–1),低于阈值的结果被过滤 |
use_smart_merging | True | 是否启用基于正则的语义单元合并(官方推荐保持开启) |
lang | "en" | ISO 639-1 语言码(en、fr、de、it、es、nl、hi、te、pt、ar、ja、tr 等),控制默认模型、正则模式与替换假数据;hi/te的拉丁/天城文、拉丁/泰卢固文混合文本会自动走脚本感知的印度临床路由 |
normalize_accents | None | 推理前是否去除变音符号;None表示对_ACCENT_NORMALIZE_LANGS(当前为西班牙语es)自动开启。结果中的实体偏移始终指向原始(带重音)文本 |
preserve_whitespace | False | 保留首尾空白,使返回偏移精确对应输入串 |
custom_recognizer | None | 自定义识别器:CustomRecognizer实例或 JSON/YAML 配置路径;deny-list 命中以custom:deny溯源加入,allow-list 命中抑制任何检测器的重叠跨度 |
abdm | None | 印度 ABDM 标识符包开关;None对印地语/泰卢固语及印度 locale 自动开启,False显式关闭 |
code_mixed | False | 显式英语/印地语混合路径,需配合token_language_tags(en/hi/ne/univ/other标签流) |
budget | None | 每次请求的墙钟时间与输入字符预算;超长输入在模型推理前即被拒绝 |
cache_results/max_cache_entries | False/128 | 进程内 LRU 结果缓存;缓存可能含 PHI,但永不落盘 |
2.3 底层流程与返回结构
从源码调用链看,extract_pii依次完成:输入校验与预算检查 → 缓存查找 → 构造_extract_pii_batch单元素批 →(可选)Unicode 归一化与变音去除、印度临床脚本窗口路由、隐私过滤模型分发 → 智能合并 → 确定性safety_sweep补充结构化标识符(SSN/身份证等)→ 实体跨度校验(validate_entity_spans)→ 返回PredictionResult。
返回的PredictionResult含text、entities、model_name、timestamp;每条实体为PIIEntity(见第 3 节)。若lang指定的语言没有捆绑模型,会抛出带明确指引的ModelLoadError(例如提示设置INDIC_NER_MODEL_ENV或显式传model_name)。
3. 核心数据结构:PIIEntity与DeidentificationResult
3.1PIIEntity
定义于 openmed/core/pii.py,继承自EntityPrediction,除基础text/label/start/end/confidence外,还包含 PII 专属字段:
entity_type:PII 类别(与label相同,构造时自动回填);redacted_text/original_text:脱敏后替换文本与脱敏前原文;hash_value:用于实体关联的一致性哈希;reversible_id:可选的可逆假名化句柄;canonical_label:规范化类别标签(用于跨模型的标签归一);sources/evidence:实体来源(如ml、locale_rule、safety_sweep、custom:deny)与证据;action/surrogate:脱敏动作与代理值。
3.2DeidentificationResult
定义于 openmed/core/pii.py,字段包括:
original_text:输入原文;deidentified_text:脱敏后文本;pii_entities:检测并脱敏的实体列表;method:所用脱敏方法;timestamp:执行时间;mapping:可选的可逆映射(keep_mapping=True时返回)。当多个原文拼写映射到同一替换面时,使用私有 occurrence key 区分,使不同的源拼写在脱敏文本不变的前提下仍可逐条恢复;audit_report:审计报告(audit=True时附带)。
三个实用方法:
to_dict():序列化为字典,含num_entities_redacted与audit_report;_repr_html_():在 Jupyter/IPython 中自动渲染高亮 PII 跨度视图(置信度默认隐藏,避免隐式展示敏感置信信息);to_dataframe():转为 pandas DataFrame(每实体一行,列含text、label、entity_type、start、end、confidence、action、result_id;未安装 pandas 时抛MissingExtraError)。
4.deidentify:七种脱敏策略与可逆映射
定义位于 openmed/core/pii.py,是 OpenMed 的脱敏主入口,内部构造 openmed/core/pipeline.py 的Pipeline并执行完整管线。
4.1 支持的脱敏方法(method)
| 方法 | 行为 |
|---|---|
mask(默认) | 替换为占位符,如[NAME]、[EMAIL] |
aadhaar_mask | 合法的印度 Aadhaar 号渲染为XXXX XXXX NNNN,其余实体用普通占位符 |
remove | 完全移除(替换为空串) |
replace | 替换为逼真的假数据(基于 Faker 与语言 locale) |
hash | 替换为一致性哈希值用于实体关联(如NAME_a1b2c3d4) |
format_preserve | 保持结构标识符的形状与分隔符生成合成值,不支持的标签回退为掩码 |
shift_dates | 按随机偏移平移日期且保持日期区间关系 |
兼容性:
shift_dates=True是method="shift_dates"的弃用别名;若shift_dates=False与method="shift_dates"冲突、或date_shift_days/patient_key等日期参数在非日期方法下使用,都会抛出带明确修复指引的InputError。
4.2 关键参数
| 参数 | 默认值 | 说明 |
|---|---|---|
confidence_threshold | 0.7 | 脱敏置信度下限;默认高于extract_pii的0.5,体现"检测可宽、脱敏从严"的安全设计 |
keep_year | False | 日期脱敏时保留年份不变 |
date_shift_days | None | 未提供patient_key时的固定偏移天数;提供patient_key时作为历史最大绝对偏移上限(除非同时给出date_shift_max_days) |
patient_key | None | 稳定患者标识,仅用于派生确定性 HMAC 日期偏移;原始键不记录、不持久化、不返回 |
date_shift_max_days | None | 最大绝对偏移;提供patient_key/seed且二者均未设置时默认365 |
date_shift_secret | None | HMAC 密钥材料;跨会话复用同一值可保持偏移稳定;与patient_key成对使用 |
keep_mapping | False | 是否保留用于reidentify的映射 |
consistent | False | replace/format_preserve下生成稳定代理(同输入→同输出,跨调用内一致) |
seed | None | 请求级整数种子,实现替换与自动日期平移的跨运行可复现;对替换方法隐含consistent=True |
locale | None | Faker locale 覆盖(如pt_BR、en_GB);未指定时由lang推导 |
surrogate_vault | None | 跨文档代理保险库;只存储 HMAC 源哈希,Indic 姓名以语音折叠的 HMAC 复用身份并按输入文字渲染,折叠本身永不持久化或审计 |
policy | None | 策略配置名,控制仲裁、动作选择、强制安全扫描与可逆映射 |
calibration_thresholds_path | None | thresholds.json工件路径;提供后按标签的校准阈值过滤检测并进入审计输出 |
use_safety_sweep | True | 模型检测后、脱敏前执行确定性结构化标识符扫描 |
audit | False | True时返回AuditReport而非DeidentificationResult |
budget | None | 请求级墙钟/字符预算 |
其余参数(config、use_smart_merging、lang、normalize_accents、loader、custom_recognizer、abdm、code_mixed、token_language_tags、lid_model、transliterated_name_config、cache_results)语义与extract_pii一致。
4.3 返回与审计
默认返回DeidentificationResult;audit=True时返回确定性AuditReport(由 openmed/core/audit.py 提供),包含DetectorInfo列表(每个检测器的来源、模型 ID、格式ml/rules、commit 等)以及经_sanitize_audit_evidence清洗的证据——所有文本类键(text、word、surface、replacement、original_text、deidentified_text等)一律从审计证据中剔除,确保 PHI 安全。
5.reidentify:基于映射的逆向恢复
定义位于 openmed/core/pii.py。要求脱敏时使用了keep_mapping=True。
reidentify(deidentified_text: str, mapping: Mapping[str, str]) -> str实现要点:
- 入参严格校验:
deidentified_text必须是str,mapping必须是字符串键值映射,否则抛InputError并给出修复指引; - 支持occurrence-aware 映射:当不同原文拼写碰撞到同一替换面时,映射键以
__openmed_occurrence_v1__:<ordinal>:<surface>形式记录,reidentify先按出现顺序恢复这些条目,再用普通映射做全局替换; - 源码模块 docstring 给出简洁示例:
from openmed import reidentify reidentify( "Patient [NAME] called [PHONE]", {"[NAME]": "Casey Example", "[PHONE]": "555-0100"}, ) # 'Patient Casey Example called 555-0100'生产环境注意:源码 docstring 明确提示重标识需要适当的授权与审计日志,属于高敏感操作。
6.analyze_text:通用临床 NER 分析
定义于 openmed/init.py,运行 token 分类模型并格式化预测结果。与extract_pii的差异在于它是通用 NER(默认模型disease_detection_superclinical),不绑定 PII 语义,可用于疾病、症状等临床概念抽取。
主要参数:
model_name/model_id:注册表键、HF 模型 ID 或本地路径(二者只能传其一);aggregation_strategy:HF 聚合策略,默认"simple",None时返回原始 token 输出;output_format:"dict"(默认)、"json"、"html"、"csv";include_confidence/confidence_threshold:置信度输出与过滤;group_entities:格式化输出中合并相邻同标签实体;sentence_detection(默认True)/sentence_language/sentence_backend:句子级分块推理,sentence_backend可为"auto"(默认路由)或"yasbd"(实验特性,需openmed[yasbd]extra);assert_context:为每个实体附加确定性否定、不确定性、体验者与时间性标签(存于metadata["clinical_context"]),默认关闭;cache_results/max_cache_entries:进程内 LRU 缓存(可能含 PHI,不落盘)。
底层实现会先按句子分段(sentence_utils.segment_text),以「最多 6 个句子 /max(480, max_length*4)字符」为界构造推理分块,随后将各块预测偏移回填到原文坐标,并在硬换行与句界处切分跨度、跳过占位符片段。若OpenMedConfig.use_medical_tokenizer=True,还会把模型跨度重映射到医学友好 token(openmed/processing/tokenization.py 的remap_predictions_to_tokens)。
7.list_models与模型发现
定义于 openmed/init.py:
list_models(*, include_registry: bool = True, include_remote: bool = True, config: Optional[OpenMedConfig] = None) -> List[str]include_registry:是否在提交的 manifest 之外并入捆绑注册表中的条目;include_remote:为兼容保留,不会执行实时远程发现(离线优先设计);- 返回可用模型标识符列表。
配套发现能力还包括get_model_info、get_models_by_category、get_default_pii_model、get_pii_models_by_language、search_models(ModelQuery)以及 HF Hub 拉取助手prefetch_model、list_cached_models、clear_cached_model、resolve_repo_id(openmed/core/hf_hub.py)。
8.BatchProcessor:批量处理
BatchProcessor定义于 openmed/processing/batch.py,配套数据结构包括BatchItem、BatchItemResult、BatchResult、BatchProgress、DatasetRedactionResult等(顶层从 openmed/processing 导出)。
典型用法是把多条文本组装为BatchItem列表(每项含文本与自定义元数据),提交后逐条执行检测/脱敏,结果通过BatchResult汇总,并可在BatchProgress中观察进度。仓库还提供更高层的process_batch函数与redact_dataset(数据集级脱敏,返回DatasetRedactionResult/DatasetRedactionSummary),以及流式能力deidentify_stream、deidentify_document_stream。异步变体见 openmed/aio.py(abatch、aextract_pii、adeidentify、aanalyze_text)。
9. 结构化错误体系:一个根、十个叶
OpenMed 在 Python、REST 与 MCP 三端暴露同一棵错误契约(详见 docs/api/errors.md)。所有期望内的公开失败都继承自OpenMedError(openmed/core/errors.py),并具备四个稳定能力:
code:稳定的小写机器可读错误码(ClassVar);message:可操作的、不含 PHI的人类可读信息;details:非敏感结构化上下文(计数、偏移、标签、哈希等);to_dict(include_details=True):返回{"code", "message", "details"}JSON 就绪对象。
9.1 错误类层级与传输映射
| Python 异常 | 稳定 code | 兼容内建基类 | REST 状态 | MCP code |
|---|---|---|---|---|
OpenMedError | openmed_error | Exception | 500 | openmed_error |
InputError | input_error | ValueError,TypeError | 400 | input_error |
ConfigurationError | configuration_error | ValueError,TypeError,KeyError | 400 | configuration_error |
CapabilityError | capability_error | ImportError | 503 | capability_error |
MissingExtraError | missing_extra | ImportError | 503 | missing_extra |
ModelLoadError | model_load_error | ImportError,ValueError | 503 | model_load_error |
PolicyError | policy_error | ValueError,TypeError | 400 | policy_error |
BudgetExceededError | budget_exceeded | RuntimeError | 503 | budget_exceeded |
InternalError | internal_error | RuntimeError | 500 | internal_error |
InferenceError | inference_error | RuntimeError | 500 | inference_error |
继承关系:MissingExtraError与ModelLoadError继承自CapabilityError;InferenceError继承自InternalError。兼容内建基类的设计让存量except ValueError/except ImportError/except RuntimeError处理器在迁移期间继续工作。
共享输入校验还保留更细的稳定叶码:text_required、text_type、invalid_encoding、empty_text、min_chars、max_chars、max_bytes、language_required、language_type、unsupported_language、suspicious_content(这些仍是InputError实例)。openmed.ERROR_CODES是类名→code 的机器可读注册表(openmed/core/errors.py),code 永不复用,变更或删除已发布 code 属于兼容性破坏。
9.2 推荐捕获模式
import openmed try: result = openmed.deidentify(payload, method="mask") except openmed.InputError as error: # 修正请求:按 code 分支,而不是匹配 message 文本 print(error.code, error.details) except openmed.CapabilityError as error: # 先安装/配置所请求的本地能力再重试 print(error.code) except openmed.OpenMedError as error: # 其余可预期失败都扎根于此 print(error.code)9.3 PHI 安全的诊断:redact_detail
错误消息绝不包含临床原文、检测到的标识符表面、可逆映射、凭据或密钥材料。当需要在本地关联不可信文本时,使用redact_detail(openmed/core/errors.py):
from openmed import redact_detail descriptor = redact_detail(untrusted_value) # <redacted bytes=... sha256=...>描述符只含 UTF-8 字节长度与完整 SHA-256 摘要;不要把原始值塞进自定义错误消息或details。
9.4 REST 与 MCP 行为
REST 侧使用标准错误信封:{"error": {"code": ..., "message": ..., "details": ...}};可纠正的输入/配置/策略失败返回 HTTP 400,能力缺失与预算超限返回 503,内部与推理失败返回 500;服务端响应将details置为null以避免暴露内部上下文。MCP 工具在结构化内容中返回同样的 code 与 message,并同时置协议错误标志与is_error: true。
10. PDF 脱敏与保真验证
openmed.multimodal提供四个面向 PDF 的公开函数,可用于「渲染红action 版 PDF + 验证脱敏完整性」的闭环:
render_redacted_pdf(...)(openmed/multimodal/render_pdf.py):依据检测/脱敏结果渲染红action(涂黑)版 PDF;measure_pdf_layout_fidelity(...)(openmed/multimodal/render_pdf.py):度量红action 后版面保真度,用于评估脱敏对布局的影响;verify_redacted_pdf(...)(openmed/multimodal/verify_pdf.py):校验输出 PDF 的脱敏状态;verify_redacted_text_removed(...)(openmed/multimodal/verify_pdf.py):验证指定文本确实已从 PDF 中移除。
这些函数与仓库中 docs/multimodal/pdf-redaction-fidelity.md、docs/multimodal/pdf-reading-order.md 描述的能力对应,适合构建"先脱敏、再验证、后发布"的文档管线。
11. 可观测性:PipelineTelemetry与StageTelemetry
定义于 openmed/core/telemetry.py:
PipelineTelemetry:默认关闭(opt-in)的 OpenTelemetry spans 与指标记录器。可传入调用方自有的 tracer/meter;OpenMed 本身从不配置 provider、从不创建 exporter 或任何网络出口,因此启用遥测不会把数据发送到任何目的地。StageTelemetry:单个管线阶段的 No-PHI 记录器,由PipelineTelemetry.stage_span创建。setter 只接受聚合值,全部 span 属性经safe_stage_attributes过滤。
StageTelemetry提供的方法(全部记录聚合值、绝不落实体原文):
set_span_count(count)/set_entity_count(count):本阶段产生的规范跨度数与实体数(openmed.stage.span_count/openmed.stage.entity_count);set_labels(labels):记录规范化类别标签集合(永远不是实体文本);set_input_length(length)/set_redacted_length(length):输入字符数与输出脱敏字符数;set_offset_range(start, end):聚合输出边界(openmed.stage.offset.start_min/end_max),不存储检测表面;mark_failed():标记失败阶段,不记录异常或消息;finish(duration_ms):结束阶段并记录时长与聚合直方图。
环境变量OPENMED_TELEMETRY可控制默认开关(见parse_telemetry_enabled/telemetry_enabled_from_env)。该设计呼应 docs/operations/no-phi-telemetry.md 的 no-PHI 遥测原则。
12. 组合实战:一条合规的端到端管线
把上述 API 串联成一个典型工作流:
import openmed note = ( "Ms. Casey Example, DOB 01/15/1970, SSN 123-45-6789, " "was seen at 555-0100 for asthma follow-up on 03/12/2026." ) # 1) 先提取,观察检测结果(阈值可放宽到 0.5) found = openmed.extract_pii(note, confidence_threshold=0.5) for entity in found.entities: print(entity.label, entity.text, round(entity.confidence, 2)) # 2) 生产脱敏:更高阈值 + replace 假名 + 保留映射 + 一致性代理 masked = openmed.deidentify( note, method="replace", # 或用 mask / hash / format_preserve confidence_threshold=0.7, keep_mapping=True, consistent=True, use_safety_sweep=True, # 覆盖 SSN 等结构化标识符 ) print(masked.deidentified_text) # 3) 受控场景下按映射还原(需授权与审计) restored = openmed.reidentify(masked.deidentified_text, masked.mapping) assert restored == note如需错误处理,在deidentify外围包裹第 9.2 节的try/except,并可按需传入budget(RequestBudget)防止超大请求拖垮本地推理。全部处理在本机完成,患者数据不出网络边界。
延伸阅读
- 结构化错误契约全文:docs/api/errors.md
- PII 实体合并与语义单元:openmed/core/pii_entity_merger.py
- 脱敏器与假数据生成:openmed/core/anonymizer
- 预算控制:openmed/core/budget.py
- 批量处理与数据集脱敏:openmed/processing/batch.py
- REST 服务形态:docs/rest-service.md 与 docs/api-reference.md 配套的 docs/api/openapi.json
- 端到端示例脚本:examples/first_five_minutes_redact_extract_fhir.py、examples/pii_batch_processing.py
【免费下载链接】openmedLocal-first healthcare AI: clinical NER & HIPAA PII de-identification that runs 100% on-device. 2,200+ medical models, 21 languages, Apple MLX + Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考