OpenMed 临床实体提取到 FHIR:从本地 NER 到确定性 R4 Bundle 的落地指南 OpenMed 临床实体提取到 FHIR从本地 NER 到确定性 R4 Bundle 的落地指南【免费下载链接】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 仓库中的技能文档 extract-clinical-entities-to-fhir 展开讲解如何把合成或已脱敏文本中的临床实体映射为确定性的 FHIR R4 资源并组装成 Bundle 提交给 FHIR 服务器。读完本文你将掌握抽取与编码分离的管线设计、analyze_text到to_bundle的完整调用链、以及避免发明术语编码、保证隐私安全的工程要点。核心思想把抽取和临床编码彻底分离OpenMed 的定位是 100% 本地运行的医疗 AI临床 NER 与 HIPAA PII 脱敏而 FHIR 导出是这条链路的最后一公里。技能文档开篇即给出原则Separate extraction from clinical coding. OpenMed finds spans and supplies the mechanical FHIR builders; the application decides which resource type and status are clinically appropriate.也就是说抽取extraction由 OpenMed 完成——找出文本中的实体 span并给出置信度、标签、偏移量编码clinical coding由应用层负责——决定每个 span 映射成哪种 FHIR 资源类型Condition / MedicationStatement / Observation……、赋予什么状态active / confirmed / final……、使用哪个术语编码只能来自用户批准的映射或术语服务。OpenMed 提供的是一套纯机械的 FHIR 装配工具从源码看bundle.py 的模块注释明确写道The assembler is purely mechanical: it never synthesises resources (a Patient removed by de-identification stays absent) and does not validate profiles.——它从不凭空捏造资源被脱敏移除的 Patient 不会复活也不做 profile 校验校验是独立的可选环节。六步操作流程技能文档给出了标准流程共六步保证数据安全输入必须是合成文本或在可信边界内先完成脱敏再进行抽取运行分析模型调用openmed.analyze_text使用任务匹配的临床模型过滤预测结果按 label 和置信度过滤并把偏移量offsets保留在 PHI 安全的审计记录中映射资源类型把每个被接受的 span 映射到正确的 FHIR 资源类型添加术语编码只能来自用户批准的映射或术语服务绝不发明编码组装与校验用to_bundle组装资源并针对目标 profile 进行校验。其中第 2 步是整个管线的入口。从源码看analyze_text 是 OpenMed 顶层公开 API默认模型为disease_detection_superclinical关键参数包括model_name注册表键、完整的 Hugging Face 模型 id 或本地模型路径confidence_threshold实体最低置信度None表示保留全部技能示例中使用0.5aggregation_strategyHugging Face 聚合策略默认simple设为None可拿原始 token 输出output_formatdict默认、json、html或csvassert_context默认关闭开启后会给每个实体附加确定性的否定、不确定性、体验者experiencer与时间性标签写入metadata[clinical_context]这与技能文档保留否定、时间性、体验者上下文的要求直接相关include_confidence/group_entities/cache_results等格式化相关开关。可运行的合成示例技能文档要求先安装模型运行时python -m pip install openmed[hf]随后即可运行完整示例技能文档原文保持可复制性import json from openmed import analyze_text from openmed.clinical.exporters.fhir import to_bundle note Assessment: type 2 diabetes mellitus is stable on metformin. result analyze_text( note, model_namedisease_detection_superclinical, confidence_threshold0.5, ) resources [{resourceType: Patient, id: synthetic-patient}] for index, entity in enumerate(result.entities, start1): if entity.label.upper() not in {CONDITION, DIAGNOSIS, DISEASE}: continue resources.append( { resourceType: Condition, id: fcondition-{index}, clinicalStatus: { coding: [ { system: ( http://terminology.hl7.org/CodeSystem/ condition-clinical ), code: active, } ] }, verificationStatus: { coding: [ { system: ( http://terminology.hl7.org/CodeSystem/ condition-ver-status ), code: confirmed, } ] }, # A text-only CodeableConcept is preferable to an invented code. code: {text: entity.text}, subject: {reference: Patient/synthetic-patient}, } ) if len(resources) 1: raise RuntimeError(No condition spans met the label and confidence rules) bundle to_bundle(resources, doc_idsynthetic-note-001) print(json.dumps(bundle, indent2))这个示例有三个值得注意的工程细节状态编码使用 HL7 官方 CodeSystem URIcondition-clinical与condition-ver-status分别承载clinicalStatusactive与verificationStatusconfirmed没有可用编码时用纯文本CodeableConceptcode: {text: entity.text}比发明一个不存在的编码安全得多空结果保护如果没有 span 通过 label 与置信度过滤直接抛出RuntimeError避免向下游提交空 Bundle 造成误导。to_bundle确定性装配的底层原理示例中的核心装配函数是to_bundle其完整签名见 bundle.pydef to_bundle( resources: Sequence[Mapping[str, Any]], *, doc_id: str openmed-document, bundle_type: str transaction, profile_check: Callable[[Mapping[str, Any]], Any] | None None, ) - dict[str, Any]参数语义resources待包装的独立 FHIR 资源按 Bundle 内顺序排列每个资源必须含resourceType带id的资源在 Bundle 内必须ResourceType/id唯一doc_id源文档的稳定标识与资源索引共同决定每个条目的确定性urn:uuidfullUrl同一输入永远产生字节级一致的输出bundle_typeBundle 的type默认transaction对transaction/batch类型每个条目会附带request块method: POST、url: resourceType服务器可直接据此创建资源profile_check可选回调收到完成 Bundle 的深拷贝作为合规或策略门禁回调返回值被忽略但异常会向上传播——这正对应流程第 6 步validate against the target profile。to_bundle内部做了三件确定性工作见 bundle.py生成稳定 fullUrl每个资源通过deterministic_fullurl(doc_id, index)得到urn:uuid重写内部引用把指向 Bundle 内已有资源的字面引用如Patient/synthetic-patient改写为对应urn:uuid杜绝悬空内部引用引用不到的资源如被脱敏移除的 Patient保持原样不动references.py 中的deterministic_fullurl隐私净化在导出前调用sanitize_india_health_identifiers将 ABHA、UPI、ration-card 等印度健康标识符从 FHIRIdentifier和 PatientID 类字段中移除见 privacy.py。to_bundle还会显式拒绝两类非法输入并抛ValueError资源缺少resourceType或两个资源共享相同resourceType与id——重复 id 会静默破坏内部引用映射因此被显式拦截。对应的测试见 tests/unit/clinical/test_fhir_bundle.py覆盖了事务 Bundle 每个资源一个 entry、fullUrl 唯一、collection 类型无 request 块、batch 类型保留 request 块、缺 resourceType 抛错、重复 id 抛错等场景。面向断言感知的导出器to_condition 与 to_observation技能文档强调不要把否定、假设、时间性、体验者上下文丢在一边就断言资源为 active/confirmed。仓库为此提供了断言感知assertion-aware的导出器它们基于AssertedGroundedSpan见 assertion_grounding.py工作。to_conditionto_condition 把断言感知的 grounded span 物化为 FHIR R4Condition体验者过滤span 属于非患者主体家人/其他人时to_condition直接返回None根本不会产生患者 Condition——这是结构性的安全边界状态仅来自受审地图clinicalStatus/verificationStatus只来自受审的 status 映射一个被否定或假设的 span 永远不可能被编码为activeconfirmed无明确状态时省略当状态不主张 active/inactive如被否定或假设的发现时clinicalStatus字段被省略符合 FHIR 不声称该状态的不变式两个 HL7 系统 URI 常量CONDITION_CLINICAL_SYSTEM与CONDITION_VER_STATUS_SYSTEM与技能示例中的字符串完全一致。to_observationto_observation 与之对称被否定/假设的观察标记为cancelled而不是作为最终结果呈现_observation_status中对 refuted/hypothetical 返回cancelled否则final数值用 FHIRvalueQuantity表达并保留可选的 UCUM 单位system: http://unitsofmeasure.org布尔用valueBoolean其他值落为valueString与to_condition相同非患者体验者的 span 返回None。其他导出器与统一门面to_diagnostic_report状态采用显式 allowlistregistered、partial、preliminary、final、amended、corrected、appended、cancelled、entered-in-error、unknown缺失/空值用unknown非法状态 fail-closed 拒绝字段名按 R4/R5 并集 allowlist 过滤且绝不从conclusion推断conclusionCodeto_fhir顶层门面返回FHIRBundle与FHIRExportSummary是 grounded-span 导出的规范公共入口to_codeable_concept受控的辅助型assist-only编码发射器每个概念携带源证据偏移量并附上显式的非自主临床决策免责声明扩展MEDICAL_DEVICE_ASSIST_ONLY_DISCLAIMER。安全检查清单技能文档给出了不可妥协的安全底线全部保留如下日志与追踪中禁止回显原始标识原始标识符、源文本、可逆映射不得出现在日志、OperationOutcome.diagnostics或 trace 元数据中患者身份服务与临床事实分离患者身份服务必须与抽取出的临床事实分开维护保留上下文再断言状态在把资源断言为 active/confirmed 之前必须保留否定negation、时间性temporality与体验者experiencer上下文无可用编码时用纯文本CodeableConcept按接收方要求校验Bundle 必须针对接收方的 FHIR 版本与 profile 要求进行校验不捆绑受限术语表受限术语restricted terminologies不要直接打进 Bundle应使用用户自己的授权许可服务。与此呼应仓库内置的校验器 validate.py 提供了无依赖的 R4 结构校验validate_bundle/validate_resource覆盖Condition、Observation、MedicationStatement、DiagnosticReport、Encounter等 9 类BASE_R4_RESOURCE_TYPES产出 FHIRPath 风格的定位与值无关value-free消息——校验报告不会回显临床内容或标识符天然适配审计场景另有 profile_check.py 的check_bundle负责实现指南包implementation guide级别的 profile 评估。仓库配套实战示例技能文档推荐阅读并运行仓库中的端到端演练 examples/first_five_minutes_redact_extract_fhir.py它以前五分钟上手为目标展示了一条离线友好的完整链路脱敏deidentify(note, methodmask, confidence_threshold0.5, use_safety_sweepTrue)对内置合成病历做掩码脱敏示例内通过自定义 loader 避免首次运行下载模型抽取TextProcessor().extract_medical_entities(redacted_text)从脱敏文本中确定性抽取vital_signs、dosages等实体组装映射为最小 FHIR 资源集——PatientEncounterstatus: finished 每条生命体征一个Observationstatus: finalvalueString承载数值 每个剂量一个MedicationStatementstatus: activemedicationCodeableConcept.text与dosage[].text均用纯文本导出to_bundle(resources, doc_idfirst-five-minutes-synthetic)生成确定性事务 Bundle。该示例的完整调用链与技能文档六步流程一一对应可作为把本指南落地的起点。示例中所有文本均为合成数据标识符DEMO-001、demo.patientexample.test均为占位符可直接运行验证输出。适用前提与限制本管线面向合成或已脱敏文本若输入含真实 PHI必须先在自己的可信边界内完成脱敏OpenMed 的deidentify即为此设计再进入抽取环节to_bundle是机械装配器不校验 profile也不代替你决定资源类型与状态——这两者属于应用层职责术语编码只能来自用户批准的映射或术语服务OpenMed 的 grounded 导出器提供的是带证据与免责声明的辅助编码assist-only需要人工复核后使用若想在本机复现请先python -m pip install openmed[hf]安装模型运行时并确认网络可拉取所选模型或配置本地模型路径。【免费下载链接】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),仅供参考