chore(#15): adopt MULTIMODAL_TEXT_WEIGHT=0.65 + close #15, open #80

A/B eval (eval_retrieval.py, 86-query gold-set) showed the 0.5 default was
mis-tuned: the image side was too heavy and dragged precedent_library recall
0.971 -> 0.885. Sweep 0.5..0.75 — at 0.65 multimodal beats text-only on every
overall metric AND every corpus (R@5 0.994 vs 0.989, nDCG@5 0.960 vs 0.944,
MRR 0.954 vs 0.936). Dafna approved.

- MULTIMODAL_TEXT_WEIGHT=0.65 set in Coolify (legal-ai, runtime) + redeploy.
- baseline.json updated to the 0.65 config (future regression reference).
- #15 done (premise was stale — multimodal already default on 110 docs; the
  win was tuning the weight, not the backfill).
- #80 opened: the costly 140-doc legacy backfill is deferred until a targeted
  image-answer gold-set proves the table/image value prop (untested here).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 08:45:06 +00:00
parent bb42aeeff4
commit 4debe9995b
2 changed files with 59 additions and 44 deletions

View File

@@ -1171,14 +1171,15 @@
},
{
"id": "15",
"title": "Backfill multimodal — החלטה על rollout מורחב לאחר A/B עם דפנה",
"description": "תזכורת לבדוק עם דפנה אם voyage-multimodal-3 על 8174-24 + 8137-24 עוזר בפועל, ולהחליט אם להריץ backfill על שאר הקורפוס (~236 docs, ~17,700 pages, ~2 שעות זמן API, ~350MB disk).",
"details": "תאריך יעד מומלץ: ~2026-05-10 (שבוע מהיום, 2026-05-03).\n\nקריטריונים להחלטה (אם מתקיים אחד — להריץ rollout):\n • דפנה זיהתה לפחות פעמיים ערך מוסף ב-8174-24 או 8137-24 (תקדים שלא הייתה מוצאת בלי image side, או חתימה/טבלה/תרשים שצף ב-top results)\n • היא ביקשה במפורש להפעיל על תיק נוסף ספציפי\n • היא מבקשת לעבור ל-search מצטלב (search_decisions, find_similar_cases) מעבר לתיק הנוכחי\n\nאם דפנה לא ראתה ערך — להחליט: לבטל / לכוונן MULTIMODAL_TEXT_WEIGHT (0.5 → 0.55-0.65) / לחכות עוד שבוע.\n\nאם החליטו להריץ — סדר עדיפויות:\n 1. שמאי-heavy: 8xxx (היטל השבחה) ו-9xxx (פיצויים) — שם הערך הגדול ביותר\n 2. תיקי 1xxx (רישוי ובניה) אחרון\n\nהרצה:\n CONTAINER=$(sudo docker ps --format '{{.Names}}' | grep gyjo | head -1)\n sudo docker cp scripts/multimodal_backfill.py $CONTAINER:/tmp/\n sudo docker cp scripts/backfill_chunk_pages.py $CONTAINER:/tmp/\n sudo docker exec $CONTAINER python /tmp/multimodal_backfill.py 8xxx-yy 9xxx-yy ...\n sudo docker exec $CONTAINER python /tmp/backfill_chunk_pages.py 8xxx-yy 9xxx-yy ...\n\nרפרנסים:\n • docs/voyage-upgrades-plan.md סעיף 'שלב C — voyage-multimodal-3 (✅ בוצע)'\n • commits 242f668..d12cdb1 על main\n • זיכרון: project_multimodal_stage_c.md, feedback_hybrid_retrieval_rrf.md",
"title": "Multimodal — כיוונון MULTIMODAL_TEXT_WEIGHT (A/B) + הכרעה על backfill",
"description": "נסגר 2026-06-03 לאחר A/B אובייקטיבי על gold-set (86 שאילתות, eval_retrieval.py). הנחת היסוד התיישנה: multimodal כבר ברירת-מחדל בייצור (110 מסמכים מוטמעים אוטומטית בהעלאה), לא רק 2 תיקי A/B. ממצא: ה-weight 0.5 (ברירת-מחדל) היה mis-tuned — צד-התמונה כבד מדי וחתך recall של precedent_library (0.971→0.885). sweep 0.5→0.75: במשקל 0.65 multimodal מנצח את text-only בכל מדד ובכל corpus (R@5 0.994 מול 0.989; nDCG@5 0.960 מול 0.944; MRR 0.954 מול 0.936; precedent_library R@5 0.983, internal_decisions nDCG 0.978). כיסוי: 28/79 מסמכי gold-set מוטמעים multimodal (35% — אות אמיתי). דפנה אישרה.",
"details": "בוצע: MULTIMODAL_TEXT_WEIGHT=0.65 הוגדר ב-Coolify env של legal-ai (runtime) + redeploy; baseline (data/eval/baseline.json) עודכן לקונפיג 0.65. ה-backfill היקר ל-140 התיקים ה-legacy *לא* בוצע — אין הצדקת-אחזור לשאלות טקסט, וערך ה-image-answer לא נבדק. מומר ל-#80 (מותנה). ראיות: data/eval/eval-report-20260603T08*.md, project_multimodal_stage_c.",
"testStrategy": "",
"status": "pending",
"status": "done",
"dependencies": [],
"priority": "low",
"subtasks": []
"priority": "medium",
"subtasks": [],
"updatedAt": "2026-06-03T00:00:00.000Z"
},
{
"id": "16",
@@ -2524,20 +2525,34 @@
"description": "ה-chunker ההיררכי הנוכחי (אחרי תיקון #55) עדיין פולט מדי פעם chunk זעיר שהוא כותרת-סעיף בודדת שלא מוזגה קדימה לתוכן שאחריה. התגלה בסגירת #57 (re-chunk legacy): מתוך 73 תקדימים שעברו reindex, נשארו 4 chunks זעירים — כולם כותרות מבודדות: 'דיון' (ע\"א 5138/04, len=4), 'טענות המשיבים' (בג\"ץ 6525/15, len=13), 'העובדות וההליכים' (בר\"מ 2340/02, len=16), ושבר-ציטוט 'כלל התושבים\". (ע' 13 להחלטה)' (403-17, len=32). לא שאריות legacy — אלה פלט דטרמיניסטי של ה-chunker הנוכחי.",
"details": "השפעה: נמוכה — chunks אלה כבר מסוננים ב-query-time (פילטר length>=50 שנוסף ב-#55), אז החיפוש לא מושפע; זו בעיית-איכות-chunking ולא בעיית-אחזור. מיקום: chunker ההיררכי ב-mcp-server (chunk_document_hierarchical / מדיניות מיזוג הכותרות שב-#55). התיקון הצפוי: כשכותרת/heading קצרה (<50, או section_type שמתחיל סעיף) נותרת כ-chunk עצמאי ללא גוף — למזג אותה קדימה אל ה-chunk הבא (anchor-forward), או אחורה אם אין הבא. לשים לב ל-section boundaries: 'דיון'/'טענות המשיבים' הן תחילת סעיף — המיזוג צריך לצרף את הכותרת לראש הסעיף שאחריה, לא לזנב הקודם. אימות: להריץ scripts/rechunk_legacy_precedents.py אחרי התיקון — אמור להגיע ל-0 chunks<50 (או רק שברי-ציטוט לגיטימיים נדירים). תלוי ב-#55. ראה גם feedback_no_reocr_retrofit (re-chunk מ-full_text בלבד).",
"testStrategy": "אחרי תיקון ה-chunker: reindex של 4 התיקים (ע\"א 5138/04, בג\"ץ 6525/15, בר\"מ 2340/02, 403-17) → 0 chunks<50 בהם; SELECT count(*) FROM precedent_chunks WHERE length(trim(content))<50 → 0 (או רק שברי-ציטוט). ללא רגרסיה: search_precedent_library עדיין מחזיר את התיקים.",
"status": "pending",
"status": "done",
"dependencies": [
"55"
],
"priority": "low",
"subtasks": [],
"updatedAt": "2026-06-03T08:10:57.844Z"
},
{
"id": "80",
"title": "[#15 follow-up] בדיקת ערך image-answer ל-multimodal → הכרעה על backfill 140 legacy",
"description": "ה-A/B של #15 הוכיח ש-multimodal עוזר לאחזור טקסט (במשקל 0.65), אבל **ערך הליבה** של multimodal — שאלות שהתשובה בהן בתוך טבלה/חתימה/עמוד-image ש-OCR מאבד (דוחות שמאי 8xxx/9xxx) — לא נבדק כי ה-gold-set טקסטואלי. כדי להכריע אם שווה לעשות backfill של 140 מסמכי התיקים ה-legacy (שהועלו לפני שה-multimodal עלה; חדשים מקבלים אוטומטית), צריך mini-gold-set ממוקד של 5-10 שאלות 'התשובה בטבלה/תמונה'.",
"details": "לבנות gold-set קטן: לזהות דוחות שמאי עם תוכן image-only/טבלאי (document_image_embeddings קיימים), לנסח שאלות שהתשובה בהן בטבלה/תרשים, ולהריץ eval_retrieval.py עם MULTIMODAL_ENABLED ON מול OFF על אותן שאלות. אם multimodal מאחזר תוכן ש-text-only מפספס → ה-backfill מוצדק (~שעתיים API, ~350MB, דורש אישור עלות chaim). אם לא → לוותר. scope ה-backfill: 140 מסמכי case ללא image embeddings (SELECT ... WHERE NOT EXISTS document_image_embeddings).",
"testStrategy": "eval על ה-image-answer gold-set: multimodal ON מאחזר ≥1 מסמך/קטע ש-OFF מפספס (R@k גבוה יותר על שאלות-טבלה).",
"status": "pending",
"dependencies": [
"15"
],
"priority": "low",
"subtasks": [],
"updatedAt": "2026-06-03T00:00:00.000Z"
}
],
"metadata": {
"version": "1.0.0",
"lastModified": "2026-06-03T07:56:21.688Z",
"taskCount": 78,
"completedCount": 71,
"lastModified": "2026-06-03T08:10:57.844Z",
"taskCount": 79,
"completedCount": 72,
"tags": [
"legal-ai"
]

View File

@@ -2,50 +2,50 @@
"gold_size": 86,
"retrieval_config": {
"MULTIMODAL_ENABLED": true,
"VOYAGE_RERANK_ENABLED": true,
"VOYAGE_RERANK_ENABLED": false,
"VOYAGE_MODEL": "voyage-3",
"MULTIMODAL_TEXT_WEIGHT": 0.5,
"MULTIMODAL_TEXT_WEIGHT": 0.65,
"MULTIMODAL_RRF_K": 60,
"BM25_HYBRID_ENABLED": true
},
"overall": {
"P@5": 0.214,
"R@5": 0.899,
"nDCG@5": 0.8311,
"P@10": 0.1163,
"R@10": 0.9649,
"nDCG@10": 0.8554,
"MRR": 0.8482
"P@5": 0.2465,
"R@5": 0.9938,
"nDCG@5": 0.9597,
"P@10": 0.1244,
"R@10": 0.9961,
"nDCG@10": 0.9611,
"MRR": 0.9535
},
"by_corpus": {
"internal_decisions": {
"P@5": 0.1963,
"R@5": 0.963,
"nDCG@5": 0.887,
"P@5": 0.2037,
"R@5": 1.0,
"nDCG@5": 0.978,
"P@10": 0.1019,
"R@10": 1.0,
"nDCG@10": 0.8994,
"MRR": 0.8713
"nDCG@10": 0.978,
"MRR": 0.9722
},
"precedent_library": {
"P@5": 0.2438,
"R@5": 0.7911,
"nDCG@5": 0.7367,
"P@10": 0.1406,
"R@10": 0.9057,
"nDCG@10": 0.7813,
"MRR": 0.8092
"P@5": 0.3188,
"R@5": 0.9833,
"nDCG@5": 0.9288,
"P@10": 0.1625,
"R@10": 0.9896,
"nDCG@10": 0.9326,
"MRR": 0.9219
}
},
"by_practice_area": {
"betterment_levy": {
"P@5": 0.1897,
"R@5": 0.9231,
"nDCG@5": 0.8595,
"P@10": 0.1,
"R@10": 0.9744,
"nDCG@10": 0.8766,
"MRR": 0.8437
"P@5": 0.2051,
"R@5": 1.0,
"nDCG@5": 0.9621,
"P@10": 0.1026,
"R@10": 1.0,
"nDCG@10": 0.9621,
"MRR": 0.9487
},
"compensation_197": {
"P@5": 0.2,
@@ -57,14 +57,14 @@
"MRR": 1.0
},
"rishuy_uvniya": {
"P@5": 0.2,
"R@5": 0.9706,
"nDCG@5": 0.861,
"P@5": 0.2059,
"R@5": 1.0,
"nDCG@5": 0.9976,
"P@10": 0.1029,
"R@10": 1.0,
"nDCG@10": 0.8708,
"MRR": 0.8346
"nDCG@10": 0.9976,
"MRR": 1.0
}
},
"generated_at": "20260531T155717Z"
"generated_at": "20260603T084350Z"
}