CQL Workbench文件
文件目錄
分析管線

分析管線

一條條文從原文變成可以審核的 IR,中間經過哪些 LLM 呼叫、每一步之後有哪些程式檢查,以及檢查失敗時怎麼修。

LLM 分析階段

分析分兩層。先把整份文件切成任務,一個任務就是一段可以單獨判斷的條文;接著每個任務各自跑下面的階段,一份文件最多 4 個任務同時進行。分析進度會顯示每個任務跑到哪個階段。

整份文件一次

  1. 1
    拆解任務extract_outline

    模型只回傳每個任務開頭的前 10–20 個字,再由程式照這些起點切開原文,所以每個任務的原文都是逐字的。沒有設定 LLM 或拆段失敗時,改用條號標題切段。

每個任務各跑一次

  1. 2
    分類triage

    判斷條文簡單(simple)或複雜(complex),附上 0 到 1 的信心值和一句理由。

  2. 3
    擷取引文ir_units

    從原文逐字抄下每一段依據,依序編成 S1、S2……

  3. 4
    擷取條件ir_nodes

    依引文拆出原子條件 C1、C2……。一個條件是醫師會問的一個是非題,至少引用一段引文。

  4. 5
    建立邏輯ir_groups

    用 AND、OR、NOT 群組把條件組起來,並指定根群組。這一步只排列條件,不新增也不改寫。

  5. 6
    覆核(遺漏與群組)ir_pass2

    整份 IR 看一次:原文有寫卻沒拆出來的條件、極性、群組結構。已經正確的原子條件不改寫。

  6. 7
    逐條件覆核ir_node_review

    每個條件各一次小呼叫,對照它引用的原文,細節見逐條件覆核。

  7. 8
    反向驗證roundtrip

    把產生的 CQL 寫回白話摘要,和原文比對語意是否一致。呼叫失敗只會記成「未判定」,不影響分析結果。

  8. 9
    編譯與消融驗證不呼叫 LLM

    cql-engine 編譯 CQL,再逐一覆寫參數跑消融驗證。結果就是審核頁的「可執行」證據。

分類的結果用在兩個地方:判為 simple 且信心 ≥ 0.8 的條文,跳過整份覆核(ir_pass2),逐條件覆核照跑,審核頁標「LLM 自動通過 · 可推翻」;其餘條文標「需醫師簽核」。這兩個標記不會改變條文狀態,簽核仍然由人來做。分類呼叫失敗時一律當成複雜,不會因為 LLM 出錯就少一輪覆核。

程式檢查與定點修正

每個階段之後都有程式檢查,通過了才進下一步。檢查失敗時,只把出錯的那一塊送回模型修,其餘部分不重跑:

檢查修正呼叫修什麼
每段引文都在原文裡找得到ir_fix_units只重寫找不到的引文
每個條件單獨檢查,定義合法ir_fix_node只修出錯的那個條件
群組與根群組合法,每個條件和群組都接得到根ir_fix_groups只重排群組
需要重組的錯誤,例如一個條件裡藏了 AND 或 ORir_fix整份 IR 修一次

有些小錯程式直接處理,不必問模型:模型把群組運算子寫成 and、or,或把群組寫成 G2 而不是 GROUP:G2。一個條件裡塞了「A 且 B」或「A 或 B」,而且每一項都是完整的原子條件時,程式直接拆成兩個條件加一個群組。NOT 一律不自動拆,否定的範圍交給模型判斷。

一個任務的修正呼叫合計最多 4 次,所有階段共用。用完之後結構仍不合法,這個任務標為失敗並記下錯誤,其他任務照常完成;如果只剩引文對不上,則保留結果,見引文驗證。

回應解析不成 JSON 時,會把解析器的錯誤訊息和出錯位置附近的片段回給模型,請它重新輸出,預設最多重問 2 次(LLM_JSON_RETRIES)。程式自己只做不會改變內容的修補:拿掉 markdown 圍欄、多餘的逗號、字串裡沒有跳脫的換行。回應被截斷時,絕不自動補上括號:只解析出一半的 IR 可能悄悄少掉條件,卻照樣通過驗證。這時會請模型輸出更精簡、完整的 JSON。

輸入如果是亂碼、空白,或和臨床條件無關,模型會回報無法拆解並說明原因。這是正常的回答,不算解析失敗,不會重問。

引文驗證

條件靠引文連回原文:每個條件用 source_ids 指向一段或多段引文,每段引文的 exact_quote 必須逐字出自條文原文。審核者就是靠這個確認條件不是模型自己編的。

比對前,引文和原文先做同樣的處理:去掉所有空白,全形英數字與符號轉成半形,「。」當成句點、「、」當成逗號,英文字母不分大小寫。引文結尾多一個句號、逗號或分號也算對得上。除此之外必須一字不差。

以 CQL 入門的範例條文為例:

本品限內科專科醫師處方,病人需為成人(年滿十八歲),且 eGFR ≥ 30 mL/min/1.73m²;未達標準者,須經腎臟科會診同意後使用。
引文結果原因
eGFR≥30mL/min/1.73m²通過空白不算。
病人需為成人(年滿十八歲)通過原文是全形括號,引文是半形,視為相同。
限內科專科醫師處方。通過結尾多一個句號,可以忽略。
須由內科醫師開立待核原文沒有這句話,是模型改寫的。

擷取引文之後馬上比對一次,找不到的引文送 ir_fix_units 修;之後每一輪檢查都會再比對。

修正額度用完仍然對不上時,分析不會失敗:條件邏輯已經通過檢查,IR 和 CQL 照樣保留,只把這些引文記成待核。工作台的任務列表會標「N 筆引文待核」;審核頁在條件的原文區塊顯示「出處 S5 在原文中找不到逐字對應」和那句引文。看到這個提示,代表這個條件可能建立在模型自己補上的文字上。

人工修改的規則更嚴:審核者新增或改寫的引文不在原文裡,存檔會直接被拒絕,見修改邏輯。

逐條件覆核

逐條件覆核(ir_node_review)是管線最後一個改動 IR 的 LLM 階段。整份 IR 定案後,每個條件各送一次小呼叫,一個任務最多 3 個同時進行。每次呼叫只帶三樣東西:條文原文、這個條件引用的引文,以及它在 AND、OR、NOT 結構裡的位置。

模型對每個條件檢查四件事:

忠實
標籤、臨床問題和定義要和引文說的一樣,不能更嚴,也不能更寬。引文沒寫的就拿掉。
原子
一個條件只問一件事。如果其實是兩個條件,保留原本的定義,另外記一則註記。
正規化
門檻寫成數字並標明單位,列舉寫成清單,期間和劑量附上單位,藥名照原文。
證據
填上能證明或否定這個條件的 FHIR R4 resource 與欄位,供證據契約使用。

放在最後,是為了不讓它補上的欄位被整份重寫蓋掉。拆成逐條件,是因為這件事以前由一次整份 IR 的覆核來做,那是整條管線最慢的呼叫,而且容易把原子條件合併回複合條件;小呼叫可以並行,某個條件有疑問時,也只要重跑那一個。

模型改不了條件的代號和引用的出處。改過的條件會單獨再檢查一次:模型想把它改成複合條件,或改完過不了檢查,就保留原條件並記一則註記。某個條件的呼叫失敗,也只記註記,其他條件照常覆核。

模型提出的疑點,例如原文有歧義、門檻要自行解讀,會存成註記,顯示在審核頁這個條件的「模型覆核註記」。註記只供審核者參考,不影響判定。

審核時對某個條件有疑問,可以從條件選單選「用 LLM 重新分析此條件」,只對這一個條件再跑一次逐條件覆核。結果當成你的一次邏輯修改存檔:條件真的有變,它的審核決定才會失效,見簽核與失效。

這是模型的覆核,不是審核:醫師在審核頁做的是逐條件審核,每個條件由人接受、退回或標為不適用。

呼叫紀錄

每次 LLM 呼叫都會留下紀錄:階段、使用的 profile 和模型、耗時、排隊等待的時間,以及送出的 prompt 和回應原文。管理員可以在「管理 → 背景作業」打開一次文件分析,依任務和階段逐筆查看。prompt 和回應全文保留 14 天,之後只留統計數字。

每個階段的 prompt 都可以在「管理 → Prompt 範本」修改,存檔的版本會取代內建版本。模型連線怎麼設定,見管理後台。