docs(voyage): mark stage C complete + record empirical fixes
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
Stage C of the voyage-upgrades-plan shipped to production on 2026-05-03. The doc now leads with the final state and the two empirical corrections vs the original plan: 1. Reciprocal Rank Fusion replaces weighted-sum hybrid merge. voyage-3 cosines (~0.4-0.5) systematically outscale voyage-multimodal-3 cosines (~0.20-0.25); a weighted sum lets text dominate even when image is the better signal. RRF is rank-based and robust to scale differences. 2. Chunker now propagates page_number end-to-end (extractor returns per-page offsets, chunker tags each chunk by its first character's page). A retrofit script backfills page_number on existing document_chunks without re-OCR — uses the stored documents.extracted_text plus PyMuPDF direct text reads as page anchors (linear interpolation for OCR-only pages). Production state on cases 8174-24 + 8137-24: 419 page-image embeddings, 819 chunks tagged with page_number, MULTIMODAL_ENABLED=true in Coolify env, hybrid search verified A/B against text-only baseline. The original stage C plan section is retained below for reference. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -163,7 +163,73 @@ queries בשעה במקרה רגיל) — מתחת ל-1% מהמכסה.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## שלב C — voyage-multimodal-3.5 (לביצוע בשיחה החדשה)
|
## שלב C — voyage-multimodal-3 (✅ בוצע 2026-05-03)
|
||||||
|
|
||||||
|
> **תיקון שם המודל מהתכנית המקורית**: השם הסופי הוא
|
||||||
|
> `voyage-multimodal-3` (לא 3.5). הוצמד לזה ש-POC #3 הריץ.
|
||||||
|
|
||||||
|
### מצב סופי בייצור
|
||||||
|
|
||||||
|
- `MULTIMODAL_ENABLED=true` ב-Coolify env
|
||||||
|
- Schema V9 ב-DB (document_image_embeddings + precedent_image_embeddings)
|
||||||
|
- 419 page-image embeddings על 8174-24 (146) + 8137-24 (273)
|
||||||
|
- 819 text chunks קיבלו page_number (100% retrofit)
|
||||||
|
- RRF hybrid merge עם boost text+image פעיל
|
||||||
|
|
||||||
|
### שינויים מהתכנית המקורית — שני תיקונים אמפיריים
|
||||||
|
|
||||||
|
1. **Score scaling — Reciprocal Rank Fusion במקום weighted sum.**
|
||||||
|
ה-cosine של voyage-3 (~0.4-0.5) שיטתית גבוה מ-voyage-multimodal-3
|
||||||
|
(~0.20-0.25). A/B ראשון על 7 שאילתות הראה: עם 0.65/0.35 weighted
|
||||||
|
sum ו-MULTIMODAL_ENABLED=true, **0** image rows הופיעו ב-top-5,
|
||||||
|
image side פשוט הוצף. עברנו ל-RRF (`rrf_score = w / (k + rank)`)
|
||||||
|
שעמיד לסקיילים שונים. תוצאה: 5/5 results עם image contribution
|
||||||
|
בכל שאילתה.
|
||||||
|
|
||||||
|
2. **Page tracking — chunker חדש + retrofit ל-819 chunks קיימים.**
|
||||||
|
ה-chunker הישן זרק את ה-page_number של chunks. בלעדיו ה-boost
|
||||||
|
text+image (join על `(document_id, page_number)`) לא יכול לפעול.
|
||||||
|
נוסף `page_offsets` ל-`extractor.extract_text` (משלשה במקום זוג —
|
||||||
|
מעודכן ב-6 callers); chunker מקבל אותו ומסמן page לכל chunk לפי
|
||||||
|
offset של התווים הראשונים שלו. retrofit ל-chunks קיימים
|
||||||
|
(`scripts/backfill_chunk_pages.py`) עובד **בלי re-OCR** —
|
||||||
|
משתמש ב-stored extracted_text כמקור (matches existing chunk
|
||||||
|
content verbatim) ו-PyMuPDF direct text reads כעיגוני page
|
||||||
|
boundaries; pages סרוקים ללא טקסט ישיר עוברים אינטרפולציה.
|
||||||
|
|
||||||
|
### למה NOT לעשות re-OCR ב-retrofit
|
||||||
|
|
||||||
|
ניסיון ראשון השתמש ב-`extractor.extract_text` להפיק page_offsets
|
||||||
|
חדשים. תוצאה: 1/29 chunks נמצאו (28 not found), כי OCR של Google
|
||||||
|
Vision לא דטרמיניסטי — ה-OCR החדש שונה מה-OCR שהפיק את ה-chunks
|
||||||
|
המקוריים. הגרסה החדשה משתמשת ב-stored `documents.extracted_text`
|
||||||
|
שמתאים לחלוטין לתוכן ה-chunks. עלות: $0 (לעומת ~$0.0015/page).
|
||||||
|
|
||||||
|
### Files שהשתנו (יחסית למה שהמסמך הזה תיכנן)
|
||||||
|
|
||||||
|
קוד שנכתב/שונה (5 commits, 242f668 → 8a815ec):
|
||||||
|
- `mcp-server/src/legal_mcp/config.py` — flags MULTIMODAL_*
|
||||||
|
- `mcp-server/src/legal_mcp/services/extractor.py` — render + page_offsets
|
||||||
|
- `mcp-server/src/legal_mcp/services/embeddings.py` — embed_images
|
||||||
|
- `mcp-server/src/legal_mcp/services/db.py` — schema V9 + 4 store/search funcs
|
||||||
|
- `mcp-server/src/legal_mcp/services/chunker.py` — page tracking
|
||||||
|
- `mcp-server/src/legal_mcp/services/processor.py` — ingest integration
|
||||||
|
- `mcp-server/src/legal_mcp/services/precedent_library.py` — same
|
||||||
|
- `mcp-server/src/legal_mcp/services/hybrid_search.py` — חדש, RRF orchestrator
|
||||||
|
- `mcp-server/src/legal_mcp/tools/search.py` — wired to hybrid
|
||||||
|
- `mcp-server/src/legal_mcp/tools/documents.py` + `tools/workflow.py` + `web/app.py` — extract_text triple unpack
|
||||||
|
- `scripts/multimodal_backfill.py` + `scripts/backfill_chunk_pages.py` — חדשים
|
||||||
|
|
||||||
|
### מה נשאר (deferred)
|
||||||
|
|
||||||
|
- UI thumbnails בתוצאות חיפוש (לא חוסם — דפנה מקבלת page numbers)
|
||||||
|
- Backfill על שאר הקורפוס (מעבר ל-2 התיקים): לא דחוף, אפשר per-case
|
||||||
|
- `text_weight` תיאום: כרגע 0.5 (vanilla RRF). אם דפנה תגיד שהיא רואה
|
||||||
|
יותר מדי image-influence, מעלים ל-0.55-0.6 דרך env בלי deploy.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## שלב C המקורי (תכנון, לרפרנס)
|
||||||
|
|
||||||
### הבעיה שהוא פותר
|
### הבעיה שהוא פותר
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user