專案

一般

配置概況

動作

Feature #393

進行中
SC

Direct-Map 票 B:Stage 0 resolver 上線 — 表單傷情查表直出確定碼,AI 退居掃尾

Feature #393: Direct-Map 票 B:Stage 0 resolver 上線 — 表單傷情查表直出確定碼,AI 退居掃尾

是由 Sashiba Chou2 天 前加入.

狀態:
New
優先權:
Normal
被分派者:
-
開始日期:
2026-07-31
完成日期:
完成比例:

0%

預估工時:

概述

Direct-Map 票 B:Stage 0 resolver 上線 — 表單傷情查表直出確定碼,AI 退居掃尾

背景

Direct-Map 的核心價值實作:醫師在人體圖/骨骼圖點的「部位 + 傷情」,
查表直接出碼(0 秒、確定性、標 confidence=certain),AI pipeline 只處理
「note 非空 / 查表未命中 / 檢傷文字裡圖上沒標的傷」。

對照表(#390 建置、#391 雙 AI 審核定稿,1,061 列)接上 /predict_icd10
設計:docs/icd10-directmap-design.md §4(本票同步定稿)。

變更內容

1. backend/directmap.py(新)— Stage 0 resolver

  • 表載入建索引(lru_cache,程序內只讀一次);resolve_soft/skeletal/joint/spine
  • 主入口 resolve_injuries(structured, sex) → (resolved, leftover)
  • 側別解析三層:id 前綴(特寫圖 left_/right_)→ id 內含 _left/_right(主體圖)
    → 名稱含 left/right;另容忍 _front/_back 視圖後綴(同部位兩視圖共用碼)
  • 症狀轉挫傷(redness/tenderness/swelling/ecchymosis/deformity → 該部位 contusion)
  • 不出碼也不送 AI:ROM 受限、(Note)
  • note 非空 → 整筆交 AI(定案 5:想讓 AI 讀就寫 note)
  • BY_GENDER:依 sex 擇一;性別未知 → 男女兩碼並陳供醫師勾選
  • 同碼去重(口腔燒傷三度同碼);查表任何例外都退回 AI,不得炸 pipeline

2. backend/main.py/predict_icd10 合併流程

  • 增收 structured_injuries: [{kind, partId, partName, injuryType, segment?, side?, note?}]sex
    (既有 fallback_injuries 保留相容)
  • 表定碼在前 + AI 碼在後合併,同傷情去重
  • AI 失敗時若已有表定碼 → 回表定碼(不讓整包歸零)
  • debug.directmap 記錄 resolved / leftover_to_ai(即使 0 筆解出也留軌跡)

3. backend/rag_service.py — AI 不重判已確定的傷

  • predict_icd10(_faceted)resolved_injuries:Stage1 抽出後濾除
    (_matches_resolved 比對傷型+側別+部位詞,非全字串 —— AI 寫法與表單字串不同也能對上)
  • prompt:swelling 條改為「從病歷文字推論不得編碼」(人體圖標記改由查表確定性處理)

4. 表單明確資訊不可丟(使用者實測發現,兩輪補齊)

D1(b)「表單沒有的資訊不假定」≠「表單的資訊不用」。原設計漏了兩項:

  • 脊椎骨折型態:表加 morphology 欄。胸/腰椎壓迫性骨折 → 楔形壓迫碼(x0),
    含「節位未特定」列(S32.000A/S22.000A —— 「知道是壓迫但不確定哪節」是最常見情境);
    頸椎 ICD 無壓迫型 → 標 NO_MORPH_IN_ICD 誠實落未特定
  • 開放性骨折:骨骼+脊椎表加 code_open 欄(第 7 碼 A→B,建表時已驗證存在);
    resolver 見 injuryType 含 open 即取用。長骨 C 級(Gustilo IIIA/B/C)未細分,交 note/AI

5. 開關與測試

  • ICD_DIRECTMAP=on/off(預設 off = 逐位元回到過往行為,已實測 rollback)
  • backend/tests/directmap_resolver_test.py(新)27 項單元測試(不需伺服器)
  • backend/tests/directmap_assert.py 擴充至 36 項(新增 code_open 存在性、型態列檢查)
  • backend/tests/smoke_test.py 新增 7.0(結構化傷情端點檢查,開/關皆通過)
  • demo_directmap.py(新)人眼可讀的示範工具,供臨床端手動驗證

驗收標準

  • 實測 7 筆表單傷情 → 3.9 秒出 10 個確定碼(零 LLM 呼叫)
  • 表定碼 + AI 掃尾:左膝擦傷由表直出、頭皮裂傷由 AI 從病歷補上,
    且 AI 未重複輸出左膝
  • 壓迫性骨折六候選型態一致(節位未特定排最前 + L1–L5 全為楔形壓迫)
  • 開放性骨折 S42.302A → S42.302B;閉鎖性維持 A
  • 測試全綠:斷言 36 + 單元 27 + 端點整合 15 + smoke 51 = 129 項
  • ICD_DIRECTMAP=off rollback 實測:零確定碼、零 debug 痕跡,行為同過往

備註

  • 部署:啟用需在 backend/.envICD_DIRECTMAP=on(不設=完全不影響現況);
    對照表隨 repo 走,無額外資料檔需求
  • 前端尚未接上:網頁點人體圖仍走純 AI 老路,要在 UI 看到「確定碼」需票 C/D
    (前端改送 structured_injuries)
  • 待辦:票 C/D 前端、_score() 具名部位護欄

沒有任何資料可供顯示

動作

匯出至 PDF Atom