01 · Overview
הארכיטקטורה במשפט אחד
Verbatim retrieval מבוסס על hybrid search (BM25 + dense embeddings) על מאגר ישראלי-עברי, מסונן דרך 9-level hierarchical graph ו-doctrine clusters, ללא שום שלב של LLM generation.
לא מכירים מונח? → מילון AI · 15 מונחים בעברית פשוטה (RAG, BM25, embeddings, verbatim retrieval, ועוד).
הסיבה המרכזית להעדפת retrieval על generation: אי אפשר להזות מקור שלא יוצרים. ChatGPT מייצר טקסט סטטיסטי שדומה למשפטי; legal-eye מאחזרת טקסט קיים שהוא משפטי. ההבדל הוא בין נשמע אמין ל-אמין בפועל.
02 · Pipeline
הצינור המלא · 7 שלבים
מהשאלה ועד התשובה, באופן סדרתי. כל שלב מוסיף constraints על השלב הבא ומקטין את המרחב.
[1. understand] parse Hebrew query · POS tagging · entity extraction ~80ms
↓
[2. classify] domain detection (employment/contracts/consumer/tenancy) ~120ms
↓
[3. retrieve] BM25 (k=200) + dense embeddings (k=200) → fusion → k=50 ~600ms
↓
[4. rerank] cross-encoder rerank · doctrine cluster filter · top k=10 ~400ms
↓
[5. verify] citation source check · relevance threshold ~80ms
↓
[6. post-filter] remove low-confidence, dedup near-duplicates ~40ms
↓
[7. enrich] attach source metadata · format verbatim quotes · build bundle ~120ms
סה"כ p95 latency: ~1,500-2,000ms. השלב הכי כבד הוא retrieval (3) בגלל ה-cold disk reads בפעמים הראשונות. אחרי warmup, הקאש פנימי + ה-mmap מורידים את זה ל-800ms.
03 · 9-Level Graph
היררכיה משפטית · 9 רמות
הפסיקה הישראלית אינה שטוחה. יש לה היררכיה ערכית-משפטית: חוק יסוד > חוק רגיל > פסיקת בית המשפט העליון > פסיקת בית הדין הארצי > ... > פסיקת שלום. ה-9-level graph מקודד את זה.
class HierarchicalGraph:
LEVELS = [
"basic_law",
"regular_law",
"regulation",
"extension_order",
"supreme_court",
"labor_court_high",
"district_court",
"labor_court_reg",
"magistrate_court",
]
כאשר המערכת מאחזרת ציטוטים, היא מעדיפה ציטוטים מרמה גבוהה (חוק, עליון) על ציטוטים מרמה נמוכה (שלום) — בהנחה שהם רלוונטיים. הציטוטים הגבוהים יותר נחשבים מחייבים יותר בפסיקה.
04 · Doctrine Clusters
אשכולות דוקטרינות
הפסיקה מתארגנת סביב דוקטרינות: תום לב, הפרה יסודית, מזעור נזק, וכו׳. כל פסק דין שמתבסס על דוקטרינה ספציפית — מתקבצים יחד באשכול.
אלגוריתם בסיסי לבניית clusters:
def build_clusters(citations, doctrines):
clusters = {}
for citation in citations:
scores = doctrine_similarity(citation, doctrines)
cluster_id = argmax(scores)
if scores[cluster_id] > THRESHOLD:
clusters.setdefault(cluster_id, []).append(citation)
return clusters
כשמשתמש שואל שאלה על "תום לב במשא ומתן", המערכת קודם מסווגת את השאלה לאשכול הדוקטרינה תום לב, ואז שולפת ציטוטים רק מהאשכול הזה — מה שמקטין את המרחב מ-10,000 מסמכים ל-~200, ומאפשר ranking מדויק יותר.
05 · Hybrid Search
חיפוש משולב: BM25 + Dense
למה לא רק embeddings? כי בעברית עם מקרקעין משפטיים, ל-match לקסיקלי יש חשיבות עצומה. אם שאלת "פיצויי הלנת שכר", אתה רוצה שיופיע בדיוק ה-string הזה בציטוטים, לא ציטוטים על נושאים דומים סמנטית.
הנוסחה
final_score = α × bm25_score + (1 - α) × cosine(query_emb, doc_emb)
למה α=0.55 ולא 0.5? בעברית-משפטית, ה-match הלקסיקלי טיפה יותר חשוב מהסמנטי. עברנו על ~50 שאלות eval וכיוונו את α עד שקיבלנו את ה-PASS rate הגבוה ביותר.
Embeddings בשימוש
- Base model: multilingual-e5-small (Hugging Face)
- Embedding dim: 384
- Pre-computed: לכל chunk במאגר, embeddings מחושבים מראש ומ-stream-ים מ-FAISS index
06 · Quality · Eval
איך מודדים איכות
ה-eval הוא הציר המרכזי של הפיתוח. בלי eval, אין דרך לדעת אם שינוי שיפר או הרע. ה-eval שלנו פתוח לכולם ב-/eval.
הסט הקנוני
50 שאלות בעברית, מכסות את 4 תחומי הבטא + edge cases. כל שאלה עם:
- Ground truth: התשובה הנכונה (אומתה ע"י עו"ד)
- Expected sources: רשימת citations שאמורות להופיע
- Difficulty band: easy / medium / hard
סוגי תוצאה
PASS
ציטוט מדויק + הקשר נכון
WEAK
ציטוט נכון אבל ניסוח רופף
היעד שלנו: ≥85% PASS לפני production release. נכון להיום: ~70-75% PASS, בעבודה לסגירת הפער.
איך אנחנו מתמודדים עם שינויים
כל שינוי בקוד שמשפיע על retrieval — מריצים את ה-eval המלא. אם ה-PASS rate ירד מעל 2% — השינוי חוזר. אם הוא עלה — נשמר. זה האכיפה היחידה של "אל תהרוס את מה שעובד".
07 · Stack
הסטאק הטכנולוגי
- Backend: FastAPI (Python 3.11) על Hugging Face Spaces (cpu-basic, 16GB RAM)
- Storage: JSONL append-only עם atomic rewrites דרך
.tmp.replace() תחת threading.RLock
- Index: FAISS (in-memory) לembeddings + Whoosh לBM25
- Frontend: Vanilla JS (אפס framework) על Vercel (free tier)
- Domain: legal-eye.1bigfam.com (1bigfam.com ב-Vercel paid)
- Auth: Magic-link דרך SMTP, no password storage
- Audit: Append-only JSONL לכל פעולה רגישה + webhook firehose
- Source control: Git ב-Hugging Face (backend) + GitHub (frontend mirror)
למה Hugging Face Space ולא AWS/GCP?
פשטות, עלות, ו-philosophy. HF Space נותן 16GB RAM חינם — מספיק ל-FAISS index שלנו. אין billing surprises. ו-HF מקושר ל-AI/ML community, מה שמתאים למיצוב שלנו.
למה Vanilla JS ולא React/Vue/Svelte?
כי הצ׳אט הוא פשוט יחסית. אין state ניהול מורכב, אין רינדור כבד. Vanilla JS = bundle 24KB (לעומת ~200KB+ ב-React minimum). זמן טעינה מהיר = פחות bounce.
08 · Known Limits
מגבלות ידועות
שקיפות = גם על מה לא עובד.
מגבלות מובנות
- עברית בלבד — המנוע לא תומך באנגלית/ערבית. תכנון לערבית ב-Q4 2026.
- 4 תחומי בטא בלבד — דיני משפחה, פלילי, נזיקין מורכב — לא ברמת הבשלות הנדרשת.
- פסיקה מ-~2024 ואחורה — עדכון רבעוני, אז פסקי דין של חודש אחרון לא יופיעו.
- אין long-context reasoning — שאלות שמצריכות שילוב של 3+ דוקטרינות עשויות להחזיר רק 1-2 ציטוטים רלוונטיים.
- p95 latency ~2s — חוויה לא "מיידית" כמו ChatGPT, אבל בלי הזיות.
מה אנחנו לא מבטיחים
- לא ייעוץ משפטי — רק מציגים מקור
- לא תשובה לכל שאלה — אם אין במאגר, המערכת אומרת זאת
- לא פסיקה מהיום (עדכון רבעוני)
- לא תחליף לעו"ד אישי
09 · Resources
קוד, מאמרים, ושיתוף פעולה
חוקרים/אקדמיה מוזמנים לפנות לשיתוף פעולה: ivri0024@gmail.com
בנית משהו דומה? יש שאלה טכנית?
פתוחים לשיתוף פעולה אקדמי, contributions ל-eval set, וביקורת קונסטרוקטיבית.
צור קשר ←
משאבים טכניים נוספים
המתודולוגיה זה הליבה. אלה הכלים והדפים שמסביב.
שתף עם דבלופר/חוקר שיתעניין: