建去重臨床問題列表(Problem List):基于 ConText 上下文軸的狀態(tài)調(diào)和與 USCDI/FHIR 輸出)
使用 OpenMed 構(gòu)建去重臨床問題列表Problem List基于 ConText 上下文軸的狀態(tài)調(diào)和與 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、現(xiàn)病史HPI和評估計劃AP中其中有些被否定denies chest pain、有些屬于歷史prior MI 2019。本文基于 OpenMed 的技能文檔 skills/reconciling-problem-lists/SKILL.md講解如何把 OpenMed 逐提及per-mention的實體流與 ConText 決策軸轉(zhuǎn)化為一份一個概念一條記錄、帶臨床狀態(tài)active / resolved / historical的干凈問題列表并組織成符合 USCDI Problem / FHIR Condition 交換形態(tài)的數(shù)據(jù)。讀完本文你將掌握analyze_textresolve_span_context的完整調(diào)用鏈、同義提及聚類與狀態(tài)聚合規(guī)則并能用倉庫中的 問題列表調(diào)和工具 直接落地實現(xiàn)。問題背景為什么需要問題列表調(diào)和實體抽取NER的輸出是提及mention而不是問題problem。同一概念在整份病歷中反復(fù)出現(xiàn)、措辭各異且?guī)в薪厝徊煌呐R床斷言assertion有的被否定、有的是條件句、有的只存在于既往史。直接把原始提及平鋪輸出會產(chǎn)生三個問題冗余同一個疾病被列出多條無法回答患者到底有幾個問題誤報denies chest pain否認(rèn)胸痛會被當(dāng)成一個真實存在的問題狀態(tài)缺失無法區(qū)分當(dāng)前活動期與既往已解決而這恰是臨床交接、質(zhì)量指標(biāo)計算和 FHIR Condition 交換最需要的信息。問題列表調(diào)和problem list reconciliation的目標(biāo)就是把上述逐提及實體流折疊為一個概念一個條目丟棄患者并不存在的問題并為每個條目賦予臨床狀態(tài)。這是 OpenMed 臨床 NLP 技能鏈中的一環(huán)它消費extracting-clinical-entities抽取實體與resolving-clinical-context解析上下文的輸出面向FHIR Condition / USCDI Problem 的下游組裝。何時使用本技能根據(jù)技能文檔的description與When to use一節(jié)適合在以下場景調(diào)用本調(diào)和流程已完成extracting-clinical-entities與resolving-clinical-context用戶需要一份干凈的問題列表、條件調(diào)和結(jié)果或?qū)χ貜?fù)診斷提及去重需要按問題給出 active / resolved / historical 狀態(tài)而不只是原始提及正在組裝 FHIR Condition 列表或 USCDI Problem 元素要求每個概念一條記錄。技能元數(shù)據(jù)中的pairs: after字段表明它應(yīng)銜接在抽取類技能之后運行。文檔明確推薦的順序是先extracting-clinical-entities再resolving-clinical-context最后執(zhí)行本調(diào)和流程若病歷結(jié)構(gòu)復(fù)雜可先用 segmenting-clinical-sections 分節(jié)處理以獲得更強的 active-vs-historical 信號??焖匍_始最小可用實現(xiàn)技能文檔給出了一段可直接運行的完整示例核心調(diào)用只有兩個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.示例輸出注釋揭示了三類典型結(jié)果type 2 diabetes聚合為 2 次提及且狀態(tài)為 activechest pain因被否定而排除MI因 temporal 軸為 historical 而標(biāo)記為 resolved。完整工作流六個步驟技能文檔將調(diào)和流程歸納為六步這里結(jié)合倉庫源碼逐一展開。第 1 步收集 Disease/Condition 實體用openmed.analyze_text在整份病歷或分節(jié)后的每個 section上抽取實體。函數(shù)默認(rèn)模型即為disease_detection_superclinical這與技能示例一致。從源碼看openmed/init.py 中analyze_text的可調(diào)參數(shù)包括參數(shù)默認(rèn)值說明model_namedisease_detection_superclinical注冊表鍵、Hugging Face 完整模型 ID 或本地模型路徑aggregation_strategysimple實體聚合策略設(shè)為None可拿到原始 token 級輸出output_formatdict可選dict/json/html/csvconfidence_threshold0.0實體最低置信度過濾None保留全部group_entitiesFalse是否合并相鄰?fù)悓嶓winclude_confidenceTrue輸出中是否攜帶置信度sentence_detectionTrue是否啟用句子檢測供上下文解析限定作用域output_formatdict時每個實體帶word表面文本等字段后續(xù)resolve_span_context即以該表面文本為輸入。第 2 步為每個提及附加臨床上下文對每個提及調(diào)用resolve_span_context獲得 negation否定、temporality時間性、certainty確定性三個決策軸。該函數(shù)定義于 openmed/clinical/context.py返回ClinicalContextResult其字段context.py為temporalityrecent/historical/hypotheticalcertaintycertain/uncertainnegationaffirmed/negatedexperiencer可選family等非患者主體信號。模塊頂部定義了常量與取值順序context.pyNEGATED、AFFIRMEDRECENT、HISTORICAL、HYPOTHETICALCERTAIN、UNCERTAIN。技能文檔要求從openmed.clinical直接導(dǎo)入resolve_span_context, NEGATED, HISTORICAL, HYPOTHETICAL倉庫 openmed/clinical/init.py 的導(dǎo)出體系保證這些符號可直接使用。第 3 步排除不是問題的提及NEGATED患者否認(rèn)、無證據(jù)與HYPOTHETICAL條件句、未斷言存在的提及絕不能進(jìn)入活動問題列表。這是調(diào)和流程的正確性底線——技能文檔明確指出若跳過上下文解析denies chest pain會被錯誤地放上活動列表。從底層實現(xiàn)看resolve_negationcontext.py會先屏蔽偽否定線索pseudo-negation cues如no increase、not ruled out、cannot be excluded再統(tǒng)計真實否定線索奇數(shù)個否定線索判定為negated偶數(shù)個判定為affirmed從而使雙重否定保持確定性。第 4 步將同義提及聚類為一個概念把表面變體縮寫、詞序、詞匯同義詞折疊到單一規(guī)范鍵。技能文檔強調(diào)兩點簡單歸一化小寫、去空白、同義詞表足以起步但有損——MI與myocardial infarction只有在你自己的歸一化器認(rèn)識該同義詞時才能折疊SNOMED CT 概念接地concept grounding才是穩(wěn)健路徑必須在進(jìn)程外out-of-process運行使用用戶自有的 license 與 key以概念代碼code而非表面字符串作為聚類鍵。需要特別強調(diào)的是OpenMed 本體不捆綁 SNOMED CT文檔的 Hand-off 一節(jié)明確說明SNOMED 代碼由用戶提供、在進(jìn)程外接地OpenMed 產(chǎn)出的是去重后的概念與狀態(tài)而非術(shù)語綁定本身。第 5 步通過聚合上下文分配狀態(tài)一個概念在任意位置典型如 AP被判定為RECENT/ active則該問題為active一個概念僅以HISTORICALhistory of、resolved、僅出現(xiàn)在 PMH出現(xiàn)則為resolved/historical同一概念同時出現(xiàn) active 與 historical 時active 優(yōu)先。技能文檔用History of asthma 在 PMH asthma exacerbation 在 AP為例這應(yīng)合并為一個active問題而不是兩條記錄。聚合必須在賦狀態(tài)之前完成否則會得到兩個互相矛盾的條目。第 6 步輸出調(diào)和后的列表每個概念輸出一條記錄包含概念、狀態(tài)、提及計數(shù)與溯源偏移量provenance offsets形態(tài)對齊 USCDI Problem / FHIR Condition。源碼級深入倉庫中的現(xiàn)成調(diào)和工具技能文檔的示例是手寫problems字典的輕量實現(xiàn)倉庫里還有一份更完備的工程化實現(xiàn)可直接復(fù)用openmed/clinical/problem_list.py。它把上述六步中聚合 狀態(tài)仲裁部分固化為確定性的數(shù)據(jù)類型與函數(shù)正是對技能文檔Active beats historical、聚合后再賦狀態(tài)等規(guī)則的代碼化驗證。核心數(shù)據(jù)結(jié)構(gòu)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溯源偏移。分組身份與狀態(tài)仲裁deduplicate_problem_listproblem_list.py采用確定性且保守的分組規(guī)則身份鍵按優(yōu)先級依次為coref_entity_id文檔級共指實體systemcode編碼身份如 SNOMED 代碼歸一化文本折疊空白、統(tǒng)一大小寫后的表面文本無編碼信號時的兜底。它不會推斷無編碼文本提及與有編碼提及是同一概念——這正是技能文檔Surface dedup is lossy警示的實現(xiàn)體現(xiàn)。狀態(tài)仲裁通過clinical_status_from_assertionproblem_list.py完成映射關(guān)系清晰斷言組合調(diào)和狀態(tài)recent affirmed certain 患者主體activehistorical affirmed certain 患者主體inactive對應(yīng) resolved否定negatedrefuted不確定 / hypothetical / 非患者 experiencerunconfirmed組內(nèi)狀態(tài)優(yōu)先級為active inactive unconfirmed refuted_reconcile_statusproblem_list.py——這正是技能文檔Active anywhere wins的工程化表達(dá)。輸出保持首次出現(xiàn)順序溯源偏移按提及貢獻(xiàn)順序保留。測試驗證倉庫為這一實現(xiàn)提供了完整測試 tests/unit/clinical/test_problem_list.py可對照技能文檔的規(guī)則逐條驗證編碼身份 active 優(yōu)先同一 SNOMED 代碼44054006diabetes mellitus兩條提及一條 recent、一條 historical合并為 1 條clinical_status active、mention_count 2、兩個偏移都被保留test_coded_affirmed_recent_outweighs_historical_and_preserves_offsets全否定 → refuted全部 negated 的提及不會被丟棄而是調(diào)和為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 規(guī)則引擎調(diào)和流程的準(zhǔn)確性依賴上下文軸其底層是 context.py 中的apply_context_rules——一個確定性、零訓(xùn)練的觸發(fā)詞與作用域掃描器。關(guān)鍵機制包括作用域限定規(guī)則作用域始終限定在目標(biāo)句內(nèi)子句級規(guī)則在配置的終止線索處停止每條規(guī)則有最大 token 傳播距離線索資源化英語起始線索位于打包資源openmed/clinical/data/context_rules.yaml含 negation、temporality 等類別而非硬編碼在模塊里逐軸決策apply_context_rules只返回原始修飾符命中modifier hits由resolve_temporality/resolve_negation/resolve_uncertainty等決策層解釋多語言隔離resolve_span_context的language參數(shù)選擇已注冊的線索詞表未注冊語言缺省退化為 recent / certain / affirmed——英語線索永遠(yuǎn)不會翻轉(zhuǎn)中文或印地語的斷言見 context.py 的 docstring。時間性決策中有一條值得注意的優(yōu)先級當(dāng) hypothetical 與 historical 線索同時出現(xiàn)時判為hypothetical——條件句未被斷言發(fā)生其時間位置不再重要resolve_temporality 的 docstring。與 OpenMed 上下游的銜接Hand-off技能文檔用清晰的契約說明了本技能的輸入輸出邊界上游消費extracting-clinical-entities產(chǎn)出的analyze_textDisease 實體依賴resolving-clinical-context的否定 / 時間性 / 不確定性軸——沒有上下文解析的調(diào)和會把 denies chest pain 放進(jìn)活動列表OpenMed 調(diào)用面from openmed import analyze_text與from openmed.clinical import resolve_span_context, NEGATED, HISTORICAL, HYPOTHETICAL下游 FHIR / USCDI每條調(diào)和后的問題映射為一條 FHIR Condition——clinicalStatus取 active/resolved源自 temporalityverificationStatus取 refuted/provisional源自 negation/uncertainty。SNOMED CT 代碼由用戶提供并在進(jìn)程外接地OpenMed 產(chǎn)出的是去重后的概念與狀態(tài)不承擔(dān)術(shù)語綁定。邊界情況與陷阱Edge cases gotchas技能文檔給出五條必須遵守的規(guī)則工程實踐中極易踩坑表面去重是有損的MI與myocardial infarction只有歸一化器認(rèn)識同義詞才能折疊。詞匯折疊只處理簡單情形真正的調(diào)和要依賴 SNOMED CT 接地永遠(yuǎn)不要捆綁 SNOMED用用戶憑據(jù)在進(jìn)程外調(diào)用Active 勝過 Historical同一概念PMH 的 asthma 病史 AP 的 asthma 加重應(yīng)合并為一個 active 問題而不是兩條——先聚合、后賦狀態(tài)不要復(fù)活已解決的問題僅以HISTORICAL/ resolved 出現(xiàn)的概念保持 resolved不能因為它出現(xiàn)就提升為 active否定與假設(shè)是排除項不是狀態(tài)它們永遠(yuǎn)不成為問題列表條目應(yīng)整體排除攜帶溯源為每個問題保留偏移量與來源段落讓審閱者能把每條記錄追溯回原文。此外技能文檔在元數(shù)據(jù)層面聲明了本技能的定位本地優(yōu)先、僅作輔助。它運行在設(shè)備端調(diào)和結(jié)果是供臨床醫(yī)生審閱的決策支持不是自主診斷。標(biāo)準(zhǔn)與參考USCDI v3 — Problems / Health Concerns 數(shù)據(jù)類HL7 FHIR R4 Condition —clinicalStatusactive/resolved與verificationStatusSNOMED CT — 臨床概念參考術(shù)語需用戶自有 license。這三項標(biāo)準(zhǔn)定義了本技能輸出形態(tài)的互操作目標(biāo)clinicalStatus與verificationStatus的取值空間正是上文clinical_status_from_assertion映射表的目的地而 SNOMED 接地則決定了聚類鍵的穩(wěn)健性上限。小結(jié)OpenMed 的問題列表調(diào)和是一條抽取 → 上下文 → 排除 → 聚類 → 聚合賦狀態(tài) → 輸出的完整流水線以 skills/reconciling-problem-lists/SKILL.md 為操作指南以 openmed/clinical/context.py 的 ConText 決策軸為上下文依據(jù)以 openmed/clinical/problem_list.py 為工程化聚合實現(xiàn)以 tests/unit/clinical/test_problem_list.py 為行為契約。核心要點可濃縮為三句話否定與假設(shè)必須排除、先聚合再賦狀態(tài)、active 優(yōu)先于 historical。在這三條規(guī)則之上產(chǎn)出即可直接映射為 USCDI Problem / FHIR Condition 形態(tài)的數(shù)據(jù)同時嚴(yán)格守住SNOMED 接地在進(jìn)程外、結(jié)果僅供臨床審閱的邊界?!久赓M下載鏈接】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創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考