Files
legal-ai/docs/architecture.md
Chaim 26c3fddf41
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m29s
feat(retrieval): add voyage rerank-2 cross-encoder stage (feature flag)
Stage B of voyage-upgrades-plan rewritten: instead of context-3 (which
4 POCs showed inconsistent improvement), add a cross-encoder rerank
layer on top of voyage-3. Default off (VOYAGE_RERANK_ENABLED=false).

POC validation (785-doc corpus, 12 queries, claude-haiku-4-5 judge):
- mean@3 +4.5% (4.306 → 4.500)
- practical-category queries +11.6% (3.78 → 4.22)
- latency +702ms per query
- no schema change, no re-embed, no double storage

Plumbing:
- config: VOYAGE_RERANK_ENABLED / _MODEL / _FETCH_K env vars
- embeddings.voyage_rerank() wraps voyageai client.rerank
- services/rerank.py: maybe_rerank() helper — fetches FETCH_K candidates
  via the bi-encoder then reranks to top-K. Fail-open if Voyage rerank is
  unavailable.
- tools/search.py: search_decisions, search_case_documents,
  find_similar_cases all wrapped
- services/precedent_library.search_library wrapped

Smoke-tested locally with flag on/off — produces expected behaviour and
latency profile. Ready for production rollout via Coolify env flip after
deploy.

POCs (kept under scripts/ for reference):
- voyage_context3_poc{_long}.py — context-3 evaluation (rejected)
- voyage_multimodal_poc.py — multimodal-3 (stage C, deferred)
- voyage_rerank_judge_poc.py — single-case rerank benchmark
- voyage_rerank_corpus_poc.py — full-corpus rerank validation

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 18:43:41 +00:00

308 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# System Architecture — Legal Decision Assistant
> עודכן: 2026-04-16 — הוספת ארכיטקטורת Track Changes לעריכת טיוטות
## רכיבי המערכת
```
┌───────────────────────────────────────────────────────────────┐
│ Nautilus Server │
│ 158.178.131.193 │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ legal-ai container (Coolify UUID: gyjo0mtw2c42ej3...) │ │
│ │ ┌────────────┐ ┌──────────────────────────┐ │ │
│ │ │ Next.js UI │ │ FastAPI backend │ │ │
│ │ │ :3000 │◄──►│ :8000 (internal) │ │ │
│ │ └────────────┘ │ + MCP server │ │ │
│ │ └──────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ PostgreSQL + │ │ Redis │ │
│ │ pgvector (1024D) │ │ (task queue) │ │
│ │ legal-ai-postgres│ │ legal-ai-redis │ │
│ └──────────────────┘ └──────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ Gitea │ │ Traefik (SSL + routing) │ │
│ │ (code + cases)│ │ (*.nautilus.marcusgroup) │ │
│ └──────────────┘ └──────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
Local (developer machine, pm2):
┌──────────────────────────────────────────────────────────────┐
│ Paperclip — agent orchestrator │
│ localhost:3100, DB localhost:54329 │
│ Runs Claude Code agents: legal-ceo, legal-writer, │
│ legal-exporter, legal-researcher, legal-qa, legal-proofreader│
└──────────────────────────────────────────────────────────────┘
External:
← Claude API (Opus 4.7 for agents)
← Voyage AI (voyage-3, 1024-dim embeddings)
← Infisical (secret management)
← Gmail SMTP (agent notifications)
```
---
## הזרימה המלאה — מהעלאת מסמכים ועד טיוטה סופית
### שלב 1 — יצירת תיק + העלאת מסמכי מקור
**מה קורה:**
1. חיים יוצר תיק דרך UI (`/cases/new`) — מקבל `case_number` (1xxx = CMP, 8xxx/9xxx = CMPA)
2. מעלה PDFs/DOCX: כתב ערר, תשובה, פרוטוקול, תכניות, היתר, פסיקה
3. ה-backend:
- שומר קובץ ב-`data/cases/{case_number}/documents/originals/`
- מפעיל OCR (Google Vision) אם PDF ללא טקסט
- מריץ proofreader להסרת artifacts מ-Nevo
- מחלץ טקסט ל-`documents.extracted_text`
- מפצל ל-chunks של ~500 מילים, מחשב embeddings (voyage-3, 1024D), שומר ב-`document_chunks`
4. סטטוס תיק: `new``proofread`
### שלב 2 — ניתוח משפטי (legal-researcher + analyst)
**מי רץ:** סוכני Paperclip (מתוזמרים ע"י legal-ceo).
1. **legal-proofreader** — מנקה את המסמכים אחרי OCR
2. **legal-researcher** — מפה תכניות, תקדימים, חקיקה רלוונטית. שומר `research_md`
3. **analyst (legal-researcher pass 1)** — מחלץ טענות (`extract_claims`), ממפה סוגיות, בודק שלמות
סטטוס: `proofread``documents_ready``analyst_verified`
### שלב 3 — החלטת תוצאה + כיוונים (CEO + חיים)
1. **legal-ceo** מציג סיכום לחיים: סיווג, טענות, פסיקה רלוונטית, שאלות מפתח
2. חיים בוחר תוצאה (דחייה/קבלה חלקית/קבלה מלאה)
3. CEO מציג 2-3 **כיוונים סילוגיסטיים** לנימוק
4. חיים מאשר כיוון
סטטוס: `analyst_verified``outcome_set``direction_approved`
### שלב 4 — ניתוח מעמיק (analyst pass 2)
legal-researcher (תפקיד analyst) מעמיק בפסיקה ובחקיקה על בסיס הכיוון שאושר, מאמת ציטוטים מדויקים.
סטטוס: `direction_approved``analysis_enriched`
### שלב 5 — כתיבת טיוטה (legal-writer)
1. CEO יוצר issue לכותב עם **כל ההקשר**: תוצאה, סוגיות, מבנה סילוגיסטי, מסמכי מקור, תקדימים
2. legal-writer כותב בלוק-אחרי-בלוק (12 בלוקים: א-יב) בסגנון דפנה
3. כל בלוק נשמר ב-DB (`decision_blocks.content`)
סטטוס: `ready_for_writing``drafted`
### שלב 6 — QA
legal-qa מריץ 6 בדיקות איכות:
- שלמות (כל 12 הבלוקים מלאים)
- ניטרליות (בלוק ו אין ציטוטים מצדדים)
- אין כפילות (בלוק י מפנה, לא חוזר)
- מספור רציף
- פסיקה מצוטטת במדויק
- תואם `chair_directions` של דפנה
אם עובר → `qa_passed`. אם נכשל → `qa_failed` + issue תיקון לכותב.
### שלב 7 — ייצוא טיוטה ראשונית (legal-exporter)
**מה עשה עד עכשיו:** בונה DOCX מאפס מבלוקים ב-DB.
**מה חדש (2026-04):** הייצוא מזריק **bookmarks** בתחילת וסיום כל בלוק — אנקורים לעריכות עתידיות:
- `<w:bookmarkStart w:name="block-alef">` ... `<w:bookmarkEnd>`
- כך עד `block-yod-bet`
הקובץ: `data/cases/{case_number}/exports/טיוטה-v1.docx` (גופן David, RTL, גודל ~43KB)
**חשוב:** הטיוטה הזו נרשמת ב-`cases.active_draft_path` = **המקור הרשמי של התיק**.
סטטוס: `qa_passed``exported`
---
## שלב 8 — לולאת עריכה מול דפנה (החלק החדש)
> זה הלב של ארכיטקטורת Track Changes שנוספה ב-2026-04.
### 8א. חיים מוריד + עורך + מעלה
1. חיים מוריד `טיוטה-v1.docx` מה-UI
2. פותח ב-Word (שולחן עבודה או Word Online)
3. עורך ידנית: תיקוני ניסוח, עיצוב, תוספות של תוכן שהמערכת לא ידעה עליו
4. שומר מחדש בשם שמתחיל ב-`עריכה-`
5. מעלה חזרה דרך ה-UI (`/cases/{case}` → "העלה גרסה מתוקנת")
### 8ב. Backend קולט — אוטומטית
ה-endpoint `POST /api/cases/{case}/exports/upload` ([web/app.py:1991](web/app.py#L1991)) עושה שלושה דברים:
1. **שומר את הקובץ** כ-`עריכה-v{N}.docx` (כאשר N = הגרסה הבאה)
2. **מריץ retrofit** דרך `apply_user_edit` ב-MCP:
- פותח את ה-DOCX, מזהה גבולות בלוקים לפי heuristic דו-שכבתי:
- א) מרקרים עבריים בתחילת פסקה: `א.`, `ב.`, ..., `יב.`
- ב) כותרות סגנון דפנה: "רקע", "תמצית טענות", "דיון והכרעה", "סוף דבר", וכו'
- מזריק `<w:bookmarkStart>` / `<w:bookmarkEnd>` חסרים
3. **מעדכן את DB**: `cases.active_draft_path = '/data/cases/{case}/exports/עריכה-v{N}.docx'`
התגובה ל-UI כוללת `bookmarks_added`, `missing_blocks`, `apply_status` — ה-UI מציג toast:
- ✓ "הועלה: עריכה-v2.docx — זוהו N בלוקים"
- ⚠ "M בלוקים לא זוהו — ייתכנו בעיות בתיקונים עתידיים"
### 8ג. חיים מבקש תיקון ספציפי מ-CEO
חיים כותב ב-Paperclip comment ל-CEO של החברה:
> "העליתי טיוטה ערוכה. בבקשה הוסף פסק הלכה של בג"ץ 1234/21 בבלוק י' (דיון), ותקן את הניסוח של סוף דבר."
### 8ד. CEO מתזמר — שלב G
[.claude/agents/legal-ceo.md — שלב G](.claude/agents/legal-ceo.md) מפעיל:
1. `list_bookmarks(case_number)` — מקבל את רשימת האנקורים הזמינים
2. אם הבקשה דורשת ניסוח חדש → מפעיל legal-writer במצב **revision**
- writer מקבל `block_id` + `bookmark_anchor` + הוראת ניסוח
- מחזיר טקסט נקי בסגנון דפנה
- **לא שומר ב-DB** (ה-revision חי בקובץ)
3. בונה JSON array של revisions:
```json
[{
"id": "r1",
"type": "insert_after",
"anchor_bookmark": "block-yod",
"content": "<הטקסט שהכותב ניסח>",
"style": "body",
"reason": "הוספת פסק הלכה לפי בקשת חיים"
}]
```
4. קורא ל-`revise_draft(case_number, revisions)`
### 8ה. docx_reviser מבצע XML surgery
[mcp-server/src/legal_mcp/services/docx_reviser.py](mcp-server/src/legal_mcp/services/docx_reviser.py):
1. פותח את `עריכה-v{N}.docx` כ-ZIP + טוען `word/document.xml` עם lxml
2. מוסיף `<w:trackRevisions/>` ב-`word/settings.xml` (אם חסר)
3. לכל revision:
- מאתר את ה-bookmark בעץ
- בונה פסקה חדשה עם RTL + David + המילה "מערכת AI" כמחבר
- עוטף את ה-runs החדשים ב-`<w:ins w:id w:author w:date>`
- שומר IDs ייחודיים (סורק max קיים)
4. שומר כ-`טיוטה-v{N+1}.docx` — **הקובץ החדש שומר על כל העיצוב המקורי של המשתמש** (הטמפלט, הפונטים, הטבלאות, הכל)
5. מעדכן `cases.active_draft_path` לקובץ החדש
### 8ו. חיים מקבל + מאשר/דוחה
1. UI מציג: "טיוטה v{N+1} (מתוקנת) מוכנה לעיון"
2. חיים מוריד, פותח ב-Word
3. ה-Track Changes מופעל — השינויים מסומנים בצבע, סרגל Review פעיל
4. חיים לוחץ Accept על כל שינוי שהוא מסכים איתו, Reject על מה שלא
5. אם יש עוד שינויים שהוא רוצה לבקש — חוזר לשלב 8א (שומר, מעלה `עריכה-v{N+2}.docx`, מבקש עוד שינוי)
### 8ז. סיום — `final`
כשחיים מרוצה, הוא מסמן בייוויי "סמן כסופי" ב-UI → הקובץ מועתק ל-`סופי-{case}.docx` + ל-`data/training/` ללמידה עתידית של דפוסי סגנון.
סטטוס: `exported` → `final`
---
## סכמת DB — 4 שכבות
### Layer 1: Core
`cases`, `documents`, `document_chunks`
**חדש (2026-04):** `cases.active_draft_path TEXT` — הנתיב המלא ל-DOCX שהוא מקור האמת הנוכחי של התיק. null עד לייצוא הראשון.
### Layer 2: Decision
`decisions`, `decision_blocks`, `decision_paragraphs`, `claims`
### Layer 3: Legal Knowledge
`case_law`, `statutory_provisions`, `transition_phrases`, `lessons_learned`, `style_corpus`, `style_patterns`
### Layer 4: Semantic Search (RAG)
`document_embeddings`, `paragraph_embeddings`, `case_law_embeddings` (pgvector 1024-dim, voyage-3)
### Layer 5 — Multi-tenancy
`companies`, `tag_company_mappings` (appeal_subtype → company_id)
---
## רב-חברתיות (CMP + CMPA)
**חברות:**
- CMP (`42a7acd0-30c5-4cbd-ac97-7424f65df294`) — תיקי 1xxx (רישוי ובניה)
- CMPA (`8639e837-4c9d-47fa-a76b-95788d651896`) — תיקי 8xxx/9xxx (היטלי השבחה, פיצויים ס' 197)
**מה משותף לשתי החברות:**
- DB יחיד, backend יחיד, frontend יחיד
- כל הקוד + agents — פועלים לפי `$PAPERCLIP_COMPANY_ID` בזמן ריצה
- ארכיטקטורת Track Changes (docx_reviser, docx_retrofit, apply_user_edit, revise_draft)
**מה כפול לכל חברה:**
- Paperclip skills (`/home/chaim/.paperclip/instances/default/skills/{company_uuid}/`)
- ניתוח סגנון נפרד (`style_patterns` filtered by appeal_subtype)
- CEO agent משלה (CMP: `752cebdd...`, CMPA: `cdbfa8bc...`)
**סקריפט סנכרון:** [scripts/deploy-track-changes.sh](scripts/deploy-track-changes.sh) — מעתיק skills מ-CMP ל-CMPA.
---
## MCP Tools (חלקי — הרלוונטיים לטיוטות)
| Tool | מה עושה |
|------|----------|
| `export_docx(case)` | ייצוא טיוטה ראשונית מה-DB, עם bookmarks. מעדכן `active_draft_path`. |
| `apply_user_edit(case, filename)` | רישום `עריכה-*.docx` כ-active_draft + הזרקת bookmarks. |
| `list_bookmarks(case)` | רשימת אנקורים זמינים ב-active_draft. |
| `revise_draft(case, revisions_json)` | החלת Track Changes על active_draft → יוצר `טיוטה-v{N+1}.docx`. |
| `write_block`, `save_block_content` | כתיבה/שמירה של בלוקים ב-DB (לשלב הכתיבה הראשוני). |
| `validate_decision` | 6 בדיקות QA. |
---
## API Endpoints (הרלוונטיים לטיוטות)
| Endpoint | שימוש |
|----------|--------|
| `POST /api/cases/{case}/export-docx` | ייצוא טיוטה מה-DB |
| `GET /api/cases/{case}/exports` | רשימת טיוטות + עריכות קיימות |
| `GET /api/cases/{case}/exports/{filename}/download` | הורדת קובץ |
| `POST /api/cases/{case}/exports/upload` | **העלאת עריכה → auto-retrofit + register כ-active_draft** |
| `DELETE /api/cases/{case}/exports/{filename}` | מחיקה |
| `POST /api/cases/{case}/exports/{filename}/mark-final` | סימון כסופי |
| `POST /api/cases/{case}/exports/revise` | החלת revisions (Track Changes) |
| `GET /api/cases/{case}/exports/bookmarks` | רשימת bookmarks ב-active_draft |
| `POST /api/cases/{case}/exports/{filename}/retrofit` | ריצת retrofit ידנית (לקבצים ישנים) |
| `GET /api/cases/{case}/active-draft` | סטטוס active_draft (path + exists) |
---
## טכנולוגיות עיקריות
- **Database**: PostgreSQL 15 + pgvector 0.8.1
- **Embeddings**: Voyage AI (`voyage-3`, 1024-dim) + cross-encoder rerank (`rerank-2`)
- bi-encoder: voyage-3 לכל chunk (חד-פעמי בעת ingestion)
- cross-encoder: rerank-2 לכל query (top-50 → top-K), feature flag `VOYAGE_RERANK_ENABLED`
- **Agents**: Claude Opus 4.7 (via Paperclip pm2)
- **DOCX manipulation**: `python-docx` 1.2+ ו-`lxml` 5.2+ (XML surgery)
- **Frontend**: Next.js + TanStack Query + Tailwind
- **Backend**: FastAPI + asyncpg
- **Deployment**: Coolify + Docker + Traefik (SSL ב-Let's Encrypt)
- **Code repo**: Gitea (`gitea.nautilus.marcusgroup.org/ezer-mishpati/legal-ai`)
- **Secret management**: Infisical
---
## מסמכים קשורים
- [`block-schema.md`](block-schema.md) — מבנה 12 הבלוקים, content model, constraints
- [`decision-methodology.md`](decision-methodology.md) — מתודולוגיה אנליטית
- [`legal-decision-lessons.md`](legal-decision-lessons.md) — לקחים מ-3 החלטות
- [`new-company-setup-guide.md`](new-company-setup-guide.md) — הקמת חברה חדשה (CMPA)
- [`product-specification.md`](product-specification.md) — איפיון מוצר מלא (persona, תהליכים עסקיים)
- [`../CLAUDE.md`](../CLAUDE.md) — הנחיות לסוכני AI שעובדים על הקוד
- [`../scripts/SCRIPTS.md`](../scripts/SCRIPTS.md) — כל הסקריפטים והשימוש בהם