Feature #289
進行中ICD-10 編碼重構 — Metadata-Facet 管線(feature-flag)
100%
概述
摘要
將 ICD-10 自動編碼從「模糊向量搜尋 + 事後補丁式四規則過濾」重構為「結構化 Stage1 → metadata where 預過濾 → LLM 排名」的 facet-aware 管線。結構性消除「挫傷被配成腐蝕傷(corrosion 洪水)」「體表撕裂被配成橈動脈撕裂」這類跨類別錯配。
新管線以環境變數 ICD_PIPELINE=faceted 切換,預設 legacy,舊路徑與舊四規則完整保留,可零風險並存比對。
背景 / 問題
來源 docs/icd10_feedback_2026-06-12.json(使用者回報):
傷型錯配:「Contusion on Upper Back」回傳 5 碼全是 T21.4x Corrosion — 通用 embedding 把「部位字面吻合」看得比「傷型語意」重。
深層結構錯配:體表撕裂傷被配到動脈/神經撕裂,且臨床關鍵詞有時只在中文描述、英文沒寫。
補丁式迭代:_filter_candidates_by_rules 四條規則「遇一種錯加一條 if」,只堵看過的洞。
變更內容
後端核心
backend/rag_service.py(+245 行)
新增 faceted 管線:predict_icd10_faceted() / extract_injuries_structured()(結構化 Stage1,對齊受控詞表)/ faceted_search()(region 擴展 + where 預過濾 + D7 放寬階梯 + 深層降權)/ _faceted_where() / _rank_faceted_llm()。
新增模組常數:FACETED_COLLECTION、REGION_EXPAND、INJURY_TYPE_VOCAB、REGION_VOCAB、STAGE1_FACETED_PROMPT。
predict_icd10() 開頭依 ICD_PIPELINE 旗標分派;legacy 路徑與四規則 100% 保留。
OLLAMA_MODEL 環境變數可覆寫 Ollama 模型名(預設 llama3.1:8b),取代寫死的 llama3。
backend/.gitignore:忽略生成物 data/(可由腳本重建)。
離線重建管線(backend/scripts/)
extract_facets.py — 規則式 facet 抽取;injury_category 由 ICD 碼段結構推導(如前臂 S51=開放傷 / S55=血管),確定性、非掃描述關鍵字。
validate_facets_full.py — 全 73k 碼 AI 逐筆驗證(gpt-4o-mini,可斷點續跑、並行;實花 ~$2.36)。
build_faceted_collection.py — 建獨立向量庫 icd10_codes_faceted(MiniLM + normalize + cosine + facet metadata)。
faceted_search_proto.py — 查詢邏輯原型(被 benchmark runner 引用)。
Benchmark 套件(backend/benchmark/)
icd10_benchmark.json + run_benchmark.py — 端對端,支援 --mode live。
icd10_benchmark_faceted.json + run_faceted_benchmark.py — 檢索層離線測試(12 案例 21 斷言,含真灼傷/真動脈傷/異物/咬傷/骨折/側別等反向案例)。
前端
frontend/next.config.ts:proxy 目標改為 BACKEND_URL 環境變數(預設仍 http://127.0.0.1:8000),僅供本機 dev 改 port,commit/production 維持原 port。
文件
docs/icd10-redesign-proposal.md — 完整設計與決策紀錄(D1–D8)。
docs/icd10-optimization-history.md — #150–#185 ICD 優化演進史。
docs/icd10_feedback_2026-06-12.json、docs/icd10_feedback_2026-06-16.json — 使用者回饋(benchmark 來源)。
設計重點
可靠度核心:injury_category 由碼段結構推導,非脆弱的描述關鍵字掃描。
分工:where 保證「不錯到別類」,LLM 只在已正確的小集合內排序。深層結構作降權訊號而非硬切,避免 facet 標錯就漏掉正確碼。
LLM 呼叫數不變(Stage1 抽傷情 + Stage3 批次排名,共 2 次)。
驗證結果
Live 端對端 benchmark:命中率 45% → 100%(24/24)。
Corrosion 誤配 3 → 0。
檢索層離線 benchmark:21/21 斷言通過。
牙齒斷裂漏抓案例由結構化 Stage1 修復。
啟用方式
於 backend/.env 設 ICD_PIPELINE=faceted 後重啟後端即生效;不設則維持 legacy。重建向量庫:extract_facets.py → validate_facets_full.py → build_faceted_collection.py。
風險 / 回滾
全程 feature flag,預設 legacy,舊路徑零改動 → 回滾僅需移除/改 ICD_PIPELINE。
facet 標錯可能誤篩 → 以 D7 放寬階梯 + 深層降權(非硬切)緩解。
向量庫為生成物(gitignored),可由腳本完整重建。
待辦 / 選配
P2b:評估 SapBERT 替代 MiniLM 比 recall(MiniLM 已達標,屬增量)。
沒有任何資料可供顯示