動作
Feature #318
進行中
SC
改善 ICD-10 檢索準確度:向量庫 cosine 正規化重建(方案A)+ L1 hybrid 字面比對 + 回歸測試基準
Feature #318:
改善 ICD-10 檢索準確度:向量庫 cosine 正規化重建(方案A)+ L1 hybrid 字面比對 + 回歸測試基準
狀態:
New
優先權:
Normal
被分派者:
-
開始日期:
2026-07-04
完成日期:
完成比例:
0%
預估工時:
概述
改善 ICD-10 檢索準確度:向量庫 cosine 正規化重建(方案A)+ L1 hybrid 字面比對 + 回歸測試基準¶
背景¶
#317 遺留「快查排名偏差」問題,根因已查明並實測確認兩層:
-
向量庫層:ChromaDB(73,681 筆)存未正規化 embedding、以原始 L2 距離排序 → 描述越短向量 norm 越小、越靠近原點,形成萬用近鄰(hub)效應。實測:查
abrasion時 A46 Erysipelas(丹毒,norm 2.51)排 #4,語意正確的 S50.311A(norm 4.6)反被壓過。 -
檢索策略層:「查詢詞一字不差就在描述裡」的查詢也全交給向量 →
epistaxis明明就是 R04.0 的描述原文,卻被拼字相近的 N45.1 Epididymitis(副睪丸炎)壓過,排不進前五。
快查(/search_icd10)與外傷 pipeline(/predict_icd10 legacy 路徑)共用同一向量庫,本次修正同時影響兩者。另收編部署機移回的 1,100 案例 golden dataset 作為回歸基準,所有改動均有改前/改後量化對照。
變更內容¶
方案A:向量庫 cosine 正規化重建(rag_service.py)¶
-
icd10_codescollection 重建:cosine metric(hnsw:space: cosine)+ 寫入端normalize_embeddings=True,73,681 筆全庫重 embed(模型不變:paraphrase-multilingual-MiniLM-L12-v2)。 - 查詢端
search_codes()同步加normalize_embeddings=True(與 collection metric 成對,單邊改會得到錯誤排名)。 - 門檻掃描:全程式碼無硬編碼距離門檻(distance 僅排序/顯示用),免改。
- faceted collection(
icd10_codes_faceted)未動(其查詢端原本就 normalize)。
L1 hybrid 字面比對(main.py + Icd10SearchPage.tsx)¶
-
/search_icd10檢索改為三層:① 代碼前綴(原有)→ ② L1 字面比對(新增) → ③ 語意向量(原有,補剩餘名額)。 - 字面比對規則:英文 = 縮寫展開後查詢詞全部整詞出現於描述;中文 = 原始輸入為 zh 描述子字串。描述越短排越前(越接近純概念)。全碼表單詞索引
_icd_literal_index()常駐記憶體,單次查詢 30~60ms。 - 前端命中標示新增「字面」徽章(代碼=綠 / 字面=藍 / 語意=灰)。
回歸測試套件(backend/tests/,新收編)¶
-
golden_dataset.json:1,100 筆 ER 外傷案例含標準答案(部署機移回)+ 既有/predict_icd10回歸腳本 + 2026-03-30 legacy 基準(76.8% code recall)存baseline_2026-03-30/。 -
benchmark_vector_search.py:純向量層 benchmark(無 LLM、確定性),自動偵測 collection metric;改前/改後結果 JSON 一併入庫。後續評估任何新 embedding 模型(如 SapBERT)只需跑一次--label對照。
文件¶
-
ICD10_Vector_DB_Improvement_Options.md:方案 A~D 決策文件 + 本次執行結果(量化對照與殘餘問題歸屬)。 -
docs/https-deployment-plan.md(部署機移回,未實作待辦)、docs/system-architecture-2026-03.md(系統快照,已加現況註記)。 -
.gitignore加backend/chroma_db_backup*/(向量庫備份目錄,避免誤 commit)。
量化結果(1,100 案例 / 1,837 期望碼)¶
| 指標 | 改前 raw-L2 | 方案A cosine | +L1 hybrid |
|---|---|---|---|
| exact recall@5(向量層/端點層) | 10.4% | 11.4% | 16.0%(+54%) |
| exact recall@50(向量層) | 30.8% | 32.3% | — |
| family recall@30(向量層) | 60.6% | 63.0% | — |
| family recall@5 | 46.8% | 46.3% | 45.5%(持平) |
驗收標準¶
-
epistaxis/nosebleed→ R04.0 字面命中排第一(改前排不進前五)。 -
abrasion/contusion/擦傷(單字查詢)→ 前五全為合理字面命中(改前為 Tetany/噯氣等 hub 垃圾)。 -
erysipelas/丹毒→ A46 穩居第一且距離差距拉開;A46 不再出現於abrasion前五(hub 病灶已除)。 - 長查詢無退步:
abrasion of right elbow→ S50.311A 字面直中。 - 縮寫鏈路正常:
DKA→ 展開 diabetic ketoacidosis → E08~E13 系列(字面找不到時正確退回語意)。 - 向量層 benchmark 整體無退步(exact@50 +1.5pp、family@30 +2.4pp、MRR +5.6%)。
- 前端
tsc --noEmit零型別錯誤;查詢延遲 30~60ms。
部署注意(重要)¶
-
程式碼與向量庫必須成對更新:部署機 pull 新程式碼後,須刪除舊
icd10_codescollection 讓其自動重建(首次啟動重算 73,681 筆約 10~25 分鐘,期間 API 無回應為正常),不可拿新程式碼配舊 L2 庫。 - 改動前備份:
backend/chroma_db_backup_2026-07-03/(git 外);回滾 = 備份目錄換回 + git revert,兩者一起。
已知限制 / 後續¶
- 純向量端殘餘 hub 雜訊:單字查詢在「字面比對接手」後已無實際影響,但根因(MiniLM 嵌入空間 anisotropy)屬模型本身限制。
- 下一步(另案):方案 D 換 embedding 模型評估(候選 SapBERT 多語版/BGE-M3),用本次入庫的 benchmark 直接對照;建獨立 collection A/B,不動現用庫。
沒有任何資料可供顯示
動作