ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

使用 OpenMed 构建去重临床问题列表(Problem List):基于 ConText 上下文轴的状态调和与 USCDI/FHIR 输出

使用 OpenMed 构建去重临床问题列表(Problem List):基于 ConText 上下文轴的状态调和与 USCDI/FHIR 输出 使用 OpenMed 构建去重临床问题列表Problem List基于 ConText 上下文轴的状态调和与 USCDI/FHIR 输出【免费下载链接】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一份病历往往用多种措辞提到同一个疾病DM2、type 2 diabetes、diabetes mellitus 分散在既往史PMH、现病史HPI和评估计划AP中其中有些被否定denies chest pain、有些属于历史prior MI 2019。本文基于 OpenMed 的技能文档 skills/reconciling-problem-lists/SKILL.md讲解如何把 OpenMed 逐提及per-mention的实体流与 ConText 决策轴转化为一份一个概念一条记录、带临床状态active / resolved / historical的干净问题列表并组织成符合 USCDI Problem / FHIR Condition 交换形态的数据。读完本文你将掌握analyze_textresolve_span_context的完整调用链、同义提及聚类与状态聚合规则并能用仓库中的 问题列表调和工具 直接落地实现。问题背景为什么需要问题列表调和实体抽取NER的输出是提及mention而不是问题problem。同一概念在整份病历中反复出现、措辞各异且带有截然不同的临床断言assertion有的被否定、有的是条件句、有的只存在于既往史。直接把原始提及平铺输出会产生三个问题冗余同一个疾病被列出多条无法回答患者到底有几个问题误报denies chest pain否认胸痛会被当成一个真实存在的问题状态缺失无法区分当前活动期与既往已解决而这恰是临床交接、质量指标计算和 FHIR Condition 交换最需要的信息。问题列表调和problem list reconciliation的目标就是把上述逐提及实体流折叠为一个概念一个条目丢弃患者并不存在的问题并为每个条目赋予临床状态。这是 OpenMed 临床 NLP 技能链中的一环它消费extracting-clinical-entities抽取实体与resolving-clinical-context解析上下文的输出面向FHIR Condition / USCDI Problem 的下游组装。何时使用本技能根据技能文档的description与When to use一节适合在以下场景调用本调和流程已完成extracting-clinical-entities与resolving-clinical-context用户需要一份干净的问题列表、条件调和结果或对重复诊断提及去重需要按问题给出 active / resolved / historical 状态而不只是原始提及正在组装 FHIR Condition 列表或 USCDI Problem 元素要求每个概念一条记录。技能元数据中的pairs: after字段表明它应衔接在抽取类技能之后运行。文档明确推荐的顺序是先extracting-clinical-entities再resolving-clinical-context最后执行本调和流程若病历结构复杂可先用 segmenting-clinical-sections 分节处理以获得更强的 active-vs-historical 信号。快速开始最小可用实现技能文档给出了一段可直接运行的完整示例核心调用只有两个openmed.analyze_text抽取疾病实体resolve_span_context解析每个提及的上下文轴。import openmed from openmed.clinical import resolve_span_context, NEGATED, HISTORICAL, HYPOTHETICAL note (PMH: type 2 diabetes, prior MI 2019 (resolved). AP: poorly controlled DM2; denies chest pain.) ents openmed.analyze_text(note, model_namedisease_detection_superclinical, output_formatdict) def normalize(surface: str) - str: # Cheap synonym folding; replace with SNOMED grounding (out-of-process). s surface.lower().strip() return {dm2: type 2 diabetes, diabetes mellitus: type 2 diabetes}.get(s, s) problems {} # concept - reconciled record for e in ents: surface e[word] ctx resolve_span_context(surface, note) if ctx.negation NEGATED: continue # patient does NOT have it - exclude concept normalize(surface) status (resolved if ctx.temporality HISTORICAL else active) if ctx.temporality HYPOTHETICAL: continue # not asserted as present rec problems.setdefault(concept, {concept: concept, status: status, mentions: 0}) rec[mentions] 1 # Active anywhere wins over a historical mention of the same concept. if status active: rec[status] active problem_list list(problems.values()) # - [{concept: type 2 diabetes, status: active, mentions: 2}, ...] # chest pain excluded (negated); MI - historical/resolved.示例输出注释揭示了三类典型结果type 2 diabetes聚合为 2 次提及且状态为 activechest pain因被否定而排除MI因 temporal 轴为 historical 而标记为 resolved。完整工作流六个步骤技能文档将调和流程归纳为六步这里结合仓库源码逐一展开。第 1 步收集 Disease/Condition 实体用openmed.analyze_text在整份病历或分节后的每个 section上抽取实体。函数默认模型即为disease_detection_superclinical这与技能示例一致。从源码看openmed/init.py 中analyze_text的可调参数包括参数默认值说明model_namedisease_detection_superclinical注册表键、Hugging Face 完整模型 ID 或本地模型路径aggregation_strategysimple实体聚合策略设为None可拿到原始 token 级输出output_formatdict可选dict/json/html/csvconfidence_threshold0.0实体最低置信度过滤None保留全部group_entitiesFalse是否合并相邻同类实体include_confidenceTrue输出中是否携带置信度sentence_detectionTrue是否启用句子检测供上下文解析限定作用域output_formatdict时每个实体带word表面文本等字段后续resolve_span_context即以该表面文本为输入。第 2 步为每个提及附加临床上下文对每个提及调用resolve_span_context获得 negation否定、temporality时间性、certainty确定性三个决策轴。该函数定义于 openmed/clinical/context.py返回ClinicalContextResult其字段context.py为temporalityrecent/historical/hypotheticalcertaintycertain/uncertainnegationaffirmed/negatedexperiencer可选family等非患者主体信号。模块顶部定义了常量与取值顺序context.pyNEGATED、AFFIRMEDRECENT、HISTORICAL、HYPOTHETICALCERTAIN、UNCERTAIN。技能文档要求从openmed.clinical直接导入resolve_span_context, NEGATED, HISTORICAL, HYPOTHETICAL仓库 openmed/clinical/init.py 的导出体系保证这些符号可直接使用。第 3 步排除不是问题的提及NEGATED患者否认、无证据与HYPOTHETICAL条件句、未断言存在的提及绝不能进入活动问题列表。这是调和流程的正确性底线——技能文档明确指出若跳过上下文解析denies chest pain会被错误地放上活动列表。从底层实现看resolve_negationcontext.py会先屏蔽伪否定线索pseudo-negation cues如no increase、not ruled out、cannot be excluded再统计真实否定线索奇数个否定线索判定为negated偶数个判定为affirmed从而使双重否定保持确定性。第 4 步将同义提及聚类为一个概念把表面变体缩写、词序、词汇同义词折叠到单一规范键。技能文档强调两点简单归一化小写、去空白、同义词表足以起步但有损——MI与myocardial infarction只有在你自己的归一化器认识该同义词时才能折叠SNOMED CT 概念接地concept grounding才是稳健路径必须在进程外out-of-process运行使用用户自有的 license 与 key以概念代码code而非表面字符串作为聚类键。需要特别强调的是OpenMed 本体不捆绑 SNOMED CT文档的 Hand-off 一节明确说明SNOMED 代码由用户提供、在进程外接地OpenMed 产出的是去重后的概念与状态而非术语绑定本身。第 5 步通过聚合上下文分配状态一个概念在任意位置典型如 AP被判定为RECENT/ active则该问题为active一个概念仅以HISTORICALhistory of、resolved、仅出现在 PMH出现则为resolved/historical同一概念同时出现 active 与 historical 时active 优先。技能文档用History of asthma 在 PMH asthma exacerbation 在 AP为例这应合并为一个active问题而不是两条记录。聚合必须在赋状态之前完成否则会得到两个互相矛盾的条目。第 6 步输出调和后的列表每个概念输出一条记录包含概念、状态、提及计数与溯源偏移量provenance offsets形态对齐 USCDI Problem / FHIR Condition。源码级深入仓库中的现成调和工具技能文档的示例是手写problems字典的轻量实现仓库里还有一份更完备的工程化实现可直接复用openmed/clinical/problem_list.py。它把上述六步中聚合 状态仲裁部分固化为确定性的数据类型与函数正是对技能文档Active beats historical、聚合后再赋状态等规则的代码化验证。核心数据结构ProblemMentionproblem_list.py上游抽取器已识别出的候选问题提及字段包括text、可选的system/code编码身份、offset起止偏移、negation、temporality、certainty、experiencer以及文档级共指层提供的coref_entity_idReconciledProblemproblem_list.py去重后的问题条目含text、normalized_text、clinical_status、mention_count、source_offsets溯源偏移。分组身份与状态仲裁deduplicate_problem_listproblem_list.py采用确定性且保守的分组规则身份键按优先级依次为coref_entity_id文档级共指实体systemcode编码身份如 SNOMED 代码归一化文本折叠空白、统一大小写后的表面文本无编码信号时的兜底。它不会推断无编码文本提及与有编码提及是同一概念——这正是技能文档Surface dedup is lossy警示的实现体现。状态仲裁通过clinical_status_from_assertionproblem_list.py完成映射关系清晰断言组合调和状态recent affirmed certain 患者主体activehistorical affirmed certain 患者主体inactive对应 resolved否定negatedrefuted不确定 / hypothetical / 非患者 experiencerunconfirmed组内状态优先级为active inactive unconfirmed refuted_reconcile_statusproblem_list.py——这正是技能文档Active anywhere wins的工程化表达。输出保持首次出现顺序溯源偏移按提及贡献顺序保留。测试验证仓库为这一实现提供了完整测试 tests/unit/clinical/test_problem_list.py可对照技能文档的规则逐条验证编码身份 active 优先同一 SNOMED 代码44054006diabetes mellitus两条提及一条 recent、一条 historical合并为 1 条clinical_status active、mention_count 2、两个偏移都被保留test_coded_affirmed_recent_outweighs_historical_and_preserves_offsets全否定 → refuted全部 negated 的提及不会被丢弃而是调和为refutedtest_all_negated_problem_reconciles_to_refuted_without_being_dropped文本兜底合并 Diabetes Mellitus 与diabetes mellitus归一化后合并stroke保持独立test_text_fallback_merges_normalized_text_and_keeps_distinct_problems。上下文轴底层原理ConText 规则引擎调和流程的准确性依赖上下文轴其底层是 context.py 中的apply_context_rules——一个确定性、零训练的触发词与作用域扫描器。关键机制包括作用域限定规则作用域始终限定在目标句内子句级规则在配置的终止线索处停止每条规则有最大 token 传播距离线索资源化英语起始线索位于打包资源openmed/clinical/data/context_rules.yaml含 negation、temporality 等类别而非硬编码在模块里逐轴决策apply_context_rules只返回原始修饰符命中modifier hits由resolve_temporality/resolve_negation/resolve_uncertainty等决策层解释多语言隔离resolve_span_context的language参数选择已注册的线索词表未注册语言缺省退化为 recent / certain / affirmed——英语线索永远不会翻转中文或印地语的断言见 context.py 的 docstring。时间性决策中有一条值得注意的优先级当 hypothetical 与 historical 线索同时出现时判为hypothetical——条件句未被断言发生其时间位置不再重要resolve_temporality 的 docstring。与 OpenMed 上下游的衔接Hand-off技能文档用清晰的契约说明了本技能的输入输出边界上游消费extracting-clinical-entities产出的analyze_textDisease 实体依赖resolving-clinical-context的否定 / 时间性 / 不确定性轴——没有上下文解析的调和会把 denies chest pain 放进活动列表OpenMed 调用面from openmed import analyze_text与from openmed.clinical import resolve_span_context, NEGATED, HISTORICAL, HYPOTHETICAL下游 FHIR / USCDI每条调和后的问题映射为一条 FHIR Condition——clinicalStatus取 active/resolved源自 temporalityverificationStatus取 refuted/provisional源自 negation/uncertainty。SNOMED CT 代码由用户提供并在进程外接地OpenMed 产出的是去重后的概念与状态不承担术语绑定。边界情况与陷阱Edge cases gotchas技能文档给出五条必须遵守的规则工程实践中极易踩坑表面去重是有损的MI与myocardial infarction只有归一化器认识同义词才能折叠。词汇折叠只处理简单情形真正的调和要依赖 SNOMED CT 接地永远不要捆绑 SNOMED用用户凭据在进程外调用Active 胜过 Historical同一概念PMH 的 asthma 病史 AP 的 asthma 加重应合并为一个 active 问题而不是两条——先聚合、后赋状态不要复活已解决的问题仅以HISTORICAL/ resolved 出现的概念保持 resolved不能因为它出现就提升为 active否定与假设是排除项不是状态它们永远不成为问题列表条目应整体排除携带溯源为每个问题保留偏移量与来源段落让审阅者能把每条记录追溯回原文。此外技能文档在元数据层面声明了本技能的定位本地优先、仅作辅助。它运行在设备端调和结果是供临床医生审阅的决策支持不是自主诊断。标准与参考USCDI v3 — Problems / Health Concerns 数据类HL7 FHIR R4 Condition —clinicalStatusactive/resolved与verificationStatusSNOMED CT — 临床概念参考术语需用户自有 license。这三项标准定义了本技能输出形态的互操作目标clinicalStatus与verificationStatus的取值空间正是上文clinical_status_from_assertion映射表的目的地而 SNOMED 接地则决定了聚类键的稳健性上限。小结OpenMed 的问题列表调和是一条抽取 → 上下文 → 排除 → 聚类 → 聚合赋状态 → 输出的完整流水线以 skills/reconciling-problem-lists/SKILL.md 为操作指南以 openmed/clinical/context.py 的 ConText 决策轴为上下文依据以 openmed/clinical/problem_list.py 为工程化聚合实现以 tests/unit/clinical/test_problem_list.py 为行为契约。核心要点可浓缩为三句话否定与假设必须排除、先聚合再赋状态、active 优先于 historical。在这三条规则之上产出即可直接映射为 USCDI Problem / FHIR Condition 形态的数据同时严格守住SNOMED 接地在进程外、结果仅供临床审阅的边界。【免费下载链接】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),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表