mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-27 09:26:22 +02:00
Structure the tech specs directory (#836)
Tech spec some subdirectories for different languages
This commit is contained in:
parent
48da6c5f8b
commit
e7efb673ef
423 changed files with 0 additions and 0 deletions
135
docs/tech-specs/he/__TEMPLATE.he.md
Normal file
135
docs/tech-specs/he/__TEMPLATE.he.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
layout: default
|
||||
title: "Command-Line Loading Knowledge Technical Specification"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# Command-Line Loading Knowledge Technical Specification
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## Overview
|
||||
|
||||
מפרט זה מתאר את ממשקי שורת הפקודה לטעינת ידע לתוך TrustGraph, ומאפשר למשתמשים לקלוט נתונים ממקורות שונים באמצעות כלי שורת פקודה. האינטגרציה תומכת בארבעה תרחישי שימוש עיקריים:
|
||||
|
||||
1. **[Use Case 1]**: [Description]
|
||||
2. **[Use Case 2]**: [Description]
|
||||
3. **[Use Case 3]**: [Description]
|
||||
4. **[Use Case 4]**: [Description]
|
||||
|
||||
## Goals
|
||||
|
||||
- **[Goal 1]**: [Description]
|
||||
- **[Goal 2]**: [Description]
|
||||
- **[Goal 3]**: [Description]
|
||||
- **[Goal 4]**: [Description]
|
||||
- **[Goal 5]**: [Description]
|
||||
- **[Goal 6]**: [Description]
|
||||
- **[Goal 7]**: [Description]
|
||||
- **[Goal 8]**: [Description]
|
||||
|
||||
## Background
|
||||
|
||||
[Describe the current state and limitations that this specification addresses]
|
||||
|
||||
מגבלות נוכחיות כוללות:
|
||||
- [Limitation 1]
|
||||
- [Limitation 2]
|
||||
- [Limitation 3]
|
||||
- [Limitation 4]
|
||||
|
||||
מפרט זה מתייחס לפערים אלה על ידי [description]. באמצעות [capability], TrustGraph יכול:
|
||||
- [Benefit 1]
|
||||
- [Benefit 2]
|
||||
- [Benefit 3]
|
||||
- [Benefit 4]
|
||||
|
||||
## Technical Design
|
||||
|
||||
### Architecture
|
||||
|
||||
טעינת ידע משורת הפקודה דורשת את הרכיבים הטכניים הבאים:
|
||||
|
||||
1. **[Component 1]**
|
||||
- [Description of component functionality]
|
||||
- [Key features]
|
||||
- [Integration points]
|
||||
|
||||
Module: [module-path]
|
||||
|
||||
2. **[Component 2]**
|
||||
- [Description of component functionality]
|
||||
- [Key features]
|
||||
- [Integration points]
|
||||
|
||||
Module: [module-path]
|
||||
|
||||
3. **[Component 3]**
|
||||
- [Description of component functionality]
|
||||
- [Key features]
|
||||
- [Integration points]
|
||||
|
||||
Module: [module-path]
|
||||
|
||||
### Data Models
|
||||
|
||||
#### [Data Model 1]
|
||||
|
||||
[Description of data model and structure]
|
||||
|
||||
Example:
|
||||
```
|
||||
[Example data structure]
|
||||
```
|
||||
|
||||
גישה זו מאפשרת:
|
||||
- [Benefit 1]
|
||||
- [Benefit 2]
|
||||
- [Benefit 3]
|
||||
- [Benefit 4]
|
||||
|
||||
### ממשקי API
|
||||
|
||||
ממשקי API חדשים:
|
||||
- [API description 1]
|
||||
- [API description 2]
|
||||
- [API description 3]
|
||||
|
||||
ממשקי API ששונו:
|
||||
- [Modified API 1] - [Description of changes]
|
||||
- [Modified API 2] - [Description of changes]
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
[גישת יישום ועקרונות]
|
||||
|
||||
[הערות נוספות בנוגע ליישום]
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
[שיקולי אבטחה ספציפיים ליישום זה]
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
[שיקולי ביצועים וצווארי בקבוק פוטנציאליים]
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
[גישת אסטרטגיית בדיקות]
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
[אסטרטגיית מעבר, אם רלוונטית]
|
||||
|
||||
## ציר זמן
|
||||
|
||||
[מידע על ציר הזמן, אם מצוין]
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
- [Open question 1]
|
||||
- [Open question 2]
|
||||
|
||||
## מקורות
|
||||
|
||||
[מקורות, אם רלוונטיים]
|
||||
280
docs/tech-specs/he/agent-explainability.he.md
Normal file
280
docs/tech-specs/he/agent-explainability.he.md
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
---
|
||||
layout: default
|
||||
title: "הסברתיות של סוכן: רישום מקורות"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# הסברתיות של סוכן: רישום מקורות
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
הוספת רישום מקורות ללולאת הסוכן של React כך שניתן יהיה לעקוב אחר סשנים של סוכנים ולבצע ניפוי באגים באמצעות אותה תשתית הסברתיות כמו GraphRAG.
|
||||
|
||||
**החלטות עיצוב:**
|
||||
כתיבה ל-`urn:graph:retrieval` (גרף הסברתיות גנרי)
|
||||
שרשרת תלות ליניארית כרגע (ניתוח N → נגזר מ → ניתוח N-1)
|
||||
כלים הם תיבות שחורות (רישום קלט/פלט בלבד)
|
||||
תמיכה ב-DAG (גרף מכוון) נדחית למהלך עתידי
|
||||
|
||||
## סוגי ישויות
|
||||
|
||||
גם GraphRAG וגם Agent משתמשים ב-PROV-O כאונטולוגיה בסיסית עם תת-סוגים ספציפיים ל-TrustGraph:
|
||||
|
||||
### סוגי GraphRAG
|
||||
| ישות | סוג PROV-O | סוגי TG | תיאור |
|
||||
|--------|-------------|----------|-------------|
|
||||
| שאלה | `prov:Activity` | `tg:Question`, `tg:GraphRagQuestion` | השאלה של המשתמש |
|
||||
| חקירה | `prov:Entity` | `tg:Exploration` | צמתים שאוחזרו מגרף ידע |
|
||||
| מיקוד | `prov:Entity` | `tg:Focus` | צמתים שנבחרו עם נימוק |
|
||||
| סינתזה | `prov:Entity` | `tg:Synthesis` | תשובה סופית |
|
||||
|
||||
### סוגי סוכן
|
||||
| ישות | סוג PROV-O | סוגי TG | תיאור |
|
||||
|--------|-------------|----------|-------------|
|
||||
| שאלה | `prov:Activity` | `tg:Question`, `tg:AgentQuestion` | השאלה של המשתמש |
|
||||
| ניתוח | `prov:Entity` | `tg:Analysis` | כל מחזור חשיבה/פעולה/תצפית |
|
||||
| מסקנה | `prov:Entity` | `tg:Conclusion` | תשובה סופית |
|
||||
|
||||
### סוגי RAG של מסמכים
|
||||
| ישות | סוג PROV-O | סוגי TG | תיאור |
|
||||
|--------|-------------|----------|-------------|
|
||||
| שאלה | `prov:Activity` | `tg:Question`, `tg:DocRagQuestion` | השאלה של המשתמש |
|
||||
| חקירה | `prov:Entity` | `tg:Exploration` | חלקים שאוחזרו מחנות מסמכים |
|
||||
| סינתזה | `prov:Entity` | `tg:Synthesis` | תשובה סופית |
|
||||
|
||||
**הערה:** RAG של מסמכים משתמש בתת-קבוצה של סוגים של GraphRAG (אין שלב מיקוד מכיוון שאין שלב בחירת/נימוק צמתים).
|
||||
|
||||
### תת-סוגים של שאלה
|
||||
|
||||
כל ישויות השאלה חולקות את `tg:Question` כסוג בסיסי אך יש להן תת-סוג ספציפי כדי לזהות את מנגנון השליפה:
|
||||
|
||||
| תת-סוג | תבנית URI | מנגנון |
|
||||
|---------|-------------|-----------|
|
||||
| `tg:GraphRagQuestion` | `urn:trustgraph:question:{uuid}` | RAG של גרף ידע |
|
||||
| `tg:DocRagQuestion` | `urn:trustgraph:docrag:{uuid}` | RAG של מסמכים/חלקים |
|
||||
| `tg:AgentQuestion` | `urn:trustgraph:agent:{uuid}` | סוכן ReAct |
|
||||
|
||||
זה מאפשר שאילתא של כל השאלות באמצעות `tg:Question` תוך סינון לפי מנגנון ספציפי באמצעות תת-הסוג.
|
||||
|
||||
## מודל מקורות
|
||||
|
||||
```
|
||||
Question (urn:trustgraph:agent:{uuid})
|
||||
│
|
||||
│ tg:query = "User's question"
|
||||
│ prov:startedAtTime = timestamp
|
||||
│ rdf:type = prov:Activity, tg:Question
|
||||
│
|
||||
↓ prov:wasDerivedFrom
|
||||
│
|
||||
Analysis1 (urn:trustgraph:agent:{uuid}/i1)
|
||||
│
|
||||
│ tg:thought = "I need to query the knowledge base..."
|
||||
│ tg:action = "knowledge-query"
|
||||
│ tg:arguments = {"question": "..."}
|
||||
│ tg:observation = "Result from tool..."
|
||||
│ rdf:type = prov:Entity, tg:Analysis
|
||||
│
|
||||
↓ prov:wasDerivedFrom
|
||||
│
|
||||
Analysis2 (urn:trustgraph:agent:{uuid}/i2)
|
||||
│ ...
|
||||
↓ prov:wasDerivedFrom
|
||||
│
|
||||
Conclusion (urn:trustgraph:agent:{uuid}/final)
|
||||
│
|
||||
│ tg:answer = "The final response..."
|
||||
│ rdf:type = prov:Entity, tg:Conclusion
|
||||
```
|
||||
|
||||
### מודל מקור (Provenance) של מסמכים בשיטת RAG
|
||||
|
||||
```
|
||||
Question (urn:trustgraph:docrag:{uuid})
|
||||
│
|
||||
│ tg:query = "User's question"
|
||||
│ prov:startedAtTime = timestamp
|
||||
│ rdf:type = prov:Activity, tg:Question
|
||||
│
|
||||
↓ prov:wasGeneratedBy
|
||||
│
|
||||
Exploration (urn:trustgraph:docrag:{uuid}/exploration)
|
||||
│
|
||||
│ tg:chunkCount = 5
|
||||
│ tg:selectedChunk = "chunk-id-1"
|
||||
│ tg:selectedChunk = "chunk-id-2"
|
||||
│ ...
|
||||
│ rdf:type = prov:Entity, tg:Exploration
|
||||
│
|
||||
↓ prov:wasDerivedFrom
|
||||
│
|
||||
Synthesis (urn:trustgraph:docrag:{uuid}/synthesis)
|
||||
│
|
||||
│ tg:content = "The synthesized answer..."
|
||||
│ rdf:type = prov:Entity, tg:Synthesis
|
||||
```
|
||||
|
||||
## שינויים נדרשים
|
||||
|
||||
### 1. שינויים בסכימה
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
|
||||
הוסף את השדות `session_id` ו-`collection` ל-`AgentRequest`:
|
||||
```python
|
||||
@dataclass
|
||||
class AgentRequest:
|
||||
question: str = ""
|
||||
state: str = ""
|
||||
group: list[str] | None = None
|
||||
history: list[AgentStep] = field(default_factory=list)
|
||||
user: str = ""
|
||||
collection: str = "default" # NEW: Collection for provenance traces
|
||||
streaming: bool = False
|
||||
session_id: str = "" # NEW: For provenance tracking across iterations
|
||||
```
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/messaging/translators/agent.py`
|
||||
|
||||
עדכון המתרגם כדי לטפל ב-`session_id` וב-`collection` הן ב-`to_pulsar()` והן ב-`from_pulsar()`.
|
||||
|
||||
### 2. הוספת יצרן הסברות לשירות הסוכנים
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/agent/react/service.py`
|
||||
|
||||
רישום יצרן "הסברות" (באותו דפוס כמו GraphRAG):
|
||||
```python
|
||||
from ... base import ProducerSpec
|
||||
from ... schema import Triples
|
||||
|
||||
# In __init__:
|
||||
self.register_specification(
|
||||
ProducerSpec(
|
||||
name = "explainability",
|
||||
schema = Triples,
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
### 3. יצירת משולש מוצא
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/provenance/agent.py`
|
||||
|
||||
צור פונקציות עזר (בדומה ל-`question_triples`, `exploration_triples` וכו' של GraphRAG):
|
||||
```python
|
||||
def agent_session_triples(session_uri, query, timestamp):
|
||||
"""Generate triples for agent Question."""
|
||||
return [
|
||||
Triple(s=session_uri, p=RDF_TYPE, o=PROV_ACTIVITY),
|
||||
Triple(s=session_uri, p=RDF_TYPE, o=TG_QUESTION),
|
||||
Triple(s=session_uri, p=TG_QUERY, o=query),
|
||||
Triple(s=session_uri, p=PROV_STARTED_AT_TIME, o=timestamp),
|
||||
]
|
||||
|
||||
def agent_iteration_triples(iteration_uri, parent_uri, thought, action, arguments, observation):
|
||||
"""Generate triples for one Analysis step."""
|
||||
return [
|
||||
Triple(s=iteration_uri, p=RDF_TYPE, o=PROV_ENTITY),
|
||||
Triple(s=iteration_uri, p=RDF_TYPE, o=TG_ANALYSIS),
|
||||
Triple(s=iteration_uri, p=TG_THOUGHT, o=thought),
|
||||
Triple(s=iteration_uri, p=TG_ACTION, o=action),
|
||||
Triple(s=iteration_uri, p=TG_ARGUMENTS, o=json.dumps(arguments)),
|
||||
Triple(s=iteration_uri, p=TG_OBSERVATION, o=observation),
|
||||
Triple(s=iteration_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri),
|
||||
]
|
||||
|
||||
def agent_final_triples(final_uri, parent_uri, answer):
|
||||
"""Generate triples for Conclusion."""
|
||||
return [
|
||||
Triple(s=final_uri, p=RDF_TYPE, o=PROV_ENTITY),
|
||||
Triple(s=final_uri, p=RDF_TYPE, o=TG_CONCLUSION),
|
||||
Triple(s=final_uri, p=TG_ANSWER, o=answer),
|
||||
Triple(s=final_uri, p=PROV_WAS_DERIVED_FROM, o=parent_uri),
|
||||
]
|
||||
```
|
||||
|
||||
### 4. הגדרות סוג
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/provenance/namespaces.py`
|
||||
|
||||
הוסף סוגי ישויות הסבר ופרדיקטים של סוכנים:
|
||||
```python
|
||||
# Explainability entity types (used by both GraphRAG and Agent)
|
||||
TG_QUESTION = TG + "Question"
|
||||
TG_EXPLORATION = TG + "Exploration"
|
||||
TG_FOCUS = TG + "Focus"
|
||||
TG_SYNTHESIS = TG + "Synthesis"
|
||||
TG_ANALYSIS = TG + "Analysis"
|
||||
TG_CONCLUSION = TG + "Conclusion"
|
||||
|
||||
# Agent predicates
|
||||
TG_THOUGHT = TG + "thought"
|
||||
TG_ACTION = TG + "action"
|
||||
TG_ARGUMENTS = TG + "arguments"
|
||||
TG_OBSERVATION = TG + "observation"
|
||||
TG_ANSWER = TG + "answer"
|
||||
```
|
||||
|
||||
## קבצים ששונו
|
||||
|
||||
| קובץ | שינוי |
|
||||
|------|--------|
|
||||
| `trustgraph-base/trustgraph/schema/services/agent.py` | הוספת session_id ו-collection ל-AgentRequest |
|
||||
| `trustgraph-base/trustgraph/messaging/translators/agent.py` | עדכון מתרגם עבור שדות חדשים |
|
||||
| `trustgraph-base/trustgraph/provenance/namespaces.py` | הוספת סוגי ישויות, טענות של סוכן וטענות של Document RAG |
|
||||
| `trustgraph-base/trustgraph/provenance/triples.py` | הוספת סוגי TG לבונים של משולשים של GraphRAG, הוספת בונים של משולשים של Document RAG |
|
||||
| `trustgraph-base/trustgraph/provenance/uris.py` | הוספת יוצרי URI של Document RAG |
|
||||
| `trustgraph-base/trustgraph/provenance/__init__.py` | ייצוא סוגים, טענות ופונקציות חדשות של Document RAG |
|
||||
| `trustgraph-base/trustgraph/schema/services/retrieval.py` | הוספת explain_id ו-explain_graph ל-DocumentRagResponse |
|
||||
| `trustgraph-base/trustgraph/messaging/translators/retrieval.py` | עדכון DocumentRagResponseTranslator עבור שדות הסברתיות |
|
||||
| `trustgraph-flow/trustgraph/agent/react/service.py` | הוספת מפיק הסברתיות + לוגיקת הקלטה |
|
||||
| `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` | הוספת קריאה חוזרת של הסברתיות ופליטת משולשים של מקור |
|
||||
| `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` | הוספת מפיק הסברתיות וחיבור הקריאה החוזרת |
|
||||
| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | טיפול בסוגי מעקב של סוכן |
|
||||
| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | הצגת סשנים של סוכן לצד GraphRAG |
|
||||
|
||||
## קבצים שנוצרו
|
||||
|
||||
| קובץ | מטרה |
|
||||
|------|---------|
|
||||
| `trustgraph-base/trustgraph/provenance/agent.py` | יוצרי משולשים ספציפיים לסוכן |
|
||||
|
||||
## עדכוני CLI
|
||||
|
||||
**זיהוי:** גם לשאלות GraphRAG וגם לשאלות סוכן יש סוג `tg:Question`. מובחנים על ידי:
|
||||
1. תבנית URI: `urn:trustgraph:agent:` לעומת `urn:trustgraph:question:`
|
||||
2. ישויות נגזרות: `tg:Analysis` (סוכן) לעומת `tg:Exploration` (GraphRAG)
|
||||
|
||||
**`list_explain_traces.py`:**
|
||||
מציג את עמודת הסוג (סוכן לעומת GraphRAG)
|
||||
|
||||
**`show_explain_trace.py`:**
|
||||
מזהה אוטומטית את סוג המעקב
|
||||
הצגת סוכן מציגה: שאלה → שלב(ים) של ניתוח → מסקנה
|
||||
|
||||
## תאימות לאחור
|
||||
|
||||
`session_id` כברירת מחדל הוא `""` - בקשות ישנות עובדות, פשוט לא יהיו להן נתונים של מקור
|
||||
`collection` כברירת מחדל הוא `"default"` - חזרה סבירה
|
||||
ה-CLI מטפל בצורה חלקה בשני סוגי המעקב
|
||||
|
||||
## אימות
|
||||
|
||||
```bash
|
||||
# Run an agent query
|
||||
tg-invoke-agent -q "What is the capital of France?"
|
||||
|
||||
# List traces (should show agent sessions with Type column)
|
||||
tg-list-explain-traces -U trustgraph -C default
|
||||
|
||||
# Show agent trace
|
||||
tg-show-explain-trace "urn:trustgraph:agent:xxx"
|
||||
```
|
||||
|
||||
## עבודה עתידית (לא בבקשה הזו)
|
||||
|
||||
תלותיות DAG (כאשר ניתוח N משתמש בתוצאות ממספר ניתוחים קודמים)
|
||||
קישור מקורות מידע ספציפי לכלי (KnowledgeQuery → המעקב GraphRAG שלו)
|
||||
פליטת מקורות מידע בסטרימינג (לשלוח תוך כדי פעולה, ולא במקשה בסוף)
|
||||
113
docs/tech-specs/he/architecture-principles.he.md
Normal file
113
docs/tech-specs/he/architecture-principles.he.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
---
|
||||
layout: default
|
||||
title: "יסודות ארכיטקטורת גרף ידע"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# יסודות ארכיטקטורת גרף ידע
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## יסוד 1: מודל גרף נושא-תכונה-אובייקט (SPO)
|
||||
**החלטה**: לאמץ את מודל SPO/RDF כמודל הייצוג הבסיסי של ידע.
|
||||
|
||||
**הצדקה**:
|
||||
מספק גמישות מרבית ותאימות עם טכנולוגיות גרף קיימות.
|
||||
מאפשר המרה חלקה לשפות שאילתות גרף אחרות (לדוגמה, SPO → Cypher, אך לא להיפך).
|
||||
יוצר בסיס ש"פותח הרבה" יכולות נלוות.
|
||||
תומך הן בקשרים בין צמתים (SPO) והן בקשרים בין צמתים לערכים (RDF).
|
||||
|
||||
**יישום**:
|
||||
מבנה נתונים מרכזי: `node → edge → {node | literal}`
|
||||
שמירה על תאימות לתקני RDF תוך תמיכה בפעולות SPO מורחבות.
|
||||
|
||||
## יסוד 2: שילוב גרף ידע מותאם למודלי שפה גדולים (LLM)
|
||||
**החלטה**: אופטימיזציה של מבנה ותפעול גרף ידע לאינטראקציה עם LLM.
|
||||
|
||||
**הצדקה**:
|
||||
מקרה שימוש עיקרי כולל LLM באינטראקציה עם גרפי ידע.
|
||||
בחירות טכנולוגיות גרף חייבות לתעדף תאימות ל-LLM על פני שיקולים אחרים.
|
||||
מאפשר זרימות עבודה של עיבוד שפה טבעית המנצלות ידע מובנה.
|
||||
|
||||
**יישום**:
|
||||
תכנון סכימות גרף ש-LLM יכולים להסיק מהן בצורה יעילה.
|
||||
אופטימיזציה לדפוסי אינטראקציה נפוצים של LLM.
|
||||
|
||||
## יסוד 3: ניווט גרף מבוסס הטבעות (Embeddings)
|
||||
**החלטה**: יישום מיפוי ישיר משאילתות בשפה טבעית לצמתים בגרף באמצעות הטבעות.
|
||||
|
||||
**הצדקה**:
|
||||
מאפשר את הנתיב הפשוט ביותר משאילת NLP לניווט בגרף.
|
||||
נמנע משלבי יצירת שאילתות ביניים מורכבים.
|
||||
מספק יכולות חיפוש סמנטיות יעילות בתוך מבנה הגרף.
|
||||
|
||||
**יישום**:
|
||||
`NLP Query → Graph Embeddings → Graph Nodes`
|
||||
שמירה על ייצוגי הטבעות עבור כל ישויות הגרף.
|
||||
תמיכה בהתאמת דמיון סמנטי ישירה לפתרון שאילתות.
|
||||
|
||||
## יסוד 4: פתרון ישויות מבוזר עם מזהים דטרמיניסטיים
|
||||
**החלטה**: תמיכה בחילוץ ידע מקבילי עם זיהוי ישויות דטרמיניסטי (כלל 80%).
|
||||
|
||||
**הצדקה**:
|
||||
**אידיאלי**: חילוץ בתהליך יחיד עם נראות של מצב מלא מאפשר פתרון ישויות מושלם.
|
||||
**מציאות**: דרישות סקיילביליות מחייבות יכולות עיבוד מקבילי.
|
||||
**פשרה**: תכנון לזיהוי ישויות דטרמיניסטי בכל תהליכים מבוזרים.
|
||||
|
||||
**יישום**:
|
||||
פיתוח מנגנונים ליצירת מזהים עקביים וייחודיים בכל חולצי הידע.
|
||||
אותה ישות המוזכרת בתהליכים שונים חייבת להתפרש לאותו מזהה.
|
||||
יש להכיר בכך ש~20% מהמקרים המיוחדים עשויים לדרוש מודלי עיבוד חלופיים.
|
||||
תכנון מנגנוני ברירת מחדל עבור תרחישי פתרון ישויות מורכבים.
|
||||
|
||||
## יסוד 5: ארכיטקטורה מונעת אירועים עם פרסום-מנוי
|
||||
**החלטה**: יישום מערכת הודעות מבוססת פרסום-מנוי לתיאום מערכות.
|
||||
|
||||
**הצדקה**:
|
||||
מאפשר צימוד רופף בין רכיבי חילוץ, אחסון ושאילתות ידע.
|
||||
תומך בעדכונים והתראות בזמן אמת ברחבי המערכת.
|
||||
מקל על זרימות עבודה מבוזרות וניתנות להרחבה.
|
||||
|
||||
**יישום**:
|
||||
תיאום מונחה הודעות בין רכיבי מערכת.
|
||||
זרמי אירועים לעדכוני ידע, השלמת חילוץ ושליחת תוצאות שאילתות.
|
||||
|
||||
## יסוד 6: תקשורת סוכנים חוזרת
|
||||
**החלטה**: תמיכה בפעולות פרסום-מנוי חוזרות לעיבוד מבוסס סוכנים.
|
||||
|
||||
**הצדקה**:
|
||||
מאפשר זרימות עבודה מורכבות של סוכנים שבהם סוכנים יכולים להפעיל ולהגיב זה לזה.
|
||||
תומך בצינורות עיבוד ידע מורכבים, רב-שלביים.
|
||||
מאפשר דפוסי עיבוד רקורסיביים ואיטרטיביים.
|
||||
|
||||
**יישום**:
|
||||
מערכת הפרסום-מנוי חייבת לטפל בשיחות חוזרות בצורה בטוחה.
|
||||
מנגנוני תיאום סוכנים שמונעים לולאות אינסופיות.
|
||||
תמיכה בתיאום זרימות עבודה של סוכנים.
|
||||
|
||||
## יסוד 7: שילוב עם חנות נתונים טבלאית
|
||||
**החלטה**: הבטחת תאימות שאילתות למערכות אחסון טבלאיות.
|
||||
|
||||
**הצדקה**:
|
||||
מאפשר שאילתות אנליטיות יעילות על פני מערכי ידע גדולים.
|
||||
תומך במקרי שימוש של מודיעין עסקי ודיווח.
|
||||
גשר בין ייצוג ידע מבוסס גרף לבין זרימות עבודה אנליטיות מסורתיות.
|
||||
|
||||
**יישום**:
|
||||
שכבת תרגום שאילתות: שאילתות גרף → שאילתות טבלאיות.
|
||||
אסטרטגיית אחסון היברידית התומכת הן בפעולות גרף והן בעומסי עבודה אנליטיים.
|
||||
שמירה על ביצועי שאילתות בשני הפרדיגמות.
|
||||
|
||||
--
|
||||
|
||||
## סיכום עקרונות ארכיטקטורה
|
||||
|
||||
1. **גמישות ראשית**: מודל SPO/RDF מספק יכולת הסתגלות מרבית.
|
||||
2. **אופטימיזציה ל-LLM**: כל החלטות התכנון מתייחסות לאינטראקציה עם LLM.
|
||||
3. **ניווט יעיל**: שימוש בטבעות (Embeddings) לניווט יעיל בגרף.
|
||||
4. **פתרון ישויות מבוזר**: תמיכה בחילוץ ידע מקבילי עם מזהים דטרמיניסטיים.
|
||||
5. **תיאום מערכות**: שימוש במערכת הודעות מבוססת פרסום-מנוי.
|
||||
6. **עיבוד סוכנים חוזר**: תמיכה בפעולות פרסום-מנוי חוזרות לעיבוד מבוסס סוכנים.
|
||||
7. **תאימות שאילתות**: הבטחת תאימות שאילתות למערכות אחסון טבלאיות.
|
||||
|
||||
יסודות אלה מציבים ארכיטקטורת גרף ידע המאזנת בין דיוק תיאורטי לדרישות מדרגיות מעשיות, ומותאמת לאינטגרציה עם מודלי שפה גדולים (LLM) ולעיבוד מבוזר.
|
||||
339
docs/tech-specs/he/cassandra-consolidation.he.md
Normal file
339
docs/tech-specs/he/cassandra-consolidation.he.md
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני: איחוד תצורת Cassandra"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני: איחוד תצורת Cassandra
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
**סטטוס:** טיוטה
|
||||
**כותב:** עוזר
|
||||
**תאריך:** 2024-09-03
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה עוסק בדפוסי שמות ותצורות לא עקביים עבור פרמטרי חיבור ל-Cassandra ברחבי בסיס הקוד של TrustGraph. כיום, קיימים שני סכימות שמות פרמטרים שונות (`cassandra_*` לעומת `graph_*`), מה שמוביל לבלבול ולמורכבות תחזוקה.
|
||||
|
||||
## הצגת הבעיה
|
||||
|
||||
בסיס הקוד משתמש כיום בשתי קבוצות נפרדות של פרמטרי תצורה של Cassandra:
|
||||
|
||||
1. **מודולים של Knowledge/Config/Library** משתמשים:
|
||||
`cassandra_host` (רשימת מארחים)
|
||||
`cassandra_user`
|
||||
`cassandra_password`
|
||||
|
||||
2. **מודולים של Graph/Storage** משתמשים:
|
||||
`graph_host` (מאריך יחיד, לעיתים מומר לרשימה)
|
||||
`graph_username`
|
||||
`graph_password`
|
||||
|
||||
3. **חשיפה לא עקבית דרך שורת הפקודה**:
|
||||
חלק מהמעבדים (לדוגמה, `kg-store`) אינם חושפים הגדרות Cassandra כארגומנטים של שורת הפקודה
|
||||
מעבדים אחרים חושפים אותם עם שמות ופורמטים שונים
|
||||
טקסט העזרה אינו משקף ערכי משתני סביבה ברירת מחדל
|
||||
|
||||
שתי קבוצות הפרמטרים מתחברות לאותו кластер Cassandra, אך עם קונבנציות שמות שונות, מה שגורם ל:
|
||||
בלבול בתצורת משתמשים
|
||||
עומס תחזוקה מוגבר
|
||||
תיעוד לא עקבי
|
||||
פוטנציאל לטעות בתצורה
|
||||
חוסר יכולת לשנות הגדרות דרך שורת הפקודה בחלק מהמעבדים
|
||||
|
||||
## פתרון מוצע
|
||||
|
||||
### 1. סטנדרטיזציה של שמות פרמטרים
|
||||
|
||||
כל המודולים ישתמשו בשמות פרמטרים עקביים של `cassandra_*`:
|
||||
`cassandra_host` - רשימת מארחים (מאוחסנת פנימית כרשימה)
|
||||
`cassandra_username` - שם משתמש לאימות
|
||||
`cassandra_password` - סיסמה לאימות
|
||||
|
||||
### 2. ארגומנטים של שורת הפקודה
|
||||
|
||||
כל המעבדים חייבים לחשוף את תצורת Cassandra דרך ארגומנטים של שורת הפקודה:
|
||||
`--cassandra-host` - רשימה מופרדת בפסיקים של מארחים
|
||||
`--cassandra-username` - שם משתמש לאימות
|
||||
`--cassandra-password` - סיסמה לאימות
|
||||
|
||||
### 3. חלופה של משתני סביבה
|
||||
|
||||
אם לא סופקו פרמטרים של שורת הפקודה, המערכת תבדוק משתני סביבה:
|
||||
`CASSANDRA_HOST` - רשימה מופרדת בפסיקים של מארחים
|
||||
`CASSANDRA_USERNAME` - שם משתמש לאימות
|
||||
`CASSANDRA_PASSWORD` - סיסמה לאימות
|
||||
|
||||
### 4. ערכי ברירת מחדל
|
||||
|
||||
אם לא צוינו פרמטרים של שורת פקודה ולא משתני סביבה:
|
||||
`cassandra_host` ברירת המחדל היא `["cassandra"]`
|
||||
`cassandra_username` ברירת המחדל היא `None` (ללא אימות)
|
||||
`cassandra_password` ברירת המחדל היא `None` (ללא אימות)
|
||||
|
||||
### 5. דרישות טקסט עזרה
|
||||
|
||||
הפלט של `--help` חייב:
|
||||
להציג ערכי משתני סביבה כברירות מחדל כאשר הם מוגדרים
|
||||
לעולם לא להציג ערכי סיסמה (להציג `****` או `<set>` במקום)
|
||||
לציין בבירור את סדר הפתרון בטקסט העזרה
|
||||
|
||||
דוגמה לפלט עזרה:
|
||||
```
|
||||
--cassandra-host HOST
|
||||
Cassandra host list, comma-separated (default: prod-cluster-1,prod-cluster-2)
|
||||
[from CASSANDRA_HOST environment variable]
|
||||
|
||||
--cassandra-username USERNAME
|
||||
Cassandra username (default: cassandra_user)
|
||||
[from CASSANDRA_USERNAME environment variable]
|
||||
|
||||
--cassandra-password PASSWORD
|
||||
Cassandra password (default: <set from environment>)
|
||||
```
|
||||
|
||||
## פרטי יישום
|
||||
|
||||
### סדר פתרון פרמטרים
|
||||
|
||||
עבור כל פרמטר של Cassandra, סדר הפתרון יהיה:
|
||||
1. ערך ארגומנט שורת הפקודה
|
||||
2. משתנה סביבה (`CASSANDRA_*`)
|
||||
3. ערך ברירת מחדל
|
||||
|
||||
### טיפול בפרמטרים של מארחים
|
||||
|
||||
הפרמטר `cassandra_host`:
|
||||
שורת הפקודה מקבלת מחרוזת מופרדת בפסיקים: `--cassandra-host "host1,host2,host3"`
|
||||
משתנה סביבה מקבל מחרוזת מופרדת בפסיקים: `CASSANDRA_HOST="host1,host2,host3"`
|
||||
באופן פנימי תמיד מאוחסן כרשימה: `["host1", "host2", "host3"]`
|
||||
מארח בודד: `"localhost"` → מומר ל-`["localhost"]`
|
||||
כבר רשימה: `["host1", "host2"]` → משמש כפי שהוא
|
||||
|
||||
### לוגיקת אימות
|
||||
|
||||
אימות ישמש כאשר גם `cassandra_username` וגם `cassandra_password` מסופקים:
|
||||
```python
|
||||
if cassandra_username and cassandra_password:
|
||||
# Use SSL context and PlainTextAuthProvider
|
||||
else:
|
||||
# Connect without authentication
|
||||
```
|
||||
|
||||
## קבצים שיש לשנות
|
||||
|
||||
### מודולים המשתמשים בפרמטרים `graph_*` (שיש לשנות):
|
||||
`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/rows/cassandra/write.py`
|
||||
`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`
|
||||
|
||||
### מודולים המשתמשים בפרמטרים `cassandra_*` (שיש לעדכן עם אפשרות חלופה):
|
||||
`trustgraph-flow/trustgraph/tables/config.py`
|
||||
`trustgraph-flow/trustgraph/tables/knowledge.py`
|
||||
`trustgraph-flow/trustgraph/tables/library.py`
|
||||
`trustgraph-flow/trustgraph/storage/knowledge/store.py`
|
||||
`trustgraph-flow/trustgraph/cores/knowledge.py`
|
||||
`trustgraph-flow/trustgraph/librarian/librarian.py`
|
||||
`trustgraph-flow/trustgraph/librarian/service.py`
|
||||
`trustgraph-flow/trustgraph/config/service/service.py`
|
||||
`trustgraph-flow/trustgraph/cores/service.py`
|
||||
|
||||
### קבצי בדיקה שיש לעדכן:
|
||||
`tests/unit/test_cores/test_knowledge_manager.py`
|
||||
`tests/unit/test_storage/test_triples_cassandra_storage.py`
|
||||
`tests/unit/test_query/test_triples_cassandra_query.py`
|
||||
`tests/integration/test_objects_cassandra_integration.py`
|
||||
|
||||
## אסטרטגיית יישום
|
||||
|
||||
### שלב 1: יצירת כלי עזר להגדרות משותפות
|
||||
צור פונקציות עזר לסטנדרטיזציה של הגדרות Cassandra בכל המעבדים:
|
||||
|
||||
```python
|
||||
import os
|
||||
import argparse
|
||||
|
||||
def get_cassandra_defaults():
|
||||
"""Get default values from environment variables or fallback."""
|
||||
return {
|
||||
'host': os.getenv('CASSANDRA_HOST', 'cassandra'),
|
||||
'username': os.getenv('CASSANDRA_USERNAME'),
|
||||
'password': os.getenv('CASSANDRA_PASSWORD')
|
||||
}
|
||||
|
||||
def add_cassandra_args(parser: argparse.ArgumentParser):
|
||||
"""
|
||||
Add standardized Cassandra arguments to an argument parser.
|
||||
Shows environment variable values in help text.
|
||||
"""
|
||||
defaults = get_cassandra_defaults()
|
||||
|
||||
# Format help text with env var indication
|
||||
host_help = f"Cassandra host list, comma-separated (default: {defaults['host']})"
|
||||
if 'CASSANDRA_HOST' in os.environ:
|
||||
host_help += " [from CASSANDRA_HOST]"
|
||||
|
||||
username_help = f"Cassandra username"
|
||||
if defaults['username']:
|
||||
username_help += f" (default: {defaults['username']})"
|
||||
if 'CASSANDRA_USERNAME' in os.environ:
|
||||
username_help += " [from CASSANDRA_USERNAME]"
|
||||
|
||||
password_help = "Cassandra password"
|
||||
if defaults['password']:
|
||||
password_help += " (default: <set>)"
|
||||
if 'CASSANDRA_PASSWORD' in os.environ:
|
||||
password_help += " [from CASSANDRA_PASSWORD]"
|
||||
|
||||
parser.add_argument(
|
||||
'--cassandra-host',
|
||||
default=defaults['host'],
|
||||
help=host_help
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--cassandra-username',
|
||||
default=defaults['username'],
|
||||
help=username_help
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--cassandra-password',
|
||||
default=defaults['password'],
|
||||
help=password_help
|
||||
)
|
||||
|
||||
def resolve_cassandra_config(args) -> tuple[list[str], str|None, str|None]:
|
||||
"""
|
||||
Convert argparse args to Cassandra configuration.
|
||||
|
||||
Returns:
|
||||
tuple: (hosts_list, username, password)
|
||||
"""
|
||||
# Convert host string to list
|
||||
if isinstance(args.cassandra_host, str):
|
||||
hosts = [h.strip() for h in args.cassandra_host.split(',')]
|
||||
else:
|
||||
hosts = args.cassandra_host
|
||||
|
||||
return hosts, args.cassandra_username, args.cassandra_password
|
||||
```
|
||||
|
||||
### שלב 2: עדכון מודולים באמצעות פרמטרים `graph_*`
|
||||
1. שנה שמות הפרמטרים מ-`graph_*` ל-`cassandra_*`
|
||||
2. החלף שיטות `add_args()` מותאמות אישית בשיטות `add_cassandra_args()` סטנדרטיות
|
||||
3. השתמש בפונקציות העזר לתצורה נפוצות
|
||||
4. עדכן מחרוזות תיעוד
|
||||
|
||||
דוגמה לטרנספורמציה:
|
||||
```python
|
||||
# OLD CODE
|
||||
@staticmethod
|
||||
def add_args(parser):
|
||||
parser.add_argument(
|
||||
'-g', '--graph-host',
|
||||
default="localhost",
|
||||
help=f'Graph host (default: localhost)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--graph-username',
|
||||
default=None,
|
||||
help=f'Cassandra username'
|
||||
)
|
||||
|
||||
# NEW CODE
|
||||
@staticmethod
|
||||
def add_args(parser):
|
||||
FlowProcessor.add_args(parser)
|
||||
add_cassandra_args(parser) # Use standard helper
|
||||
```
|
||||
|
||||
### שלב 3: עדכון מודולים באמצעות פרמטרים `cassandra_*`
|
||||
1. הוספת תמיכה בארגומנטים משורת הפקודה היכן שחסרים (לדוגמה, `kg-store`)
|
||||
2. החלפת הגדרות ארגומנטים קיימות ב-`add_cassandra_args()`
|
||||
3. שימוש ב-`resolve_cassandra_config()` עבור פתרון עקבי
|
||||
4. הבטחת טיפול עקבי ברשימת השרתים
|
||||
|
||||
### שלב 4: עדכון בדיקות ותיעוד
|
||||
1. עדכון כל קבצי הבדיקה לשימוש בשמות פרמטרים חדשים
|
||||
2. עדכון תיעוד שורת הפקודה (CLI)
|
||||
3. עדכון תיעוד API
|
||||
4. הוספת תיעוד עבור משתני סביבה
|
||||
|
||||
## תאימות לאחור
|
||||
|
||||
על מנת לשמור על תאימות לאחור במהלך המעבר:
|
||||
|
||||
1. **אזהרות הפסקה** עבור פרמטרים `graph_*`
|
||||
2. **כינוי פרמטרים** - קבלת שמות ישנים וחדשים בתחילה
|
||||
3. **פריסה מדורגת** על פני מספר גרסאות
|
||||
4. **עדכוני תיעוד** עם מדריך מעבר
|
||||
|
||||
דוגמה לקוד תאימות לאחור:
|
||||
```python
|
||||
def __init__(self, **params):
|
||||
# Handle deprecated graph_* parameters
|
||||
if 'graph_host' in params:
|
||||
warnings.warn("graph_host is deprecated, use cassandra_host", DeprecationWarning)
|
||||
params.setdefault('cassandra_host', params.pop('graph_host'))
|
||||
|
||||
if 'graph_username' in params:
|
||||
warnings.warn("graph_username is deprecated, use cassandra_username", DeprecationWarning)
|
||||
params.setdefault('cassandra_username', params.pop('graph_username'))
|
||||
|
||||
# ... continue with standard resolution
|
||||
```
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
1. **בדיקות יחידה** עבור לוגיקת פתרון תצורה
|
||||
2. **בדיקות אינטגרציה** עם שילובים שונים של תצורות
|
||||
3. **בדיקות משתני סביבה**
|
||||
4. **בדיקות תאימות לאחור** עם פרמטרים מיושנים
|
||||
5. **בדיקות Docker Compose** עם משתני סביבה
|
||||
|
||||
## עדכוני תיעוד
|
||||
|
||||
1. עדכון כל התיעוד של פקודות שורת הפקודה
|
||||
2. עדכון תיעוד API
|
||||
3. יצירת מדריך מעבר
|
||||
4. עדכון דוגמאות Docker Compose
|
||||
5. עדכון תיעוד הפניה לתצורה
|
||||
|
||||
## סיכונים ודרכי התמודדות
|
||||
|
||||
| סיכון | השפעה | דרך התמודדות |
|
||||
|------|--------|------------|
|
||||
| שינויים שעלולים לפגוע במשתמשים | גבוהה | יישום תקופת תאימות לאחור |
|
||||
| בלבול בתצורה במהלך המעבר | בינונית | תיעוד ברור ואזהרות על הפסקה |
|
||||
| כשלים בבדיקות | בינונית | עדכוני בדיקות מקיפים |
|
||||
| בעיות בפריסת Docker | גבוהה | עדכון כל דוגמאות Docker Compose |
|
||||
|
||||
## קריטריוני הצלחה
|
||||
|
||||
[ ] כל המודולים משתמשים בשמות פרמטרים אחידים `cassandra_*`
|
||||
[ ] כל המעבדים חושפים הגדרות Cassandra באמצעות ארגומנטים של שורת הפקודה
|
||||
[ ] טקסט העזרה של שורת הפקודה מציג ערכי ברירת מחדל של משתני סביבה
|
||||
[ ] ערכי סיסמה לעולם אינם מוצגים בטקסט העזרה
|
||||
[ ] מנגנון החלפה למשתני סביבה פועל כהלכה
|
||||
[ ] `cassandra_host` מטופל באופן עקבי כרשימה באופן פנימי
|
||||
[ ] תאימות לאחור נשמרת לפחות עבור 2 גרסאות
|
||||
[ ] כל הבדיקות עוברות עם מערכת התצורה החדשה
|
||||
[ ] התיעוד מעודכן במלואו
|
||||
[ ] דוגמאות Docker Compose עובדות עם משתני סביבה
|
||||
|
||||
## ציר זמן
|
||||
|
||||
**שבוע 1:** יישום עזר תצורה משותף ועדכון מודולי `graph_*`
|
||||
**שבוע 2:** הוספת תמיכה במשתני סביבה למודולי `cassandra_*` קיימים
|
||||
**שבוע 3:** עדכון בדיקות ותיעוד
|
||||
**שבוע 4:** בדיקות אינטגרציה ותיקון באגים
|
||||
|
||||
## שיקולים עתידיים
|
||||
|
||||
שקול להרחיב את התבנית הזו לתצורות מסדי נתונים אחרות (לדוגמה, Elasticsearch)
|
||||
יישום אימות תצורה והודעות שגיאה טובות יותר
|
||||
הוספת תמיכה בתצורת חיבור בריכת חיבורים של Cassandra
|
||||
שקול להוסיף תמיכה בקבצי תצורה (.env files)
|
||||
687
docs/tech-specs/he/cassandra-performance-refactor.he.md
Normal file
687
docs/tech-specs/he/cassandra-performance-refactor.he.md
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני: שיפור ביצועים של בסיס הידע Cassandra"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני: שיפור ביצועים של בסיס הידע Cassandra
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
**סטטוס:** טיוטה
|
||||
**כותב:** עוזר
|
||||
**תאריך:** 2025-09-18
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה עוסק בבעיות ביצועים ביישום בסיס הידע Cassandra של TrustGraph ומציע אופטימיזציות לאחסון ושליפה של משולשות RDF.
|
||||
|
||||
## יישום נוכחי
|
||||
|
||||
### עיצוב הסכימה
|
||||
|
||||
היישום הנוכחי משתמש בעיצוב טבלה יחידה ב-`trustgraph-flow/trustgraph/direct/cassandra_kg.py`:
|
||||
|
||||
```sql
|
||||
CREATE TABLE triples (
|
||||
collection text,
|
||||
s text,
|
||||
p text,
|
||||
o text,
|
||||
PRIMARY KEY (collection, s, p, o)
|
||||
);
|
||||
```
|
||||
|
||||
**אינדקסים משניים:**
|
||||
`triples_s` על `s` (נושא)
|
||||
`triples_p` על `p` (נשוא)
|
||||
`triples_o` על `o` (אובייקט)
|
||||
|
||||
### תבניות שאילתה
|
||||
|
||||
המימוש הנוכחי תומך ב-8 תבניות שאילתה מובחנות:
|
||||
|
||||
1. **get_all(collection, limit=50)** - שליפה של כל השלשות עבור אוסף
|
||||
```sql
|
||||
SELECT s, p, o FROM triples WHERE collection = ? LIMIT 50
|
||||
```
|
||||
|
||||
2. **get_s(collection, s, limit=10)** - שאילתה לפי נושא.
|
||||
```sql
|
||||
SELECT p, o FROM triples WHERE collection = ? AND s = ? LIMIT 10
|
||||
```
|
||||
|
||||
3. **get_p(collection, p, limit=10)** - שאילתה לפי תנאי.
|
||||
```sql
|
||||
SELECT s, o FROM triples WHERE collection = ? AND p = ? LIMIT 10
|
||||
```
|
||||
|
||||
4. **get_o(collection, o, limit=10)** - שאילתה לפי אובייקט.
|
||||
```sql
|
||||
SELECT s, p FROM triples WHERE collection = ? AND o = ? LIMIT 10
|
||||
```
|
||||
|
||||
5. **get_sp(collection, s, p, limit=10)** - שאילתה לפי נושא + טענה
|
||||
```sql
|
||||
SELECT o FROM triples WHERE collection = ? AND s = ? AND p = ? LIMIT 10
|
||||
```
|
||||
|
||||
6. **get_po(collection, p, o, limit=10)** - שאילתה לפי תנאי + אובייקט ⚠️
|
||||
```sql
|
||||
SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING
|
||||
```
|
||||
|
||||
7. **get_os(collection, o, s, limit=10)** - שאילתה לפי אובייקט + נושא ⚠️
|
||||
```sql
|
||||
SELECT p FROM triples WHERE collection = ? AND o = ? AND s = ? LIMIT 10 ALLOW FILTERING
|
||||
```
|
||||
|
||||
8. **get_spo(collection, s, p, o, limit=10)** - התאמה מדויקת לשלושה חלקים (subject, predicate, object).
|
||||
```sql
|
||||
SELECT s as x FROM triples WHERE collection = ? AND s = ? AND p = ? AND o = ? LIMIT 10
|
||||
```
|
||||
|
||||
### ארכיטקטורה נוכחית
|
||||
|
||||
**קובץ: `trustgraph-flow/trustgraph/direct/cassandra_kg.py`**
|
||||
מחלקה יחידה `KnowledgeGraph` המטפלת בכל הפעולות
|
||||
בריכת חיבורים באמצעות רשימה גלובלית `_active_clusters`
|
||||
שם טבלה קבוע: `"triples"`
|
||||
מרחב מפתחות לכל מודל משתמש
|
||||
שכפול SimpleStrategy עם גורם 1
|
||||
|
||||
**נקודות אינטגרציה:**
|
||||
**נתיב כתיבה:** `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`
|
||||
**נתיב שאילתה:** `trustgraph-flow/trustgraph/query/triples/cassandra/service.py`
|
||||
**מאגר ידע:** `trustgraph-flow/trustgraph/tables/knowledge.py`
|
||||
|
||||
## בעיות ביצועים שזוהו
|
||||
|
||||
### בעיות ברמת הסכימה
|
||||
|
||||
1. **עיצוב מפתח ראשי לא יעיל**
|
||||
נוכחי: `PRIMARY KEY (collection, s, p, o)`
|
||||
גורם לקיבוץ לקוי עבור דפוסי גישה נפוצים
|
||||
מחייב שימוש באינדקסים משניים יקרים
|
||||
|
||||
2. **שימוש יתר באינדקסים משניים** ⚠️
|
||||
שלושה אינדקסים משניים על עמודות עם קרדינליות גבוהה (s, p, o)
|
||||
אינדקסים משניים ב-Cassandra הם יקרים ואינם מתאימים להרחבה
|
||||
שאילתות 6 ו-7 דורשות `ALLOW FILTERING` המצביע על מודל נתונים לקוי
|
||||
|
||||
3. **סיכון לחלוקות חמות**
|
||||
מפתח חלוקה יחיד `collection` יכול ליצור חלוקות חמות
|
||||
אוספים גדולים יתרכזו בצמתים בודדים
|
||||
אין אסטרטגיית חלוקה לאיזון עומסים
|
||||
|
||||
### בעיות ברמת השאילתה
|
||||
|
||||
1. **שימוש ב-ALLOW FILTERING** ⚠️
|
||||
שני סוגי שאילתות (get_po, get_os) דורשים `ALLOW FILTERING`
|
||||
שאילתות אלו סורקות מספר חלוקות ויקרות מאוד
|
||||
הביצועים יורדים באופן ליניארי עם גודל הנתונים
|
||||
|
||||
2. **דפוסי גישה לא יעילים**
|
||||
אין אופטימיזציה עבור דפוסי שאילתות RDF נפוצים
|
||||
חסרים אינדקסים מורכבים עבור שילובים תכופים של שאילתות
|
||||
אין התחשבות בדפוסי מעבר גרפים
|
||||
|
||||
3. **חוסר באופטימיזציה של שאילתות**
|
||||
אין שמירת מטמון של הצהרות מוכנות
|
||||
אין רמזים או אסטרטגיות אופטימיזציה לשאילתות
|
||||
אין התחשבות בדף אחרי דף מעבר לפונקציית LIMIT פשוטה
|
||||
|
||||
## הצהרת בעיה
|
||||
|
||||
ליישום בסיס הידע הנוכחי של Cassandra ישנם שני צווארי בקבוק ביצועים קריטיים:
|
||||
|
||||
### 1. ביצועים לא יעילים של שאילתת get_po
|
||||
|
||||
השאילתה `get_po(collection, p, o)` אינה יעילה מאוד מכיוון שהיא דורשת `ALLOW FILTERING`:
|
||||
|
||||
```sql
|
||||
SELECT s FROM triples WHERE collection = ? AND p = ? AND o = ? LIMIT 10 ALLOW FILTERING
|
||||
```
|
||||
|
||||
**מדוע זה בעייתי:**
|
||||
`ALLOW FILTERING` גורם לקסנדרה לסרוק את כל המחיצות בתוך האוסף.
|
||||
הביצועים יורדים באופן ליניארי עם גודל הנתונים.
|
||||
זהו דפוס שאילתות RDF נפוץ (מציאת נושאים שיש להם קשר ספציפי של נשוא-פועל-מושא).
|
||||
זה יוצר עומס משמעותי על האשכול ככל שהנתונים גדלים.
|
||||
|
||||
### 2. אסטרטגיית קיבוץ לקויה
|
||||
|
||||
המפתח הראשי הנוכחי `PRIMARY KEY (collection, s, p, o)` מספק יתרונות קיבוץ מינימליים:
|
||||
|
||||
**בעיות עם הקיבוץ הנוכחי:**
|
||||
`collection` כמפתח מחיצה לא מפזר את הנתונים בצורה יעילה.
|
||||
רוב האוספים מכילים נתונים מגוונים, מה שהופך את הקיבוץ ללא יעיל.
|
||||
אין התחשבות בדפוסי גישה נפוצים בשאילתות RDF.
|
||||
אוספים גדולים יוצרים מחיצות "חמות" על צמתים בודדים.
|
||||
עמודות הקיבוץ (s, p, o) אינן מייעלות עבור דפוסי מעבר גרפים טיפוסיים.
|
||||
|
||||
**השפעה:**
|
||||
שאילתות אינן נהנות ממיקום נתונים.
|
||||
ניצולת מטמון לקויה.
|
||||
חלוקת עומסים לא אחידה בין צמתי האשכול.
|
||||
צווארי בקבוק של יכולת הרחבה ככל שהאוספים גדלים.
|
||||
|
||||
## פתרון מוצע: אסטרטגיית דה-נורמליזציה של 4 טבלאות
|
||||
|
||||
### סקירה כללית
|
||||
|
||||
החליפו את הטבלה הבודדת `triples` בארבע טבלאות ייעודיות, כל אחת מותאמת לדפוסי שאילתות ספציפיים. זה מבטל את הצורך באינדקסים משניים וב-ALLOW FILTERING תוך מתן ביצועים אופטימליים לכל סוגי השאילתות. הטבלה הרביעית מאפשרת מחיקת אוספים יעילה למרות מפתחות מחיצה מורכבים.
|
||||
|
||||
### עיצוב סכימה חדש
|
||||
|
||||
**טבלה 1: שאילתות ממוקדות בנושא (triples_s)**
|
||||
```sql
|
||||
CREATE TABLE triples_s (
|
||||
collection text,
|
||||
s text,
|
||||
p text,
|
||||
o text,
|
||||
PRIMARY KEY ((collection, s), p, o)
|
||||
);
|
||||
```
|
||||
**משפר:** get_s, get_sp, get_os
|
||||
**מפתח מחיצה:** (collection, s) - פיזור טוב יותר מאשר רק collection
|
||||
**קיבוץ:** (p, o) - מאפשר חיפושים יעילים של טווחים/אובייקטים עבור נושא
|
||||
|
||||
**טבלה 2: שאילתות של טריפלטים (predicate-object) (triples_p)**
|
||||
```sql
|
||||
CREATE TABLE triples_p (
|
||||
collection text,
|
||||
p text,
|
||||
o text,
|
||||
s text,
|
||||
PRIMARY KEY ((collection, p), o, s)
|
||||
);
|
||||
```
|
||||
**משפר:** get_p, get_po (מבטל את ALLOW FILTERING!)
|
||||
**מפתח מחיצה:** (collection, p) - גישה ישירה באמצעות תנאי
|
||||
**קיבוץ:** (o, s) - מעבר יעיל בין אובייקט לנושא
|
||||
|
||||
**טבלה 3: שאילתות ממוקדות אובייקט (triples_o)**
|
||||
```sql
|
||||
CREATE TABLE triples_o (
|
||||
collection text,
|
||||
o text,
|
||||
s text,
|
||||
p text,
|
||||
PRIMARY KEY ((collection, o), s, p)
|
||||
);
|
||||
```
|
||||
**אופטימיזציה:** get_o
|
||||
**מפתח מחיצה:** (collection, o) - גישה ישירה באמצעות אובייקט
|
||||
**קיבוץ:** (s, p) - מעבר יעיל בין נושא ופועל
|
||||
|
||||
**טבלה 4: ניהול אוספים ושאילתות SPO (triples_collection)**
|
||||
```sql
|
||||
CREATE TABLE triples_collection (
|
||||
collection text,
|
||||
s text,
|
||||
p text,
|
||||
o text,
|
||||
PRIMARY KEY (collection, s, p, o)
|
||||
);
|
||||
```
|
||||
**אופטימיזציה:** get_spo, delete_collection
|
||||
**מפתח מחיצה:** רק אוסף - מאפשר פעולות יעילות ברמת האוסף.
|
||||
**קיבוץ:** (s, p, o) - סדר משולש סטנדרטי.
|
||||
**מטרה:** שימוש כפול לחיפושים מדויקים של SPO וגם כמדד למחיקה.
|
||||
|
||||
### מיפוי שאילתות
|
||||
|
||||
| שאילתה מקורית | טבלה יעד | שיפור ביצועים |
|
||||
|----------------|-------------|------------------------|
|
||||
| get_all(collection) | triples_s | ALLOW FILTERING (מתאים לסריקה) |
|
||||
| get_s(collection, s) | triples_s | גישה ישירה למחיצה |
|
||||
| get_p(collection, p) | triples_p | גישה ישירה למחיצה |
|
||||
| get_o(collection, o) | triples_o | גישה ישירה למחיצה |
|
||||
| get_sp(collection, s, p) | triples_s | מחיצה + קיבוץ |
|
||||
| get_po(collection, p, o) | triples_p | **אין יותר ALLOW FILTERING!** |
|
||||
| get_os(collection, o, s) | triples_o | מחיצה + קיבוץ |
|
||||
| get_spo(collection, s, p, o) | triples_collection | חיפוש מפתח מדויק |
|
||||
| delete_collection(collection) | triples_collection | קריאת מדד, מחיקה אצווה של הכל |
|
||||
|
||||
### אסטרטגיית מחיקת אוסף
|
||||
|
||||
עם מפתחות מחיצה מורכבים, אי אפשר פשוט לבצע `DELETE FROM table WHERE collection = ?`. במקום זאת:
|
||||
|
||||
1. **שלב קריאה:** שאילתא `triples_collection` כדי לרשום את כל המשולשים:
|
||||
```sql
|
||||
SELECT s, p, o FROM triples_collection WHERE collection = ?
|
||||
```
|
||||
זה יעיל מכיוון ש-`collection` הוא מפתח החלוקה עבור הטבלה הזו.
|
||||
|
||||
2. **שלב המחיקה:** עבור כל שלישייה (s, p, o), מחקו מכל 4 הטבלאות תוך שימוש במפתחות חלוקה מלאים:
|
||||
```sql
|
||||
DELETE FROM triples_s WHERE collection = ? AND s = ? AND p = ? AND o = ?
|
||||
DELETE FROM triples_p WHERE collection = ? AND p = ? AND o = ? AND s = ?
|
||||
DELETE FROM triples_o WHERE collection = ? AND o = ? AND s = ? AND p = ?
|
||||
DELETE FROM triples_collection WHERE collection = ? AND s = ? AND p = ? AND o = ?
|
||||
```
|
||||
מחולק לקבוצות של 100 רשומות לטובת יעילות.
|
||||
|
||||
**ניתוח פשרות:**
|
||||
✅ שומר על ביצועי שאילתות אופטימליים עם מחיצות מבוזרות.
|
||||
✅ אין מחיצות עמוסות עבור אוספים גדולים.
|
||||
❌ לוגיקת מחיקה מורכבת יותר (קריאה ואז מחיקה).
|
||||
❌ זמן מחיקה תלוי בגודל האוסף.
|
||||
|
||||
### יתרונות
|
||||
|
||||
1. **מבטל את ALLOW FILTERING** - לכל שאילתה יש נתיב גישה אופטימלי (מלבד סריקת get_all).
|
||||
2. **ללא אינדקסים משניים** - כל טבלה היא האינדקס לדפוס השאילתה שלה.
|
||||
3. **הפצת נתונים טובה יותר** - מפתחות מחיצה מורכבים מפזרים את העומס בצורה יעילה.
|
||||
4. **ביצועים צפויים** - זמן שאילתה תלוי בגודל התוצאה, ולא בגודל הנתונים הכולל.
|
||||
5. **מנצל את החוזקות של Cassandra** - תוכנן עבור ארכיטקטורת Cassandra.
|
||||
6. **מאפשר מחיקת אוספים** - triples_collection משמש כמחירון מחיקה.
|
||||
|
||||
## תוכנית יישום
|
||||
|
||||
### קבצים הדורשים שינוי
|
||||
|
||||
#### קובץ יישום ראשי
|
||||
|
||||
**`trustgraph-flow/trustgraph/direct/cassandra_kg.py`** - נדרש כתיבה מחדש מלאה.
|
||||
|
||||
**שיטות שיש לשכתב:**
|
||||
```python
|
||||
# Schema initialization
|
||||
def init(self) -> None # Replace single table with three tables
|
||||
|
||||
# Insert operations
|
||||
def insert(self, collection, s, p, o) -> None # Write to all three tables
|
||||
|
||||
# Query operations (API unchanged, implementation optimized)
|
||||
def get_all(self, collection, limit=50) # Use triples_by_subject
|
||||
def get_s(self, collection, s, limit=10) # Use triples_by_subject
|
||||
def get_p(self, collection, p, limit=10) # Use triples_by_po
|
||||
def get_o(self, collection, o, limit=10) # Use triples_by_object
|
||||
def get_sp(self, collection, s, p, limit=10) # Use triples_by_subject
|
||||
def get_po(self, collection, p, o, limit=10) # Use triples_by_po (NO ALLOW FILTERING!)
|
||||
def get_os(self, collection, o, s, limit=10) # Use triples_by_subject
|
||||
def get_spo(self, collection, s, p, o, limit=10) # Use triples_by_subject
|
||||
|
||||
# Collection management
|
||||
def delete_collection(self, collection) -> None # Delete from all three tables
|
||||
```
|
||||
|
||||
#### קבצי אינטגרציה (אין צורך בשינויים לוגיים)
|
||||
|
||||
**`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`**
|
||||
אין צורך בשינויים - משתמשים ב-API של KnowledgeGraph הקיים
|
||||
נהנים אוטומטית משיפורי ביצועים
|
||||
|
||||
**`trustgraph-flow/trustgraph/query/triples/cassandra/service.py`**
|
||||
אין צורך בשינויים - משתמשים ב-API של KnowledgeGraph הקיים
|
||||
נהנים אוטומטית משיפורי ביצועים
|
||||
|
||||
### קבצי בדיקה הדורשים עדכונים
|
||||
|
||||
#### בדיקות יחידה
|
||||
**`tests/unit/test_storage/test_triples_cassandra_storage.py`**
|
||||
עדכון ציפיות הבדיקה עבור שינויים בסכימה
|
||||
הוספת בדיקות עבור עקביות בין טבלאות מרובות
|
||||
אימות היעדר ALLOW FILTERING בתוכניות שאילתות
|
||||
|
||||
**`tests/unit/test_query/test_triples_cassandra_query.py`**
|
||||
עדכון טענות ביצועים
|
||||
בדיקת כל 8 דפוסי השאילתות מול טבלאות חדשות
|
||||
אימות ניתוב השאילתות לטבלאות הנכונות
|
||||
|
||||
#### בדיקות אינטגרציה
|
||||
**`tests/integration/test_cassandra_integration.py`**
|
||||
בדיקות מקצה לקצה עם סכימה חדשה
|
||||
השוואות ביצועים
|
||||
אימות עקביות נתונים בין טבלאות
|
||||
|
||||
**`tests/unit/test_storage/test_cassandra_config_integration.py`**
|
||||
עדכון בדיקות אימות סכימה
|
||||
בדיקת תרחישי מעבר
|
||||
|
||||
### אסטרטגיית יישום
|
||||
|
||||
#### שלב 1: סכימה ושיטות ליבה
|
||||
1. **כתיבת מחדש של `init()`** - יצירת ארבע טבלאות במקום אחת
|
||||
2. **כתיבת מחדש של `insert()`** - כתיבה באצווה לכל ארבע הטבלאות
|
||||
3. **יישום הצהרות מוכנות** - לביצועים אופטימליים
|
||||
4. **הוספת לוגיקת ניתוב טבלאות** - הפניית שאילתות לטבלאות האופטימליות
|
||||
5. **יישום מחיקת אוספים** - קריאה מ-triples_collection, מחיקה באצווה מכל הטבלאות
|
||||
|
||||
#### שלב 2: אופטימיזציה של שיטות שאילתה
|
||||
1. **כתיבת מחדש של כל שיטת get_*** לשימוש בטבלה האופטימלית
|
||||
2. **הסרת כל השימושים ב-ALLOW FILTERING**
|
||||
3. **יישום שימוש יעיל במפתח מיון**
|
||||
4. **הוספת רישום ביצועי שאילתות**
|
||||
|
||||
#### שלב 3: ניהול אוספים
|
||||
1. **עדכון `delete_collection()`** - הסרה מכל שלושת הטבלאות
|
||||
2. **הוספת אימות עקביות** - הבטחת סנכרון בין כל הטבלאות
|
||||
3. **יישום פעולות באצווה** - לפעולות מרובות טבלאות אטומיות
|
||||
|
||||
### פרטי יישום מרכזיים
|
||||
|
||||
#### אסטרטגיית כתיבה באצווה
|
||||
```python
|
||||
def insert(self, collection, s, p, o):
|
||||
batch = BatchStatement()
|
||||
|
||||
# Insert into all four tables
|
||||
batch.add(self.insert_subject_stmt, (collection, s, p, o))
|
||||
batch.add(self.insert_po_stmt, (collection, p, o, s))
|
||||
batch.add(self.insert_object_stmt, (collection, o, s, p))
|
||||
batch.add(self.insert_collection_stmt, (collection, s, p, o))
|
||||
|
||||
self.session.execute(batch)
|
||||
```
|
||||
|
||||
#### לוגיקת ניתוב שאילתות
|
||||
```python
|
||||
def get_po(self, collection, p, o, limit=10):
|
||||
# Route to triples_p table - NO ALLOW FILTERING!
|
||||
return self.session.execute(
|
||||
self.get_po_stmt,
|
||||
(collection, p, o, limit)
|
||||
)
|
||||
|
||||
def get_spo(self, collection, s, p, o, limit=10):
|
||||
# Route to triples_collection table for exact SPO lookup
|
||||
return self.session.execute(
|
||||
self.get_spo_stmt,
|
||||
(collection, s, p, o, limit)
|
||||
)
|
||||
```
|
||||
|
||||
#### לוגיקת מחיקת אוספים
|
||||
```python
|
||||
def delete_collection(self, collection):
|
||||
# Step 1: Read all triples from collection table
|
||||
rows = self.session.execute(
|
||||
f"SELECT s, p, o FROM {self.collection_table} WHERE collection = %s",
|
||||
(collection,)
|
||||
)
|
||||
|
||||
# Step 2: Batch delete from all 4 tables
|
||||
batch = BatchStatement()
|
||||
count = 0
|
||||
|
||||
for row in rows:
|
||||
s, p, o = row.s, row.p, row.o
|
||||
|
||||
# Delete using full partition keys for each table
|
||||
batch.add(SimpleStatement(
|
||||
f"DELETE FROM {self.subject_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?"
|
||||
), (collection, s, p, o))
|
||||
|
||||
batch.add(SimpleStatement(
|
||||
f"DELETE FROM {self.po_table} WHERE collection = ? AND p = ? AND o = ? AND s = ?"
|
||||
), (collection, p, o, s))
|
||||
|
||||
batch.add(SimpleStatement(
|
||||
f"DELETE FROM {self.object_table} WHERE collection = ? AND o = ? AND s = ? AND p = ?"
|
||||
), (collection, o, s, p))
|
||||
|
||||
batch.add(SimpleStatement(
|
||||
f"DELETE FROM {self.collection_table} WHERE collection = ? AND s = ? AND p = ? AND o = ?"
|
||||
), (collection, s, p, o))
|
||||
|
||||
count += 1
|
||||
|
||||
# Execute every 100 triples to avoid oversized batches
|
||||
if count % 100 == 0:
|
||||
self.session.execute(batch)
|
||||
batch = BatchStatement()
|
||||
|
||||
# Execute remaining deletions
|
||||
if count % 100 != 0:
|
||||
self.session.execute(batch)
|
||||
|
||||
logger.info(f"Deleted {count} triples from collection {collection}")
|
||||
```
|
||||
|
||||
#### אופטימיזציה של הצהרת הכנה (Prepared Statement)
|
||||
```python
|
||||
def prepare_statements(self):
|
||||
# Cache prepared statements for better performance
|
||||
self.insert_subject_stmt = self.session.prepare(
|
||||
f"INSERT INTO {self.subject_table} (collection, s, p, o) VALUES (?, ?, ?, ?)"
|
||||
)
|
||||
self.insert_po_stmt = self.session.prepare(
|
||||
f"INSERT INTO {self.po_table} (collection, p, o, s) VALUES (?, ?, ?, ?)"
|
||||
)
|
||||
self.insert_object_stmt = self.session.prepare(
|
||||
f"INSERT INTO {self.object_table} (collection, o, s, p) VALUES (?, ?, ?, ?)"
|
||||
)
|
||||
self.insert_collection_stmt = self.session.prepare(
|
||||
f"INSERT INTO {self.collection_table} (collection, s, p, o) VALUES (?, ?, ?, ?)"
|
||||
)
|
||||
# ... query statements
|
||||
```
|
||||
|
||||
## אסטרטגיית מעבר
|
||||
|
||||
### גישת מעבר נתונים
|
||||
|
||||
#### אפשרות 1: פריסה בצבע כחול-ירוק (מומלץ)
|
||||
1. **פריסת הסכימה החדשה לצד הקיימת** - השתמש בשמות טבלאות שונים באופן זמני
|
||||
2. **תקופת כתיבה כפולה** - כתיבה גם לסכימה הישנה וגם לחדשה במהלך המעבר
|
||||
3. **מעבר נתונים ברקע** - העתקת נתונים קיימים לטבלאות חדשות
|
||||
4. **הפניית שאילתות** - הפניית שאילתות לטבלאות החדשות לאחר שהנתונים עברו
|
||||
5. **מחיקת הטבלאות הישנות** - לאחר תקופת אימות
|
||||
|
||||
#### אפשרות 2: מעבר במקום
|
||||
1. **הוספת סכימה** - יצירת טבלאות חדשות במרחב מפתחות קיים
|
||||
2. **סקריפט מעבר נתונים** - העתקה באצווה מטבלה ישנה לטבלאות חדשות
|
||||
3. **עדכון יישום** - פריסת קוד חדש לאחר השלמת המעבר
|
||||
4. **ניקוי הטבלה הישנה** - הסרת הטבלה הישנה והאינדקסים
|
||||
|
||||
### תאימות לאחור
|
||||
|
||||
#### אסטרטגיית פריסה
|
||||
```python
|
||||
# Environment variable to control table usage during migration
|
||||
USE_LEGACY_TABLES = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true'
|
||||
|
||||
class KnowledgeGraph:
|
||||
def __init__(self, ...):
|
||||
if USE_LEGACY_TABLES:
|
||||
self.init_legacy_schema()
|
||||
else:
|
||||
self.init_optimized_schema()
|
||||
```
|
||||
|
||||
#### סקריפט הגירה
|
||||
```python
|
||||
def migrate_data():
|
||||
# Read from old table
|
||||
old_triples = session.execute("SELECT collection, s, p, o FROM triples")
|
||||
|
||||
# Batch write to new tables
|
||||
for batch in batched(old_triples, 100):
|
||||
batch_stmt = BatchStatement()
|
||||
for row in batch:
|
||||
# Add to all three new tables
|
||||
batch_stmt.add(insert_subject_stmt, row)
|
||||
batch_stmt.add(insert_po_stmt, (row.collection, row.p, row.o, row.s))
|
||||
batch_stmt.add(insert_object_stmt, (row.collection, row.o, row.s, row.p))
|
||||
session.execute(batch_stmt)
|
||||
```
|
||||
|
||||
### אסטרטגיית אימות
|
||||
|
||||
#### בדיקות עקביות נתונים
|
||||
```python
|
||||
def validate_migration():
|
||||
# Count total records in old vs new tables
|
||||
old_count = session.execute("SELECT COUNT(*) FROM triples WHERE collection = ?", (collection,))
|
||||
new_count = session.execute("SELECT COUNT(*) FROM triples_by_subject WHERE collection = ?", (collection,))
|
||||
|
||||
assert old_count == new_count, f"Record count mismatch: {old_count} vs {new_count}"
|
||||
|
||||
# Spot check random samples
|
||||
sample_queries = generate_test_queries()
|
||||
for query in sample_queries:
|
||||
old_result = execute_legacy_query(query)
|
||||
new_result = execute_optimized_query(query)
|
||||
assert old_result == new_result, f"Query results differ for {query}"
|
||||
```
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות ביצועים
|
||||
|
||||
#### תרחישי ביצוע
|
||||
1. **השוואת ביצועי שאילתות**
|
||||
מדדי ביצועים לפני ואחרי עבור כל 8 סוגי השאילתות
|
||||
התמקדות בשיפור ביצועים של שאילתת get_po (הסרת ALLOW FILTERING)
|
||||
מדידת השהייה של שאילתות בתנאי גדלי נתונים שונים
|
||||
|
||||
2. **בדיקות עומסים**
|
||||
ביצוע שאילתות במקביל
|
||||
קצב כתיבה עם פעולות אצווה
|
||||
ניצול זיכרון ו-CPU
|
||||
|
||||
3. **בדיקות סקלאביליות**
|
||||
ביצועים עם גדלי אוספים גדלים
|
||||
חלוקת שאילתות בין אוספים מרובים
|
||||
ניצול צמתים באשכול
|
||||
|
||||
#### סטי נתוני בדיקה
|
||||
**קטן:** 10 אלף משולשים לאוסף
|
||||
**בינוני:** 100 אלף משולשים לאוסף
|
||||
**גדול:** 1 מיליון+ משולשים לאוסף
|
||||
**אוספים מרובים:** בדיקת חלוקת מחיצות
|
||||
|
||||
### בדיקות פונקציונליות
|
||||
|
||||
#### עדכוני בדיקות יחידה
|
||||
```python
|
||||
# Example test structure for new implementation
|
||||
class TestCassandraKGPerformance:
|
||||
def test_get_po_no_allow_filtering(self):
|
||||
# Verify get_po queries don't use ALLOW FILTERING
|
||||
with patch('cassandra.cluster.Session.execute') as mock_execute:
|
||||
kg.get_po('test_collection', 'predicate', 'object')
|
||||
executed_query = mock_execute.call_args[0][0]
|
||||
assert 'ALLOW FILTERING' not in executed_query
|
||||
|
||||
def test_multi_table_consistency(self):
|
||||
# Verify all tables stay in sync
|
||||
kg.insert('test', 's1', 'p1', 'o1')
|
||||
|
||||
# Check all tables contain the triple
|
||||
assert_triple_exists('triples_by_subject', 'test', 's1', 'p1', 'o1')
|
||||
assert_triple_exists('triples_by_po', 'test', 'p1', 'o1', 's1')
|
||||
assert_triple_exists('triples_by_object', 'test', 'o1', 's1', 'p1')
|
||||
```
|
||||
|
||||
#### עדכונים לבדיקות אינטגרציה
|
||||
```python
|
||||
class TestCassandraIntegration:
|
||||
def test_query_performance_regression(self):
|
||||
# Ensure new implementation is faster than old
|
||||
old_time = benchmark_legacy_get_po()
|
||||
new_time = benchmark_optimized_get_po()
|
||||
assert new_time < old_time * 0.5 # At least 50% improvement
|
||||
|
||||
def test_end_to_end_workflow(self):
|
||||
# Test complete write -> query -> delete cycle
|
||||
# Verify no performance degradation in integration
|
||||
```
|
||||
|
||||
### תוכנית חזרה אחורה
|
||||
|
||||
#### אסטרטגיה מהירה לחזרה אחורה
|
||||
1. **החלפת משתנה סביבה** - חזרה מיידית לטבלאות הישנות.
|
||||
2. **שמירה על הטבלאות הישנות** - לא למחוק עד שיוכח שיפור בביצועים.
|
||||
3. **התראות ניטור** - הפעלת חזרה אוטומטית בהתבסס על שיעורי שגיאות/השהייה.
|
||||
|
||||
#### אימות חזרה אחורה
|
||||
```python
|
||||
def rollback_to_legacy():
|
||||
# Set environment variable
|
||||
os.environ['CASSANDRA_USE_LEGACY'] = 'true'
|
||||
|
||||
# Restart services to pick up change
|
||||
restart_cassandra_services()
|
||||
|
||||
# Validate functionality
|
||||
run_smoke_tests()
|
||||
```
|
||||
|
||||
## סיכונים ושיקולים
|
||||
|
||||
### סיכוני ביצועים
|
||||
**עלייה בלעדי כתיבה** - 4 פעולות כתיבה לכל הוספה (33% יותר מהגישה של 3 טבלאות)
|
||||
**תקורת אחסון** - דרישת אחסון של 4x (33% יותר מהגישה של 3 טבלאות)
|
||||
**כשלים בכתיבה אצווה** - יש צורך בטיפול תקין בשגיאות
|
||||
**מורכבות מחיקה** - מחיקת אוסף דורשת לולאה של קריאה ולאחר מכן מחיקה
|
||||
|
||||
### סיכונים תפעוליים
|
||||
**מורכבות העברה** - העברת נתונים עבור מערכי נתונים גדולים
|
||||
**אתגרים של עקביות** - הבטחת סנכרון של כל הטבלאות
|
||||
**פערים בניטור** - יש צורך במדדים חדשים עבור פעולות מרובות טבלאות
|
||||
|
||||
### אסטרטגיות הפחתת סיכונים
|
||||
1. **פריסה הדרגתית** - התחילו עם אוספים קטנים
|
||||
2. **ניטור מקיף** - מעקב אחר כל מדדי הביצועים
|
||||
3. **אימות אוטומטי** - בדיקת עקביות רציפה
|
||||
4. **יכולת ביטול מהירה** - בחירת טבלה מבוססת סביבה
|
||||
|
||||
## קריטריוני הצלחה
|
||||
|
||||
### שיפורי ביצועים
|
||||
[ ] **ביטול ALLOW FILTERING** - שאילתות get_po ו-get_os פועלות ללא סינון
|
||||
[ ] **הפחתת השהייה בשאילתות** - שיפור של 50%+ בזמני תגובה של שאילתות
|
||||
[ ] **חלוקת עומסים טובה יותר** - ללא מחיצות "חמות", חלוקת עומסים שווה על פני צמתים בקלאסטר
|
||||
[ ] **ביצועים ניתנים להרחבה** - זמן שאילתה תלוי בגודל התוצאה, ולא בנפח הנתונים הכולל
|
||||
|
||||
### דרישות פונקציונליות
|
||||
[ ] **תאימות API** - כל הקוד הקיים ממשיך לעבוד ללא שינוי
|
||||
[ ] **עקביות נתונים** - שלוש הטבלאות נשארות מסונכרנות
|
||||
[ ] **אפס אובדן נתונים** - העברה שומרת על כל הטרפלים הקיימים
|
||||
[ ] **תאימות לאחור** - אפשרות לחזור לסקמה הישנה
|
||||
|
||||
### דרישות תפעוליות
|
||||
[ ] **העברה בטוחה** - פריסה בצורה כחולה-ירוקה עם יכולת ביטול
|
||||
[ ] **כיסוי ניטור** - מדדים מקיפים עבור פעולות מרובות טבלאות
|
||||
[ ] **כיסוי בדיקות** - כל דפוסי השאילתות נבדקו עם מדדי ביצועים
|
||||
[ ] **תיעוד** - עדכון נהלי פריסה ותפעול
|
||||
|
||||
## ציר זמן
|
||||
|
||||
### שלב 1: יישום
|
||||
[ ] כתיבה מחדש של `cassandra_kg.py` עם סכימת טבלאות מרובות
|
||||
[ ] יישום פעולות כתיבה אצווה
|
||||
[ ] הוספת אופטימיזציה של הצהרות מוכנות
|
||||
[ ] עדכון בדיקות יחידה
|
||||
|
||||
### שלב 2: בדיקות אינטגרציה
|
||||
[ ] עדכון בדיקות אינטגרציה
|
||||
[ ] מדידת ביצועים
|
||||
[ ] בדיקת עומסים עם נפחי נתונים ריאליים
|
||||
[ ] סקריפטים לאימות עקביות נתונים
|
||||
|
||||
### שלב 3: תכנון העברה
|
||||
[ ] סקריפטים לפריסה בצורה כחולה-ירוקה
|
||||
[ ] כלים להעברת נתונים
|
||||
[ ] עדכוני לוח מחוונים לניטור
|
||||
[ ] נהלי ביטול
|
||||
|
||||
### שלב 4: פריסה לייצור
|
||||
[ ] פריסה הדרגתית לסביבת ייצור
|
||||
[ ] ניטור ואימות ביצועים
|
||||
[ ] ניקוי טבלאות ישנות
|
||||
[ ] עדכוני תיעוד
|
||||
|
||||
## מסקנה
|
||||
|
||||
אסטרטגיית הדה-נורמליזציה מרובת טבלאות פותרת ישירות את שני צווארי הבקבוק הקריטיים בביצועים:
|
||||
|
||||
1. **מבטלת את ALLOW FILTERING היקר** על ידי מתן מבני טבלאות אופטימליים עבור כל דפוס שאילתה
|
||||
2. **משפרת את יעילות הקיבוץ** באמצעות מפתחות מחיצה מורכבים שמפיצים את העומס כראוי
|
||||
|
||||
הגישה ממנפת את החוזקות של Cassandra תוך שמירה על תאימות API מלאה, ומבטיחה שלקוד הקיים יש יתרונות אוטומטיים משיפורי הביצועים.
|
||||
410
docs/tech-specs/he/collection-management.he.md
Normal file
410
docs/tech-specs/he/collection-management.he.md
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לניהול אוספים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לניהול אוספים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר את יכולות ניהול האוספים עבור TrustGraph, הדורש יצירת אוספים באופן מפורש ומספק שליטה ישירה על מחזור החיים של האוסף. יש ליצור אוספים באופן מפורש לפני השימוש, כדי להבטיח סנכרון תקין בין מטא-הנתונים של הספרן לבין כל אחסני הנתונים. הפיצ'ר תומך בארבעה תרחישי שימוש עיקריים:
|
||||
|
||||
1. **יצירת אוסף**: ליצור אוספים באופן מפורש לפני אחסון נתונים
|
||||
2. **רשימת אוספים**: להציג את כל האוספים הקיימים במערכת
|
||||
3. **ניהול מטא-נתונים של אוסף**: לעדכן שמות, תיאורים ותגיות של אוספים
|
||||
4. **מחיקת אוסף**: להסיר אוספים ונתונים הקשורים אליהם בכל סוגי האחסון
|
||||
|
||||
## מטרות
|
||||
|
||||
**יצירת אוסף מפורשת**: לדרוש יצירת אוספים לפני שאפשר לאחסן נתונים
|
||||
**סנכרון אחסון**: להבטיח שאוספים קיימים בכל אחסני הנתונים (וקטורים, אובייקטים, טריפלטים)
|
||||
**נראות של אוסף**: לאפשר למשתמשים לרשום ולבדוק את כל האוספים בסביבה שלהם
|
||||
**ניקוי אוספים**: לאפשר מחיקת אוספים שכבר אינם נחוצים
|
||||
**ארגון אוספים**: לתמוך בתגיות ובתוויות למעקב וגילוי טובים יותר של אוספים
|
||||
**ניהול מטא-נתונים**: לקשר מטא-נתונים בעלי משמעות לאוספים לצורך בהירות תפעולית
|
||||
**גילוי אוספים**: להקל על מציאת אוספים ספציפיים באמצעות סינון וחיפוש
|
||||
**שקיפות תפעולית**: לספק נראות ברורה על מחזור החיים ושימוש האוספים
|
||||
**ניהול משאבים**: לאפשר ניקוי של אוספים לא בשימוש כדי לייעל את ניצול המשאבים
|
||||
**שלמות נתונים**: למנוע קיום של אוספים יתומים באחסון ללא מעקב מטא-נתונים
|
||||
|
||||
## רקע
|
||||
|
||||
בעבר, אוספים ב-TrustGraph נוצרו באופן סמוי במהלך פעולות טעינת נתונים, מה שגרם לבעיות סנכרון שבהן אוספים יכלו להתקיים באחסני נתונים ללא מטא-נתונים תואמים בספרן. זה יצר אתגרים בניהול ואפשרות של נתונים יתומים.
|
||||
|
||||
מודל יצירת האוספים המפורש פותר בעיות אלה על ידי:
|
||||
דרישה ליצירת אוספים לפני השימוש באמצעות `tg-set-collection`
|
||||
שידור יצירת אוסף לכל אחסני הנתונים
|
||||
שמירה על מצב מסונכרן בין מטא-נתונים של הספרן ואחסון
|
||||
מניעת כתיבה לאוספים שאינם קיימים
|
||||
מתן ניהול ברור של מחזור החיים של האוסף
|
||||
|
||||
מפרט זה מגדיר את מודל ניהול האוספים המפורש. על ידי דרישה ליצירת אוסף מפורשת, TrustGraph מבטיחה:
|
||||
אוספים מתועדים במטא-נתונים של הספרן החל מיצירתם
|
||||
כל אחסני הנתונים מודעים לאוספים לפני קבלת נתונים
|
||||
לא קיימים אוספים יתומים באחסון
|
||||
נראות ושליטה ברורים על מחזור החיים של האוסף
|
||||
טיפול שגיאות עקבי כאשר פעולות מפנות לאוספים שאינם קיימים
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
מערכת ניהול האוספים תיושם בתוך התשתית הקיימת של TrustGraph:
|
||||
|
||||
1. **שילוב עם שירות הספרן**
|
||||
פעולות ניהול אוספים יתווספו לשירות הספרן הקיים
|
||||
לא נדרש שירות חדש - משתמש בדפוסי אימות וגישה קיימים
|
||||
מטפל ברשימת אוספים, מחיקה וניהול מטא-נתונים
|
||||
|
||||
מודול: trustgraph-librarian
|
||||
|
||||
2. **טבלת מטא-נתונים של אוסף ב-Cassandra**
|
||||
טבלה חדשה במרחב המפתחות הקיים של הספרן
|
||||
מאחסנת מטא-נתונים של אוסף עם גישה מבוססת משתמש
|
||||
מפתח ראשי: (user_id, collection_id) עבור ריבוי שוכרים תקין
|
||||
|
||||
מודול: trustgraph-librarian
|
||||
|
||||
3. **ממשק שורת פקודה לניהול אוספים**
|
||||
ממשק שורת פקודה לפעולות ניהול אוספים
|
||||
מספק פקודות לרשימה, מחיקה, תווית וניהול תגיות
|
||||
משתלב עם מסגרת שורת הפקודה הקיימת
|
||||
|
||||
מודול: trustgraph-cli
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### טבלת מטא-נתונים של אוסף ב-Cassandra
|
||||
|
||||
מטא-הנתונים של האוסף יאוחסנו בטבלה מובנית ב-Cassandra במרחב המפתחות של הספרן:
|
||||
|
||||
```sql
|
||||
CREATE TABLE collections (
|
||||
user text,
|
||||
collection text,
|
||||
name text,
|
||||
description text,
|
||||
tags set<text>,
|
||||
created_at timestamp,
|
||||
updated_at timestamp,
|
||||
PRIMARY KEY (user, collection)
|
||||
);
|
||||
```
|
||||
|
||||
מבנה טבלה:
|
||||
**user** + **collection**: מפתח ראשי מורכב המבטיח בידוד משתמשים
|
||||
**name**: שם קריא לבן-אדם של האוסף
|
||||
**description**: תיאור מפורט של מטרת האוסף
|
||||
**tags**: קבוצת תגיות למיון וסינון
|
||||
**created_at**: חותמת זמן של יצירת האוסף
|
||||
**updated_at**: חותמת זמן של השינוי האחרון
|
||||
|
||||
גישה זו מאפשרת:
|
||||
ניהול אוספים מרובי-דיירים עם בידוד משתמשים
|
||||
שאילתות יעילות לפי משתמש ואוסף
|
||||
מערכת תיוג גמישה לארגון
|
||||
מעקב אחר מחזור החיים לצורך תובנות תפעוליות
|
||||
|
||||
#### מחזור החיים של אוסף
|
||||
|
||||
אוספים נוצרים באופן מפורש בספרן לפני שניתן לבצע פעולות נתונים:
|
||||
|
||||
1. **יצירת אוסף** (שני מסלולים):
|
||||
|
||||
**מסלול א': יצירה על ידי משתמש** באמצעות `tg-set-collection`:
|
||||
המשתמש מספק מזהה אוסף, שם, תיאור ותגיות
|
||||
הספרן יוצר רשומת מטא-נתונים בטבלת `collections`
|
||||
הספרן משדר "create-collection" לכל מערכות האחסון
|
||||
כל מעבדי האחסון יוצרים את האוסף ומאשרים הצלחה
|
||||
האוסף מוכן כעת לפעולות נתונים
|
||||
|
||||
**מסלול ב': יצירה אוטומטית בעת הגשת מסמך**:
|
||||
המשתמש מגיש מסמך המציין מזהה אוסף
|
||||
הספרן בודק אם האוסף קיים בטבלת המטא-נתונים
|
||||
אם לא קיים: הספרן יוצר מטא-נתונים עם ברירות מחדל (שם=מזהה האוסף, תיאור/תגיות ריקים)
|
||||
הספרן משדר "create-collection" לכל מערכות האחסון
|
||||
כל מעבדי האחסון יוצרים את האוסף ומאשרים הצלחה
|
||||
עיבוד המסמך ממשיך עם יצירת האוסף
|
||||
|
||||
שני המסלולים מבטיחים שהאוסף קיים במטא-נתונים של הספרן ובכל מערכות האחסון לפני ביצוע פעולות נתונים.
|
||||
|
||||
2. **אימות אחסון**: פעולות כתיבה מאמתות את קיומו של האוסף:
|
||||
מעבדי האחסון בודקים את מצב האוסף לפני קבלת כתיבות
|
||||
כתיבות לאוספים שאינם קיימים מחזירות שגיאה
|
||||
זה מונע כתיבות ישירות העוקפות את לוגיקת יצירת האוסף של הספרן
|
||||
|
||||
3. **התנהגות שאילתה**: פעולות שאילתה מטפלות באוספים שאינם קיימים בצורה חלקה:
|
||||
שאילתות לאוספים שאינם קיימים מחזירות תוצאות ריקות
|
||||
לא נזרקת שגיאה עבור פעולות שאילתה
|
||||
מאפשרת חקירה מבלי לדרוש קיום האוסף
|
||||
|
||||
4. **עדכוני מטא-נתונים**: משתמשים יכולים לעדכן מטא-נתונים של אוסף לאחר יצירתו:
|
||||
עדכון שם, תיאור ותגיות באמצעות `tg-set-collection`
|
||||
העדכונים חלים רק על מטא-נתונים של הספרן
|
||||
מערכות האחסון שומרות על האוסף, אך עדכוני מטא-נתונים אינם מועברים
|
||||
|
||||
5. **מחיקה מפורשת**: משתמשים מוחקים אוספים באמצעות `tg-delete-collection`:
|
||||
הספרן משדר "delete-collection" לכל מערכות האחסון
|
||||
ממתין לאישור מכל מעבדי האחסון
|
||||
מוחק רשומת מטא-נתונים של הספרן רק לאחר השלמת הניקוי של האחסון
|
||||
מבטיח שלא יישארו נתונים יתומים באחסון
|
||||
|
||||
**עקרון מפתח**: הספרן הוא נקודת השליטה היחידה ליצירת אוספים. בין אם זהו פקודה של משתמש או הגשת מסמך, הספרן מבטיח מעקב נכון אחר מטא-נתונים וסנכרון של מערכות אחסון לפני שהוא מאפשר פעולות נתונים.
|
||||
|
||||
פעולות נדרשות:
|
||||
**יצירת אוסף**: פעולה של משתמש באמצעות `tg-set-collection` או אוטומטית בעת הגשת מסמך
|
||||
**עדכון מטא-נתונים של אוסף**: פעולה של משתמש לשינוי שם, תיאור ותגיות
|
||||
**מחיקת אוסף**: פעולה של משתמש להסרת אוסף ונתונים שלו בכל האחסונים
|
||||
**רשימת אוספים**: פעולה של משתמש לצפייה באוספים עם סינון לפי תגיות
|
||||
|
||||
#### ניהול אוספים מרובי-חנות
|
||||
|
||||
אוספים קיימים על פני מספר מערכות אחסון ב-TrustGraph:
|
||||
**מאגרי וקטורים** (Qdrant, Milvus, Pinecone): אחסון הטבעות ונתוני וקטור
|
||||
**מאגרי אובייקטים** (Cassandra): אחסון מסמכים ונתוני קבצים
|
||||
**מאגרי משולשים** (Cassandra, Neo4j, Memgraph, FalkorDB): אחסון נתוני גרף/RDF
|
||||
פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא).
|
||||
כל סוג חנות מיישם:
|
||||
**מעקב אחר מצב איסוף**: שמירה על ידע אילו איסופים קיימים
|
||||
**יצירת איסוף**: קבלת עיבוד פעולות "יצירת-איסוף"
|
||||
**אימות איסוף**: בדיקת קיום האיסוף לפני קבלת כתיבות
|
||||
**מחיקת איסוף**: הסרת כל הנתונים עבור איסוף מסוים
|
||||
|
||||
שירות הספרין מתאם פעולות איסוף בין כל סוגי החנויות, תוך הבטחה ש:
|
||||
איסופים נוצרים בכל ה-backends לפני השימוש
|
||||
כל ה-backends מאשרים יצירה לפני החזרת הצלחה
|
||||
מחזור חיים מסונכרן של איסופים בין סוגי אחסון
|
||||
טיפול עקבי בשגיאות כאשר איסופים אינם קיימים
|
||||
|
||||
#### מעקב אחר מצב איסוף לפי סוג אחסון
|
||||
|
||||
כל backend אחסון עוקב אחר מצב איסוף בצורה שונה בהתאם ליכולותיו:
|
||||
|
||||
**Cassandra Triple Store:**
|
||||
משתמש בטבלה קיימת `triples_collection`
|
||||
יוצר טריפל מערכת כאשר איסוף נוצר
|
||||
שאילתה: `SELECT collection FROM triples_collection WHERE collection = ? LIMIT 1`
|
||||
בדיקה יעילה של מחיצה יחידה לקיום איסוף
|
||||
|
||||
**Qdrant/Milvus/Pinecone Vector Stores:**
|
||||
ממשקי API מקוריים לאיסופים מספקים בדיקת קיום
|
||||
איסופים נוצרים עם תצורת וקטור מתאימה
|
||||
שיטה `collection_exists()` משתמשת ב-API של האחסון
|
||||
יצירת איסוף מאמת דרישות מימד
|
||||
|
||||
**Neo4j/Memgraph/FalkorDB Graph Stores:**
|
||||
משתמש בצמתים `:CollectionMetadata` כדי לעקוב אחר איסופים
|
||||
מאפייני צומת: `{user, collection, created_at}`
|
||||
שאילתה: `MATCH (c:CollectionMetadata {user: $user, collection: $collection})`
|
||||
נפרד מצמתי נתונים לצורך הפרדה נקייה
|
||||
מאפשר רישום ואימות יעילים של איסופים
|
||||
|
||||
**Cassandra Object Store:**
|
||||
משתמש בטבלת מטא-נתונים של איסוף או שורות סימון
|
||||
דפוס דומה ל-triple store
|
||||
מאמת איסוף לפני כתיבת מסמכים
|
||||
|
||||
### ממשקים
|
||||
|
||||
ממשקי ניהול איסופים (ספרין):
|
||||
**יצירת/עדכון איסוף**: יצירת איסוף חדש או עדכון מטא-נתונים קיימים באמצעות `tg-set-collection`
|
||||
**רשימת איסופים**: שליפה של איסופים עבור משתמש עם סינון תגיות אופציונלי
|
||||
**מחיקת איסוף**: הסרת איסוף ונתונים קשורים, עם העברה לכל סוגי החנויות
|
||||
|
||||
ממשקי ניהול אחסון (כל מעבדי אחסון):
|
||||
**יצירת איסוף**: טיפול בפעולת "יצירת-איסוף", הקמת איסוף באחסון
|
||||
**מחיקת איסוף**: טיפול בפעולת "מחיקת-איסוף", הסרת כל נתוני איסוף
|
||||
**בדיקת קיום איסוף**: אימות פנימי לפני קבלת פעולות כתיבה
|
||||
|
||||
ממשקי פעולות נתונים (התנהגות משתנה):
|
||||
**ממשקי כתיבה**: אימות קיום איסוף לפני קבלת נתונים, החזרת שגיאה אם לא קיים
|
||||
**ממשקי שאילתה**: החזרת תוצאות ריקות עבור איסופים שאינם קיימים ללא שגיאה
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
היישום יעקוב לדפוסי TrustGraph קיימים לשילוב שירותים ומבנה פקודות שורת פקודה.
|
||||
|
||||
#### מחיקת איסוף בשרשרת
|
||||
|
||||
כאשר משתמש יוזם מחיקת איסוף דרך שירות הספרין:
|
||||
|
||||
1. **אימות מטא-נתונים**: אימות קיום איסוף ושהמשתמש מורשה למחוק
|
||||
2. **שרשרת אחסון**: הספרין מתאם מחיקה בכל כותבי האחסון:
|
||||
כותב אחסון וקטור: הסרת הטמעות ואינדקסים וקטוריים עבור המשתמש והאיסוף
|
||||
כותב אחסון אובייקטים: הסרת מסמכים וקבצים עבור המשתמש והאיסוף
|
||||
כותב triple store: הסרת נתוני גרף וטריפלים עבור המשתמש והאיסוף
|
||||
3. **ניקוי מטא-נתונים**: הסרת רשומת מטא-נתונים של איסוף מ-Cassandra
|
||||
4. **טיפול בשגיאות**: אם מחיקת אחסון כלשהי נכשלת, שמירה על עקביות באמצעות ביטול או מנגנוני ניסיון חוזר
|
||||
|
||||
#### ממשק ניהול איסופים
|
||||
|
||||
**⚠️ גישה מיושנת - הוחלפה בדפוס מבוסס תצורה**
|
||||
|
||||
הארכיטקטורה המבוססת על תורים המתוארת להלן הוחלפה בגישה מבוססת תצורה באמצעות `CollectionConfigHandler`. כל ה-backends אחסון מקבלים כעת עדכוני איסופים באמצעות הודעות דחיפה לתצורה במקום תורי ניהול ייעודיים.
|
||||
|
||||
~~כל כותבי האחסון מיישמים ממשק ניהול איסופים סטנדרטי עם סכימה משותפת:~~
|
||||
|
||||
~~**סכימת הודעה (`StorageManagementRequest`):**~~
|
||||
```json
|
||||
{
|
||||
"operation": "create-collection" | "delete-collection",
|
||||
"user": "user123",
|
||||
"collection": "documents-2024"
|
||||
}
|
||||
```
|
||||
|
||||
~~**ארכיטקטורת תורים:**~~
|
||||
~~**תור ניהול מאגרי וקטורים** (`vector-storage-management`): מאגרי וקטורים/הטבעות~~
|
||||
~~**תור ניהול אחסון אובייקטים** (`object-storage-management`): אחסון אובייקטים/מסמכים~~
|
||||
~~**תור ניהול מאגרי טריפל** (`triples-storage-management`): מאגרי גרפים/RDF~~
|
||||
~~**תור תגובות אחסון** (`storage-management-response`): כל התגובות נשלחות לכאן~~
|
||||
|
||||
**יישום נוכחי:**
|
||||
|
||||
כל מערכות האחסון משתמשות כעת ב-`CollectionConfigHandler`:
|
||||
**אינטגרציה של דחיפת תצורה**: שירותי אחסון נרשמים לקבלת התראות על שינויי תצורה
|
||||
**סנכרון אוטומטי**: אוספים נוצרים/נמחקים בהתבסס על שינויי תצורה
|
||||
**מודל הצהרתי**: אוספים מוגדרים בשירות התצורה, מערכות האחסון מסתנכרנות כדי להתאים
|
||||
**ללא בקשות/תגובות**: מבטל את התקורה של תיאום ומעקב אחר תגובות
|
||||
**מעקב אחר מצב אוסף**: נשמר באמצעות מטמון `known_collections`
|
||||
**פעולות אידמפוטנטיות**: בטוח לעבד את אותה תצורה מספר פעמים
|
||||
|
||||
כל מערכת אחסון מיישמת:
|
||||
`create_collection(user: str, collection: str, metadata: dict)` - יצירת מבני אוסף
|
||||
`delete_collection(user: str, collection: str)` - הסרת כל נתוני האוסף
|
||||
`collection_exists(user: str, collection: str) -> bool` - אימות לפני כתיבה
|
||||
|
||||
#### שינוי מבנה מאגר טריפל של Cassandra
|
||||
|
||||
כחלק מיישום זה, מאגר הטריפל של Cassandra ישונה ממודל של טבלה לכל אוסף למודל טבלה מאוחדת:
|
||||
|
||||
**ארכיטקטורה נוכחית:**
|
||||
מרחב מפתחות לכל משתמש, טבלה נפרדת לכל אוסף
|
||||
סכימה: `(s, p, o)` עם `PRIMARY KEY (s, p, o)`
|
||||
שמות טבלאות: אוספי משתמשים הופכים לטבלאות Cassandra נפרדות
|
||||
|
||||
**ארכיטקטורה חדשה:**
|
||||
מרחב מפתחות לכל משתמש, טבלה יחידה בשם "triples" לכל האוספים
|
||||
סכימה: `(collection, s, p, o)` עם `PRIMARY KEY (collection, s, p, o)`
|
||||
בידוד אוספים באמצעות חלוקה לאוספים
|
||||
|
||||
**שינויים נדרשים:**
|
||||
|
||||
1. **שינוי מבנה מחלקה TrustGraph** (`trustgraph/direct/cassandra.py`):
|
||||
הסרת פרמטר `table` מהקונסטרוקטור, שימוש בטבלה קבועה "triples"
|
||||
הוספת פרמטר `collection` לכל השיטות
|
||||
עדכון הסכימה כדי לכלול את האוסף בעמודה הראשונה
|
||||
**עדכוני אינדקסים**: ייוצרו אינדקסים חדשים לתמיכה בכל 8 דפוסי השאילתות:
|
||||
אינדקס על `(s)` עבור שאילתות מבוססות סובייקט
|
||||
אינדקס על `(p)` עבור שאילתות מבוססות פרידיקט
|
||||
אינדקס על `(o)` עבור שאילתות מבוססות אובייקט
|
||||
הערה: Cassandra אינה תומכת באינדקסים משניים רב-עמודתיים, לכן אלו הם אינדקסים בעמודה יחידה
|
||||
|
||||
**ביצועי דפוסי שאילתות:**
|
||||
✅ `get_all()` - סריקת מחיצה על `collection`
|
||||
✅ `get_s(s)` - משתמשת ביעילות במפתח ראשי (`collection, s`)
|
||||
✅ `get_p(p)` - משתמשת ב-`idx_p` עם סינון `collection`
|
||||
✅ `get_o(o)` - משתמשת ב-`idx_o` עם סינון `collection`
|
||||
✅ `get_sp(s, p)` - משתמשת ביעילות במפתח ראשי (`collection, s, p`)
|
||||
⚠️ `get_po(p, o)` - דורשת `ALLOW FILTERING` (משתמשת או ב-`idx_p` או ב-`idx_o` בתוספת סינון)
|
||||
✅ `get_os(o, s)` - משתמשת ב-`idx_o` עם סינון נוסף על `s`
|
||||
✅ `get_spo(s, p, o)` - משתמשת ביעילות במפתח ראשי מלא
|
||||
|
||||
**הערה על ALLOW FILTERING**: דפוס השאילתה `get_po` דורש `ALLOW FILTERING` מכיוון שהוא זקוק גם לאילוצי פרידיקט וגם לאובייקט ללא אינדקס מורכב מתאים. זה מקובל מכיוון שדפוס השאילתה הזה פחות נפוץ משאילתות מבוססות סובייקט בשימוש טיפוסי במאגר טריפל.
|
||||
|
||||
2. **עדכוני כותב אחסון** (`trustgraph/storage/triples/cassandra/write.py`):
|
||||
שמירה על חיבור TrustGraph יחיד לכל משתמש במקום לכל (משתמש, אוסף)
|
||||
העברת האוסף לפעולות הכנסה
|
||||
שיפור ניצול משאבים עם פחות חיבורים
|
||||
|
||||
3. **עדכוני שירות שאילתות** (`trustgraph/query/triples/cassandra/service.py`):
|
||||
חיבור TrustGraph יחיד לכל משתמש
|
||||
העברת האוסף לכל פעולות השאילתה
|
||||
שמירה על לוגיקת שאילתה זהה עם פרמטר האוסף
|
||||
|
||||
**יתרונות:**
|
||||
**מחיקת אוספים מפושטת:** מחיקה באמצעות מפתח מחיצה `collection` בכל 4 הטבלאות
|
||||
**יעילות משאבים:** פחות חיבורי מסד נתונים ואובייקטי טבלה
|
||||
**פעולות חוצות אוספים:** קל יותר ליישם פעולות המשתרעות על פני מספר אוספים
|
||||
**ארכיטקטורה עקבית:** מתאימה לגישה מאוחדת למטא-נתונים של אוספים
|
||||
**אימות אוסף:** קל לבדוק את קיום האוסף באמצעות טבלת `triples_collection`
|
||||
|
||||
פעולות איסוף יהיו אטומיות במידת האפשר, ויספקו טיפול בשגיאות ואימות מתאימים.
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
פעולות ניהול איסוף דורשות הרשאות מתאימות כדי למנוע גישה או מחיקה לא מורשית של איסופים. בקרת הגישה תתאים למודלי האבטחה הקיימים של TrustGraph.
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
פעולות הצגת איסופים עשויות לדרוש דפוס של חלוקה לדפים (pagination) עבור סביבות עם מספר גדול של איסופים. שאילתות מטא-נתונים צריכות להיות מותאמות לשיטות סינון נפוצות.
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
בדיקות מקיפות יכסו:
|
||||
זרימת עבודה של יצירת איסוף מקצה לקצה
|
||||
סנכרון עם ה-backend של האחסון
|
||||
אימות כתיבה עבור איסופים שאינם קיימים
|
||||
טיפול בשאילתות עבור איסופים שאינם קיימים
|
||||
מחיקת איסוף עם השפעה על כל האחסונים
|
||||
טיפול בשגיאות ותסריטי התאוששות
|
||||
בדיקות יחידה עבור כל ה-backend של האחסון
|
||||
בדיקות אינטגרציה עבור פעולות חוצות-אחסונים
|
||||
|
||||
## סטטוס יישום
|
||||
|
||||
### ✅ רכיבים שהושלמו
|
||||
|
||||
1. **שירות ניהול איסופים של Librarian** (`trustgraph-flow/trustgraph/librarian/collection_manager.py`)
|
||||
פעולות CRUD של מטא-נתונים של איסוף (רשימה, עדכון, מחיקה)
|
||||
שילוב עם טבלת מטא-נתונים של איסוף ב-Cassandra באמצעות `LibraryTableStore`
|
||||
תיאום מחיקת איסוף עם השפעה על כל סוגי האחסון
|
||||
טיפול בבקשות/תגובות אסינכרוניות עם ניהול שגיאות מתאים
|
||||
|
||||
2. **סכימת מטא-נתונים של איסוף** (`trustgraph-base/trustgraph/schema/services/collection.py`)
|
||||
סכימות `CollectionManagementRequest` ו-`CollectionManagementResponse`
|
||||
סכימה `CollectionMetadata` עבור רשומות איסוף
|
||||
הגדרות נושא תורים עבור בקשות/תגובות של איסוף
|
||||
|
||||
3. **סכימת ניהול אחסון** (`trustgraph-base/trustgraph/schema/services/storage.py`)
|
||||
סכימות `StorageManagementRequest` ו-`StorageManagementResponse`
|
||||
נושאים של תורי ניהול אחסון הוגדרו
|
||||
פורמט הודעה עבור פעולות של איסוף ברמת האחסון
|
||||
|
||||
4. **סכימת 4-טבלאות של Cassandra** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py`)
|
||||
מפתחות מחיצה מורכבים לביצועי שאילתה
|
||||
טבלה `triples_collection` עבור שאילתות SPO ומעקב אחר מחיקה
|
||||
יישום מחיקת איסוף עם דפוס של קריאה ולאחר מכן מחיקה
|
||||
|
||||
### ✅ מעבר לדפוס מבוסס תצורה - הושלם
|
||||
|
||||
**כל ה-backend של האחסון עברו מדפוס מבוסס תורים לדפוס מבוסס תצורה `CollectionConfigHandler`.**
|
||||
|
||||
מעברים שהושלמו:
|
||||
✅ `trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/triples/neo4j/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/triples/memgraph/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/triples/falkordb/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py`
|
||||
✅ `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py`
|
||||
|
||||
כל ה-backend כעת:
|
||||
יורשים מ-`CollectionConfigHandler`
|
||||
נרשמים לקבלת הודעות דחיפה של תצורה באמצעות `self.register_config_handler(self.on_collection_config)`
|
||||
מיישמים `create_collection(user, collection, metadata)` ו-`delete_collection(user, collection)`
|
||||
משתמשים ב-`collection_exists(user, collection)` לאימות לפני כתיבה
|
||||
מסתנכרנים באופן אוטומטי עם שינויים בשירות התצורה
|
||||
|
||||
תשתית מבוססת תורים ישנה הוסרה:
|
||||
✅ הוסרו סכימות `StorageManagementRequest` ו-`StorageManagementResponse`
|
||||
✅ הוסרו הגדרות נושאים של תורי ניהול אחסון
|
||||
✅ הוסר צרכן/מפיק תורים מכל ה-backend
|
||||
✅ הוסרו מטפלים `on_storage_management` מכל ה-backend
|
||||
144
docs/tech-specs/he/document-embeddings-chunk-id.he.md
Normal file
144
docs/tech-specs/he/document-embeddings-chunk-id.he.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מזהה מקטע של הטמעות מסמכים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מזהה מקטע של הטמעות מסמכים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
אחסון הטמעות מסמכים מאחסן כרגע את הטקסט של המקטעים ישירות בתוך מטען ה-vector store, מה שמשכפל נתונים הקיימים ב-Garage. מפרט זה מחליף את אחסון הטקסט של המקטעים עם הפניות ל-`chunk_id`.
|
||||
|
||||
## מצב נוכחי
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ChunkEmbeddings:
|
||||
chunk: bytes = b""
|
||||
vectors: list[list[float]] = field(default_factory=list)
|
||||
|
||||
@dataclass
|
||||
class DocumentEmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
chunks: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
מטען אחסון וקטורים:
|
||||
```python
|
||||
payload={"doc": chunk} # Duplicates Garage content
|
||||
```
|
||||
|
||||
## עיצוב
|
||||
|
||||
### שינויים בסכימה
|
||||
|
||||
**ChunkEmbeddings** - החלפת "chunk" ב-"chunk_id":
|
||||
```python
|
||||
@dataclass
|
||||
class ChunkEmbeddings:
|
||||
chunk_id: str = ""
|
||||
vectors: list[list[float]] = field(default_factory=list)
|
||||
```
|
||||
|
||||
**תגובת DocumentEmbeddingsResponse** - החזרת מזהי חלקים (chunk_ids) במקום חלקים (chunks):
|
||||
```python
|
||||
@dataclass
|
||||
class DocumentEmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
chunk_ids: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
### מטען של אחסון וקטורים
|
||||
|
||||
כל האחסונים (Qdrant, Milvus, Pinecone):
|
||||
```python
|
||||
payload={"chunk_id": chunk_id}
|
||||
```
|
||||
|
||||
### שינויים במסמך RAG
|
||||
|
||||
מעבד מסמכי ה-RAG שולף תוכן מקטעים מ-Garage:
|
||||
|
||||
```python
|
||||
# Get chunk_ids from embeddings store
|
||||
chunk_ids = await self.rag.doc_embeddings_client.query(...)
|
||||
|
||||
# Fetch chunk content from Garage
|
||||
docs = []
|
||||
for chunk_id in chunk_ids:
|
||||
content = await self.rag.librarian_client.get_document_content(
|
||||
chunk_id, self.user
|
||||
)
|
||||
docs.append(content)
|
||||
```
|
||||
|
||||
### שינויים ב-API/SDK
|
||||
|
||||
**DocumentEmbeddingsClient** מחזיר את chunk_ids:
|
||||
```python
|
||||
return resp.chunk_ids # Changed from resp.chunks
|
||||
```
|
||||
|
||||
**פורמט של נתונים** (DocumentEmbeddingsResponseTranslator):
|
||||
```python
|
||||
result["chunk_ids"] = obj.chunk_ids # Changed from chunks
|
||||
```
|
||||
|
||||
### שינויים בממשק שורת הפקודה (CLI)
|
||||
|
||||
כלי ה-CLI מציג מזהי חלקים (chunk_ids) (המשתמשים יכולים לשלוף את התוכן בנפרד אם יש צורך).
|
||||
|
||||
## קבצים לשינוי
|
||||
|
||||
### סכימה (Schema)
|
||||
`trustgraph-base/trustgraph/schema/knowledge/embeddings.py` - ChunkEmbeddings
|
||||
`trustgraph-base/trustgraph/schema/services/query.py` - DocumentEmbeddingsResponse
|
||||
|
||||
### הודעות/מתרגמים
|
||||
`trustgraph-base/trustgraph/messaging/translators/embeddings_query.py` - DocumentEmbeddingsResponseTranslator
|
||||
|
||||
### לקוח (Client)
|
||||
`trustgraph-base/trustgraph/base/document_embeddings_client.py` - החזרת מזהי חלקים (chunk_ids)
|
||||
|
||||
### ערכת פיתוח תוכנה (SDK) / API בפייתון
|
||||
`trustgraph-base/trustgraph/api/flow.py` - document_embeddings_query
|
||||
`trustgraph-base/trustgraph/api/socket_client.py` - document_embeddings_query
|
||||
`trustgraph-base/trustgraph/api/async_flow.py` - אם רלוונטי
|
||||
`trustgraph-base/trustgraph/api/bulk_client.py` - ייבוא/ייצוא של הטמעות מסמכים (document embeddings)
|
||||
`trustgraph-base/trustgraph/api/async_bulk_client.py` - ייבוא/ייצוא של הטמעות מסמכים (document embeddings)
|
||||
|
||||
### שירות הטמעות
|
||||
`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py` - העברת מזהה חלק (chunk_id)
|
||||
|
||||
### כותבי אחסון
|
||||
`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py`
|
||||
|
||||
### שירותי שאילתות
|
||||
`trustgraph-flow/trustgraph/query/doc_embeddings/qdrant/service.py`
|
||||
`trustgraph-flow/trustgraph/query/doc_embeddings/milvus/service.py`
|
||||
`trustgraph-flow/trustgraph/query/doc_embeddings/pinecone/service.py`
|
||||
|
||||
### שער (Gateway)
|
||||
`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_query.py`
|
||||
`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_export.py`
|
||||
`trustgraph-flow/trustgraph/gateway/dispatch/document_embeddings_import.py`
|
||||
|
||||
### אחזור מידע ממסמכים (Document RAG)
|
||||
`trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` - הוספת לקוח של "ספרן" (librarian)
|
||||
`trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py` - שליפה מ-"Garage"
|
||||
|
||||
### ממשק שורת הפקודה (CLI)
|
||||
`trustgraph-cli/trustgraph/cli/invoke_document_embeddings.py`
|
||||
`trustgraph-cli/trustgraph/cli/save_doc_embeds.py`
|
||||
`trustgraph-cli/trustgraph/cli/load_doc_embeds.py`
|
||||
|
||||
## יתרונות
|
||||
|
||||
1. מקור יחיד לאמת - טקסט החלקים נמצא רק ב-"Garage".
|
||||
2. הפחתת נפח האחסון של מאגר הווקטורים.
|
||||
3. מאפשר מעקב אחר מקור המידע בזמן השאילתה באמצעות מזהה החלק (chunk_id).
|
||||
675
docs/tech-specs/he/embeddings-batch-processing.he.md
Normal file
675
docs/tech-specs/he/embeddings-batch-processing.he.md
Normal file
|
|
@ -0,0 +1,675 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לעיבוד אצווה של הטמעות (Embeddings)"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לעיבוד אצווה של הטמעות (Embeddings)
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר אופטימיזציות עבור שירות ההטמעות כדי לתמוך בעיבוד אצווה של מספר טקסטים בבקשה אחת. היישום הנוכחי מעבד טקסט אחד בכל פעם, ואינו מנצל את היתרונות המשמעותיים בביצועים שמודלי הטמעה מספקים בעת עיבוד אצוות.
|
||||
|
||||
1. **חוסר יעילות בעיבוד טקסט בודד**: היישום הנוכחי עוטף טקסטים בודדים ברשימה, ובכך אינו מנצל את יכולות האצווה של FastEmbed.
|
||||
2. **תקורה של בקשה לטקסט**: כל טקסט דורש הודעת Pulsar נפרדת הלוך ושוב.
|
||||
3. **חוסר יעילות בהסקת מודל**: למודלי הטמעה יש תקורה קבועה לכל אצווה; אצוות קטנות מבזבזות משאבי GPU/CPU.
|
||||
4. **עיבוד סדרתי בלקוחות**: שירותים מרכזיים עוברים בלולאה על פריטים וקוראים להטמעות אחד בכל פעם.
|
||||
|
||||
## מטרות
|
||||
|
||||
**תמיכה בממשק API לאצוות**: לאפשר עיבוד של מספר טקסטים בבקשה אחת.
|
||||
**תאימות לאחור**: לשמור על תמיכה בבקשות לטקסט בודד.
|
||||
**שיפור משמעותי בביצועים**: לכוון לשיפור של 5-10x בביצועים עבור פעולות אצווה.
|
||||
**הפחתת השהייה לטקסט**: להוריד את ההשהייה הממוצעת בעת הטמעת מספר טקסטים.
|
||||
**יעילות בשימוש בזיכרון**: לעבד אצוות מבלי לצרוך כמות מוגזמת של זיכרון.
|
||||
**אי-תלות בספק**: לתמוך באצוות בין FastEmbed, Ollama וספקים אחרים.
|
||||
**מעבר של לקוחות**: לעדכן את כל לקוחות ההטמעות כדי להשתמש בממשק ה-API לאצוות כאשר זה מועיל.
|
||||
|
||||
## רקע
|
||||
|
||||
### יישום נוכחי - שירות הטמעות
|
||||
|
||||
היישום של ההטמעות ב-`trustgraph-flow/trustgraph/embeddings/fastembed/processor.py` מציג חוסר יעילות משמעותי בביצועים:
|
||||
|
||||
```python
|
||||
# fastembed/processor.py line 56
|
||||
async def on_embeddings(self, text, model=None):
|
||||
use_model = model or self.default_model
|
||||
self._load_model(use_model)
|
||||
|
||||
vecs = self.embeddings.embed([text]) # Single text wrapped in list
|
||||
|
||||
return [v.tolist() for v in vecs]
|
||||
```
|
||||
|
||||
**בעיות:**
|
||||
|
||||
1. **גודל אצווה 1**: השיטה `embed()` של FastEmbed מותאמת לעיבוד באצווה, אך אנו תמיד משתמשים בה עם `[text]` - אצווה בגודל 1.
|
||||
|
||||
2. **תקורה לכל בקשה:** כל בקשת הטמעה כרוכה ב:
|
||||
סריאליזציה/דה-סריאליזציה של הודעת Pulsar
|
||||
השהייה של תקשורת רשת
|
||||
תקורה של אתחול הסקה של המודל
|
||||
תקורה של תזמון אסינכרוני של Python
|
||||
|
||||
3. **מגבלת סכימה:** הסכימה `EmbeddingsRequest` תומכת רק בטקסט אחד:
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsRequest:
|
||||
text: str = "" # Single text only
|
||||
```
|
||||
|
||||
### לקוחות נוכחיים - עיבוד סדרתי
|
||||
|
||||
#### 1. שער API
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py`
|
||||
|
||||
השער מקבל בקשות להטמעה של טקסט בודד באמצעות HTTP/WebSocket ומעביר אותן לשירות ההטמעה. כרגע אין נקודת קצה לעיבוד אצווה.
|
||||
|
||||
```python
|
||||
class EmbeddingsRequestor(ServiceRequestor):
|
||||
# Handles single EmbeddingsRequest -> EmbeddingsResponse
|
||||
request_schema=EmbeddingsRequest, # Single text only
|
||||
response_schema=EmbeddingsResponse,
|
||||
```
|
||||
|
||||
**השפעה:** לקוחות חיצוניים (אפליקציות אינטרנט, סקריפטים) חייבים לבצע N בקשות HTTP כדי להטמיע N טקסטים.
|
||||
|
||||
#### 2. שירות הטמעת מסמכים
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py`
|
||||
|
||||
מעבד פיסות של מסמכים אחת בכל פעם:
|
||||
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
v = msg.value()
|
||||
|
||||
# Single chunk per request
|
||||
resp = await flow("embeddings-request").request(
|
||||
EmbeddingsRequest(text=v.chunk)
|
||||
)
|
||||
vectors = resp.vectors
|
||||
```
|
||||
|
||||
**השפעה:** כל חלק במסמך דורש קריאת הטמעה נפרדת. מסמך עם 100 חלקים = 100 בקשות הטמעה.
|
||||
|
||||
#### 3. שירות הטמעת גרפים
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py`
|
||||
|
||||
עובר בלולאה על ישויות ומטמיע כל אחת בנפרד:
|
||||
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
for entity in v.entities:
|
||||
# Serial embedding - one entity at a time
|
||||
vectors = await flow("embeddings-request").embed(
|
||||
text=entity.context
|
||||
)
|
||||
entities.append(EntityEmbeddings(
|
||||
entity=entity.entity,
|
||||
vectors=vectors,
|
||||
chunk_id=entity.chunk_id,
|
||||
))
|
||||
```
|
||||
|
||||
**השפעה:** הודעה עם 50 ישויות = 50 בקשות הטמעה סדרתיות. זהו צוואר בקבוק משמעותי במהלך בניית גרף ידע.
|
||||
|
||||
#### 4. שירות הטמעת שורות
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py`
|
||||
|
||||
חוזר על טקסטים ייחודיים ומטמיע כל אחד מהם באופן סדרתי:
|
||||
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
for text, (index_name, index_value) in texts_to_embed.items():
|
||||
# Serial embedding - one text at a time
|
||||
vectors = await flow("embeddings-request").embed(text=text)
|
||||
|
||||
embeddings_list.append(RowIndexEmbedding(
|
||||
index_name=index_name,
|
||||
index_value=index_value,
|
||||
text=text,
|
||||
vectors=vectors
|
||||
))
|
||||
```
|
||||
|
||||
**השפעה:** עיבוד טבלה עם 100 ערכים ייחודיים עם אינדקס = 100 בקשות הטמעה סדרתיות.
|
||||
|
||||
#### 5. EmbeddingsClient (לקוח בסיסי)
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/base/embeddings_client.py`
|
||||
|
||||
הלקוח המשמש את כל מעבדי הזרימה תומך רק בהטמעה של טקסט בודד:
|
||||
|
||||
```python
|
||||
class EmbeddingsClient(RequestResponse):
|
||||
async def embed(self, text, timeout=30):
|
||||
resp = await self.request(
|
||||
EmbeddingsRequest(text=text), # Single text
|
||||
timeout=timeout
|
||||
)
|
||||
return resp.vectors
|
||||
```
|
||||
|
||||
**השפעה:** כל המשתמשים בלקוח זה מוגבלים לפעולות טקסט יחידות.
|
||||
|
||||
#### 6. כלי שורת הפקודה
|
||||
|
||||
**קובץ:** `trustgraph-cli/trustgraph/cli/invoke_embeddings.py`
|
||||
|
||||
כלי שורת הפקודה מקבל ארגומנט טקסט יחיד:
|
||||
|
||||
```python
|
||||
def query(url, flow_id, text, token=None):
|
||||
result = flow.embeddings(text=text) # Single text
|
||||
vectors = result.get("vectors", [])
|
||||
```
|
||||
|
||||
**השפעה:** משתמשים אינם יכולים לבצע הטמעה אצווה משורת הפקודה. עיבוד קובץ של טקסטים דורש N הפעלות.
|
||||
|
||||
#### 7. ערכת פיתוח תוכנה (SDK) עבור Python
|
||||
|
||||
ערכת הפיתוח תוכנה עבור Python מספקת שתי מחלקות לקוח לצורך אינטראקציה עם שירותי TrustGraph. שתיהן תומכות רק בהטמעה של טקסט בודד.
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/api/flow.py`
|
||||
|
||||
```python
|
||||
class FlowInstance:
|
||||
def embeddings(self, text):
|
||||
"""Get embeddings for a single text"""
|
||||
input = {"text": text}
|
||||
return self.request("service/embeddings", input)["vectors"]
|
||||
```
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/api/socket_client.py`
|
||||
|
||||
```python
|
||||
class SocketFlowInstance:
|
||||
def embeddings(self, text: str, **kwargs: Any) -> Dict[str, Any]:
|
||||
"""Get embeddings for a single text via WebSocket"""
|
||||
request = {"text": text}
|
||||
return self.client._send_request_sync(
|
||||
"embeddings", self.flow_id, request, False
|
||||
)
|
||||
```
|
||||
|
||||
**השפעה:** מפתחי Python המשתמשים ב-SDK חייבים לעבור על הטקסטים ולבצע N קריאות API נפרדות. אין תמיכה בהטמעה באצווה עבור משתמשי ה-SDK.
|
||||
|
||||
### השפעה על הביצועים
|
||||
|
||||
עבור הכנסת מסמכים טיפוסית (1000 מקטעי טקסט):
|
||||
**נוכחי**: 1000 בקשות נפרדות, 1000 קריאות למודל
|
||||
**באצווה (batch_size=32)**: 32 בקשות, 32 קריאות למודל (הפחתה של 96.8%)
|
||||
|
||||
עבור הטמעת גרפים (הודעה עם 50 ישויות):
|
||||
**נוכחי**: 50 קריאות await סדרתיות, ~5-10 שניות
|
||||
**באצווה**: 1-2 קריאות באצווה, ~0.5-1 שניה (שיפור של 5-10x)
|
||||
|
||||
ספריות כמו FastEmbed ודומות משיגות התרחבות כמעט ליניארית של התפוקה עם גודל האצווה עד לגבולות החומרה (בדרך כלל 32-128 טקסטים לאצווה).
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
אופטימיזציה של עיבוד אצווה להטמעות דורשת שינויים ברכיבים הבאים:
|
||||
|
||||
#### 1. **שיפור סכימה**
|
||||
הרחבת `EmbeddingsRequest` לתמיכה במספר טקסטים
|
||||
הרחבת `EmbeddingsResponse` להחזרת מספר סטים של וקטורים
|
||||
שמירה על תאימות לאחור לבקשות טקסט בודדות
|
||||
|
||||
מודול: `trustgraph-base/trustgraph/schema/services/llm.py`
|
||||
|
||||
#### 2. **שיפור שירות בסיסי**
|
||||
עדכון `EmbeddingsService` לטיפול בבקשות באצווה
|
||||
הוספת תצורת גודל אצווה
|
||||
יישום טיפול בבקשות מודע לאצווה
|
||||
|
||||
מודול: `trustgraph-base/trustgraph/base/embeddings_service.py`
|
||||
|
||||
#### 3. **עדכוני מעבד ספק**
|
||||
עדכון מעבד FastEmbed להעברת אצווה שלמה ל-`embed()`
|
||||
עדכון מעבד Ollama לטיפול באצווה (אם נתמך)
|
||||
הוספת עיבוד רציף כברירת מחדל עבור ספקים שאינם תומכים באצווה
|
||||
|
||||
מודולים:
|
||||
`trustgraph-flow/trustgraph/embeddings/fastembed/processor.py`
|
||||
`trustgraph-flow/trustgraph/embeddings/ollama/processor.py`
|
||||
|
||||
#### 4. **שיפור לקוח**
|
||||
הוספת שיטה להטמעה באצווה ל-`EmbeddingsClient`
|
||||
תמיכה גם ב-API של טקסט בודד וגם ב-API של אצווה
|
||||
הוספת אצווה אוטומטית עבור קלט גדול
|
||||
|
||||
מודול: `trustgraph-base/trustgraph/base/embeddings_client.py`
|
||||
|
||||
#### 5. **עדכוני קוראים - מעבדי זרימה**
|
||||
עדכון `graph_embeddings` לאצווה של הקשרים של ישויות
|
||||
עדכון `row_embeddings` לאצווה של טקסטים לאינדקס
|
||||
עדכון `document_embeddings` אם אצווה של הודעות אפשרית
|
||||
|
||||
מודולים:
|
||||
`trustgraph-flow/trustgraph/embeddings/graph_embeddings/embeddings.py`
|
||||
`trustgraph-flow/trustgraph/embeddings/row_embeddings/embeddings.py`
|
||||
`trustgraph-flow/trustgraph/embeddings/document_embeddings/embeddings.py`
|
||||
|
||||
#### 6. **שיפור שער API**
|
||||
הוספת נקודת קצה להטמעה באצווה
|
||||
תמיכה במערך של טקסטים בגוף הבקשה
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/gateway/dispatch/embeddings.py`
|
||||
|
||||
#### 7. **שיפור כלי שורת הפקודה**
|
||||
הוספת תמיכה במספר טקסטים או קלט של קובץ
|
||||
הוספת פרמטר גודל אצווה
|
||||
|
||||
מודול: `trustgraph-cli/trustgraph/cli/invoke_embeddings.py`
|
||||
|
||||
#### 8. **שיפור SDK של Python**
|
||||
הוספת שיטה `embeddings_batch()` ל-`FlowInstance`
|
||||
הוספת שיטה `embeddings_batch()` ל-`SocketFlowInstance`
|
||||
תמיכה גם ב-API של טקסט בודד וגם ב-API של אצווה עבור משתמשי SDK
|
||||
|
||||
מודולים:
|
||||
`trustgraph-base/trustgraph/api/flow.py`
|
||||
`trustgraph-base/trustgraph/api/socket_client.py`
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### EmbeddingsRequest
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsRequest:
|
||||
texts: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
שימוש:
|
||||
טקסט בודד: `EmbeddingsRequest(texts=["hello world"])`
|
||||
אצווה: `EmbeddingsRequest(texts=["text1", "text2", "text3"])`
|
||||
|
||||
#### EmbeddingsResponse
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
vectors: list[list[list[float]]] = field(default_factory=list)
|
||||
```
|
||||
|
||||
מבנה התגובה:
|
||||
`vectors[i]` מכיל את קבוצת הווקטורים עבור `texts[i]`
|
||||
כל קבוצת וקטורים היא `list[list[float]]` (מודלים עשויים להחזיר מספר וקטורים עבור כל טקסט)
|
||||
דוגמה: 3 טקסטים → `vectors` מכיל 3 רשומות, כאשר כל רשומה מכילה את הטבעות של הטקסט המתאים
|
||||
|
||||
### ממשקי API
|
||||
|
||||
#### EmbeddingsClient
|
||||
|
||||
```python
|
||||
class EmbeddingsClient(RequestResponse):
|
||||
async def embed(
|
||||
self,
|
||||
texts: list[str],
|
||||
timeout: float = 300,
|
||||
) -> list[list[list[float]]]:
|
||||
"""
|
||||
Embed one or more texts in a single request.
|
||||
|
||||
Args:
|
||||
texts: List of texts to embed
|
||||
timeout: Timeout for the operation
|
||||
|
||||
Returns:
|
||||
List of vector sets, one per input text
|
||||
"""
|
||||
resp = await self.request(
|
||||
EmbeddingsRequest(texts=texts),
|
||||
timeout=timeout
|
||||
)
|
||||
if resp.error:
|
||||
raise RuntimeError(resp.error.message)
|
||||
return resp.vectors
|
||||
```
|
||||
|
||||
#### נקודת קצה של הטמעות (Embeddings) עבור שער API
|
||||
|
||||
נקודת קצה מעודכנת התומכת בהטמעה בודדת או באצווה:
|
||||
|
||||
```
|
||||
POST /api/v1/embeddings
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"texts": ["text1", "text2", "text3"],
|
||||
"flow_id": "default"
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"vectors": [
|
||||
[[0.1, 0.2, ...]],
|
||||
[[0.3, 0.4, ...]],
|
||||
[[0.5, 0.6, ...]]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
#### שלב 1: שינויי סכימה
|
||||
|
||||
**EmbeddingsRequest:**
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsRequest:
|
||||
texts: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
**תגובת הטבעה (EmbeddingsResponse):**
|
||||
```python
|
||||
@dataclass
|
||||
class EmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
vectors: list[list[list[float]]] = field(default_factory=list)
|
||||
```
|
||||
|
||||
**עדכון של EmbeddingsService.on_request:**
|
||||
```python
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
request = msg.value()
|
||||
id = msg.properties()["id"]
|
||||
model = flow("model")
|
||||
|
||||
vectors = await self.on_embeddings(request.texts, model=model)
|
||||
response = EmbeddingsResponse(error=None, vectors=vectors)
|
||||
|
||||
await flow("response").send(response, properties={"id": id})
|
||||
```
|
||||
|
||||
#### שלב 2: עדכון מעבד FastEmbed
|
||||
|
||||
**נוכחי (לא יעיל):**
|
||||
```python
|
||||
async def on_embeddings(self, text, model=None):
|
||||
use_model = model or self.default_model
|
||||
self._load_model(use_model)
|
||||
vecs = self.embeddings.embed([text]) # Batch of 1
|
||||
return [v.tolist() for v in vecs]
|
||||
```
|
||||
|
||||
**עדכון:**
|
||||
```python
|
||||
async def on_embeddings(self, texts: list[str], model=None):
|
||||
"""Embed texts - processes all texts in single model call"""
|
||||
if not texts:
|
||||
return []
|
||||
|
||||
use_model = model or self.default_model
|
||||
self._load_model(use_model)
|
||||
|
||||
# FastEmbed handles the full batch efficiently
|
||||
all_vecs = list(self.embeddings.embed(texts))
|
||||
|
||||
# Return list of vector sets, one per input text
|
||||
return [[v.tolist()] for v in all_vecs]
|
||||
```
|
||||
|
||||
#### שלב 3: עדכון שירות הטמעת גרפים
|
||||
|
||||
**נוכחי (סדרתי):**
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
entities = []
|
||||
for entity in v.entities:
|
||||
vectors = await flow("embeddings-request").embed(text=entity.context)
|
||||
entities.append(EntityEmbeddings(...))
|
||||
```
|
||||
|
||||
**עדכון (אצווה):**
|
||||
```python
|
||||
async def on_message(self, msg, consumer, flow):
|
||||
# Collect all contexts
|
||||
contexts = [entity.context for entity in v.entities]
|
||||
|
||||
# Single batch embedding call
|
||||
all_vectors = await flow("embeddings-request").embed(texts=contexts)
|
||||
|
||||
# Pair results with entities
|
||||
entities = [
|
||||
EntityEmbeddings(
|
||||
entity=entity.entity,
|
||||
vectors=vectors[0], # First vector from the set
|
||||
chunk_id=entity.chunk_id,
|
||||
)
|
||||
for entity, vectors in zip(v.entities, all_vectors)
|
||||
]
|
||||
```
|
||||
|
||||
#### שלב 4: עדכון שירות הטמעת שורות
|
||||
|
||||
**נוכחי (סדרתי):**
|
||||
```python
|
||||
for text, (index_name, index_value) in texts_to_embed.items():
|
||||
vectors = await flow("embeddings-request").embed(text=text)
|
||||
embeddings_list.append(RowIndexEmbedding(...))
|
||||
```
|
||||
|
||||
**עדכון (אצווה):**
|
||||
```python
|
||||
# Collect texts and metadata
|
||||
texts = list(texts_to_embed.keys())
|
||||
metadata = list(texts_to_embed.values())
|
||||
|
||||
# Single batch embedding call
|
||||
all_vectors = await flow("embeddings-request").embed(texts=texts)
|
||||
|
||||
# Pair results
|
||||
embeddings_list = [
|
||||
RowIndexEmbedding(
|
||||
index_name=meta[0],
|
||||
index_value=meta[1],
|
||||
text=text,
|
||||
vectors=vectors[0] # First vector from the set
|
||||
)
|
||||
for text, meta, vectors in zip(texts, metadata, all_vectors)
|
||||
]
|
||||
```
|
||||
|
||||
#### שלב 5: שיפור כלי שורת הפקודה
|
||||
|
||||
**שורת פקודה מעודכנת:**
|
||||
```python
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(...)
|
||||
|
||||
parser.add_argument(
|
||||
'text',
|
||||
nargs='*', # Zero or more texts
|
||||
help='Text(s) to convert to embedding vectors',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-f', '--file',
|
||||
help='File containing texts (one per line)',
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--batch-size',
|
||||
type=int,
|
||||
default=32,
|
||||
help='Batch size for processing (default: 32)',
|
||||
)
|
||||
```
|
||||
|
||||
שימוש:
|
||||
```bash
|
||||
# Single text (existing)
|
||||
tg-invoke-embeddings "hello world"
|
||||
|
||||
# Multiple texts
|
||||
tg-invoke-embeddings "text one" "text two" "text three"
|
||||
|
||||
# From file
|
||||
tg-invoke-embeddings -f texts.txt --batch-size 64
|
||||
```
|
||||
|
||||
#### שלב 6: שיפור ערכת הפיתוח של Python
|
||||
|
||||
**FlowInstance (לקוח HTTP):**
|
||||
|
||||
```python
|
||||
class FlowInstance:
|
||||
def embeddings(self, texts: list[str]) -> list[list[list[float]]]:
|
||||
"""
|
||||
Get embeddings for one or more texts.
|
||||
|
||||
Args:
|
||||
texts: List of texts to embed
|
||||
|
||||
Returns:
|
||||
List of vector sets, one per input text
|
||||
"""
|
||||
input = {"texts": texts}
|
||||
return self.request("service/embeddings", input)["vectors"]
|
||||
```
|
||||
|
||||
**SocketFlowInstance (לקוח WebSocket):**
|
||||
|
||||
```python
|
||||
class SocketFlowInstance:
|
||||
def embeddings(self, texts: list[str], **kwargs: Any) -> list[list[list[float]]]:
|
||||
"""
|
||||
Get embeddings for one or more texts via WebSocket.
|
||||
|
||||
Args:
|
||||
texts: List of texts to embed
|
||||
|
||||
Returns:
|
||||
List of vector sets, one per input text
|
||||
"""
|
||||
request = {"texts": texts}
|
||||
response = self.client._send_request_sync(
|
||||
"embeddings", self.flow_id, request, False
|
||||
)
|
||||
return response["vectors"]
|
||||
```
|
||||
|
||||
**דוגמאות לשימוש ב-SDK:**
|
||||
|
||||
```python
|
||||
# Single text
|
||||
vectors = flow.embeddings(["hello world"])
|
||||
print(f"Dimensions: {len(vectors[0][0])}")
|
||||
|
||||
# Batch embedding
|
||||
texts = ["text one", "text two", "text three"]
|
||||
all_vectors = flow.embeddings(texts)
|
||||
|
||||
# Process results
|
||||
for text, vecs in zip(texts, all_vectors):
|
||||
print(f"{text}: {len(vecs[0])} dimensions")
|
||||
```
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
**מגבלות גודל בקשה**: אכוף גודל מקסימלי לאצווה כדי למנוע מיצוי משאבים
|
||||
**טיפול בזמני המתנה**: התאם את זמני ההמתנה בהתאם לגודל האצווה
|
||||
**מגבלות זיכרון**: עקוב אחר השימוש בזיכרון עבור אצוות גדולות
|
||||
**אימות קלט**: אשר את כל הטקסטים באצווה לפני העיבוד
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
### שיפורים צפויים
|
||||
|
||||
**קצב העברה (Throughput):**
|
||||
טקסט בודד: ~10-50 טקסטים/שנייה (תלוי במודל)
|
||||
אצווה (גודל 32): ~200-500 טקסטים/שנייה (שיפור של 5-10x)
|
||||
|
||||
**זמן תגובה לטקסט:**
|
||||
טקסט בודד: 50-200ms לטקסט
|
||||
אצווה (גודל 32): 5-20ms לטקסט (ממוצע)
|
||||
|
||||
**שיפורים ספציפיים לשירות:**
|
||||
|
||||
| שירות | נוכחי | באצווה | שיפור |
|
||||
|---------|---------|---------|-------------|
|
||||
| הטמעת גרפים (50 ישויות) | 5-10 שניות | 0.5-1 שניות | 5-10x |
|
||||
| הטמעת שורות (100 טקסטים) | 10-20 שניות | 1-2 שניות | 5-10x |
|
||||
| קליטת מסמכים (1000 מקטעים) | 100-200 שניות | 10-30 שניות | 5-10x |
|
||||
|
||||
### פרמטרי תצורה
|
||||
|
||||
```python
|
||||
# Recommended defaults
|
||||
DEFAULT_BATCH_SIZE = 32
|
||||
MAX_BATCH_SIZE = 128
|
||||
BATCH_TIMEOUT_MULTIPLIER = 2.0
|
||||
```
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות יחידה
|
||||
הטמעה של טקסט בודד (תאימות לאחור)
|
||||
טיפול באצווה ריקה
|
||||
אכיפת גודל אצווה מקסימלי
|
||||
טיפול בשגיאות עבור כשלים חלקיים באצווה
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
הטמעת אצווה מקצה לקצה דרך Pulsar
|
||||
עיבוד אצווה בשירות הטמעת גרפים
|
||||
עיבוד אצווה בשירות הטמעת שורות
|
||||
נקודת קצה של אצווה בשער ה-API
|
||||
|
||||
### בדיקות ביצועים
|
||||
השוואת תפוקה של הטמעה בודדת לעומת אצווה
|
||||
שימוש בזיכרון בגדלי אצווה שונים
|
||||
ניתוח התפלגות השהייה
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
זו גרסה הכוללת שינויים משמעותיים. כל השלבים מיושמים יחד.
|
||||
|
||||
### שלב 1: שינויי סכימה
|
||||
החלפת `text: str` ב-`texts: list[str]` ב-EmbeddingsRequest
|
||||
שינוי סוג של `vectors` ל-`list[list[list[float]]]` ב-EmbeddingsResponse
|
||||
|
||||
### שלב 2: עדכוני מעבד
|
||||
עדכון חתימה של `on_embeddings` במעבדים FastEmbed ו-Ollama
|
||||
עיבוד אצווה שלמה בפעילת מודל אחת
|
||||
|
||||
### שלב 3: עדכוני לקוח
|
||||
עדכון `EmbeddingsClient.embed()` כדי לקבל `texts: list[str]`
|
||||
|
||||
### שלב 4: עדכוני משתמשים
|
||||
עדכון graph_embeddings להטמעת הקשרים של ישויות באצווה
|
||||
עדכון row_embeddings לעיבוד אצווה של טקסטים באינדקס
|
||||
עדכון document_embeddings לשימוש בסכימה החדשה
|
||||
עדכון כלי שורת הפקודה
|
||||
|
||||
### שלב 5: שער API
|
||||
עדכון נקודת קצה של הטמעה עבור סכימה חדשה
|
||||
|
||||
### שלב 6: SDK של Python
|
||||
עדכון חתימה של `FlowInstance.embeddings()`
|
||||
עדכון חתימה של `SocketFlowInstance.embeddings()`
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
**הטמעת אצוות גדולות**: האם עלינו לתמוך בהעברת תוצאות עבור אצוות גדולות מאוד (>100 טקסטים)?
|
||||
**מגבלות ספציפיות לספק**: כיצד עלינו להתמודד עם ספקים עם גודל אצווה מקסימלי שונה?
|
||||
**טיפול בכשלים חלקיים**: אם טקסט אחד באצווה נכשל, האם עלינו לגרום לכשל באצווה כולה או להחזיר תוצאות חלקיות?
|
||||
**הטמעת מסמכים באצווה**: האם עלינו לבצע אצווה בין הודעות Chunk מרובות או לשמור על עיבוד פר-הודעה?
|
||||
|
||||
## הפניות
|
||||
|
||||
[תיעוד FastEmbed](https://github.com/qdrant/fastembed)
|
||||
[ממשק API של הטמעות Ollama](https://github.com/ollama/ollama)
|
||||
[יישום של EmbeddingsService](trustgraph-base/trustgraph/base/embeddings_service.py)
|
||||
[אופטימיזציה של ביצועים של GraphRAG](graphrag-performance-optimization.md)
|
||||
269
docs/tech-specs/he/entity-centric-graph.he.md
Normal file
269
docs/tech-specs/he/entity-centric-graph.he.md
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
---
|
||||
layout: default
|
||||
title: "אחסון גרף ידע ממוקד ישויות ב-Cassandra"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# אחסון גרף ידע ממוקד ישויות ב-Cassandra
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מתאר מודל אחסון עבור גרפי ידע מסוג RDF ב-Apache Cassandra. המודל משתמש בגישה **ממוקדת ישויות**, כאשר כל ישות יודעת כל רביעיות (quads) בהן היא משתתפת והתפקיד שלה. זה מחליף גישה מסורתית של מספר טבלאות המייצגות את כל הפרמוטציות של Subject, Predicate, Object ו-Dataset (SPOD) עם שתי טבלאות בלבד.
|
||||
|
||||
## רקע ומניעים
|
||||
|
||||
### הגישה המסורתית
|
||||
|
||||
חנות רביעיות RDF סטנדרטית ב-Cassandra דורשת מספר טבלאות לא מנורמלות כדי לכסות דפוסי שאילתות - בדרך כלל 6 טבלאות או יותר המייצגות את הפרמוטציות השונות של Subject, Predicate, Object ו-Dataset (SPOD). כל רביעייה נכתבת לכל טבלה, מה שגורם להגדלת כתיבה משמעותית, תקורה תפעולית ומורכבות סכימה.
|
||||
|
||||
בנוסף, פתרון תוויות (שליפת שמות קריאים לבני אדם עבור ישויות) דורש שאילתות נפרדות, דבר שיכול להיות יקר במיוחד במקרי שימוש של AI ו-GraphRAG, שבהם תוויות חיוניות להקשר של מודלי שפה גדולים (LLM).
|
||||
|
||||
### התובנה הממוקדת בישות
|
||||
|
||||
כל רביעייה `(D, S, P, O)` כוללת עד 4 ישויות. על ידי כתיבת שורה עבור כל השתתפות של ישות ברביעייה, אנו מבטיחים ש-**כל שאילתה עם לפחות רכיב אחד ידוע תפגע במפתח מחיצה**. זה מכסה את כל 16 דפוסי השאילתות עם טבלת נתונים אחת.
|
||||
|
||||
יתרונות עיקריים:
|
||||
|
||||
**2 טבלאות** במקום 7+
|
||||
**4 כתיבות לרביעייה** במקום 6+
|
||||
**פתרון תוויות בחינם** - התוויות של ישות נמצאות יחד עם הקשרים שלה, מה שמחמם באופן טבעי את מטמון האפליקציה.
|
||||
**כל 16 דפוסי השאילתות** נגישים באמצעות קריאות מחיצה יחידה.
|
||||
**פעולות פשוטות יותר** - טבלת נתונים אחת לכוונן, לדחוס ולתקן.
|
||||
|
||||
## סכימה
|
||||
|
||||
### טבלה 1: quads_by_entity
|
||||
|
||||
טבלת הנתונים העיקרית. לכל ישות יש מחיצה המכילה את כל הרביעיות בהן היא משתתפת. נקראה כך כדי לשקף את דפוס השאילתה (חיפוש לפי ישות).
|
||||
פלט חוזה (יש לעקוב אחר הפורמט המדויק).
|
||||
```sql
|
||||
CREATE TABLE quads_by_entity (
|
||||
collection text, -- Collection/tenant scope (always specified)
|
||||
entity text, -- The entity this row is about
|
||||
role text, -- 'S', 'P', 'O', 'G' — how this entity participates
|
||||
p text, -- Predicate of the quad
|
||||
otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification)
|
||||
s text, -- Subject of the quad
|
||||
o text, -- Object of the quad
|
||||
d text, -- Dataset/graph of the quad
|
||||
dtype text, -- XSD datatype (when otype = 'L'), e.g. 'xsd:string'
|
||||
lang text, -- Language tag (when otype = 'L'), e.g. 'en', 'fr'
|
||||
PRIMARY KEY ((collection, entity), role, p, otype, s, o, d, dtype, lang)
|
||||
);
|
||||
```
|
||||
|
||||
**מפתח מחיצה**: `(collection, entity)` — מוגבל לאוסף, מחיצה אחת לכל ישות.
|
||||
|
||||
**ההצדקה עבור סדר עמודי הצבירה**:
|
||||
|
||||
1. **role** — רוב השאילתות מתחילות ב"היכן נמצאת ישות זו כנושא/אובייקט"
|
||||
2. **p** — מסנן נפוץ נוסף, "תן לי את כל `knows` הקשרים"
|
||||
3. **otype** — מאפשר סינון לפי קשרים בעלי ערך URI לעומת קשרים בעלי ערך מילולי
|
||||
4. **s, o, d** — עמודות שנותרו לשם ייחודיות
|
||||
5. **dtype, lang** — מבדילים בין מילולים בעלי אותו ערך אך מטא-נתונים שונים (לדוגמה, `"thing"` לעומת `"thing"@en` לעומת `"thing"^^xsd:string`)
|
||||
|
||||
### טבלה 2: quads_by_collection
|
||||
|
||||
תומך בשאילתות ובמחיקות ברמת האוסף. מספק תצוגה של כל ה-quads השייכים לאוסף. נקרא כך כדי לשקף את דפוס השאילתה (חיפוש לפי אוסף).
|
||||
|
||||
```sql
|
||||
CREATE TABLE quads_by_collection (
|
||||
collection text,
|
||||
d text, -- Dataset/graph of the quad
|
||||
s text, -- Subject of the quad
|
||||
p text, -- Predicate of the quad
|
||||
o text, -- Object of the quad
|
||||
otype text, -- 'U' (URI), 'L' (literal), 'T' (triple/reification)
|
||||
dtype text, -- XSD datatype (when otype = 'L')
|
||||
lang text, -- Language tag (when otype = 'L')
|
||||
PRIMARY KEY (collection, d, s, p, o, otype, dtype, lang)
|
||||
);
|
||||
```
|
||||
|
||||
מאוגדים לפי קבוצת נתונים תחילה, מה שמאפשר מחיקה ברמת אוסף או ברמת קבוצת נתונים. העמודות `otype`, `dtype` ו-`lang` כלולות במפתח האריגה כדי להבחין בין ערכים המילוליים עם אותו ערך אך עם מטא-נתונים מסוג שונים - ב-RDF, `"thing"`, `"thing"@en` ו-`"thing"^^xsd:string` הם ערכים שונים מבחינה סמנטית.
|
||||
|
||||
## נתיב כתיבה
|
||||
|
||||
עבור כל רביעייה נכנסת `(D, S, P, O)` בתוך אוסף `C`, כתבו **4 שורות** ל-`quads_by_entity` ו-**שורה אחת** ל-`quads_by_collection`.
|
||||
|
||||
### דוגמה
|
||||
|
||||
בהינתן הרביעייה באוסף `tenant1`:
|
||||
|
||||
```
|
||||
Dataset: https://example.org/graph1
|
||||
Subject: https://example.org/Alice
|
||||
Predicate: https://example.org/knows
|
||||
Object: https://example.org/Bob
|
||||
```
|
||||
|
||||
כתוב 4 שורות ל-`quads_by_entity`:
|
||||
|
||||
| collection | entity | role | p | otype | s | o | d |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| tenant1 | https://example.org/graph1 | G | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
|
||||
| tenant1 | https://example.org/Alice | S | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
|
||||
| tenant1 | https://example.org/knows | P | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
|
||||
| tenant1 | https://example.org/Bob | O | https://example.org/knows | U | https://example.org/Alice | https://example.org/Bob | https://example.org/graph1 |
|
||||
|
||||
כתוב שורה אחת ל-`quads_by_collection`:
|
||||
|
||||
| collection | d | s | p | o | otype | dtype | lang |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| tenant1 | https://example.org/graph1 | https://example.org/Alice | https://example.org/knows | https://example.org/Bob | U | | |
|
||||
|
||||
### דוגמה מילולית
|
||||
|
||||
עבור משולש תווית:
|
||||
|
||||
```
|
||||
Dataset: https://example.org/graph1
|
||||
Subject: https://example.org/Alice
|
||||
Predicate: http://www.w3.org/2000/01/rdf-schema#label
|
||||
Object: "Alice Smith" (lang: en)
|
||||
```
|
||||
|
||||
הקוד `otype` הוא `'L'`, `dtype` הוא `'xsd:string'`, ו-`lang` הוא `'en'`. הערך המילולי `"Alice Smith"` מאוחסן ב-`o`. נדרשות רק 3 שורות ב-`quads_by_entity` - שורה אינה נכתבת עבור הערך המילולי כישות, מכיוון שערכים מילוליים אינם ישויות שאפשר לשאול אותן באופן עצמאי.
|
||||
|
||||
## תבניות שאילתה
|
||||
|
||||
### כל 16 תבניות DSPO
|
||||
|
||||
בטבלה למטה, "קידומת מושלמת" פירושה שהשאילתה משתמשת בקידומת רציפה של עמודי הקיבוץ. "סריקת מחיצה + סינון" פירושה ש-Cassandra קוראת חלק ממחיצה ומסננת בזיכרון - יעיל, אבל לא התאמה מדויקת לקידומת.
|
||||
|
||||
| # | ידוע | ישות | קידומת קיבוץ | יעילות |
|
||||
|---|---|---|---|---|
|
||||
| 1 | D,S,P,O | entity=S, role='S', p=P | התאמה מלאה | קידומת מושלמת |
|
||||
| 2 | D,S,P,? | entity=S, role='S', p=P | סינון על D | סריקת מחיצה + סינון |
|
||||
| 3 | D,S,?,O | entity=S, role='S' | סינון על D, O | סריקת מחיצה + סינון |
|
||||
| 4 | D,?,P,O | entity=O, role='O', p=P | סינון על D | סריקת מחיצה + סינון |
|
||||
| 5 | ?,S,P,O | entity=S, role='S', p=P | סינון על O | סריקת מחיצה + סינון |
|
||||
| 6 | D,S,?,? | entity=S, role='S' | סינון על D | סריקת מחיצה + סינון |
|
||||
| 7 | D,?,P,? | entity=P, role='P' | סינון על D | סריקת מחיצה + סינון |
|
||||
| 8 | D,?,?,O | entity=O, role='O' | סינון על D | סריקת מחיצה + סינון |
|
||||
| 9 | ?,S,P,? | entity=S, role='S', p=P | — | **קידומת מושלמת** |
|
||||
| 10 | ?,S,?,O | entity=S, role='S' | סינון על O | סריקת מחיצה + סינון |
|
||||
| 11 | ?,?,P,O | entity=O, role='O', p=P | — | **קידומת מושלמת** |
|
||||
| 12 | D,?,?,? | entity=D, role='G' | — | **קידומת מושלמת** |
|
||||
| 13 | ?,S,?,? | entity=S, role='S' | — | **קידומת מושלמת** |
|
||||
| 14 | ?,?,P,? | entity=P, role='P' | — | **קידומת מושלמת** |
|
||||
| 15 | ?,?,?,O | entity=O, role='O' | — | **קידומת מושלמת** |
|
||||
| 16 | ?,?,?,? | — | סריקה מלאה | חקירה בלבד |
|
||||
|
||||
**תוצאה עיקרית**: 7 מתוך 15 התבניות הלא טריוויאליות הן התאמות מושלמות לקידומת קיבוץ. שמונה הנותרות הן קריאות מחיצה בודדות עם סינון בתוך המחיצה. כל שאילתה עם לפחות רכיב ידוע פוגעת במפתח המחיצה.
|
||||
|
||||
התבנית 16 (?,?,?,?) אינה מתרחשת בפועל מכיוון שאוסף תמיד מצוין, מה שמצמצם אותה לתבנית 12.
|
||||
|
||||
### דוגמאות נפוצות לשאילתות
|
||||
|
||||
**כל דבר על ישות:**
|
||||
|
||||
```sql
|
||||
SELECT * FROM quads_by_entity
|
||||
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice';
|
||||
```
|
||||
|
||||
**כל הקשרים יוצאים עבור ישות:**
|
||||
|
||||
```sql
|
||||
SELECT * FROM quads_by_entity
|
||||
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
|
||||
AND role = 'S';
|
||||
```
|
||||
|
||||
**תכונה ספציפית עבור ישות:**
|
||||
|
||||
```sql
|
||||
SELECT * FROM quads_by_entity
|
||||
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
|
||||
AND role = 'S' AND p = 'https://example.org/knows';
|
||||
```
|
||||
|
||||
**תווית עבור ישות (שפה ספציפית):**
|
||||
|
||||
```sql
|
||||
SELECT * FROM quads_by_entity
|
||||
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
|
||||
AND role = 'S' AND p = 'http://www.w3.org/2000/01/rdf-schema#label'
|
||||
AND otype = 'L';
|
||||
```
|
||||
|
||||
לאחר מכן, במידת הצורך, סננו באמצעות `lang = 'en'` בצד האפליקציה.
|
||||
|
||||
**רק קשרים בעלי ערך URI (קישורים בין ישויות לישויות):**
|
||||
|
||||
```sql
|
||||
SELECT * FROM quads_by_entity
|
||||
WHERE collection = 'tenant1' AND entity = 'https://example.org/Alice'
|
||||
AND role = 'S' AND p = 'https://example.org/knows' AND otype = 'U';
|
||||
```
|
||||
|
||||
**חיפוש הפוך — מה מצביע על ישות זו:**
|
||||
|
||||
```sql
|
||||
SELECT * FROM quads_by_entity
|
||||
WHERE collection = 'tenant1' AND entity = 'https://example.org/Bob'
|
||||
AND role = 'O';
|
||||
```
|
||||
|
||||
## פתרון תוויות וחימום מטמון
|
||||
|
||||
אחד היתרונות המשמעותיים ביותר של מודל המרכז את הישות הוא ש**פתרון תוויות הופך לתופעת לוואי חופשית**.
|
||||
|
||||
במודל הרב-טבלאי המסורתי, שליפת תוויות דורשת שאילתות נפרדות: יש לשלוף משולשות, לזהות את כתובות ה-URI של הישויות בתוצאות, ולאחר מכן לשלוף `rdfs:label` עבור כל אחת. דפוס N+1 זה יקר.
|
||||
|
||||
במודל המרכז את הישות, שאילתה של ישות מחזירה את כל ה-quads שלה - כולל התוויות, הסוגים ותכונות אחרות. כאשר האפליקציה שומרת תוצאות שאילתה במטמון, התוויות מחוממות מראש לפני שמישהו מבקש אותן.
|
||||
|
||||
שני מצבי שימוש מאשרים שזה עובד היטב בפועל:
|
||||
|
||||
**שאילתות המיועדות למשתמשים**: קבוצות תוצאות קטנות באופן טבעי, תוויות חיוניות. קריאות לישות מחממות את המטמון מראש.
|
||||
**שאילתות AI/מערכיות**: קבוצות תוצאות גדולות עם מגבלות קשות. תוויות או שאינן נחוצות או נדרשות רק עבור תת-קבוצה מבוקרת של ישויות שכבר נמצאות במטמון.
|
||||
|
||||
החשש התיאורטי של פתרון תוויות עבור קבוצות תוצאות גדולות (לדוגמה, 30,000 ישויות) מופחת על ידי התצפית המעשית שאף צרכן אנושי או AI לא מעבד שימושית כמות כזו של תוויות. מגבלות שאילתה ברמת האפליקציה מבטיחות שלחץ המטמון נשאר ניתן לניהול.
|
||||
|
||||
## מחיצות רחבות ומימוש
|
||||
|
||||
מימוש (הצהרות מסוג RDF-star על הצהרות) יוצר ישויות מרכזיות - לדוגמה, מסמך מקור התומך באלפי עובדות שחולצו. זה יכול ליצור מחיצות רחבות.
|
||||
|
||||
גורמים מקלים:
|
||||
|
||||
**מגבלות שאילתה ברמת האפליקציה**: כל שאילתות GraphRAG ושאילתות המיועדות למשתמשים מאכפות מגבלות קשות, כך שמחיצות רחבות לעולם אינן נסרקות במלואן בנתיב הקריאה החמה
|
||||
**Cassandra מטפלת בקריאות חלקיות בצורה יעילה**: סריקת עמודת קיבוץ עם עצירה מוקדמת היא מהירה גם על מחיצות גדולות
|
||||
**מחיקת אוסף** (הפעולה היחידה שעשויה לעבור על מחיצות מלאות) היא תהליך רקע מקובל
|
||||
|
||||
## מחיקת אוסף
|
||||
|
||||
מופעלת על ידי קריאת API, רצה ברקע (עקביות בסופו של דבר).
|
||||
|
||||
1. קרא `quads_by_collection` עבור האוסף המיועד כדי לקבל את כל ה-quads
|
||||
2. חלץ ישויות ייחודיות מה-quads (ערכי s, p, o, d)
|
||||
3. עבור כל ישות ייחודית, מחק את המחיצה מ-`quads_by_entity`
|
||||
4. מחק את השורות מ-`quads_by_collection`
|
||||
|
||||
הטבלה `quads_by_collection` מספקת את האינדקס הדרוש כדי לאתר את כל מחיצות הישויות מבלי לסרוק את הטבלה כולה. מחיקות ברמת המחיצה יעילות מכיוון ש-`(collection, entity)` הוא מפתח המחיצה.
|
||||
|
||||
## נתיב מעבר ממודל רב-טבלאי
|
||||
|
||||
מודל המרכז את הישות יכול לדור בכפיפות למודל הרב-טבלאי הקיים במהלך המעבר:
|
||||
|
||||
1. פרוס את הטבלאות `quads_by_entity` ו-`quads_by_collection` לצד הטבלאות הקיימות
|
||||
2. כתוב כפול quads חדשים גם לטבלאות הישנות וגם לטבלאות החדשות
|
||||
3. מלא נתונים קיימים לתוך הטבלאות החדשות
|
||||
4. העבר נתיבי קריאה דפוס שאילתה בכל פעם
|
||||
5. הפסק את פעולת הטבלאות הישנות לאחר שכל הקריאות עברו
|
||||
|
||||
## סיכום
|
||||
|
||||
| היבט | מסורתי (6 טבלאות) | מרכז ישות (2 טבלאות) |
|
||||
|---|---|---|
|
||||
| טבלאות | 7+ | 2 |
|
||||
| כתיבות לכל quad | 6+ | 5 (4 נתונים + 1 מניפסט) |
|
||||
| פתרון תוויות | מעברי נסיעה נפרדים | חימום מטמון חופשי |
|
||||
| דפוסי שאילתה | 16 על פני 6 טבלאות | 16 על טבלה אחת |
|
||||
| מורכבות סכימה | גבוהה | נמוכה |
|
||||
| תקורה תפעולית | 6 טבלאות לכיול/תיקון | טבלת נתונים אחת |
|
||||
| תמיכה במימוש | מורכבות נוספת | התאמה טבעית |
|
||||
| סינון סוגי אובייקטים | לא זמין | ילידי (דרך קיבוץ otype) |
|
||||
פלט חוזה (יש לעקוב בדיוק אחר הפורמט).
|
||||
228
docs/tech-specs/he/explainability-cli.he.md
Normal file
228
docs/tech-specs/he/explainability-cli.he.md
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של כלי שורת הפקודה (CLI) להסברתיות"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של כלי שורת הפקודה (CLI) להסברתיות
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סטטוס
|
||||
|
||||
טיוטה
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר כלי שורת פקודה (CLI) לניפוי באגים ובדיקת נתוני הסברתיות ב-TrustGraph. כלים אלה מאפשרים למשתמשים לעקוב אחר אופן קבלת התשובות ולבצע ניפוי באגים בשרשרת המקור, החל מצמתים ועד למסמכים מקוריים.
|
||||
|
||||
שלושה כלים של שורת פקודה:
|
||||
|
||||
1. **`tg-show-document-hierarchy`** - הצגת היררכיה של מסמך → עמוד → מקטע → צומת
|
||||
2. **`tg-list-explain-traces`** - הצגת רשימה של כל הסשנים של GraphRAG עם שאלות
|
||||
3. **`tg-show-explain-trace`** - הצגת מעקב הסברתיות מלא עבור סשן
|
||||
|
||||
## מטרות
|
||||
|
||||
**ניפוי באגים**: לאפשר למפתחים לבדוק את תוצאות עיבוד המסמכים
|
||||
**ביקורת**: לעקוב אחר כל עובדה שחולצה בחזרה למסמך המקור שלה
|
||||
**שקיפות**: להציג בדיוק כיצד GraphRAG הגיע לתשובה
|
||||
**שימושיות**: ממשק שורת פקודה פשוט עם הגדרות ברירת מחדל הגיוניות
|
||||
|
||||
## רקע
|
||||
|
||||
ל-TrustGraph יש שתי מערכות מעקב מקור:
|
||||
|
||||
1. **מעקב מקור בזמן חילוץ** (ראה `extraction-time-provenance.md`): מתעד את היחסים בין מסמך → עמוד → מקטע → צומת במהלך הטעינה. מאוחסן בגרף בשם `urn:graph:source` באמצעות `prov:wasDerivedFrom`.
|
||||
|
||||
2. **הסברתיות בזמן שאילתה** (ראה `query-time-explainability.md`): מתעד את שרשרת השאלות → חקירה → מיקוד → סינתזה במהלך שאילתות GraphRAG. מאוחסן בגרף בשם `urn:graph:retrieval`.
|
||||
|
||||
מגבלות נוכחיות:
|
||||
אין דרך קלה להציג את היררכיית המסמכים לאחר העיבוד
|
||||
יש לבצע שאילתות ידניות על משולשים כדי לראות נתוני הסברתיות
|
||||
אין תצוגה מאוחדת של סשן GraphRAG
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### כלי 1: tg-show-document-hierarchy
|
||||
|
||||
**מטרה**: בהינתן מזהה מסמך, לעבור ולציין את כל הישויות הנגזרות.
|
||||
|
||||
**שימוש**:
|
||||
```bash
|
||||
tg-show-document-hierarchy "urn:trustgraph:doc:abc123"
|
||||
tg-show-document-hierarchy --show-content --max-content 500 "urn:trustgraph:doc:abc123"
|
||||
```
|
||||
|
||||
**ארגומנטים**:
|
||||
| Arg | תיאור |
|
||||
|-----|-------------|
|
||||
| `document_id` | כתובת URI של המסמך (מיקום) |
|
||||
| `-u/--api-url` | כתובת URL של ה-Gateway (ברירת מחדל: `$TRUSTGRAPH_URL`) |
|
||||
| `-t/--token` | טוקן אימות (ברירת מחדל: `$TRUSTGRAPH_TOKEN`) |
|
||||
| `-U/--user` | מזהה משתמש (ברירת מחדל: `trustgraph`) |
|
||||
| `-C/--collection` | אוסף (ברירת מחדל: `default`) |
|
||||
| `--show-content` | לכלול תוכן של קבצים/מסמכים |
|
||||
| `--max-content` | מספר תווים מקסימלי לכל קובץ (ברירת מחדל: 200) |
|
||||
| `--format` | פלט: `tree` (ברירת מחדל), `json` |
|
||||
|
||||
**יישום**:
|
||||
1. שאילת משולשות: `?child prov:wasDerivedFrom <document_id>` ב-`urn:graph:source`
|
||||
2. שאילת באופן רקורסיבי את הילדים של כל תוצאה
|
||||
3. בניית מבנה עץ: מסמך → עמודים → חלקים
|
||||
4. אם `--show-content`, שליפה של תוכן מ-API של הספרן
|
||||
5. הצגה כמבנה עץ עם הזחות או JSON
|
||||
|
||||
**דוגמה לפלט**:
|
||||
```
|
||||
Document: urn:trustgraph:doc:abc123
|
||||
Title: "Sample PDF"
|
||||
Type: application/pdf
|
||||
|
||||
└── Page 1: urn:trustgraph:doc:abc123/p1
|
||||
├── Chunk 0: urn:trustgraph:doc:abc123/p1/c0
|
||||
│ Content: "The quick brown fox..." [truncated]
|
||||
└── Chunk 1: urn:trustgraph:doc:abc123/p1/c1
|
||||
Content: "Machine learning is..." [truncated]
|
||||
```
|
||||
|
||||
### כלי 2: tg-list-explain-traces
|
||||
|
||||
**מטרה**: הצגת כל הסשנים (שאלות) של GraphRAG באוסף.
|
||||
|
||||
**שימוש**:
|
||||
```bash
|
||||
tg-list-explain-traces
|
||||
tg-list-explain-traces --limit 20 --format json
|
||||
```
|
||||
|
||||
**ארגומנטים**:
|
||||
| Arg | תיאור |
|
||||
|-----|-------------|
|
||||
| `-u/--api-url` | כתובת URL של ה-Gateway |
|
||||
| `-t/--token` | טוקן אימות |
|
||||
| `-U/--user` | מזהה משתמש |
|
||||
| `-C/--collection` | אוסף |
|
||||
| `--limit` | מספר תוצאות מקסימלי (ברירת מחדל: 50) |
|
||||
| `--format` | פלט: `table` (ברירת מחדל), `json` |
|
||||
|
||||
**יישום**:
|
||||
1. שאילתה: `?session tg:query ?text` ב-`urn:graph:retrieval`
|
||||
2. שאילתת חותמות זמן: `?session prov:startedAtTime ?time`
|
||||
3. הצגה כטבלה
|
||||
|
||||
**דוגמה לפלט**:
|
||||
```
|
||||
Session ID | Question | Time
|
||||
----------------------------------------------|--------------------------------|---------------------
|
||||
urn:trustgraph:question:abc123 | What was the War on Terror? | 2024-01-15 10:30:00
|
||||
urn:trustgraph:question:def456 | Who founded OpenAI? | 2024-01-15 09:15:00
|
||||
```
|
||||
|
||||
### כלי 3: tg-show-explain-trace
|
||||
|
||||
**מטרה**: הצגת שרשרת ההסברים המלאה עבור סשן GraphRAG.
|
||||
|
||||
**שימוש**:
|
||||
```bash
|
||||
tg-show-explain-trace "urn:trustgraph:question:abc123"
|
||||
tg-show-explain-trace --max-answer 1000 --show-provenance "urn:trustgraph:question:abc123"
|
||||
```
|
||||
|
||||
**ארגומנטים**:
|
||||
| Arg | תיאור |
|
||||
|-----|-------------|
|
||||
| `question_id` | כתובת URI של שאלה (מיקום) |
|
||||
| `-u/--api-url` | כתובת URL של שער |
|
||||
| `-t/--token` | טוקן אימות |
|
||||
| `-U/--user` | מזהה משתמש |
|
||||
| `-C/--collection` | אוסף |
|
||||
| `--max-answer` | מספר תווים מקסימלי לתשובה (ברירת מחדל: 500) |
|
||||
| `--show-provenance` | לעקוב אחר קשרים למסמכים מקוריים |
|
||||
| `--format` | פלט: `text` (ברירת מחדל), `json` |
|
||||
|
||||
**יישום**:
|
||||
1. קבל את טקסט השאלה מ-`tg:query` (predicate)
|
||||
2. מצא חקירה: `?exp prov:wasGeneratedBy <question_id>`
|
||||
3. מצא מיקוד: `?focus prov:wasDerivedFrom <exploration_id>`
|
||||
4. קבל קשרים שנבחרו: `<focus_id> tg:selectedEdge ?edge`
|
||||
5. עבור כל קשר, קבל `tg:edge` (משולש מצוטט) ו-`tg:reasoning`
|
||||
6. מצא סינתזה: `?synth prov:wasDerivedFrom <focus_id>`
|
||||
7. קבל את התשובה מ-`tg:document` דרך הספרן |
|
||||
8. אם `--show-provenance`, עקוב אחר קשרים למסמכים מקוריים
|
||||
|
||||
**דוגמה לפלט**:
|
||||
```
|
||||
=== GraphRAG Session: urn:trustgraph:question:abc123 ===
|
||||
|
||||
Question: What was the War on Terror?
|
||||
Time: 2024-01-15 10:30:00
|
||||
|
||||
--- Exploration ---
|
||||
Retrieved 50 edges from knowledge graph
|
||||
|
||||
--- Focus (Edge Selection) ---
|
||||
Selected 12 edges:
|
||||
|
||||
1. (War on Terror, definition, "A military campaign...")
|
||||
Reasoning: Directly defines the subject of the query
|
||||
Source: chunk → page 2 → "Beyond the Vigilant State"
|
||||
|
||||
2. (Guantanamo Bay, part_of, War on Terror)
|
||||
Reasoning: Shows key component of the campaign
|
||||
|
||||
--- Synthesis ---
|
||||
Answer:
|
||||
The War on Terror was a military campaign initiated...
|
||||
[truncated at 500 chars]
|
||||
```
|
||||
|
||||
## קבצים ליצירה
|
||||
|
||||
| קובץ | מטרה |
|
||||
|------|---------|
|
||||
| `trustgraph-cli/trustgraph/cli/show_document_hierarchy.py` | כלי 1 |
|
||||
| `trustgraph-cli/trustgraph/cli/list_explain_traces.py` | כלי 2 |
|
||||
| `trustgraph-cli/trustgraph/cli/show_explain_trace.py` | כלי 3 |
|
||||
|
||||
## קבצים לשינוי
|
||||
|
||||
| קובץ | שינוי |
|
||||
|------|--------|
|
||||
| `trustgraph-cli/setup.py` | הוספת רשומות ל-console_scripts |
|
||||
|
||||
## הערות יישום
|
||||
|
||||
1. **בטיחות תוכן בינארי**: נסה לפענח UTF-8; אם נכשל, הצג `[Binary: {size} bytes]`
|
||||
2. **חיתוך**: שמור על `--max-content`/`--max-answer` עם מציין `[truncated]`
|
||||
3. **משולשות מצוטטות**: נתח פורמט RDF-star מ-predicate `tg:edge`
|
||||
4. **תבניות**: עקוב אחר תבניות CLI קיימות מ-`query_graph.py`
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
כל השאילתות מכבדות את גבולות המשתמש/אוסף
|
||||
אימות טוקן נתמך באמצעות `--token` או `$TRUSTGRAPH_TOKEN`
|
||||
|
||||
## אסטרטגיית בדיקה
|
||||
|
||||
אימות ידני עם נתוני דוגמה:
|
||||
```bash
|
||||
# Load a test document
|
||||
tg-load-pdf -f test.pdf -c test-collection
|
||||
|
||||
# Verify hierarchy
|
||||
tg-show-document-hierarchy "urn:trustgraph:doc:test"
|
||||
|
||||
# Run a GraphRAG query with explainability
|
||||
tg-invoke-graph-rag --explainable -q "Test question"
|
||||
|
||||
# List and inspect traces
|
||||
tg-list-explain-traces
|
||||
tg-show-explain-trace "urn:trustgraph:question:xxx"
|
||||
```
|
||||
|
||||
## הפניות
|
||||
|
||||
הסבר בזמן שאילתה: `docs/tech-specs/query-time-explainability.md`
|
||||
מקור בזמן חילוץ: `docs/tech-specs/extraction-time-provenance.md`
|
||||
דוגמה קיימת של שורת פקודה: `trustgraph-cli/trustgraph/cli/invoke_graph_rag.py`
|
||||
355
docs/tech-specs/he/extraction-flows.he.md
Normal file
355
docs/tech-specs/he/extraction-flows.he.md
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
---
|
||||
layout: default
|
||||
title: "זרימות חילוץ"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# זרימות חילוץ
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
מסמך זה מתאר כיצד נתונים זורמים דרך צינור החילוץ של TrustGraph, החל מהגשת המסמכים ועד לאחסון במאגרי ידע.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
```
|
||||
┌──────────┐ ┌─────────────┐ ┌─────────┐ ┌────────────────────┐
|
||||
│ Librarian│────▶│ PDF Decoder │────▶│ Chunker │────▶│ Knowledge │
|
||||
│ │ │ (PDF only) │ │ │ │ Extraction │
|
||||
│ │────────────────────────▶│ │ │ │
|
||||
└──────────┘ └─────────────┘ └─────────┘ └────────────────────┘
|
||||
│ │
|
||||
│ ├──▶ Triples
|
||||
│ ├──▶ Entity Contexts
|
||||
│ └──▶ Rows
|
||||
│
|
||||
└──▶ Document Embeddings
|
||||
```
|
||||
|
||||
## אחסון תוכן
|
||||
|
||||
### אחסון בלובים (S3/Minio)
|
||||
|
||||
תוכן מסמכים מאוחסן באחסון בלובים התואם ל-S3:
|
||||
פורמט נתיב: `doc/{object_id}` כאשר object_id הוא מזהה UUID
|
||||
כל סוגי המסמכים מאוחסנים כאן: מסמכים מקוריים, עמודים, חלקים
|
||||
|
||||
### אחסון מטא-דאטה (Cassandra)
|
||||
|
||||
מטא-דאטה של מסמכים המאוחסן ב-Cassandra כולל:
|
||||
מזהה מסמך, כותרת, סוג (MIME type)
|
||||
הפניה לאחסון הבלובים `object_id`
|
||||
`parent_id` עבור מסמכים משניים (עמודים, חלקים)
|
||||
`document_type`: "source", "page", "chunk", "answer"
|
||||
|
||||
### סף בין הטמעה להזרמה
|
||||
|
||||
העברת תוכן משתמשת באסטרטגיה המבוססת על גודל:
|
||||
**פחות מ-2MB**: התוכן כלול בתוך ההודעה (מקודד ב-base64)
|
||||
**גדול או שווה ל-2MB**: נשלח רק `document_id`; המעבד שולף דרך ממשק ה-librarian API
|
||||
|
||||
## שלב 1: הגשת מסמך (Librarian)
|
||||
|
||||
### נקודת כניסה
|
||||
|
||||
מסמכים נכנסים למערכת דרך הפעולה `add-document` של ה-librarian:
|
||||
1. התוכן מועלה לאחסון הבלובים
|
||||
2. רשומה של מטא-דאטה נוצרת ב-Cassandra
|
||||
3. מחזיר מזהה מסמך
|
||||
|
||||
### הפעלת חילוץ
|
||||
|
||||
הפעולה `add-processing` מפעילה חילוץ:
|
||||
מציין `document_id`, `flow` (מזהה צינור), `collection` (מחסן יעד)
|
||||
הפעולה `load_document()` של ה-librarian שולפת את התוכן ומפרסמת לתור הקלט של ה-flow
|
||||
|
||||
### סכימה: מסמך
|
||||
|
||||
```
|
||||
Document
|
||||
├── metadata: Metadata
|
||||
│ ├── id: str # Document identifier
|
||||
│ ├── user: str # Tenant/user ID
|
||||
│ ├── collection: str # Target collection
|
||||
│ └── metadata: list[Triple] # (largely unused, historical)
|
||||
├── data: bytes # PDF content (base64, if inline)
|
||||
└── document_id: str # Librarian reference (if streaming)
|
||||
```
|
||||
|
||||
**ניתוב:** בהתבסס על השדה `kind`:
|
||||
`application/pdf` → תור `document-load` → מפענח PDF
|
||||
`text/plain` → תור `text-load` → מפרק
|
||||
|
||||
## שלב 2: מפענח PDF
|
||||
|
||||
ממיר מסמכי PDF לעמודי טקסט.
|
||||
|
||||
### תהליך
|
||||
|
||||
1. שליפת תוכן (בשורת `data` או דרך `document_id` מהספרן)
|
||||
2. חילוץ עמודים באמצעות PyPDF
|
||||
3. עבור כל עמוד:
|
||||
שמירה כמסמך משני בספרן (`{doc_id}/p{page_num}`)
|
||||
שליחת טריפלים של מקור (עמוד שמקורו במסמך)
|
||||
העברה למפרק
|
||||
|
||||
### סכימה: TextDocument
|
||||
|
||||
```
|
||||
TextDocument
|
||||
├── metadata: Metadata
|
||||
│ ├── id: str # Page URI (e.g., https://trustgraph.ai/doc/xxx/p1)
|
||||
│ ├── user: str
|
||||
│ ├── collection: str
|
||||
│ └── metadata: list[Triple]
|
||||
├── text: bytes # Page text content (if inline)
|
||||
└── document_id: str # Librarian reference (e.g., "doc123/p1")
|
||||
```
|
||||
|
||||
## שלב 3: חלוקה לחלקים
|
||||
|
||||
מחלק טקסט לחלקים בגודל מוגדר.
|
||||
|
||||
### פרמטרים (ניתנים להגדרה בתוך זרימת העבודה)
|
||||
|
||||
`chunk_size`: גודל החלק המיועד בתווים (ברירת מחדל: 2000)
|
||||
`chunk_overlap`: חפיפה בין חלקים (ברירת מחדל: 100)
|
||||
|
||||
### תהליך
|
||||
|
||||
1. שליפת תוכן הטקסט (בשורת הקוד או דרך הספרן)
|
||||
2. חלוקה באמצעות מפריד תווים רקורסיבי
|
||||
3. עבור כל חלק:
|
||||
שמירה כמסמך משני בספרן (`{parent_id}/c{index}`)
|
||||
שליחת טריפלים של מקור (החלק נגזר מדף/מסמך)
|
||||
העברה למעבדי חילוץ
|
||||
|
||||
### סכימה: חלק
|
||||
|
||||
```
|
||||
Chunk
|
||||
├── metadata: Metadata
|
||||
│ ├── id: str # Chunk URI
|
||||
│ ├── user: str
|
||||
│ ├── collection: str
|
||||
│ └── metadata: list[Triple]
|
||||
├── chunk: bytes # Chunk text content
|
||||
└── document_id: str # Librarian chunk ID (e.g., "doc123/p1/c3")
|
||||
```
|
||||
|
||||
### היררכיית מזהי מסמכים
|
||||
|
||||
מסמכים משניים מקודדים את שושלתם במזהה:
|
||||
מקור: `doc123`
|
||||
עמוד: `doc123/p5`
|
||||
מקטע מעמוד: `doc123/p5/c2`
|
||||
מקטע מטקסט: `doc123/c2`
|
||||
|
||||
## שלב 4: חילוץ ידע
|
||||
|
||||
קיימים דפוסי חילוץ מרובים, הנבחרים על ידי תצורת זרימת העבודה.
|
||||
|
||||
### דפוס א': GraphRAG בסיסי
|
||||
|
||||
שני מעבדים מקבילים:
|
||||
|
||||
**kg-extract-definitions**
|
||||
קלט: מקטע
|
||||
פלט: משולשים (הגדרות ישויות), הקשרים של ישויות
|
||||
מחלץ: תוויות ישויות, הגדרות
|
||||
|
||||
**kg-extract-relationships**
|
||||
קלט: מקטע
|
||||
פלט: משולשים (יחסים), הקשרים של ישויות
|
||||
מחלץ: יחסי נושא-נשוא-אובייקט
|
||||
|
||||
### דפוס ב': מונחה אונטולוגיה (kg-extract-ontology)
|
||||
|
||||
קלט: מקטע
|
||||
פלט: משולשים, הקשרים של ישויות
|
||||
משתמש באונטולוגיה מוגדרת כדי להנחות את החילוץ
|
||||
|
||||
### דפוס ג': מבוסס סוכן (kg-extract-agent)
|
||||
|
||||
קלט: מקטע
|
||||
פלט: משולשים, הקשרים של ישויות
|
||||
משתמש במסגרת סוכן לחילוץ
|
||||
|
||||
### דפוס ד': חילוץ שורות (kg-extract-rows)
|
||||
|
||||
קלט: מקטע
|
||||
פלט: שורות (נתונים מובנים, לא משולשים)
|
||||
משתמש בהגדרת סכימה כדי לחלץ רשומות מובנות
|
||||
|
||||
### סכימה: משולשים
|
||||
|
||||
```
|
||||
Triples
|
||||
├── metadata: Metadata
|
||||
│ ├── id: str
|
||||
│ ├── user: str
|
||||
│ ├── collection: str
|
||||
│ └── metadata: list[Triple] # (set to [] by extractors)
|
||||
└── triples: list[Triple]
|
||||
└── Triple
|
||||
├── s: Term # Subject
|
||||
├── p: Term # Predicate
|
||||
├── o: Term # Object
|
||||
└── g: str | None # Named graph
|
||||
```
|
||||
|
||||
### סכימה: EntityContexts
|
||||
|
||||
```
|
||||
EntityContexts
|
||||
├── metadata: Metadata
|
||||
└── entities: list[EntityContext]
|
||||
└── EntityContext
|
||||
├── entity: Term # Entity identifier (IRI)
|
||||
├── context: str # Textual description for embedding
|
||||
└── chunk_id: str # Source chunk ID (provenance)
|
||||
```
|
||||
|
||||
### סכימה: שורות
|
||||
|
||||
```
|
||||
Rows
|
||||
├── metadata: Metadata
|
||||
├── row_schema: RowSchema
|
||||
│ ├── name: str
|
||||
│ ├── description: str
|
||||
│ └── fields: list[Field]
|
||||
└── rows: list[dict[str, str]] # Extracted records
|
||||
```
|
||||
|
||||
## שלב 5: יצירת הטמעות (Embeddings)
|
||||
|
||||
### הטמעות גרפיות (Graph Embeddings)
|
||||
|
||||
ממיר הקשרים של ישויות להטמעות וקטוריות.
|
||||
|
||||
**תהליך:**
|
||||
1. קבלת הקשרים של ישויות (EntityContexts)
|
||||
2. הפעלת שירות הטמעות עם טקסט ההקשר
|
||||
3. פלט הטמעות גרפיות (מיפוי ישות ← וקטור)
|
||||
|
||||
**סכימה: הטמעות גרפיות (GraphEmbeddings)**
|
||||
|
||||
```
|
||||
GraphEmbeddings
|
||||
├── metadata: Metadata
|
||||
└── entities: list[EntityEmbeddings]
|
||||
└── EntityEmbeddings
|
||||
├── entity: Term # Entity identifier
|
||||
├── vector: list[float] # Embedding vector
|
||||
└── chunk_id: str # Source chunk (provenance)
|
||||
```
|
||||
|
||||
### הטמעות מסמכים
|
||||
|
||||
ממיר טקסט מחולק ישירות להטמעות וקטוריות.
|
||||
|
||||
**תהליך:**
|
||||
1. קבלת מקטע
|
||||
2. הפעלת שירות הטמעות עם טקסט המקטע
|
||||
3. פלט הטמעות מסמכים
|
||||
|
||||
**סכימה: הטמעות מסמכים**
|
||||
|
||||
```
|
||||
DocumentEmbeddings
|
||||
├── metadata: Metadata
|
||||
└── chunks: list[ChunkEmbeddings]
|
||||
└── ChunkEmbeddings
|
||||
├── chunk_id: str # Chunk identifier
|
||||
└── vector: list[float] # Embedding vector
|
||||
```
|
||||
|
||||
### הטמעות שורות
|
||||
|
||||
ממיר שדות אינדקס שורות להטמעות וקטוריות.
|
||||
|
||||
**תהליך:**
|
||||
1. קבלת שורות
|
||||
2. הטמעת שדות אינדקס מוגדרים
|
||||
3. פלט לאחסון וקטורים של שורות
|
||||
|
||||
## שלב 6: אחסון
|
||||
|
||||
### מאגר משולשות
|
||||
|
||||
מקבל: משולשות
|
||||
אחסון: Cassandra (טבלאות ממוקדות ישויות)
|
||||
גרפים בעלי שמות מפרידים ידע ליבה ממידע על מקור:
|
||||
`""` (ברירת מחדל): עובדות ידע ליבה
|
||||
`urn:graph:source`: מידע על מקור החילוץ
|
||||
`urn:graph:retrieval`: הסבר בזמן שאילתה
|
||||
|
||||
### מאגר וקטורים (הטמעות גרפים)
|
||||
|
||||
מקבל: הטמעות גרפים
|
||||
אחסון: Qdrant, Milvus, או Pinecone
|
||||
מאוּינדקס על ידי: IRI של ישות
|
||||
מטא-דאטה: chunk_id עבור מידע על מקור
|
||||
|
||||
### מאגר וקטורים (הטמעות מסמכים)
|
||||
|
||||
מקבל: הטמעות מסמכים
|
||||
אחסון: Qdrant, Milvus, או Pinecone
|
||||
מאוּינדקס על ידי: chunk_id
|
||||
|
||||
### מאגר שורות
|
||||
|
||||
מקבל: שורות
|
||||
אחסון: Cassandra
|
||||
מבנה טבלאות המונחה סכימה
|
||||
|
||||
### מאגר וקטורים של שורות
|
||||
|
||||
מקבל: הטמעות שורות
|
||||
אחסון: מסד נתונים וקטורי
|
||||
מאוּנדקס על ידי: שדות אינדקס שורה
|
||||
|
||||
## ניתוח שדות מטא-דאטה
|
||||
|
||||
### שדות בשימוש פעיל
|
||||
|
||||
| שדה | שימוש |
|
||||
|-------|-------|
|
||||
| `metadata.id` | מזהה מסמך/חלק, רישום, מקור
|
||||
| `metadata.user` | ריבוי דיירים, ניתוב אחסון
|
||||
| `metadata.collection` | בחירת אוסף יעד
|
||||
| `document_id` | הפניה לספרן, קישור למקור
|
||||
| `chunk_id` | מעקב אחר מקור לאורך הצינור
|
||||
|
||||
<<<<<<< HEAD
|
||||
### שדות שעלולים להיות מיותרים
|
||||
|
||||
| שדה | סטטוס |
|
||||
|-------|--------|
|
||||
| `metadata.metadata` | מוגדר ל-`[]` על ידי כל המחלצים; מטא-דאטה ברמת המסמך מטופלים כעת על ידי הספרן בזמן ההגשה |
|
||||
=======
|
||||
### שדות שהוסרו
|
||||
|
||||
| שדה | סטטוס |
|
||||
|-------|--------|
|
||||
| `metadata.metadata` | הוסר ממחלקת `Metadata`. משולשות מטא-דאטה ברמת המסמך משודרים כעת ישירות על ידי הספרן למאגר משולשות בזמן ההגשה, ולא מועברים דרך צינור החילוץ. |
|
||||
>>>>>>> e3bcbf73 (The metadata field (list of triples) in the pipeline Metadata class)
|
||||
|
||||
### תבניות שדות בייטים
|
||||
|
||||
כל שדות התוכן (`data`, `text`, `chunk`) הם `bytes` אך מפענחים מיד לשרשורי UTF-8 על ידי כל המעבדים. אף מעבד לא משתמש בבייטים גולמיים.
|
||||
|
||||
## תצורת זרימה
|
||||
|
||||
זרימות מוגדרות מחוץ למערכת ומועברות לספרן באמצעות שירות התצורה. כל זרימה מציינת:
|
||||
|
||||
תורי קלט (`text-load`, `document-load`)
|
||||
שרשרת מעבדים
|
||||
פרמטרים (גודל חתיכה, שיטת חילוץ, וכו')
|
||||
|
||||
דוגמאות לתבניות זרימה:
|
||||
`pdf-graphrag`: PDF → מפענח → חולק → הגדרות + קשרים → הטמעות
|
||||
`text-graphrag`: טקסט → חולק → הגדרות + קשרים → הטמעות
|
||||
`pdf-ontology`: PDF → מפענח → חולק → חילוץ אונטולוגיה → הטמעות
|
||||
`text-rows`: טקסט → חולק → חילוץ שורות → אחסון שורות
|
||||
243
docs/tech-specs/he/extraction-provenance-subgraph.he.md
Normal file
243
docs/tech-specs/he/extraction-provenance-subgraph.he.md
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מקור החילוץ: מודל תת-גרף"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מקור החילוץ: מודל תת-גרף
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## בעיה
|
||||
|
||||
מעקב מקורות מידע בזמן החילוץ מייצר כיום מימוש מלא לכל טריפל
|
||||
<<<<<<< HEAD
|
||||
שחולץ: `stmt_uri` ייחודי, `activity_uri` ו-מטא-דאטה של PROV-O עבור כל
|
||||
עובדה ידע בודדת. עיבוד של חלק אחד שמייצר 20 קשרים מייצר כ-220
|
||||
טריפלי מעקב מקורות מידע בנוסף ל-כ-20 טריפלי ידע - תקורה של בערך 10:1.
|
||||
=======
|
||||
שחולץ: `stmt_uri` ייחודי, `activity_uri` ו-מטא-דאטה של PROV-O הקשורים
|
||||
לכל עובדה בידע. עיבוד של חלק אחד שמניב 20 קשרים מייצר כ-220 טריפלי
|
||||
מעקב מקורות מידע בנוסף ל-כ-20 טריפלי ידע - תקורה של בערך 10:1.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
|
||||
זה יקר (אחסון, אינדקס, העברה) וגם לא מדויק מבחינה סמנטית. כל חלק
|
||||
מעובד על ידי קריאה אחת של מודל שפה גדול (LLM) שמייצר את כל
|
||||
<<<<<<< HEAD
|
||||
הטריפלים שלו בעסקה אחת. המודל הנוכחי של טריפל בודד מטשטש את זה
|
||||
על ידי יצירת האשליה של 20 אירועי חילוץ עצמאיים.
|
||||
|
||||
|
||||
בנוסף, לשני מתוך ארבעה מעבדי החילוץ (kg-extract-ontology,
|
||||
=======
|
||||
הטריפלים שלו בפעולה אחת. המודל הנוכחי, שמבוסס על טריפל בודד,
|
||||
מטעה בכך שהוא יוצר את האשליה של 20 אירועי חילוץ עצמאיים.
|
||||
|
||||
|
||||
בנוסף, לשני מתוך ארבעת מעבדי החילוץ (kg-extract-ontology,
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
kg-extract-agent) אין מעקב מקורות מידע כלל, מה שמשאיר פערים
|
||||
במסלול הביקורת.
|
||||
|
||||
## פתרון
|
||||
|
||||
<<<<<<< HEAD
|
||||
החליפו את הפירוט של כל שלישייה במודל תת-גרף: רשומת מוצא אחת לכל חילוץ, המשותפת לכל השלישיות שנוצרו מחלק זה.
|
||||
=======
|
||||
החליפו את הפירוט של כל טריפל במודל תת-גרף: רשומת מוצא אחת לכל חילוץ, המשותפת לכל הטריפלים שנוצרו מחלק זה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
|
||||
### שינוי מונחים
|
||||
|
||||
|
||||
| ישן | חדש |
|
||||
|-----|-----|
|
||||
| `stmt_uri` (`https://trustgraph.ai/stmt/{uuid}`) | `subgraph_uri` (`https://trustgraph.ai/subgraph/{uuid}`) |
|
||||
| `statement_uri()` | `subgraph_uri()` |
|
||||
| `tg:reifies` (1:1, זהות) | `tg:contains` (1:רבים, הכלה) |
|
||||
|
||||
### מבנה מטרה
|
||||
|
||||
<<<<<<< HEAD
|
||||
כל השלישיות של המוצא נכנסות לגרף המקוּם בשם `urn:graph:source`.
|
||||
=======
|
||||
כל הטריפלים של המוצא נכנסים לגרף המקוּם `urn:graph:source`.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```
|
||||
# Subgraph contains each extracted triple (RDF-star quoted triples)
|
||||
<subgraph> tg:contains <<s1 p1 o1>> .
|
||||
<subgraph> tg:contains <<s2 p2 o2>> .
|
||||
<subgraph> tg:contains <<s3 p3 o3>> .
|
||||
|
||||
# Derivation from source chunk
|
||||
<subgraph> prov:wasDerivedFrom <chunk_uri> .
|
||||
<subgraph> prov:wasGeneratedBy <activity> .
|
||||
|
||||
# Activity: one per chunk extraction
|
||||
<activity> rdf:type prov:Activity .
|
||||
<activity> rdfs:label "{component_name} extraction" .
|
||||
<activity> prov:used <chunk_uri> .
|
||||
<activity> prov:wasAssociatedWith <agent> .
|
||||
<activity> prov:startedAtTime "2026-03-13T10:00:00Z" .
|
||||
<activity> tg:componentVersion "0.25.0" .
|
||||
<activity> tg:llmModel "gpt-4" . # if available
|
||||
<activity> tg:ontology <ontology_uri> . # if available
|
||||
|
||||
# Agent: stable per component
|
||||
<agent> rdf:type prov:Agent .
|
||||
<agent> rdfs:label "{component_name}" .
|
||||
```
|
||||
|
||||
### השוואת נפחים
|
||||
|
||||
עבור קטע המייצר N משולשים חילוצים:
|
||||
|
||||
| | ישן (למשולש) | חדש (תת-גרף) |
|
||||
|---|---|---|
|
||||
| `tg:contains` / `tg:reifies` | N | N |
|
||||
| משולשי פעילות | ~9 x N | ~9 |
|
||||
| משולשי סוכנים | 2 x N | 2 |
|
||||
| מטא-נתונים של הצהרה/תת-גרף | 2 x N | 2 |
|
||||
| **סה"כ משולשי מקור** | **~13N** | **N + 13** |
|
||||
| **דוגמה (N=20)** | **~260** | **33** |
|
||||
|
||||
## היקף
|
||||
|
||||
### מעבדים לעדכון (מקור קיים, לכל משולש)
|
||||
|
||||
**kg-extract-definitions**
|
||||
(`trustgraph-flow/trustgraph/extract/kg/definitions/extract.py`)
|
||||
|
||||
כיום קורא ל-`statement_uri()` + `triple_provenance_triples()` בתוך
|
||||
הלולאה לכל הגדרה.
|
||||
|
||||
שינויים:
|
||||
העברת יצירת `subgraph_uri()` ו-`activity_uri()` לפני הלולאה
|
||||
איסוף משולשי `tg:contains` בתוך הלולאה
|
||||
פליטת בלוק פעילות/סוכן/הסקה משותף פעם אחת לאחר הלולאה
|
||||
|
||||
**kg-extract-relationships**
|
||||
(`trustgraph-flow/trustgraph/extract/kg/relationships/extract.py`)
|
||||
|
||||
דפוס זהה כמו הגדרות. שינויים זהים.
|
||||
|
||||
### מעבדים להוספת מקור (חסרים כרגע)
|
||||
|
||||
**kg-extract-ontology**
|
||||
(`trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`)
|
||||
|
||||
כיום פולט משולשים ללא מקור. הוספת מקור תת-גרף
|
||||
באמצעות הדפוס הזהה: תת-גרף אחד לכל קטע, `tg:contains` עבור כל
|
||||
משולש חילוץ.
|
||||
|
||||
**kg-extract-agent**
|
||||
(`trustgraph-flow/trustgraph/extract/kg/agent/extract.py`)
|
||||
|
||||
כיום פולט משולשים ללא מקור. הוספת מקור תת-גרף
|
||||
באמצעות הדפוס הזהה.
|
||||
|
||||
### שינויים בספריית המקור המשותפת
|
||||
|
||||
**`trustgraph-base/trustgraph/provenance/triples.py`**
|
||||
|
||||
החלפת `triple_provenance_triples()` עם `subgraph_provenance_triples()`
|
||||
פונקציה חדשה מקבלת רשימה של משולשים חילוצים במקום משולש בודד
|
||||
מייצרת `tg:contains` אחד לכל משולש, בלוק פעילות/סוכן משותף
|
||||
הסרת `triple_provenance_triples()` הישן
|
||||
|
||||
**`trustgraph-base/trustgraph/provenance/uris.py`**
|
||||
|
||||
החלפת `statement_uri()` עם `subgraph_uri()`
|
||||
|
||||
**`trustgraph-base/trustgraph/provenance/namespaces.py`**
|
||||
|
||||
החלפת `TG_REIFIES` עם `TG_CONTAINS`
|
||||
|
||||
### לא בתחום
|
||||
|
||||
**kg-extract-topics**: מעבד מסוג ישן, לא בשימוש כרגע ב
|
||||
זרימות סטנדרטיות
|
||||
**kg-extract-rows**: מייצר שורות ולא משולשים, מודל מקור
|
||||
שונה
|
||||
**מקור בזמן שאילתה** (`urn:graph:retrieval`): נושא נפרד,
|
||||
כבר משתמש בדפוס שונה (שאילתה/חקירה/מיקוד/סינתזה)
|
||||
<<<<<<< HEAD
|
||||
**מקור של מסמך/עמוד/קטע** (מקודד PDF, מפצל): כבר משתמש
|
||||
=======
|
||||
**מקור של מסמך/עמוד/קטע** (מקודד PDF, חותך): כבר משתמש
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
ב-`derived_entity_triples()` שהוא לכל ישות, ולא לכל משולש — אין
|
||||
בעיית יתירות
|
||||
|
||||
## הערות יישום
|
||||
|
||||
### שינוי מבנה הלולאה של המעבד
|
||||
|
||||
לפני (לכל משולש, ביחסים):
|
||||
```python
|
||||
for rel in rels:
|
||||
# ... build relationship_triple ...
|
||||
stmt_uri = statement_uri()
|
||||
prov_triples = triple_provenance_triples(
|
||||
stmt_uri=stmt_uri,
|
||||
extracted_triple=relationship_triple,
|
||||
...
|
||||
)
|
||||
triples.extend(set_graph(prov_triples, GRAPH_SOURCE))
|
||||
```
|
||||
|
||||
אחרי (תת-גרף):
|
||||
```python
|
||||
sg_uri = subgraph_uri()
|
||||
|
||||
for rel in rels:
|
||||
# ... build relationship_triple ...
|
||||
extracted_triples.append(relationship_triple)
|
||||
|
||||
prov_triples = subgraph_provenance_triples(
|
||||
subgraph_uri=sg_uri,
|
||||
extracted_triples=extracted_triples,
|
||||
chunk_uri=chunk_uri,
|
||||
component_name=default_ident,
|
||||
component_version=COMPONENT_VERSION,
|
||||
llm_model=llm_model,
|
||||
ontology_uri=ontology_uri,
|
||||
)
|
||||
triples.extend(set_graph(prov_triples, GRAPH_SOURCE))
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
### חתימה חדשה של עוזר
|
||||
=======
|
||||
### חתימה חדשה עבור עוזר
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```python
|
||||
def subgraph_provenance_triples(
|
||||
subgraph_uri: str,
|
||||
extracted_triples: List[Triple],
|
||||
chunk_uri: str,
|
||||
component_name: str,
|
||||
component_version: str,
|
||||
llm_model: Optional[str] = None,
|
||||
ontology_uri: Optional[str] = None,
|
||||
timestamp: Optional[str] = None,
|
||||
) -> List[Triple]:
|
||||
"""
|
||||
Build provenance triples for a subgraph of extracted knowledge.
|
||||
|
||||
Creates:
|
||||
- tg:contains link for each extracted triple (RDF-star quoted)
|
||||
- One prov:wasDerivedFrom link to source chunk
|
||||
- One activity with agent metadata
|
||||
"""
|
||||
```
|
||||
|
||||
### שינוי משמעותי
|
||||
|
||||
זוהי שינוי משמעותי במודל המקור. המקור טרם פורסם, ולכן אין צורך בביצוע שדרוג. ניתן להסיר את קוד ⟦CODE_0⟧ /
|
||||
`tg:reifies` הישן לחלוטין.
|
||||
קוד `statement_uri` ניתן להסרה לחלוטין.
|
||||
830
docs/tech-specs/he/extraction-time-provenance.he.md
Normal file
830
docs/tech-specs/he/extraction-time-provenance.he.md
Normal file
|
|
@ -0,0 +1,830 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מקור המידע בזמן החילוץ: שכבת המקור"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מקור המידע בזמן החילוץ: שכבת המקור
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מתעד הערות על מקור המידע בזמן החילוץ לצורך עבודה עתידית על מפרטים. מקור המידע בזמן החילוץ מתעד את "שכבת המקור" - מאיפה הנתונים הגיעו במקור, וכיצד הם חולצו ועובדו.
|
||||
|
||||
זה נפרד ממקור המידע בזמן השאילתה (ראה `query-time-provenance.md`) אשר מתעד את הנימוקים של המערכת.
|
||||
|
||||
## הצהרת בעיה
|
||||
|
||||
### יישום נוכחי
|
||||
|
||||
כיום, מקור המידע פועל באופן הבא:
|
||||
מטא-נתונים של מסמכים מאוחסנים כמשולשים RDF בגרף הידע.
|
||||
מזהה מסמך מקשר בין מטא-נתונים למסמך, כך שהמסמך מופיע כצומת בגרף.
|
||||
כאשר קשרים (יחסים/עובדות) מחולצים ממסמכים, קשר `subjectOf` מקשר את הקשר המחולץ בחזרה למסמך המקור.
|
||||
|
||||
### בעיות בגישה הנוכחית
|
||||
|
||||
1. **טעינת מטא-נתונים חוזרת:** מטא-נתונים של מסמכים מקובצים ונטענים שוב ושוב עם כל אצווה של משולשים המחולצים ממסמך זה. זה בזבוז ומיותר - אותם מטא-נתונים מועברים כחלק מהפלט בכל חילוץ.
|
||||
|
||||
<<<<<<< HEAD
|
||||
2. **מקור מידע שטחי:** הקשר `subjectOf` הנוכחי מקשר רק עובדות ישירות למסמך הראשי. אין נראות לגבי שרשרת השינויים - מאיזו עמוד הגיעה העובדה, מאיזה חלק, באיזו שיטת חילוץ נעשה שימוש.
|
||||
=======
|
||||
2. **מקור מידע שטחי:** הקשר `subjectOf` הנוכחי מקשר רק עובדות ישירות למסמך הראשי. אין נראות לגבי שרשרת השינויים - מאיזו עמוד הגיעה העובדה, מאיזה חלק, באיזו שיטת חילוץ השתמשו.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### מצב רצוי
|
||||
|
||||
1. **טעינת מטא-נתונים פעם אחת:** מטא-נתונים של מסמכים צריכים להיטען פעם אחת ולהיות מחוברים לצומת המסמך הראשי, ולא לחזור על עצמם עם כל אצווה של משולשים.
|
||||
|
||||
<<<<<<< HEAD
|
||||
2. **גרף מקור מידע עשיר:** לתפוס את שרשרת השינויים המלאה ממסמך המקור דרך כל הארטיפקטים הביניים ועד לעובדות המחולצות. לדוגמה, טרנספורמציה של מסמך PDF:
|
||||
=======
|
||||
2. **גרף מקור מידע עשיר:** לתפוס את שרשרת השינויים המלאה מהמסמך המקור דרך כל הארטיפקטים הביניים ועד לעובדות המחולצות. לדוגמה, טרנספורמציה של מסמך PDF:
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```
|
||||
PDF file (source document with metadata)
|
||||
→ Page 1 (decoded text)
|
||||
→ Chunk 1
|
||||
→ Extracted edge/fact (via subjectOf)
|
||||
→ Extracted edge/fact
|
||||
→ Chunk 2
|
||||
→ Extracted edge/fact
|
||||
→ Page 2
|
||||
→ Chunk 3
|
||||
→ ...
|
||||
```
|
||||
|
||||
3. **אחסון מאוחד:** גרף המוצא (provenance DAG) מאוחסן באותו גרף ידע כמו הידע שחולץ. זה מאפשר שאילתת מוצא באותה צורה כמו שאילתת ידע - מעקב אחר קשרים לאחור בשרשרת מכל עובדה למיקום המקור המדויק שלה.
|
||||
|
||||
4. **מזהים יציבים:** לכל ארטיפקט ביניים (עמוד, מקטע) יש מזהה יציב כצומת בגרף.
|
||||
|
||||
5. **קישור הורה-ילד:** מסמכים נגזרים מקושרים להוריהם עד למסמך המקור העליון באמצעות סוגי קשרים עקביים.
|
||||
|
||||
6. **הקצאת עובדות מדויקת:** הקשר `subjectOf` בקשרים שחולצו מצביע על ההורה המיידי (מקטע), ולא על מסמך המקור העליון. ניתן לשחזר את כל המוצא על ידי מעבר ב-DAG.
|
||||
|
||||
## תרחישי שימוש
|
||||
|
||||
<<<<<<< HEAD
|
||||
### UC1: הקצאת מקור בתגובות GraphRAG
|
||||
=======
|
||||
### תרחיש שימוש 1: הקצאת מקור בתגובות GraphRAG
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**תרחיש:** משתמש מריץ שאילתה של GraphRAG ומקבל תגובה מהסוכן.
|
||||
|
||||
**תהליך:**
|
||||
1. משתמש מגיש שאילתה לסוכן GraphRAG.
|
||||
2. הסוכן שולף עובדות רלוונטיות מגרף הידע כדי לנסח תגובה.
|
||||
3. בהתאם למפרט המוצא בזמן השאילתה, הסוכן מדווח אילו עובדות תרמו לתגובה.
|
||||
4. כל עובדה מקושרת למקטע המקור שלה באמצעות גרף המוצא.
|
||||
5. מקטעים מקושרים לעמודים, עמודים מקושרים למסמכי מקור.
|
||||
|
||||
**תוצאה עבור המשתמש:** הממשק מציג את תגובת מודל השפה הגדול (LLM) יחד עם הקצאת מקור. המשתמש יכול:
|
||||
לראות אילו עובדות תמכו בתגובה.
|
||||
לעבור ממקטעים → עמודים → מסמכים.
|
||||
לעיין במסמכי המקור המקוריים כדי לאמת טענות.
|
||||
להבין בדיוק מאיפה במסמך (איזה עמוד, איזה חלק) עובדה מסוימת הגיעה.
|
||||
|
||||
**ערך:** משתמשים יכולים לאמת תגובות שנוצרו על ידי AI מול מקורות ראשוניים, ובכך לבנות אמון ולאפשר בדיקת עובדות.
|
||||
|
||||
<<<<<<< HEAD
|
||||
### UC2: ניפוי באגים של איכות חילוץ
|
||||
|
||||
עובדה נראית שגויה. ניתן לעקוב אחורה דרך מקטע → עמוד → מסמך כדי לראות את הטקסט המקורי. האם זו הייתה שגיאת חילוץ, או שהמקור עצמו היה שגוי?
|
||||
|
||||
### UC3: חילוץ חוזר מצטבר
|
||||
|
||||
מסמך מקור מתעדכן. אילו מקטעים/עובדות נגזרו ממנו? לבטל ולחדש רק את אלה, ולא לעבד הכל מחדש.
|
||||
|
||||
### UC4: מחיקת נתונים / הזכות להיות נשכח
|
||||
|
||||
יש להסיר מסמך מקור (GDPR, סיבות משפטיות וכו'). יש לעבור ב-DAG כדי למצוא ולהסיר את כל העובדות הנגזרות.
|
||||
|
||||
### UC5: פתרון קונפליקטים
|
||||
|
||||
שתי עובדות סותרות אחת את השנייה. ניתן לעקוב אחורה לשני המקורות שלהן כדי להבין מדוע ולהחליט איזו עובדה לתת לה עדיפות (מקור סמכותי יותר, עדכני יותר וכו').
|
||||
|
||||
### UC6: שקלול סמכות מקור
|
||||
|
||||
למקורות מסוימים יש סמכות רבה יותר מאחרים. ניתן לשקלל או לסנן עובדות בהתאם לסמכות/איכות מסמכי המקור שלהן.
|
||||
|
||||
### UC7: השוואת צינורות חילוץ
|
||||
=======
|
||||
### תרחיש שימוש 2: ניפוי באגים של איכות חילוץ
|
||||
|
||||
עובדה נראית שגויה. ניתן לחזור אחורה דרך מקטע → עמוד → מסמך כדי לראות את הטקסט המקורי. האם זו הייתה שגיאת חילוץ, או שהמקור עצמו שגוי?
|
||||
|
||||
### תרחיש שימוש 3: חילוץ חוזר מצטבר
|
||||
|
||||
מסמך מקור מתעדכן. אילו מקטעים/עובדות נגזרו ממנו? לבטל ולחדש רק את אלה, ולא לעבד הכל מחדש.
|
||||
|
||||
### תרחיש שימוש 4: מחיקת נתונים / הזכות להימחק
|
||||
|
||||
יש להסיר מסמך מקור (GDPR, סיבות משפטיות וכו'). יש לעבור ב-DAG כדי למצוא ולהסיר את כל העובדות הנגזרות.
|
||||
|
||||
### תרחיש שימוש 5: פתרון קונפליקטים
|
||||
|
||||
שתי עובדות סותרות אחת את השנייה. ניתן לחזור לשתי העובדות למקורות שלהן כדי להבין מדוע ולהחליט איזו מהן לתת לה עדיפות (מקור סמכותי יותר, עדכני יותר וכו').
|
||||
|
||||
### תרחיש שימוש 6: שקלול סמכות מקור
|
||||
|
||||
למקורות מסוימים יש סמכות רבה יותר מאחרים. ניתן לשקלל או לסנן עובדות בהתאם לסמכות/איכות מסמכי המקור שלהן.
|
||||
|
||||
### תרחיש שימוש 7: השוואת צינורות חילוץ
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
השוואת תוצאות משיטות/גרסאות חילוץ שונות. איזה מחלץ הפיק עובדות טובות יותר מאותו מקור?
|
||||
|
||||
## נקודות אינטגרציה
|
||||
|
||||
### ספרן
|
||||
|
||||
רכיב הספרן כבר מספק אחסון מסמכים עם מזהי מסמכים ייחודיים. מערכת המקור משתלבת בתשתית הקיימת.
|
||||
|
||||
#### יכולות קיימות (שיושמו כבר)
|
||||
|
||||
**קישור מסמכים הורה-ילד:**
|
||||
`parent_id` שדה ב-`DocumentMetadata` - מקשר מסמך ילד למסמך הורה
|
||||
`document_type` שדה - ערכים: `"source"` (מקור) או `"extracted"` (נגזר)
|
||||
`add-child-document` API - יוצר מסמך ילד עם `document_type = "extracted"` אוטומטי
|
||||
`list-children` API - שולף את כל ילדי מסמך הורה
|
||||
מחיקה מדורגת - הסרת מסמך הורה מוחקת אוטומטית את כל מסמכי הילד
|
||||
|
||||
**זיהוי מסמכים:**
|
||||
מזהי מסמכים מוגדרים על ידי הלקוח (לא נוצרים אוטומטית)
|
||||
מסמכים מאוחסנים לפי מפתח מורכב `(user, document_id)` ב-Cassandra
|
||||
מזהי אובייקטים (UUIDs) נוצרים באופן פנימי עבור אחסון בלובים
|
||||
|
||||
**תמיכה במטא-נתונים:**
|
||||
`metadata: list[Triple]` שדה - משולשים RDF עבור מטא-נתונים מובנים
|
||||
`title`, `comments`, `tags` - מטא-נתונים בסיסיים של מסמך
|
||||
`time` - חותמת זמן, `kind` - סוג MIME
|
||||
|
||||
**ארכיטקטורת אחסון:**
|
||||
מטא-נתונים מאוחסנים ב-Cassandra (מרחב מפתחות `librarian`, טבלה `document`)
|
||||
תוכן מאוחסן ב-MinIO/S3 blob storage (דלי `library`)
|
||||
העברת תוכן חכמה: מסמכים קטנים מ-2MB משובצים, מסמכים גדולים יותר מועברים
|
||||
|
||||
#### קבצים מרכזיים
|
||||
|
||||
`trustgraph-flow/trustgraph/librarian/librarian.py` - פעולות ליבה של הספרן
|
||||
`trustgraph-flow/trustgraph/librarian/service.py` - מעבד שירות, טעינת מסמכים
|
||||
`trustgraph-flow/trustgraph/tables/library.py` - חנות טבלאות Cassandra
|
||||
`trustgraph-base/trustgraph/schema/services/library.py` - הגדרות סכימה
|
||||
|
||||
#### פערים לטיפול
|
||||
|
||||
ל-ספרן יש את אבני הבניין, אך כרגע:
|
||||
1. קישור הורה-ילד הוא בעומק של רמה אחת - אין עזרי מעבר DAG מרובי רמות
|
||||
2. אין אוצר מילים סטנדרטי לסוגי יחסים (לדוגמה, `derivedFrom`, `extractedFrom`)
|
||||
3. מטא-נתונים של מקור (שיטת חילוץ, רמת אמון, מיקום מקטע) אינם סטנדרטיים
|
||||
4. אין API שאילתה למעבר על שרשרת המקור המלאה מעובדה חזרה למקור
|
||||
|
||||
## תכנון זרימת עבודה מקצה לקצה
|
||||
|
||||
כל מעבד בצינור עוקב אחר דפוס עקבי:
|
||||
מקבל מזהה מסמך מהשורה העליונה
|
||||
שולף תוכן מהספרן
|
||||
מייצר ארטיפקטים ילדים
|
||||
עבור כל ילד: שומר בספרן, פולט קצה לגרף, מעביר מזהה לשורה התחתונה
|
||||
|
||||
### זרימות עיבוד
|
||||
|
||||
ישנן שתי זרימות בהתאם לסוג המסמך:
|
||||
|
||||
#### זרימת מסמכי PDF
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Librarian (initiate processing) │
|
||||
│ 1. Emit root document metadata to knowledge graph (once) │
|
||||
│ 2. Send root document ID to PDF extractor │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ PDF Extractor (per page) │
|
||||
│ 1. Fetch PDF content from librarian using document ID │
|
||||
│ 2. Extract pages as text │
|
||||
│ 3. For each page: │
|
||||
│ a. Save page as child document in librarian (parent = root doc) │
|
||||
│ b. Emit parent-child edge to knowledge graph │
|
||||
│ c. Send page document ID to chunker │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Chunker (per chunk) │
|
||||
│ 1. Fetch page content from librarian using document ID │
|
||||
│ 2. Split text into chunks │
|
||||
│ 3. For each chunk: │
|
||||
│ a. Save chunk as child document in librarian (parent = page) │
|
||||
│ b. Emit parent-child edge to knowledge graph │
|
||||
│ c. Send chunk document ID + chunk content to next processor │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
Post-chunker optimization: messages carry both
|
||||
chunk ID (for provenance) and content (to avoid
|
||||
librarian round-trip). Chunks are small (2-4KB).
|
||||
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Knowledge Extractor (per chunk) │
|
||||
│ 1. Receive chunk ID + content directly (no librarian fetch needed) │
|
||||
│ 2. Extract facts/triples and embeddings from chunk content │
|
||||
│ 3. For each triple: │
|
||||
│ a. Emit triple to knowledge graph │
|
||||
│ b. Emit reified edge linking triple → chunk ID (edge pointing │
|
||||
│ to edge - first use of reification support) │
|
||||
│ 4. For each embedding: │
|
||||
│ a. Emit embedding with its entity ID │
|
||||
│ b. Link entity ID → chunk ID in knowledge graph │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### זרימת מסמכי טקסט
|
||||
|
||||
מסמכי טקסט עוקפים את מודל החילוץ של PDF ועוברים ישירות למקטע:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Librarian (initiate processing) │
|
||||
│ 1. Emit root document metadata to knowledge graph (once) │
|
||||
│ 2. Send root document ID directly to chunker (skip PDF extractor) │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Chunker (per chunk) │
|
||||
│ 1. Fetch text content from librarian using document ID │
|
||||
│ 2. Split text into chunks │
|
||||
│ 3. For each chunk: │
|
||||
│ a. Save chunk as child document in librarian (parent = root doc) │
|
||||
│ b. Emit parent-child edge to knowledge graph │
|
||||
│ c. Send chunk document ID + chunk content to next processor │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Knowledge Extractor │
|
||||
│ (same as PDF flow) │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
הגרף המכוון (DAG) המתקבל הוא ברמה אחת קצרה יותר:
|
||||
|
||||
```
|
||||
PDF: Document → Pages → Chunks → Triples/Embeddings
|
||||
Text: Document → Chunks → Triples/Embeddings
|
||||
```
|
||||
|
||||
העיצוב מתאים לשני המקרים מכיוון שהמקטע (chunker) מטפל בקלט שלו באופן כללי - הוא משתמש בכל מזהה מסמך שהוא מקבל כאב, ללא קשר לשאלה האם מדובר במסמך מקור או בעמוד.
|
||||
|
||||
### סכימת מטא-נתונים (PROV-O)
|
||||
|
||||
מטא-נתונים של מקור (Provenance) משתמשים באונטולוגיה W3C PROV-O. זה מספק אוצר מילים סטנדרטי ומאפשר חתימה/אימות עתידי של תוצרי חילוץ.
|
||||
|
||||
#### מושגים מרכזיים ב-PROV-O
|
||||
|
||||
| סוג PROV-O | שימוש ב-TrustGraph |
|
||||
|-------------|------------------|
|
||||
| `prov:Entity` | מסמך, עמוד, מקטע, טריפל, הטמעה |
|
||||
| `prov:Activity` | מופעים של פעולות חילוץ |
|
||||
| `prov:Agent` | רכיבי TG (תוכנת חילוץ PDF, מקטע, וכו') עם גרסאות |
|
||||
|
||||
#### קשרים ב-PROV-O
|
||||
|
||||
| פרידיקט | משמעות | דוגמה |
|
||||
|-----------|---------|---------|
|
||||
<<<<<<< HEAD
|
||||
| `prov:wasDerivedFrom` | ישות שמקורה בישות אחרת | עמוד היה-מבוסס-על מסמך |
|
||||
| `prov:wasGeneratedBy` | ישות שנוצרה על ידי פעילות | עמוד נוצר-על-ידי פעולת חילוץ PDF |
|
||||
| `prov:used` | פעילות השתמשה בישות כקלט | פעולת חילוץ PDF השתמשה במסמך |
|
||||
| `prov:wasAssociatedWith` | פעילות בוצעה על ידי סוכן | פעולת חילוץ PDF הייתה-קשורה ל-tg:PDFExtractor |
|
||||
=======
|
||||
| `prov:wasDerivedFrom` | ישות שמקורה בישות אחרת | עמוד wasDerivedFrom מסמך |
|
||||
| `prov:wasGeneratedBy` | ישות שנוצרה על ידי פעילות | עמוד wasGeneratedBy PDFExtractionActivity |
|
||||
| `prov:used` | פעילות השתמשה בישות כקלט | PDFExtractionActivity used Document |
|
||||
| `prov:wasAssociatedWith` | פעילות בוצעה על ידי סוכן | PDFExtractionActivity wasAssociatedWith tg:PDFExtractor |
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### מטא-נתונים בכל רמה
|
||||
|
||||
**מסמך מקור (נפלט על ידי הספרן):**
|
||||
```
|
||||
doc:123 a prov:Entity .
|
||||
doc:123 dc:title "Research Paper" .
|
||||
doc:123 dc:source <https://example.com/paper.pdf> .
|
||||
doc:123 dc:date "2024-01-15" .
|
||||
doc:123 dc:creator "Author Name" .
|
||||
doc:123 tg:pageCount 42 .
|
||||
doc:123 tg:mimeType "application/pdf" .
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
**עמוד (נפלט על ידי מופשט PDF):**
|
||||
=======
|
||||
**עמוד (נפלט על ידי מחלץ PDF):**
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
```
|
||||
page:123-1 a prov:Entity .
|
||||
page:123-1 prov:wasDerivedFrom doc:123 .
|
||||
page:123-1 prov:wasGeneratedBy activity:pdf-extract-456 .
|
||||
page:123-1 tg:pageNumber 1 .
|
||||
|
||||
activity:pdf-extract-456 a prov:Activity .
|
||||
activity:pdf-extract-456 prov:used doc:123 .
|
||||
activity:pdf-extract-456 prov:wasAssociatedWith tg:PDFExtractor .
|
||||
activity:pdf-extract-456 tg:componentVersion "1.2.3" .
|
||||
activity:pdf-extract-456 prov:startedAtTime "2024-01-15T10:30:00Z" .
|
||||
```
|
||||
|
||||
**חלק (נפלט על ידי מודול החלוקה):**
|
||||
```
|
||||
chunk:123-1-1 a prov:Entity .
|
||||
chunk:123-1-1 prov:wasDerivedFrom page:123-1 .
|
||||
chunk:123-1-1 prov:wasGeneratedBy activity:chunk-789 .
|
||||
chunk:123-1-1 tg:chunkIndex 1 .
|
||||
chunk:123-1-1 tg:charOffset 0 .
|
||||
chunk:123-1-1 tg:charLength 2048 .
|
||||
|
||||
activity:chunk-789 a prov:Activity .
|
||||
activity:chunk-789 prov:used page:123-1 .
|
||||
activity:chunk-789 prov:wasAssociatedWith tg:Chunker .
|
||||
activity:chunk-789 tg:componentVersion "1.0.0" .
|
||||
activity:chunk-789 tg:chunkSize 2048 .
|
||||
activity:chunk-789 tg:chunkOverlap 200 .
|
||||
```
|
||||
|
||||
**משולש (נפלט על ידי מפיק ידע):**
|
||||
```
|
||||
# The extracted triple (edge)
|
||||
entity:JohnSmith rel:worksAt entity:AcmeCorp .
|
||||
|
||||
# Subgraph containing the extracted triples
|
||||
subgraph:001 tg:contains <<entity:JohnSmith rel:worksAt entity:AcmeCorp>> .
|
||||
subgraph:001 prov:wasDerivedFrom chunk:123-1-1 .
|
||||
subgraph:001 prov:wasGeneratedBy activity:extract-999 .
|
||||
|
||||
activity:extract-999 a prov:Activity .
|
||||
activity:extract-999 prov:used chunk:123-1-1 .
|
||||
activity:extract-999 prov:wasAssociatedWith tg:KnowledgeExtractor .
|
||||
activity:extract-999 tg:componentVersion "2.1.0" .
|
||||
activity:extract-999 tg:llmModel "claude-3" .
|
||||
activity:extract-999 tg:ontology <http://example.org/ontologies/business-v1> .
|
||||
```
|
||||
|
||||
**הטמעה (מאוחסנת במאגר וקטורים, ולא במאגר משולשות):**
|
||||
|
||||
הטמעות מאוחסנות במאגר הווקטורים עם מטא-נתונים, ולא כמשולשות RDF. כל רשומה של הטמעה מכילה:
|
||||
|
||||
| שדה | תיאור | דוגמה |
|
||||
|-------|-------------|---------|
|
||||
| וקטור | וקטור ההטמעה | [0.123, -0.456, ...] |
|
||||
| ישות | מזהה צומת שההטמעה מייצגת | `entity:JohnSmith` |
|
||||
| מזהה_קטע | קטע מקור (מקור) | `chunk:123-1-1` |
|
||||
| מודל | מודל הטמעה ששימש | `text-embedding-ada-002` |
|
||||
| גרסת_רכיב | גרסת הטמעת TG | `1.0.0` |
|
||||
|
||||
השדה `entity` מקשר את ההטמעה לגרף הידע (מזהה צומת). השדה `chunk_id` מספק מידע על המקור חזרה לקטע המקור, ומאפשר מעבר במבנה ה-DAG אל המסמך המקורי.
|
||||
|
||||
#### הרחבות מרחב השמות של TrustGraph
|
||||
|
||||
פרדיקטים מותאמים אישית תחת מרחב השמות `tg:` עבור מטא-נתונים ספציפיים לחילוץ:
|
||||
|
||||
| פרדיקט | תחום | תיאור |
|
||||
|-----------|--------|-------------|
|
||||
| `tg:contains` | תת-גרף | מצביע על משולש הכלול בתת-גרף החילוץ הזה |
|
||||
| `tg:pageCount` | מסמך | מספר כולל של עמודים במסמך המקור |
|
||||
| `tg:mimeType` | מסמך | סוג MIME של המסמך המקור |
|
||||
| `tg:pageNumber` | עמוד | מספר עמוד במסמך המקור |
|
||||
<<<<<<< HEAD
|
||||
| `tg:chunkIndex` | קטע | אינדקס של קטע בתוך הורה |
|
||||
| `tg:charOffset` | קטע | התאמה אופסט בטקסט הורה |
|
||||
| `tg:charLength` | קטע | אורך הקטע בתווים |
|
||||
| `tg:chunkSize` | פעילות | גודל קטע מוגדר |
|
||||
| `tg:chunkOverlap` | פעילות | חפיפה מוגדרת בין קטעים |
|
||||
| `tg:componentVersion` | פעילות | גרסת רכיב TG |
|
||||
=======
|
||||
| `tg:chunkIndex` | קטע | אינדקס של קטע בתוך ההורה |
|
||||
| `tg:charOffset` | קטע | התאמה אופסט בטקסט ההורה |
|
||||
| `tg:charLength` | קטע | אורך הקטע בתווים |
|
||||
| `tg:chunkSize` | פעילות | גודל קטע מוגדר |
|
||||
| `tg:chunkOverlap` | פעילות | חפיפה מוגדרת בין קטעים |
|
||||
| `tg:componentVersion` | פעילות | גרסה של רכיב TG |
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
| `tg:llmModel` | פעילות | מודל LLM ששימש לחילוץ |
|
||||
| `tg:ontology` | פעילות | אונטולוגיה ששימשה להכוונת החילוץ |
|
||||
| `tg:embeddingModel` | פעילות | מודל ששימש להטמעות |
|
||||
| `tg:sourceText` | הצהרה | הטקסט המדויק ממנו חולצה משולשת |
|
||||
<<<<<<< HEAD
|
||||
| `tg:sourceCharOffset` | הצהרה | התאמה אופסט בתוך קטע שבו מתחיל הטקסט המקור |
|
||||
=======
|
||||
| `tg:sourceCharOffset` | הצהרה | התאמה אופסט בתוך הקטע שבו מתחיל הטקסט המקור |
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
| `tg:sourceCharLength` | הצהרה | אורך הטקסט המקור בתווים |
|
||||
|
||||
#### אתחול אוצר מילים (לכל אוסף)
|
||||
|
||||
<<<<<<< HEAD
|
||||
גרף הידע הוא ניטרלי אוטולוגי ומתחיל ריק. בעת כתיבת נתוני provenance של PROV-O לאוסף בפעם הראשונה, יש לאתחל את אוצר המילים עם תגיות RDF עבור כל מחלקות ופרדיקטים. זה מבטיח תצוגה קריאה על ידי בני אדם בשאילתות ובממשק המשתמש.
|
||||
=======
|
||||
גרף הידע הוא ניטרלי מבחינת אונטולוגיה ומתחיל ריק. בעת כתיבת נתוני provenance של PROV-O לאוסף בפעם הראשונה, יש לאתחל את אוצר המילים עם תגיות RDF עבור כל מחלקות ופרדיקטים. זה מבטיח תצוגה קריאה על ידי בני אדם בשאילתות ובממשק המשתמש.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**מחלקות PROV-O:**
|
||||
```
|
||||
prov:Entity rdfs:label "Entity" .
|
||||
prov:Activity rdfs:label "Activity" .
|
||||
prov:Agent rdfs:label "Agent" .
|
||||
```
|
||||
|
||||
**נשואים של PROV-O:**
|
||||
```
|
||||
prov:wasDerivedFrom rdfs:label "was derived from" .
|
||||
prov:wasGeneratedBy rdfs:label "was generated by" .
|
||||
prov:used rdfs:label "used" .
|
||||
prov:wasAssociatedWith rdfs:label "was associated with" .
|
||||
prov:startedAtTime rdfs:label "started at" .
|
||||
```
|
||||
|
||||
**משפטי TrustGraph:**
|
||||
```
|
||||
tg:contains rdfs:label "contains" .
|
||||
tg:pageCount rdfs:label "page count" .
|
||||
tg:mimeType rdfs:label "MIME type" .
|
||||
tg:pageNumber rdfs:label "page number" .
|
||||
tg:chunkIndex rdfs:label "chunk index" .
|
||||
tg:charOffset rdfs:label "character offset" .
|
||||
tg:charLength rdfs:label "character length" .
|
||||
tg:chunkSize rdfs:label "chunk size" .
|
||||
tg:chunkOverlap rdfs:label "chunk overlap" .
|
||||
tg:componentVersion rdfs:label "component version" .
|
||||
tg:llmModel rdfs:label "LLM model" .
|
||||
tg:ontology rdfs:label "ontology" .
|
||||
tg:embeddingModel rdfs:label "embedding model" .
|
||||
tg:sourceText rdfs:label "source text" .
|
||||
tg:sourceCharOffset rdfs:label "source character offset" .
|
||||
tg:sourceCharLength rdfs:label "source character length" .
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
**הערה בנושא יישום:** אוצר המילים הזה צריך להיות בעל תכונה של אידמפוטנטיות - בטוח להפעיל אותו מספר פעמים מבלי ליצור כפילויות. ניתן להפעיל אותו בפעם הראשונה בעיבוד מסמך באוסף, או כשלב נפרד של אתחול אוסף.
|
||||
|
||||
#### מקור של חלקים קטנים (שאפתני)
|
||||
|
||||
לצורך מעקב מקור מדויק יותר, יהיה שימושי לתעד בדיוק מאיפה בתוך חלק קטן נשלפה טריפלט. זה מאפשר:
|
||||
=======
|
||||
**הערה בנושא יישום:** אוצר המילים הזה צריך להיות בעל תכונה של "אידמפוטנטיות" - בטוח להפעיל אותו מספר פעמים מבלי ליצור כפילויות. ניתן להפעיל אותו בפעם הראשונה בעיבוד מסמך באוסף, או כשלב נפרד של אתחול אוסף.
|
||||
|
||||
#### מקור (Provenance) של תת-קטע (שאיפה)
|
||||
|
||||
לצורך מעקב מדויק יותר, יהיה מועיל לתעד בדיוק מאיפה בתוך קטע נשלפה טריפלט. זה מאפשר:
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
הדגשת הטקסט המדויק ממנו נשלף הטריפלט בממשק המשתמש
|
||||
אימות דיוק החילוץ מול המקור
|
||||
ניפוי באגים באיכות החילוץ ברמת המשפט
|
||||
|
||||
**דוגמה עם מעקב מיקום:**
|
||||
```
|
||||
# The extracted triple
|
||||
entity:JohnSmith rel:worksAt entity:AcmeCorp .
|
||||
|
||||
# Subgraph with sub-chunk provenance
|
||||
subgraph:001 tg:contains <<entity:JohnSmith rel:worksAt entity:AcmeCorp>> .
|
||||
subgraph:001 prov:wasDerivedFrom chunk:123-1-1 .
|
||||
subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" .
|
||||
subgraph:001 tg:sourceCharOffset 1547 .
|
||||
subgraph:001 tg:sourceCharLength 46 .
|
||||
```
|
||||
|
||||
**דוגמה עם טווח טקסט (חלופה):**
|
||||
```
|
||||
subgraph:001 tg:contains <<entity:JohnSmith rel:worksAt entity:AcmeCorp>> .
|
||||
subgraph:001 prov:wasDerivedFrom chunk:123-1-1 .
|
||||
subgraph:001 tg:sourceRange "1547-1593" .
|
||||
subgraph:001 tg:sourceText "John Smith has worked at Acme Corp since 2019" .
|
||||
```
|
||||
|
||||
**שיקולי יישום:**
|
||||
|
||||
<<<<<<< HEAD
|
||||
חילוץ מבוסס מודל שפה גדול (LLM) עשוי שלא לספק באופן טבעי מיקומי תווים.
|
||||
ניתן לבקש מה-LLM להחזיר את המשפט/הביטוי המקורי יחד עם הטריפלים החילוצים.
|
||||
לחלופין, ניתן לבצע עיבוד לאחר החילוץ כדי להתאים את הישויות החילוצות בחזרה לטקסט המקור.
|
||||
איזון בין מורכבות החילוץ ובין רמת הפירוט של מקור המידע.
|
||||
ייתכן שיהיה קל יותר להשיג זאת באמצעות שיטות חילוץ מובנות מאשר חילוץ חופשי מבוסס LLM.
|
||||
|
||||
זה מסומן כשאיפה - יש ליישם תחילה את מקור המידע ברמת החלקים, כאשר מעקב אחר תת-חלקים הוא שיפור עתידי אם אפשרי.
|
||||
|
||||
### מודל אחסון כפול
|
||||
|
||||
גרף מקור המידע נבנה בהדרגה ככל שהמסמכים עוברים דרך הצינור:
|
||||
|
||||
| אחסון | מה מאוחסן | מטרה |
|
||||
|-------|---------------|---------|
|
||||
| ספרן (Librarian) | תוכן מסמך + קישורים הורה-ילד | אחזור תוכן, מחיקה מדורגת |
|
||||
| גרף ידע (Knowledge Graph) | קצוות הורה-ילד + מטא-נתונים | שאילתות מקור מידע, ייחוס עובדות |
|
||||
|
||||
שני האחסונים שומרים על מבנה גרף זהה. הספרן שומר על התוכן; הגרף שומר על קשרים ומאפשר שאילתות מעבר.
|
||||
|
||||
### עקרונות עיצוב מרכזיים
|
||||
|
||||
1. **מזהה מסמך כיחידת זרימה** - מעבדים מעבירים מזהים, לא תוכן. התוכן נשאב מהספרן בעת הצורך.
|
||||
|
||||
2. **פליטה חד-פעמית במקור** - מטא-נתונים נכתבים לגרף פעם אחת בתחילת העיבוד, ולא חוזרים על עצמם במעלה הצינור.
|
||||
|
||||
3. **תבנית מעבד עקבית** - כל מעבד פועל לפי אותה תבנית של קבלה/שאילתא/יצירה/שמירה/פליטה/העברה.
|
||||
|
||||
4. **בניית גרף הדרגתית** - כל מעבד מוסיף את השכבה שלו לגרף. שרשרת מקור המידע השלמה נבנית בהדרגה.
|
||||
|
||||
5. **אופטימיזציה לאחר חלוקה לחלקים** - לאחר חלוקה לחלקים, הודעות נושאות גם מזהה וגם תוכן. החלקים קטנים (2-4KB), כך שכלול התוכן מונע מעברים מיותרים לספרן תוך שמירה על מקור המידע באמצעות המזהה.
|
||||
=======
|
||||
חילוץ מבוסס מודל שפה גדול (LLM) עשוי שלא לספק באופן טבעי מיקומי תווים
|
||||
ניתן לבקש מה-LLM להחזיר את המשפט/הביטוי המקורי יחד עם הטריפלים החולצים
|
||||
לחלופין, ניתן לבצע עיבוד לאחר החילוץ כדי להתאים את הישויות החולצות בחזרה לטקסט המקור
|
||||
פשרה בין מורכבות החילוץ וגרנולריות המקור
|
||||
ייתכן שיהיה קל יותר להשיג זאת באמצעות שיטות חילוץ מובנות מאשר חילוץ LLM חופשי
|
||||
|
||||
זה מסומן כשאיפה - יש ליישם תחילה את המקור הבסיסי ברמת החלקים, כאשר מעקב אחר תת-חלקים הוא שיפור עתידי אם זה אפשרי.
|
||||
|
||||
### מודל אחסון כפול
|
||||
|
||||
גרף המקור נבנה בהדרגה ככל שהמסמכים עוברים דרך הצינור:
|
||||
|
||||
| חנות | מה מאוחסן | מטרה |
|
||||
|-------|---------------|---------|
|
||||
| ספרן | תוכן מסמך + קישורים הורה-ילד | אחזור תוכן, מחיקה מדורגת |
|
||||
| גרף ידע | קצוות הורה-ילד + מטא-נתונים | שאילתות מקור, הקצאת עובדות |
|
||||
|
||||
שתי החנויות שומרות על מבנה גרף זהה. הספרן מחזיק בתוכן; הגרף מחזיק ביחסים ומאפשר שאילתות ניווט.
|
||||
|
||||
### עקרונות עיצוב מרכזיים
|
||||
|
||||
1. **מזהה מסמך כיחידת זרימה** - מעבדים מעבירים מזהים, לא תוכן. תוכן נשאב מהספרן בעת הצורך.
|
||||
|
||||
2. **פליטה פעם אחת במקור** - מטא-נתונים נכתבים לגרף פעם אחת כאשר עיבוד מתחיל, ולא חוזרים על עצמם במורד הזרם.
|
||||
|
||||
3. **דפוס מעבד עקבי** - כל מעבד עוקב אחר דפוס קבלה/שאילתא/יצירה/שמירה/פליטה/העברה זהה.
|
||||
|
||||
4. **בניית גרף הדרגתית** - כל מעבד מוסיף את השכבה שלו לגרף. שרשרת המקור השלמה נבנית באופן מצטבר.
|
||||
|
||||
5. **אופטימיזציה לאחר חלוקה לחלקים** - לאחר חלוקה לחלקים, הודעות נושאות גם מזהה וגם תוכן. החלקים קטנים (2-4KB), כך שכלול התוכן נמנע ממסעות הלוך ושוב מיותרים לספרן תוך שמירה על המקור באמצעות המזהה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## משימות יישום
|
||||
|
||||
### שינויים בספרן
|
||||
|
||||
#### מצב נוכחי
|
||||
|
||||
<<<<<<< HEAD
|
||||
מתחיל עיבוד מסמכים על ידי שליחת מזהה מסמך למעבד הראשון.
|
||||
אין חיבור למאגר טריפלים - מטא-נתונים נכללים בפלט החילוץ.
|
||||
`add-child-document` יוצר קישורים הורה-ילד ברמה אחת.
|
||||
`list-children` מחזיר רק ילדים מיידיים.
|
||||
=======
|
||||
מתחיל עיבוד מסמכים על ידי שליחת מזהה מסמך למעבד הראשון
|
||||
אין חיבור למאגר טריפלים - מטא-נתונים מקובצים עם פלטי חילוץ
|
||||
`add-child-document` יוצר קישורים הורה-ילד חד-שכבתיים
|
||||
`list-children` מחזיר רק ילדים מיידיים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### שינויים נדרשים
|
||||
|
||||
**1. ממשק חדש: חיבור למאגר טריפלים**
|
||||
|
||||
<<<<<<< HEAD
|
||||
הספרן צריך לפלוט קצוות מטא-נתונים של מסמכים ישירות לגרף הידע בעת התחלת העיבוד.
|
||||
הוספת לקוח/מפרסם של מאגר טריפלים לשירות הספרן.
|
||||
בעת התחלת עיבוד: פליטת מטא-נתונים של מסמך השורש כקצוות גרף (פעם אחת).
|
||||
|
||||
**2. אוצר מילים של סוגי מסמכים**
|
||||
|
||||
סטנדרטיזציה של ערכים `document_type` עבור מסמכי ילד:
|
||||
`source` - מסמך שהועלה במקור.
|
||||
`page` - עמוד שחולץ מהמקור (PDF, וכו').
|
||||
`chunk` - חלק טקסט שמקורו בעמוד או במקור.
|
||||
|
||||
#### סיכום שינויים בממשק
|
||||
|
||||
| ממשק | שינוי |
|
||||
|-----------|--------|
|
||||
| מאגר טריפלים | חיבור יוצא חד - פליטת קצוות מטא-נתונים של מסמכים |
|
||||
| התחלת עיבוד | פליטת מטא-נתונים לגרף לפני העברת מזהה מסמך |
|
||||
=======
|
||||
הספרן צריך לפלוט קצוות מטא-נתונים של מסמכים ישירות לגרף הידע בעת התחלת עיבוד.
|
||||
הוסף לקוח/מפרסם של מאגר טריפלים לשירות הספרן
|
||||
בעת התחלת עיבוד: פלט מטא-נתונים של מסמך שורש כקצוות גרף (פעם אחת)
|
||||
|
||||
**2. אוצר מילים של סוגי מסמכים**
|
||||
|
||||
תקנן ערכים של `document_type` עבור מסמכי ילד:
|
||||
`source` - מסמך שהועלה במקור
|
||||
`page` - עמוד שחולץ מהמקור (PDF, וכו')
|
||||
`chunk` - חלק טקסט שמקורו בעמוד או במקור
|
||||
|
||||
#### סיכום שינויי ממשק
|
||||
|
||||
| ממשק | שינוי |
|
||||
|-----------|--------|
|
||||
| מאגר טריפלים | חיבור יוצא חד - פלט קצוות מטא-נתונים של מסמכים |
|
||||
| התחלת עיבוד | פלט מטא-נתונים לגרף לפני העברת מזהה מסמך |
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### שינויים בחולץ PDF
|
||||
|
||||
#### מצב נוכחי
|
||||
|
||||
<<<<<<< HEAD
|
||||
מקבל תוכן מסמך (או זורם מסמכים גדולים).
|
||||
מחלץ טקסט מעמודי PDF.
|
||||
מעביר תוכן עמוד לחולץ חלקים.
|
||||
אין אינטראקציה עם הספרן או מאגר הטריפלים.
|
||||
=======
|
||||
מקבל תוכן מסמך (או זורם מסמכים גדולים)
|
||||
מחלץ טקסט מעמודי PDF
|
||||
מעביר תוכן עמוד לחולץ
|
||||
אין אינטראקציה עם הספרן או מאגר הטריפלים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### שינויים נדרשים
|
||||
|
||||
**1. ממשק חדש: לקוח ספרן**
|
||||
|
||||
חולץ PDF צריך לשמור כל עמוד כמסמך ילד בספרן.
|
||||
<<<<<<< HEAD
|
||||
הוספת לקוח ספרן לשירות חולץ PDF.
|
||||
עבור כל עמוד: קריאה ל-`add-child-document` עם מזהה הורה = מזהה מסמך השורש.
|
||||
=======
|
||||
הוסף לקוח ספרן לשירות חולץ PDF
|
||||
עבור כל עמוד: התקשר ל-`add-child-document` עם parent = מזהה מסמך שורש
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**2. ממשק חדש: חיבור למאגר טריפלים**
|
||||
|
||||
חולץ PDF צריך לפלוט קצוות הורה-ילד לגרף הידע.
|
||||
<<<<<<< HEAD
|
||||
הוספת לקוח/מפרסם של מאגר טריפלים.
|
||||
עבור כל עמוד: פליטת קצה המקשר עמוד מסמך למסמך הורה.
|
||||
|
||||
**3. שינוי פורמט פלט**
|
||||
פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא).
|
||||
=======
|
||||
הוסף לקוח/מפרסם של מאגר טריפלים
|
||||
עבור כל עמוד: פלט קצה המקשר את מסמך העמוד למסמך הורה
|
||||
|
||||
**3. שנה פורמט פלט**
|
||||
פלט חוזה (יש לעקוב אחר הפורמט המדויק).
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
במקום להעביר ישירות את תוכן העמוד, יש להעביר את מזהה המסמך של העמוד.
|
||||
ה-Chunker ישלוף את התוכן מה-librarian באמצעות המזהה.
|
||||
|
||||
#### סיכום שינויים בממשק
|
||||
|
||||
| ממשק | שינוי |
|
||||
|-----------|--------|
|
||||
| Librarian | יציאה חדשה - שמירת מסמכים ילדים |
|
||||
| Triple store | יציאה חדשה - פליטת קשרים הורה-ילד |
|
||||
| הודעת פלט | שינוי מתוכן למזהה מסמך |
|
||||
|
||||
### שינויים ב-Chunker
|
||||
|
||||
#### מצב נוכחי
|
||||
|
||||
מקבל תוכן עמוד/טקסט
|
||||
מחלק לחלקים
|
||||
מעביר את תוכן החלק למעבדים downstream
|
||||
אין אינטראקציה עם ה-librarian או ה-triple store
|
||||
|
||||
#### שינויים נדרשים
|
||||
|
||||
**1. שינוי טיפול בקלט**
|
||||
|
||||
<<<<<<< HEAD
|
||||
לקבל מזהה מסמך במקום תוכן, לשלוף מה-librarian.
|
||||
להוסיף לקוח librarian לשירות ה-chunker
|
||||
לשלוף תוכן עמוד באמצעות מזהה מסמך
|
||||
|
||||
**2. ממשק חדש: לקוח Librarian (כתיבה)**
|
||||
|
||||
לשמור כל חלק כמסמך ילד ב-librarian.
|
||||
עבור כל חלק: לקרוא לפונקציה `add-child-document` עם parent = מזהה מסמך העמוד
|
||||
|
||||
**3. ממשק חדש: חיבור ל-Triple store**
|
||||
|
||||
לפלוט קשרים הורה-ילד לגרף הידע.
|
||||
להוסיף לקוח/מפרסם triple store
|
||||
עבור כל חלק: לפלוט קשר המקשר בין מסמך החלק למסמך העמוד
|
||||
|
||||
**4. שינוי פורמט פלט**
|
||||
|
||||
להעביר גם את מזהה מסמך החלק וגם את תוכן החלק (אופטימיזציה לאחר ה-chunker).
|
||||
מעבדים downstream מקבלים מזהה לצורך מעקב מקור + תוכן לעבודה איתו
|
||||
=======
|
||||
יש לקבל מזהה מסמך במקום תוכן, ולשלוף אותו מה-librarian.
|
||||
יש להוסיף לקוח librarian לשירות ה-chunker
|
||||
יש לשלוף את תוכן העמוד באמצעות מזהה המסמך
|
||||
|
||||
**2. ממשק חדש: לקוח Librarian (כתיבה)**
|
||||
|
||||
יש לשמור כל חלק כמסמך ילד ב-librarian.
|
||||
עבור כל חלק: יש לקרוא ל-`add-child-document` עם parent = מזהה מסמך העמוד
|
||||
|
||||
**3. ממשק חדש: חיבור ל-Triple store**
|
||||
|
||||
יש לפלוט קשרים הורה-ילד לגרף הידע.
|
||||
יש להוסיף לקוח/מפרסם triple store
|
||||
עבור כל חלק: יש לפלוט קשר המקשר בין מסמך החלק למסמך העמוד
|
||||
|
||||
**4. שינוי פורמט פלט**
|
||||
|
||||
יש להעביר גם את מזהה מסמך החלק וגם את תוכן החלק (אופטימיזציה לאחר חלוקה).
|
||||
מעבדים downstream מקבלים מזהה לצורך מעקב מקור + תוכן לעבודה
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### סיכום שינויים בממשק
|
||||
|
||||
| ממשק | שינוי |
|
||||
|-----------|--------|
|
||||
| הודעת קלט | שינוי מתוכן למזהה מסמך |
|
||||
| Librarian | יציאה חדשה (קריאה + כתיבה) - שליפת תוכן, שמירת מסמכים ילדים |
|
||||
| Triple store | יציאה חדשה - פליטת קשרים הורה-ילד |
|
||||
<<<<<<< HEAD
|
||||
| הודעת פלט | שינוי מתוכן בלבד ל-ID + תוכן |
|
||||
=======
|
||||
| הודעת פלט | שינוי מתוכן בלבד ל-מזהה + תוכן |
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### שינויים ב-Knowledge Extractor
|
||||
|
||||
#### מצב נוכחי
|
||||
|
||||
<<<<<<< HEAD
|
||||
מקבל תוכן חלק
|
||||
=======
|
||||
מקבל תוכן של חלק
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
מחלץ טריפל ו-embeddings
|
||||
פולט ל-triple store ול-embedding store
|
||||
`subjectOf` הקשר מצביע למסמך ברמה העליונה (ולא לחלק)
|
||||
|
||||
#### שינויים נדרשים
|
||||
|
||||
**1. שינוי טיפול בקלט**
|
||||
|
||||
<<<<<<< HEAD
|
||||
לקבל מזהה מסמך חלק יחד עם התוכן.
|
||||
להשתמש במזהה החלק לצורך קישור מעקב מקור (תוכן כלול כבר בהתאם לאופטימיזציה)
|
||||
|
||||
**2. עדכון מעקב טריפל**
|
||||
|
||||
לקשר טריפל מחולץ לחלק (ולא למסמך ברמה העליונה).
|
||||
להשתמש ב-reification ליצירת קשר המצביע לקשר
|
||||
`subjectOf` הקשר: טריפל → מזהה מסמך חלק
|
||||
=======
|
||||
יש לקבל מזהה מסמך של חלק יחד עם התוכן.
|
||||
יש להשתמש במזהה החלק לצורך קישור מעקב מקור (תוכן כלול כבר בהתאם לאופטימיזציה)
|
||||
|
||||
**2. עדכון מעקב טריפל**
|
||||
|
||||
יש לקשר טריפל מחולץ לחלק (ולא למסמך ברמה העליונה).
|
||||
יש להשתמש ב-reification ליצירת קשר המצביע לקשר
|
||||
`subjectOf` קשר: טריפל → מזהה מסמך של חלק
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
שימוש ראשון בתמיכה קיימת ב-reification
|
||||
|
||||
**3. עדכון מעקב embedding**
|
||||
|
||||
<<<<<<< HEAD
|
||||
לקשר מזהי ישויות embedding לחלק.
|
||||
לפלוט קשר: מזהה ישות embedding → מזהה מסמך חלק
|
||||
=======
|
||||
יש לקשר מזהי ישויות embedding לחלק.
|
||||
יש לפלוט קשר: מזהה ישות embedding → מזהה מסמך של חלק
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### סיכום שינויים בממשק
|
||||
|
||||
| ממשק | שינוי |
|
||||
|-----------|--------|
|
||||
| הודעת קלט | מצפים למזהה חלק + תוכן (ולא רק תוכן) |
|
||||
<<<<<<< HEAD
|
||||
| Triple store | להשתמש ב-reification למעקב טריפל → חלק |
|
||||
| מעקב embedding | לקשר מזהה ישות → מזהה חלק |
|
||||
=======
|
||||
| Triple store | שימוש ב-reification למעקב טריפל → חלק |
|
||||
| מעקב embedding | קישור מזהה ישות → מזהה חלק |
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## הפניות
|
||||
|
||||
מעקב בזמן שאילתה: `docs/tech-specs/query-time-provenance.md`
|
||||
תקן PROV-O למודל מעקב מקור
|
||||
מטא-נתונים קיימים ממקור בגרף הידע (דורש ביקורת)
|
||||
328
docs/tech-specs/he/flow-class-definition.he.md
Normal file
328
docs/tech-specs/he/flow-class-definition.he.md
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
---
|
||||
layout: default
|
||||
title: "הגדרת מפרט תוכנית זרימה"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
<<<<<<< HEAD
|
||||
# הגדרת מפרט תוכנית זרימה
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
=======
|
||||
# מפרט הגדרת תוכנית זרימה
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
תוכנית זרימה מגדירה תבנית מלאה של דפוסי זרימת נתונים במערכת TrustGraph. כאשר היא מופעלת, היא יוצרת רשת מקושרת של מעבדים המטפלים בקליטת נתונים, עיבוד, אחסון ושליפה כחלק ממערכת מאוחדת.
|
||||
|
||||
## מבנה
|
||||
|
||||
הגדרת תוכנית זרימה מורכבת מחמש קטעים עיקריים:
|
||||
|
||||
### 1. קטע מחלקה
|
||||
<<<<<<< HEAD
|
||||
מגדיר מעבדי שירות משותפים המופעלים פעם אחת לכל תוכנית זרימה. מעבדים אלה מטפלים בבקשות מכל מופעי הזרימה של מחלקה זו.
|
||||
=======
|
||||
מגדיר מעבדים משותפים המופעלים פעם אחת לכל תוכנית זרימה. מעבדים אלה מטפלים בבקשות מכל מופעי הזרימה של מחלקה זו.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```json
|
||||
"class": {
|
||||
"service-name:{class}": {
|
||||
"request": "queue-pattern:{class}",
|
||||
"response": "queue-pattern:{class}",
|
||||
"settings": {
|
||||
"setting-name": "fixed-value",
|
||||
"parameterized-setting": "{parameter-name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**מאפיינים:**
|
||||
משותפים לכל מופעי זרימה מאותו סוג.
|
||||
בדרך כלל שירותים יקרים או חסרי מצב (מודלים של שפה גדולים, מודלים להטמעה).
|
||||
השתמשו במשתנה תבנית `{class}` עבור שמות תורים.
|
||||
הגדרות יכולות להיות ערכים קבועים או פרמטריות באמצעות תחביר `{parameter-name}`.
|
||||
דוגמאות: `embeddings:{class}`, `text-completion:{class}`, `graph-rag:{class}`
|
||||
|
||||
### 2. סעיף זרימה
|
||||
<<<<<<< HEAD
|
||||
מגדיר מעבדים ספציפיים לזרימה, אשר מופעלים עבור כל מופע זרימה בודד. לכל זרימה יש סט נפרד משלה של מעבדים אלה.
|
||||
=======
|
||||
מגדיר מעבדים ספציפיים לזרימה אשר מופעלים עבור כל מופע זרימה בודד. לכל זרימה יש סט נפרד משלה של מעבדים אלה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```json
|
||||
"flow": {
|
||||
"processor-name:{id}": {
|
||||
"input": "queue-pattern:{id}",
|
||||
"output": "queue-pattern:{id}",
|
||||
"settings": {
|
||||
"setting-name": "fixed-value",
|
||||
"parameterized-setting": "{parameter-name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**מאפיינים:**
|
||||
מופע ייחודי לכל זרימה
|
||||
טיפול בנתונים ובמצב ספציפיים לזרימה
|
||||
שימוש במשתנה תבנית `{id}` עבור שמות תורים
|
||||
הגדרות יכולות להיות ערכים קבועים או פרמטריות באמצעות תחביר `{parameter-name}`
|
||||
דוגמאות: `chunker:{id}`, `pdf-decoder:{id}`, `kg-extract-relationships:{id}`
|
||||
|
||||
### 3. סעיף ממשקים
|
||||
מגדיר את נקודות הכניסה ואת חוזי האינטראקציה עבור הזרימה. אלה מהווים את ממשק ה-API עבור מערכות חיצוניות ותקשורת בין רכיבים פנימיים.
|
||||
|
||||
ממשקים יכולים לקבל שתי צורות:
|
||||
|
||||
<<<<<<< HEAD
|
||||
**תבנית "שלח ושכח"** (תור יחיד):
|
||||
=======
|
||||
**תבנית "שלח והשכח"** (תור יחיד):
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
```json
|
||||
"interfaces": {
|
||||
"document-load": "persistent://tg/flow/document-load:{id}",
|
||||
"triples-store": "persistent://tg/flow/triples-store:{id}"
|
||||
}
|
||||
```
|
||||
|
||||
**תבנית בקשה/תגובה** (אובייקט עם שדות בקשה/תגובה):
|
||||
```json
|
||||
"interfaces": {
|
||||
"embeddings": {
|
||||
"request": "non-persistent://tg/request/embeddings:{class}",
|
||||
"response": "non-persistent://tg/response/embeddings:{class}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**סוגי ממשקים:**
|
||||
<<<<<<< HEAD
|
||||
**נקודות כניסה:** נקודות שבהן מערכות חיצוניות מזריקות נתונים (`document-load`, `agent`)
|
||||
**ממשקי שירות:** תבניות בקשה/תגובה עבור שירותים (`embeddings`, `text-completion`)
|
||||
**ממשקי נתונים:** נקודות חיבור לזרימת נתונים מסוג "שלח וסגור" (`triples-store`, `entity-contexts-load`)
|
||||
=======
|
||||
**נקודות כניסה:** נקודות בהן מערכות חיצוניות מזריקות נתונים (`document-load`, `agent`)
|
||||
**ממשקי שירות:** תבניות בקשה/תגובה עבור שירותים (`embeddings`, `text-completion`)
|
||||
**ממשקי נתונים:** נקודות חיבור לזרימת נתונים מסוג "שלח ושים" (`triples-store`, `entity-contexts-load`)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### 4. סעיף פרמטרים
|
||||
ממפה שמות פרמטרים ספציפיים לזרימה להגדרות פרמטרים המאוחסנות באופן מרכזי:
|
||||
|
||||
```json
|
||||
"parameters": {
|
||||
"model": "llm-model",
|
||||
"temp": "temperature",
|
||||
"chunk": "chunk-size"
|
||||
}
|
||||
```
|
||||
|
||||
**מאפיינים:**
|
||||
המפתחות הם שמות הפרמטרים המשמשים בהגדרות המעבד (לדוגמה, `{model}`)
|
||||
הערכים מפנים להגדרות הפרמטרים המאוחסנות ב-schema/config
|
||||
מאפשר שימוש חוזר בהגדרות פרמטרים נפוצות בין זרימות
|
||||
מפחית כפילויות של סכימות פרמטרים
|
||||
|
||||
### 5. מטא-נתונים
|
||||
מידע נוסף על תוכנית הזרימה:
|
||||
|
||||
```json
|
||||
"description": "Human-readable description",
|
||||
"tags": ["capability-1", "capability-2"]
|
||||
```
|
||||
|
||||
## משתנים בתבנית
|
||||
|
||||
### משתנים של המערכת
|
||||
|
||||
#### {id}
|
||||
מוחלף במזהה הייחודי של מופע ה-flow
|
||||
יוצר משאבים מבודדים עבור כל flow
|
||||
דוגמה: `flow-123`, `customer-A-flow`
|
||||
|
||||
#### {class}
|
||||
מוחלף בשם התבנית של ה-flow
|
||||
יוצר משאבים משותפים בין flows של אותה תבנית
|
||||
דוגמה: `standard-rag`, `enterprise-rag`
|
||||
|
||||
### משתנים של פרמטרים
|
||||
|
||||
#### {parameter-name}
|
||||
פרמטרים מותאמים אישית המוגדרים בזמן הפעלת ה-flow
|
||||
שמות הפרמטרים תואמים למפתחות במקטע `parameters` של ה-flow
|
||||
משמש בהגדרות של מעבדים כדי להתאים אישית את ההתנהגות
|
||||
דוגמאות: `{model}`, `{temp}`, `{chunk}`
|
||||
מוחלף בערכים המסופקים בעת הפעלת ה-flow
|
||||
<<<<<<< HEAD
|
||||
מאומתים מול הגדרות פרמטרים המאוחסנות באופן מרכזי
|
||||
=======
|
||||
מאומתים מול הגדרות פרמטרים המאוחסנות במרכז
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## הגדרות מעבד
|
||||
|
||||
הגדרות מספקות ערכי תצורה למעבדים בזמן יצירתם. ניתן להגדיר אותן כ:
|
||||
|
||||
### הגדרות קבועות
|
||||
ערכים ישירים שאינם משתנים:
|
||||
```json
|
||||
"settings": {
|
||||
"model": "gemma3:12b",
|
||||
"temperature": 0.7,
|
||||
"max_retries": 3
|
||||
}
|
||||
```
|
||||
|
||||
### הגדרות מותאמות אישית
|
||||
ערכים המשתמשים בפרמטרים המסופקים בעת הפעלת ה-flow:
|
||||
```json
|
||||
"settings": {
|
||||
"model": "{model}",
|
||||
"temperature": "{temp}",
|
||||
"endpoint": "https://{region}.api.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
שמות הפרמטרים בהגדרות תואמים למפתחות במקטע `parameters` של ה-flow.
|
||||
|
||||
### דוגמאות להגדרות
|
||||
|
||||
**מעבד LLM עם פרמטרים:**
|
||||
```json
|
||||
// In parameters section:
|
||||
"parameters": {
|
||||
"model": "llm-model",
|
||||
"temp": "temperature",
|
||||
"tokens": "max-tokens",
|
||||
"key": "openai-api-key"
|
||||
}
|
||||
|
||||
// In processor definition:
|
||||
"text-completion:{class}": {
|
||||
"request": "non-persistent://tg/request/text-completion:{class}",
|
||||
"response": "non-persistent://tg/response/text-completion:{class}",
|
||||
"settings": {
|
||||
"model": "{model}",
|
||||
"temperature": "{temp}",
|
||||
"max_tokens": "{tokens}",
|
||||
"api_key": "{key}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**חלוקה למקטעים עם הגדרות קבועות וניתנות לשינוי:**
|
||||
```json
|
||||
// In parameters section:
|
||||
"parameters": {
|
||||
"chunk": "chunk-size"
|
||||
}
|
||||
|
||||
// In processor definition:
|
||||
"chunker:{id}": {
|
||||
"input": "persistent://tg/flow/chunk:{id}",
|
||||
"output": "persistent://tg/flow/chunk-load:{id}",
|
||||
"settings": {
|
||||
"chunk_size": "{chunk}",
|
||||
"chunk_overlap": 100,
|
||||
"encoding": "utf-8"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## תבניות תורים (פולסר)
|
||||
|
||||
תבניות זרימה משתמשות ב-Apache Pulsar עבור העברת הודעות. שמות התורים עוקבים אחר הפורמט של פולסר:
|
||||
```
|
||||
<persistence>://<tenant>/<namespace>/<topic>
|
||||
```
|
||||
|
||||
### רכיבים:
|
||||
**persistence**: `persistent` או `non-persistent` (מצב אחסון של Pulsar)
|
||||
**tenant**: `tg` עבור הגדרות תבניות זרימה המסופקות על ידי TrustGraph
|
||||
**namespace**: מציין את דפוס העברת ההודעות
|
||||
`flow`: שירותים מסוג "שלח וגע" (fire-and-forget)
|
||||
<<<<<<< HEAD
|
||||
`request`: החלק של הבקשה בשירותי בקשה/תגובה (request/response)
|
||||
`response`: החלק של התגובה בשירותי בקשה/תגובה (request/response)
|
||||
=======
|
||||
`request`: החלק של הבקשה בשירותי "בקשה/תגובה" (request/response)
|
||||
`response`: החלק של התגובה בשירותי "בקשה/תגובה" (request/response)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**topic**: שם התור/נושא הספציפי עם משתני תבנית
|
||||
|
||||
### תורים קבועים (Persistent Queues)
|
||||
דפוס: `persistent://tg/flow/<topic>:{id}`
|
||||
משמש עבור שירותים מסוג "שלח וגע" וזרימת נתונים עמידה
|
||||
<<<<<<< HEAD
|
||||
הנתונים נשמרים באחסון של Pulsar בין הפעלות מחדש
|
||||
=======
|
||||
הנתונים נשמרים באחסון של Pulsar גם לאחר אתחולים מחדש
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
דוגמה: `persistent://tg/flow/chunk-load:{id}`
|
||||
|
||||
### תורים לא קבועים (Non-Persistent Queues)
|
||||
דפוס: `non-persistent://tg/request/<topic>:{class}` או `non-persistent://tg/response/<topic>:{class}`
|
||||
<<<<<<< HEAD
|
||||
משמש עבור דפוסי העברת הודעות מסוג בקשה/תגובה
|
||||
=======
|
||||
משמש עבור דפוסי העברת הודעות מסוג "בקשה/תגובה"
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
זמני, אינו נשמר בדיסק על ידי Pulsar
|
||||
השהיה נמוכה יותר, מתאים לתקשורת בסגנון RPC
|
||||
דוגמה: `non-persistent://tg/request/embeddings:{class}`
|
||||
|
||||
## ארכיטקטורת זרימת נתונים
|
||||
|
||||
תבנית זרימת הנתונים יוצרת זרימה מאוחדת שבה:
|
||||
|
||||
1. **צינור עיבוד מסמכים**: זרימה מאיסוף דרך טרנספורמציה לאחסון
|
||||
2. **שירותי שאילתות**: מעבדים משולבים השואלים את אותם מאגרי נתונים ושירותים
|
||||
3. **שירותים משותפים**: מעבדים מרכזיים שכל הזרימות יכולות להשתמש בהם
|
||||
4. **כותבי אחסון**: שומרים נתונים מעובדים לאחסונים המתאימים
|
||||
|
||||
כל המעבדים (גם `{id}` וגם `{class}`) עובדים יחד כגרף זרימת נתונים מגובש, ולא כמערכות נפרדות.
|
||||
|
||||
## דוגמה להפעלה של זרימה
|
||||
|
||||
בהינתן:
|
||||
מזהה מופע של זרימה: `customer-A-flow`
|
||||
תבנית זרימה: `standard-rag`
|
||||
מיפוי פרמטרים של זרימה:
|
||||
`"model": "llm-model"`
|
||||
`"temp": "temperature"`
|
||||
`"chunk": "chunk-size"`
|
||||
פרמטרים שסופקו על ידי המשתמש:
|
||||
`model`: `gpt-4`
|
||||
`temp`: `0.5`
|
||||
`chunk`: `512`
|
||||
|
||||
הרחבות תבניות:
|
||||
`persistent://tg/flow/chunk-load:{id}` → `persistent://tg/flow/chunk-load:customer-A-flow`
|
||||
`non-persistent://tg/request/embeddings:{class}` → `non-persistent://tg/request/embeddings:standard-rag`
|
||||
`"model": "{model}"` → `"model": "gpt-4"`
|
||||
`"temperature": "{temp}"` → `"temperature": "0.5"`
|
||||
`"chunk_size": "{chunk}"` → `"chunk_size": "512"`
|
||||
|
||||
זה יוצר:
|
||||
<<<<<<< HEAD
|
||||
צינור עיבוד מסמכים נפרד עבור `customer-A-flow`
|
||||
=======
|
||||
צינור עיבוד מסמכים מבודד עבור `customer-A-flow`
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
שירות הטמעה משותף עבור כל זרימות `standard-rag`
|
||||
זרימת נתונים שלמה מאיסוף מסמכים דרך שאילתות
|
||||
מעבדים מוגדרים עם ערכי הפרמטרים שסופקו
|
||||
|
||||
## יתרונות
|
||||
|
||||
1. **יעילות משאבים**: שירותים יקרים משותפים בין זרימות
|
||||
2. **בידוד זרימות**: לכל זרימה יש את צינור עיבוד הנתונים שלה
|
||||
3. **מדרגיות**: ניתן להפעיל מספר זרימות מאותה תבנית
|
||||
4. **מודולריות**: הפרדה ברורה בין רכיבים משותפים ורכיבים ספציפיים לזרימה
|
||||
5. **ארכיטקטורה מאוחדת**: שאילתות ועיבוד הם חלק מאותה זרימת נתונים
|
||||
590
docs/tech-specs/he/flow-configurable-parameters.he.md
Normal file
590
docs/tech-specs/he/flow-configurable-parameters.he.md
Normal file
|
|
@ -0,0 +1,590 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של פרמטרים הניתנים להגדרה עבור תבניות זרימה"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של פרמטרים הניתנים להגדרה עבור תבניות זרימה
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
<<<<<<< HEAD
|
||||
מפרט זה מתאר את יישום הפרמטרים הניתנים להגדרה עבור תבניות זרימה ב-TrustGraph. פרמטרים מאפשרים למשתמשים להתאים אישית את פרמטרי המעבד בזמן הפעלת הזרימה על ידי מתן ערכים המחליפים את מקומות הפרמטרים בהגדרת תבנית הזרימה.
|
||||
=======
|
||||
מפרט זה מתאר את יישום הפרמטרים הניתנים להגדרה עבור תבניות זרימה ב-TrustGraph. פרמטרים מאפשרים למשתמשים להתאים אישית את פרמטרי המעבד בזמן הפעלת הזרימה על ידי מתן ערכים שמחליפים את מקומות הפרמטרים בהגדרת תבנית הזרימה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
פרמטרים פועלים באמצעות החלפת משתנים בתבניות בפרמטרי המעבד, בדומה לאופן שבו משתנים `{id}` ו-`{class}` פועלים, אך עם ערכים שמסופקים על ידי המשתמש.
|
||||
|
||||
האינטגרציה תומכת בארבעה תרחישי שימוש עיקריים:
|
||||
|
||||
1. **בחירת מודל**: לאפשר למשתמשים לבחור מודלים שונים של LLM (לדוגמה, `gemma3:8b`, `gpt-4`, `claude-3`) עבור מעבדים.
|
||||
2. **תצורת משאבים**: התאמת פרמטרי מעבד כגון גודל חבילות, גודל אצווה ומגבלות מקביליות.
|
||||
<<<<<<< HEAD
|
||||
3. **כוונון התנהגות**: שינוי התנהגות המעבד באמצעות פרמטרים כגון טמפרטורה, מקסימום טוקנים או ספי תאחזור.
|
||||
=======
|
||||
3. **כוונון התנהגות**: שינוי התנהגות המעבד באמצעות פרמטרים כגון טמפרטורה, מקסימום טוקנים או ספי הצעת מחיר.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
4. **פרמטרים ספציפיים לסביבה**: הגדרת נקודות קצה, מפתחות API או כתובות URL ספציפיות לאזור עבור כל פריסה.
|
||||
|
||||
## מטרות
|
||||
|
||||
**תצורת מעבד דינמית**: לאפשר תצורת זמן ריצה של פרמטרי מעבד באמצעות החלפת פרמטרים.
|
||||
**אימות פרמטרים**: לספק בדיקת סוג ואימות עבור פרמטרים בזמן הפעלת הזרימה.
|
||||
**ערכי ברירת מחדל**: לתמוך בערכי ברירת מחדל הגיוניים תוך מתן אפשרות לשנות אותם עבור משתמשים מתקדמים.
|
||||
**החלפת תבניות**: להחליף בצורה חלקה את מקומות הפרמטרים בפרמטרי המעבד.
|
||||
**אינטגרציה עם ממשק משתמש**: לאפשר הזנת פרמטרים באמצעות ממשקי API וממשקי משתמש.
|
||||
**בטיחות סוגים**: להבטיח שטיפוסי הפרמטרים תואמים לטיפוסי פרמטרי המעבד הצפויים.
|
||||
<<<<<<< HEAD
|
||||
**תיעוד**: סכימות פרמטרים המתועדות באופן עצמי בתוך הגדרות תבניות הזרימה.
|
||||
=======
|
||||
**תיעוד**: סכימות פרמטרים המתועדות באופן עצמי בתוך הגדרות תבניות זרימה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**תאימות לאחור**: לשמור על תאימות לתבניות זרימה קיימות שאינן משתמשות בפרמטרים.
|
||||
|
||||
## רקע
|
||||
|
||||
<<<<<<< HEAD
|
||||
תבניות זרימה ב-TrustGraph תומכות כעת בפרמטרי מעבד שניתן להכיל ערכים קבועים או מקומות שמירת פרמטרים. זה יוצר הזדמנות להתאמה אישית בזמן ריצה.
|
||||
|
||||
פרמטרי מעבד קיימים תומכים ב:
|
||||
ערכים קבועים: `"model": "gemma3:12b"`
|
||||
מקומות שמירת פרמטרים: `"model": "gemma3:{model-size}"`
|
||||
=======
|
||||
תבניות זרימה ב-TrustGraph תומכות כעת בפרמטרי מעבד שניתן להכיל ערכים קבועים או מקומות פרמטרים. זה יוצר הזדמנות להתאמה אישית בזמן ריצה.
|
||||
|
||||
פרמטרי מעבד קיימים תומכים ב:
|
||||
ערכים קבועים: `"model": "gemma3:12b"`
|
||||
מקומות פרמטרים: `"model": "gemma3:{model-size}"`
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
מפרט זה מגדיר כיצד פרמטרים:
|
||||
מוצהרים בהגדרות תבניות זרימה
|
||||
מאומתים כאשר זרימות מופעלות
|
||||
מוכנסים לפרמטרי מעבד
|
||||
נחשפים באמצעות ממשקי API וממשקי משתמש
|
||||
|
||||
<<<<<<< HEAD
|
||||
על ידי שימוש בפרמטרי מעבד מוגדרים, TrustGraph יכולה:
|
||||
=======
|
||||
על ידי שימוש בפרמטרי מעבד מותאמים אישית, TrustGraph יכולה:
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
להפחית שכפול של תבניות זרימה על ידי שימוש בפרמטרים עבור וריאציות
|
||||
לאפשר למשתמשים לכוונן את התנהגות המעבד מבלי לשנות הגדרות
|
||||
לתמוך בתצורות ספציפיות לסביבה באמצעות ערכי פרמטרים
|
||||
לשמור על בטיחות סוגים באמצעות אימות סכימת פרמטרים
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
מערכת הפרמטרים הניתנים להגדרה דורשת את הרכיבים הטכניים הבאים:
|
||||
|
||||
1. **הגדרת סכימת פרמטרים**
|
||||
<<<<<<< HEAD
|
||||
הגדרות פרמטרים מבוססות סכימת JSON בתוך מטא-נתונים של תבניות זרימה
|
||||
הגדרות סוגים כולל מחרוזות, מספרים, בוליאנים, enum ואובייקטים
|
||||
כללי אימות כולל ערכים מינימליים/מקסימליים, תבניות ושדות חובה
|
||||
=======
|
||||
הגדרות פרמטרים המבוססות על סכימת JSON בתוך מטא-נתונים של תבניות זרימה
|
||||
הגדרות סוגים כולל מחרוזות, מספרים, בוליאנים, enum ואובייקטים
|
||||
כללי אימות כולל ערכים מינימליים/מקסימליים, תבניות ושדות נדרשים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/flow/definition.py
|
||||
|
||||
2. **מנוע פתרון פרמטרים**
|
||||
אימות פרמטרים בזמן ריצה מול סכימה
|
||||
יישום ערכי ברירת מחדל עבור פרמטרים לא מוגדרים
|
||||
הכנסת פרמטרים להקשר ביצוע הזרימה
|
||||
המרה והסבה של סוגים לפי הצורך
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/flow/parameter_resolver.py
|
||||
|
||||
3. **אינטגרציה עם מאגר פרמטרים**
|
||||
אחזור הגדרות פרמטרים ממערכת סכימות/תצורה
|
||||
שמירת פרמטרי הגדרה בשימוש תכוף
|
||||
אימות מול סכימות המאוחסנות באופן מרכזי
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/flow/parameter_store.py
|
||||
|
||||
4. **הרחבות משגר זרימה**
|
||||
הרחבות API לקבלת ערכי פרמטרים במהלך הפעלת זרימה
|
||||
רזולוציית מיפוי פרמטרים (שמות זרימה לשמות הגדרה)
|
||||
טיפול בשגיאות עבור שילובים לא חוקיים של פרמטרים
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/flow/launcher.py
|
||||
|
||||
5. **טפסי פרמטרים של ממשק משתמש**
|
||||
יצירת טפסים דינמיים ממטא-נתוני פרמטרים של זרימה
|
||||
תצוגה מסודרת של פרמטרים באמצעות שדה `order`
|
||||
תגיות תיאוריות של פרמטרים באמצעות שדה `description`
|
||||
אימות קלט מול הגדרות סוג פרמטרים
|
||||
<<<<<<< HEAD
|
||||
ערכות מקדימות ותבניות פרמטרים
|
||||
=======
|
||||
ערכות חכמות ותבניות פרמטרים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
מודול: trustgraph-ui/components/flow-parameters/
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### הגדרות פרמטרים (מאוחסנות בסכימה/תצורה)
|
||||
|
||||
הגדרות פרמטרים מאוחסנות באופן מרכזי במערכת הסכימות והתצורה עם סוג "parameter-type":
|
||||
<<<<<<< HEAD
|
||||
פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא).
|
||||
=======
|
||||
פלט חוזה (יש לעקוב אחר הפורמט המדויק).
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
```json
|
||||
{
|
||||
"llm-model": {
|
||||
"type": "string",
|
||||
"description": "LLM model to use",
|
||||
"default": "gpt-4",
|
||||
"enum": [
|
||||
{
|
||||
"id": "gpt-4",
|
||||
"description": "OpenAI GPT-4 (Most Capable)"
|
||||
},
|
||||
{
|
||||
"id": "gpt-3.5-turbo",
|
||||
"description": "OpenAI GPT-3.5 Turbo (Fast & Efficient)"
|
||||
},
|
||||
{
|
||||
"id": "claude-3",
|
||||
"description": "Anthropic Claude 3 (Thoughtful & Safe)"
|
||||
},
|
||||
{
|
||||
"id": "gemma3:8b",
|
||||
"description": "Google Gemma 3 8B (Open Source)"
|
||||
}
|
||||
],
|
||||
"required": false
|
||||
},
|
||||
"model-size": {
|
||||
"type": "string",
|
||||
"description": "Model size variant",
|
||||
"default": "8b",
|
||||
"enum": ["2b", "8b", "12b", "70b"],
|
||||
"required": false
|
||||
},
|
||||
"temperature": {
|
||||
"type": "number",
|
||||
"description": "Model temperature for generation",
|
||||
"default": 0.7,
|
||||
"minimum": 0.0,
|
||||
"maximum": 2.0,
|
||||
"required": false
|
||||
},
|
||||
"chunk-size": {
|
||||
"type": "integer",
|
||||
"description": "Document chunk size",
|
||||
"default": 512,
|
||||
"minimum": 128,
|
||||
"maximum": 2048,
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### תרשים זרימה עם הפניות לפרמטרים
|
||||
|
||||
תרשימי זרימה מגדירים מטא-נתונים של פרמטרים עם הפניות לסוג, תיאורים וסדר:
|
||||
|
||||
```json
|
||||
{
|
||||
"flow_class": "document-analysis",
|
||||
"parameters": {
|
||||
"llm-model": {
|
||||
"type": "llm-model",
|
||||
"description": "Primary LLM model for text completion",
|
||||
"order": 1
|
||||
},
|
||||
"llm-rag-model": {
|
||||
"type": "llm-model",
|
||||
"description": "LLM model for RAG operations",
|
||||
"order": 2,
|
||||
"advanced": true,
|
||||
"controlled-by": "llm-model"
|
||||
},
|
||||
"llm-temperature": {
|
||||
"type": "temperature",
|
||||
"description": "Generation temperature for creativity control",
|
||||
"order": 3,
|
||||
"advanced": true
|
||||
},
|
||||
"chunk-size": {
|
||||
"type": "chunk-size",
|
||||
"description": "Document chunk size for processing",
|
||||
"order": 4,
|
||||
"advanced": true
|
||||
},
|
||||
"chunk-overlap": {
|
||||
"type": "integer",
|
||||
"description": "Overlap between document chunks",
|
||||
"order": 5,
|
||||
"advanced": true,
|
||||
"controlled-by": "chunk-size"
|
||||
}
|
||||
},
|
||||
"class": {
|
||||
"text-completion:{class}": {
|
||||
"request": "non-persistent://tg/request/text-completion:{class}",
|
||||
"response": "non-persistent://tg/response/text-completion:{class}",
|
||||
"parameters": {
|
||||
"model": "{llm-model}",
|
||||
"temperature": "{llm-temperature}"
|
||||
}
|
||||
},
|
||||
"rag-completion:{class}": {
|
||||
"request": "non-persistent://tg/request/rag-completion:{class}",
|
||||
"response": "non-persistent://tg/response/rag-completion:{class}",
|
||||
"parameters": {
|
||||
"model": "{llm-rag-model}",
|
||||
"temperature": "{llm-temperature}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flow": {
|
||||
"chunker:{id}": {
|
||||
"input": "persistent://tg/flow/chunk:{id}",
|
||||
"output": "persistent://tg/flow/chunk-load:{id}",
|
||||
"parameters": {
|
||||
"chunk_size": "{chunk-size}",
|
||||
"chunk_overlap": "{chunk-overlap}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
הסעיף `parameters` ממפה שמות פרמטרים ספציפיים לזרימה (מפתחות) לאובייקטי מטא-נתונים של פרמטרים המכילים:
|
||||
`type`: הפניה להגדרה מרכזית של פרמטר (לדוגמה, "llm-model")
|
||||
`description`: תיאור קריא לבני אדם לצורך הצגה בממשק המשתמש
|
||||
`order`: סדר הצגה של טפסי פרמטרים (מספרים נמוכים יותר מופיעים ראשונים)
|
||||
`advanced` (אופציונלי): דגל בוליאני המציין אם זהו פרמטר מתקדם (ברירת מחדל: false). כאשר מוגדר כ-true, הממשק המשתמש עשוי להסתיר את הפרמטר הזה כברירת מחדל או למקם אותו בסעיף "מתקדם"
|
||||
`controlled-by` (אופציונלי): שם של פרמטר אחר השולט בערך של הפרמטר הזה במצב פשוט. כאשר מצוין, פרמטר זה יורש את הערך שלו מהפרמטר השולט, אלא אם כן הוא מוגדר במפורש אחרת
|
||||
|
||||
גישה זו מאפשרת:
|
||||
הגדרות סוג פרמטרים שניתן לעשות בהן שימוש חוזר במספר תבניות זרימה
|
||||
ניהול ובדיקת תוקף מרכזיים של סוגי פרמטרים
|
||||
תיאורים וסדר הצגה ספציפיים לזרימה של פרמטרים
|
||||
חוויית ממשק משתמש משופרת עם טפסי פרמטרים תיאוריים
|
||||
בדיקת תוקף עקבית של פרמטרים בכל הזרימות
|
||||
הוספה קלה של סוגי פרמטרים סטנדרטיים חדשים
|
||||
ממשק משתמש מפושט עם הפרדה בין מצב בסיסי/מתקדם
|
||||
ירושת ערכי פרמטרים עבור הגדרות קשורות
|
||||
|
||||
#### בקשת הפעלת זרימה
|
||||
|
||||
ממשק ה-API להפעלת זרימה מקבל פרמטרים באמצעות שמות הפרמטרים של הזרימה:
|
||||
|
||||
```json
|
||||
{
|
||||
"flow_class": "document-analysis",
|
||||
"flow_id": "customer-A-flow",
|
||||
"parameters": {
|
||||
"llm-model": "claude-3",
|
||||
"llm-temperature": 0.5,
|
||||
"chunk-size": 1024
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
הערה: בדוגמה זו, `llm-rag-model` אינו מסופק באופן מפורש, אך הוא יירש את הערך "claude-3" מ-`llm-model` בשל הקשר `controlled-by` שלו. באופן דומה, `chunk-overlap` יכול לרשת ערך מחושב המבוסס על `chunk-size`.
|
||||
=======
|
||||
הערה: בדוגמה זו, `llm-rag-model` אינו מסופק באופן מפורש, אך הוא יירש את הערך "claude-3" מ-`llm-model` עקב הקשר `controlled-by` שלו. באופן דומה, `chunk-overlap` יכול לרשת ערך מחושב המבוסס על `chunk-size`.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
המערכת תבצע את הפעולות הבאות:
|
||||
1. חילוץ מטא-נתונים של פרמטרים מהגדרת תבנית זרימה
|
||||
2. מיפוי שמות פרמטרים של זרימה להגדרות הסוג שלהם (לדוגמה, `llm-model` → סוג `llm-model`)
|
||||
3. פתרון קשרים "שולט ב" (controlled-by) (לדוגמה, `llm-rag-model` יורש מ-`llm-model`)
|
||||
4. אימות ערכים שסופקו על ידי המשתמש וערכים שירשו בהתאם להגדרות הסוג של הפרמטרים
|
||||
<<<<<<< HEAD
|
||||
5. החלפת ערכים שפתורים לתוך פרמטרים של מעבדים במהלך יצירת זרימה
|
||||
=======
|
||||
5. החלפת ערכים פתורים לפרמטרים של מעבדים במהלך יצירת זרימה
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
#### תהליך פתרון פרמטרים
|
||||
|
||||
כאשר זרימה מתחילה, המערכת מבצעת את שלבי פתרון הפרמטרים הבאים:
|
||||
|
||||
1. **טעינת תבנית זרימה**: טעינת הגדרת תבנית זרימה וחילוץ מטא-נתונים של פרמטרים
|
||||
2. **חילוץ מטא-נתונים**: חילוץ `type`, `description`, `order`, `advanced` ו-`controlled-by` עבור כל פרמטר המוגדר בתבנית הזרימה בסעיף `parameters`
|
||||
3. **חיפוש הגדרת סוג**: עבור כל פרמטר בתבנית הזרימה:
|
||||
<<<<<<< HEAD
|
||||
אחזור הגדרת הסוג של הפרמטר ממחסן הסכימה/התצורה באמצעות השדה `type`
|
||||
הגדרות הסוג מאוחסנות עם הסוג "parameter-type" במערכת התצורה
|
||||
=======
|
||||
אחזור הגדרת הסוג של הפרמטר ממחסן הסכימה/הגדרות באמצעות השדה `type`
|
||||
הגדרות הסוג מאוחסנות עם הסוג "parameter-type" במערכת ההגדרות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
כל הגדרת סוג מכילה את הסכימה של הפרמטר, ערך ברירת מחדל וכללי אימות
|
||||
4. **פתרון ערך ברירת מחדל**:
|
||||
עבור כל פרמטר המוגדר בתבנית הזרימה:
|
||||
בדיקה האם המשתמש סיפק ערך עבור פרמטר זה
|
||||
אם לא סופק ערך על ידי המשתמש, השתמש בערך `default` מהגדרת סוג הפרמטר
|
||||
<<<<<<< HEAD
|
||||
יצירת מפת פרמטרים שלמה המכילה הן ערכים שסופקו על ידי המשתמש והן ערכי ברירת מחדל
|
||||
5. **פתרון ירושה של פרמטרים** (קשרים "שולט ב"):
|
||||
עבור פרמטרים עם שדה `controlled-by`, בדוק האם סופק ערך באופן מפורש
|
||||
אם לא סופק ערך מפורש, יורשים את הערך מהפרמטר השולט
|
||||
אם גם לפרמטר השולט אין ערך, משתמשים בברירת המחדל מהגדרת הסוג
|
||||
אימות שאין תלות מעגלית בקשרי `controlled-by`
|
||||
6. **אימות**: אימות קבוצת הפרמטרים השלמה (ערכים שסופקו על ידי המשתמש, ברירות מחדל וערכים שירשו) בהתאם להגדרות הסוג
|
||||
7. **אחסון**: אחסון קבוצת הפרמטרים השלמה שפתורה עם מופע הזרימה לצורך ביקורת
|
||||
8. **החלפת תבניות**: החלפת מקומות שמורות של פרמטרים בפרמטרים של מעבדים עם ערכים שפתורים
|
||||
=======
|
||||
יצירת מפת פרמטרים שלמה המכילה גם ערכים שסופקו על ידי המשתמש וגם ערכי ברירת מחדל
|
||||
5. **פתרון ירושה של פרמטרים** (קשרים "שולט ב"):
|
||||
עבור פרמטרים עם שדה `controlled-by`, בדוק האם סופק ערך באופן מפורש
|
||||
אם לא סופק ערך מפורש, ירוש את הערך מהפרמטר השולט
|
||||
אם גם לפרמטר השולט אין ערך, השתמש בברירת המחדל מהגדרת הסוג
|
||||
ודא שאין תלות מעגלית בקשרי `controlled-by`
|
||||
6. **אימות**: אימות קבוצת הפרמטרים השלמה (ערכים שסופקו על ידי המשתמש, ברירות מחדל וערכים שירשו) בהתאם להגדרות הסוג
|
||||
7. **אחסון**: אחסון קבוצת הפרמטרים הפתורים השלמה עם מופע הזרימה לצורך ביקורת
|
||||
8. **החלפת תבניות**: החלפת מקומות שמורות של פרמטרים בפרמטרים של מעבדים עם ערכים פתורים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
9. **יצירת מעבדים**: יצירת מעבדים עם פרמטרים שהוחלפו
|
||||
|
||||
**הערות חשובות ליישום:**
|
||||
שירות הזרימה חייב למזג פרמטרים שסופקו על ידי המשתמש עם ברירות מחדל מהגדרות סוג הפרמטרים
|
||||
קבוצת הפרמטרים השלמה (כולל ברירות המחדל המיושמות) חייבת להיות מאוחסנת עם הזרימה לצורך מעקב
|
||||
פתרון פרמטרים מתרחש בזמן התחלת הזרימה, ולא בזמן יצירת המעבד
|
||||
<<<<<<< HEAD
|
||||
פרמטרים חסרים שנדרשים ללא ברירות מחדל חייבים לגרום לכישלון התחלת הזרימה עם הודעת שגיאה ברורה
|
||||
=======
|
||||
פרמטרים חסרים הדורשים ברירות מחדל חייבים לגרום לכישלון התחלת הזרימה עם הודעת שגיאה ברורה
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### ירושת פרמטרים עם "שולט ב"
|
||||
|
||||
השדה `controlled-by` מאפשר ירושת ערכי פרמטרים, שימושי במיוחד לפשט ממשקי משתמש תוך שמירה על גמישות:
|
||||
|
||||
**תרחיש לדוגמה**:
|
||||
פרמטר `llm-model` שולט במודל LLM הראשי
|
||||
פרמטר `llm-rag-model` מכיל `"controlled-by": "llm-model"`
|
||||
במצב פשוט, הגדרת `llm-model` ל-"gpt-4" מגדירה אוטומטית גם את `llm-rag-model` ל-"gpt-4"
|
||||
במצב מתקדם, משתמשים יכולים לדרוס את `llm-rag-model` עם ערך שונה
|
||||
|
||||
**כללי פתרון**:
|
||||
1. אם לפרמטר יש ערך שסופק באופן מפורש, השתמש בערך זה
|
||||
2. אם אין ערך מפורש ו-`controlled-by` מוגדר, השתמש בערך של הפרמטר השולט
|
||||
3. אם לפרמטר השולט אין ערך, חזור לברירת המחדל מהגדרת הסוג
|
||||
4. תלות מעגלית בקשרי `controlled-by` גורמת לשגיאת אימות
|
||||
|
||||
**התנהגות ממשק משתמש**:
|
||||
במצב בסיסי/פשוט: פרמטרים עם `controlled-by` עשויים להיות מוסתרים או מוצגים כקריאה בלבד עם ערך שירש
|
||||
במצב מתקדם: מוצגים כל הפרמטרים וניתן להגדיר אותם באופן אינדיבידואלי
|
||||
<<<<<<< HEAD
|
||||
כאשר פרמטר שולט משתנה, פרמטרים תלויים מתעדכנים אוטומטית אלא אם כן הם נדחפים באופן מפורש
|
||||
=======
|
||||
כאשר פרמטר שולט משתנה, פרמטרים תלויים מתעדכנים אוטומטית אלא אם כן הם דורסים באופן מפורש
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### אינטגרציה עם Pulsar
|
||||
|
||||
1. **פעולת התחלת זרימה**
|
||||
פעולת התחלת הזרימה של Pulsar צריכה לקבל שדה `parameters` המכיל מפה של ערכי פרמטרים
|
||||
הסכימה של בקשת התחלת הזרימה של Pulsar חייבת להיות מעודכנת כדי לכלול את השדה האופציונלי `parameters`
|
||||
דוגמת בקשה:
|
||||
```json
|
||||
{
|
||||
"flow_class": "document-analysis",
|
||||
"flow_id": "customer-A-flow",
|
||||
"parameters": {
|
||||
"model": "claude-3",
|
||||
"size": "12b",
|
||||
"temp": 0.5,
|
||||
"chunk": 1024
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **פעולת Get-Flow**
|
||||
הסכימה של Pulsar עבור תגובת ה-get-flow חייבת להיות מעודכנת כדי לכלול את השדה `parameters`
|
||||
זה מאפשר ללקוחות לשלוף את ערכי הפרמטרים ששימשו כאשר ה-flow הופעל
|
||||
דוגמה לתגובה:
|
||||
```json
|
||||
{
|
||||
"flow_id": "customer-A-flow",
|
||||
"flow_class": "document-analysis",
|
||||
"status": "running",
|
||||
"parameters": {
|
||||
"model": "claude-3",
|
||||
"size": "12b",
|
||||
"temp": 0.5,
|
||||
"chunk": 1024
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### יישום שירות זרימה
|
||||
|
||||
שירות תצורת הזרימה (`trustgraph-flow/trustgraph/config/service/flow.py`) דורש את השיפורים הבאים:
|
||||
|
||||
1. **פונקציית פתרון פרמטרים**
|
||||
```python
|
||||
async def resolve_parameters(self, flow_class, user_params):
|
||||
"""
|
||||
Resolve parameters by merging user-provided values with defaults.
|
||||
|
||||
Args:
|
||||
flow_class: The flow blueprint definition dict
|
||||
user_params: User-provided parameters dict
|
||||
|
||||
Returns:
|
||||
Complete parameter dict with user values and defaults merged
|
||||
"""
|
||||
```
|
||||
|
||||
פונקציה זו צריכה:
|
||||
<<<<<<< HEAD
|
||||
לחלץ מטא-נתונים של פרמטרים מתוך סעיף `parameters` של תוכנית העבודה (blueprint).
|
||||
עבור כל פרמטר, לשלוף את הגדרת הסוג שלו ממאגר התצורה.
|
||||
להחיל ערכי ברירת מחדל עבור כל פרמטרים שאינם מסופקים על ידי המשתמש.
|
||||
=======
|
||||
לחלץ מטא-נתונים של פרמטרים מסעיף `parameters` של תוכנית העבודה (blueprint).
|
||||
עבור כל פרמטר, לשלוף את הגדרת הסוג שלו ממאגר התצורה.
|
||||
להחיל ערכי ברירת מחדל עבור כל פרמטרים שלא סופקו על ידי המשתמש.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
לטפל ביחסי ירושה `controlled-by`.
|
||||
להחזיר את קבוצת הפרמטרים השלמה.
|
||||
|
||||
2. **שיטה `handle_start_flow` שעברה שינוי**
|
||||
לקרוא ל-`resolve_parameters` לאחר טעינת תוכנית העבודה.
|
||||
להשתמש בקבוצת הפרמטרים המפורטת והפתורה עבור החלפת תבניות.
|
||||
לשמור את קבוצת הפרמטרים השלמה (ולא רק את אלה שסופקו על ידי המשתמש) יחד עם תוכנית העבודה.
|
||||
לוודא שכל הפרמטרים הנדרשים מכילים ערכים.
|
||||
|
||||
3. **שליפת סוגי פרמטרים**
|
||||
הגדרות סוגי פרמטרים מאוחסנות בתצורה עם הסוג "parameter-type".
|
||||
כל הגדרת סוג מכילה סכימה, ערך ברירת מחדל וכללי אימות.
|
||||
לשמור סוגי פרמטרים בשימוש נפוץ במטמון כדי להפחית את מספר הפניות לתצורה.
|
||||
|
||||
#### שילוב עם מערכת התצורה
|
||||
|
||||
3. **אחסון אובייקטי זרימה**
|
||||
כאשר אובייקט זרימה מתווסף למערכת התצורה על ידי רכיב הזרימה בניהול התצורה, אובייקט הזרימה חייב לכלול את ערכי הפרמטרים הפתורים.
|
||||
מנהל התצורה צריך לאחסן גם את הפרמטרים שסופקו על ידי המשתמש וגם את הערכים הפתורים (עם יישום ברירת המחדל).
|
||||
אובייקטי זרימה במערכת התצורה צריכים לכלול:
|
||||
`parameters`: ערכי הפרמטרים הפתורים הסופיים המשמשים עבור הזרימה.
|
||||
|
||||
#### שילוב עם ממשק שורת הפקודה (CLI)
|
||||
|
||||
4. **פקודות CLI של הספריה**
|
||||
פקודות CLI המתחילות זרימות צריכות לתמוך בפרמטרים:
|
||||
לקבל ערכי פרמטרים באמצעות דגלי שורת הפקודה או קבצי תצורה.
|
||||
לאמת פרמטרים מול הגדרות תוכנית העבודה לפני שליחה.
|
||||
לתמוך בקלט של קובץ פרמטרים (JSON/YAML) עבור קבוצות פרמטרים מורכבות.
|
||||
|
||||
פקודות CLI המציגות זרימות צריכות להציג מידע על פרמטרים:
|
||||
להציג את ערכי הפרמטרים ששימשו בעת התחלת הזרימה.
|
||||
להציג את הפרמטרים הזמינים עבור תוכנית עבודה של זרימה.
|
||||
להציג סכימות אימות של פרמטרים וערכי ברירת מחדל.
|
||||
|
||||
#### שילוב עם מחלקת בסיס של מעבד (Processor)
|
||||
|
||||
5. **תמיכה ב-ParameterSpec**
|
||||
מחלקות בסיס של מעבדים צריכות לתמוך בהחלפת פרמטרים באמצעות מנגנון ה-ParametersSpec הקיים.
|
||||
המחלקה ParametersSpec (הנמצאת באותו מודול כמו ConsumerSpec ו-ProducerSpec) צריכה להיות משופרת במידת הצורך כדי לתמוך בהחלפת תבניות של פרמטרים.
|
||||
מעבדים צריכים להיות מסוגלים להשתמש ב-ParametersSpec כדי להגדיר את הפרמטרים שלהם עם ערכי פרמטרים שפתורים בזמן הפעלת הזרימה.
|
||||
יישום ה-ParametersSpec צריך:
|
||||
לקבל תצורות פרמטרים המכילות מקומות שמורות של פרמטרים (לדוגמה, `{model}`, `{temperature}`).
|
||||
לתמוך בהחלפת פרמטרים בזמן ריצה בעת יצירת המעבד.
|
||||
לוודא שערכים שהוחלפו תואמים לסוגים ולמגבלות הצפויים.
|
||||
לספק טיפול בשגיאות עבור הפניות חסרות או לא חוקיות של פרמטרים.
|
||||
|
||||
#### כללי החלפה
|
||||
|
||||
פרמטרים משתמשים בפורמט `{parameter-name}` בפרמטרים של מעבד.
|
||||
שמות הפרמטרים בפרמטרים תואמים למפתחות בסעיף `parameters` של תוכנית העבודה.
|
||||
החלפה מתרחשת יחד עם החלפת `{id}` ו-`{class}`.
|
||||
הפניות לא חוקיות של פרמטרים גורמות לשגיאות בזמן ההפעלה.
|
||||
אימות סוג מתרחש בהתבסס על הגדרת הפרמטר המאוחסנת במרכז.
|
||||
**חשוב**: כל ערכי הפרמטרים מאוחסנים ומועברים כרצף תווים.
|
||||
מספרים מומרים לרצף תווים (לדוגמה, `0.7` הופך ל-`"0.7"`).
|
||||
<<<<<<< HEAD
|
||||
ערכים בוליאניים מומרים לרצף תווים קטן (לדוגמה, `true` הופך ל-`"true"`).
|
||||
=======
|
||||
בוליאנים מומרים לרצף תווים קטן (לדוגמה, `true` הופך ל-`"true"`).
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
זה נדרש על ידי הסכימה של Pulsar, אשר מגדירה `parameters = Map(String())`.
|
||||
|
||||
דוגמה לפענוח:
|
||||
```
|
||||
Flow parameter mapping: "model": "llm-model"
|
||||
Processor parameter: "model": "{model}"
|
||||
User provides: "model": "gemma3:8b"
|
||||
Final parameter: "model": "gemma3:8b"
|
||||
|
||||
Example with type conversion:
|
||||
Parameter type default: 0.7 (number)
|
||||
Stored in flow: "0.7" (string)
|
||||
Substituted in processor: "0.7" (string)
|
||||
```
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
בדיקות יחידה לאימות סכימת הפרמטרים
|
||||
בדיקות אינטגרציה להחלפת פרמטרים בפרמטרים של המעבד
|
||||
בדיקות מקצה לקצה להפעלת זרימות עם ערכי פרמטרים שונים
|
||||
בדיקות ממשק משתמש ליצירה ואימות של טופס פרמטרים
|
||||
בדיקות ביצועים עבור זרימות עם פרמטרים רבים
|
||||
מקרים קצה: פרמטרים חסרים, סוגים לא חוקיים, הפניות לפרמטרים לא מוגדרים
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
1. המערכת צריכה להמשיך לתמוך בתבניות זרימה ללא פרמטרים
|
||||
<<<<<<< HEAD
|
||||
מוצהרים.
|
||||
=======
|
||||
מוגדרים.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
2. המערכת צריכה להמשיך לתמוך בזרימות ללא פרמטרים מוגדרים:
|
||||
זה עובד עבור זרימות ללא פרמטרים, וזרימות עם פרמטרים
|
||||
(שיש להם ערכי ברירת מחדל).
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
<<<<<<< HEAD
|
||||
ש: האם הפרמטרים צריכים לתמוך באובייקטים מקוננים מורכבים או להישאר בסוגים פשוטים?
|
||||
=======
|
||||
ש: האם פרמטרים צריכים לתמוך באובייקטים מקוננים מורכבים או להישאר בסוגים פשוטים?
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
ת: ערכי הפרמטרים יועברו כרצף תווים, סביר להניח שנרצה
|
||||
להישאר ברצפים תווים.
|
||||
|
||||
ש: האם מותר להשתמש במחזיקי פרמטרים בשמות תורים או רק ב
|
||||
פרמטרים?
|
||||
ת: רק בפרמטרים כדי למנוע הזרקות ותופעות לוואי.
|
||||
|
||||
ש: כיצד לטפל בקונפליקטים בין שמות פרמטרים למשתנים של המערכת כמו
|
||||
<<<<<<< HEAD
|
||||
`id` ו- `class`?
|
||||
ת: לא חוקי לציין id ו-class בעת הפעלת זרימה.
|
||||
|
||||
ש: האם אנו תומכים בפרמטרים מחושבים (נגזרים מפרמטרים אחרים)?
|
||||
ת: רק החלפת רצפי תווים כדי למנוע הזרקות ותופעות לוואי.
|
||||
=======
|
||||
`id` ו-`class`?
|
||||
ת: לא חוקי לציין id ו-class בעת הפעלת זרימה.
|
||||
|
||||
ש: האם אנו תומכים בפרמטרים מחושבים (נגזרים מפרמטרים אחרים)?
|
||||
ת: רק החלפת רצפים תווים כדי למנוע הזרקות ותופעות לוואי.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## הפניות
|
||||
|
||||
מפרט JSON Schema: https://json-schema.org/
|
||||
מפרט הגדרת תבנית זרימה: docs/tech-specs/flow-class-definition.md
|
||||
324
docs/tech-specs/he/graph-contexts.he.md
Normal file
324
docs/tech-specs/he/graph-contexts.he.md
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של הקשרים בגרף"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של הקשרים בגרף
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר שינויים בפרימיטיבים הבסיסיים של הגרף ב-TrustGraph,
|
||||
כדי להתאים ל-RDF 1.2 ולתמוך בסמנטיקה מלאה של סט נתונים RDF.
|
||||
זוהי שינוי משמעותי עבור סדרת השחרורים 2.x.
|
||||
|
||||
### גרסאות
|
||||
|
||||
- **2.0**: גרסה למתקדמים. תכונות ליבה זמינות, ייתכן שאינן
|
||||
מוכנות לחלוטין לשימוש בייצור.
|
||||
- **2.1 / 2.2**: גרסת ייצור. יציבות ושלמות אומתו.
|
||||
|
||||
הגמישות בנוגע לבשלות היא מכוונת - משתמשים מתקדמים יכולים לגשת
|
||||
ליכולות חדשות לפני שכל התכונות מוכנות לשימוש בייצור.
|
||||
|
||||
## מטרות
|
||||
|
||||
המטרות העיקריות של עבודה זו הן לאפשר מטא-נתונים על עובדות/הצהרות:
|
||||
|
||||
- **מידע זמני**: קשר עובדות עם מטא-נתונים של זמן
|
||||
- מתי עובדה נחשבה לנכונה
|
||||
- מתי עובדה הפכה לנכונה
|
||||
- מתי עובדה התגלתה כלא נכונה
|
||||
|
||||
- **מקורות/מקורות**: מעקב אחר מקורות התומכים בעובדה
|
||||
- "עובדה זו נתמכה על ידי המקור X"
|
||||
- קישור עובדות למסמכי המקור שלהן
|
||||
|
||||
- **נכונות/אמינות**: תיעוד הצהרות על אמת
|
||||
- "האדם P טען שזה נכון"
|
||||
- "האדם Q טוען שזה לא נכון"
|
||||
- אפשרות לחישוב ציון אמינות וגילוי סתירות
|
||||
|
||||
**השערה**: Reification (RDF-star / משולשות מצוטטות) הוא המנגנון העיקרי
|
||||
לשם השגת תוצאות אלה, מכיוון שכולן דורשות הצהרות על הצהרות.
|
||||
|
||||
## רקע
|
||||
|
||||
כדי להביע "העובדה (אליס יודעת את בוב) התגלתה ב-2024-01-15" או
|
||||
"מקור X תומך בטענה (Y גורם ל-Z)", אתה צריך להתייחס לקצה
|
||||
כאל דבר שאפשר להצהיר עליו. משולשות סטנדרטיים אינם תומכים בכך.
|
||||
|
||||
### מגבלות נוכחיות
|
||||
|
||||
המחלקת `Value` הנוכחית ב-`trustgraph-base/trustgraph/schema/core/primitives.py`
|
||||
יכולה לייצג:
|
||||
- צומתי URI (`is_uri=True`)
|
||||
- ערכים מילוליים (`is_uri=False`)
|
||||
|
||||
השדה `type` קיים אך אינו משמש לייצוג טיפוסי נתונים של XSD.
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### תכונות RDF לתמיכה
|
||||
|
||||
#### תכונות ליבה (קשור למטרות ה-Reification)
|
||||
|
||||
תכונות אלו קשורות ישירות למטרות הזמן, המקור והנכונות:
|
||||
|
||||
1. **משולשות מצוטטות של RDF 1.2 (RDF-star)**
|
||||
- קצוות המצביעים על קצוות אחרים
|
||||
- משולש יכול להופיע כנושא או כאובייקט של משולש אחר
|
||||
- מאפשר הצהרות על הצהרות (reification)
|
||||
- מנגנון ליבה לסימון עובדות בודדות
|
||||
|
||||
2. **סט נתונים RDF / גרפים בעלי שם**
|
||||
- תמיכה במספר גרפים בעלי שם בתוך סט נתונים
|
||||
- כל גרף מזוהה על ידי IRI
|
||||
- מעבר משלשות (s, p, o) לארבעיות (s, p, o, g)
|
||||
- כולל גרף ברירת מחדל ואחד או יותר גרפים בעלי שם
|
||||
- ניתן להשתמש ב-IRI של הגרף כנושא בהצהרות, לדוגמה:
|
||||
```
|
||||
<graph-source-A> <discoveredOn> "2024-01-15"
|
||||
<graph-source-A> <hasVeracity> "high"
|
||||
```
|
||||
- הערה: גרפים בעלי שם הם תכונה נפרדת מ-reification. יש להם
|
||||
שימושים מעבר לסימון הצהרות (מחיצה, בקרת גישה, ארגון סט נתונים)
|
||||
ועליהם להתייחס אליהם כלי יכולת נפרדת.
|
||||
|
||||
3. **צמתים ריקים** (תמיכה מוגבלת)
|
||||
- צמתים אנונימיים ללא URI גלובלי
|
||||
- נתמך לצורך תאימות בעת טעינת נתוני RDF חיצוניים
|
||||
- **סטטוס מוגבל**: אין ערובות לזהות יציבה לאחר הטעינה
|
||||
- ניתן למצוא אותם באמצעות שאילתות wildcard (התאמה לפי חיבורים, לא לפי מזהה)
|
||||
- לא תכונה ראשית - אין להסתמך על טיפול מדויק בצמתים ריקים
|
||||
|
||||
#### תיקונים הזדמנותיים (שינוי שבירה 2.0)
|
||||
|
||||
תכונות אלה אינן קשורות ישירות למטרות ה-reification, אך הן שיפורים
|
||||
חשובים שצריך לכלול בעת ביצוע שינויים שבירים:
|
||||
|
||||
4. **טיפוסי מילוליים**
|
||||
- שימוש נכון בשדה `type` עבור טיפוסי נתונים של XSD
|
||||
- דוגמאות: xsd:string, xsd:integer, xsd:dateTime וכו'
|
||||
- פותר מגבלה קיימת: לא ניתן לייצג תאריכים או מספרים שלמים כראוי
|
||||
|
||||
5. **תגיות שפה**
|
||||
- תמיכה בתכונות שפה על מילוליים (en, fr וכו')
|
||||
- הערה: למילול יש תגית שפה או טיפוס נתונים, לא את שניהם
|
||||
(מלבד rdf:langString)
|
||||
- חשוב עבור מקרי שימוש בבינה מלאכותית/רב-לשוניים
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### Term (שינוי שם מ-Value)
|
||||
|
||||
המחלקת `Value` תשנה את שמה ל-`Term` כדי לשקף טוב יותר את המונחים של RDF.
|
||||
שינוי שם זה משרת שני מטרות:
|
||||
1. מיישר את שמות עם מושגים של RDF (ה- "Term" יכול להיות IRI, מילול, צומת ריק או משולש מצוטט - ולא רק "ערך")
|
||||
2. גורם לסקירת קוד בממשק לשינוי השבירה - כל קוד שעדיין מתייחס ל-`Value`
|
||||
נראה שבור באופן גלוי ויש לעדכן אותו
|
||||
|
||||
Term יכול לייצג:
|
||||
|
||||
- **IRI/URI** - צומת/משאב בעל שם
|
||||
- **צומת ריק** - צומת אנונימי עם תחום מקומי
|
||||
- **מילול** - ערך נתונים עם:
|
||||
- טיפוס נתונים (טיפוס XSD), או
|
||||
- תגית שפה
|
||||
- **משולש מצוטט** - משולש המשמש כ-term (RDF 1.2)
|
||||
|
||||
##### גישה שנבחרה: מחלקה אחת עם מפריד טיפוס
|
||||
|
||||
דרישות הסתרה חשובות למבנה - מפריד טיפוס נחוץ
|
||||
בפורמט ה-wire ללא קשר לייצוג ה-Python. מחלקה אחת עם שדה טיפוס היא
|
||||
ההתאמה הטבעית ותואמת לדפוס ה-`Value` הנוכחי.
|
||||
|
||||
קודים חד-תווים של טיפוסים מספקים הסתרה קומפקטית:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
# קבועים של סוג Term
|
||||
IRI = "i" # צומת IRI/URI
|
||||
BLANK = "b" # צומת ריק
|
||||
LITERAL = "l" # ערך מילולי
|
||||
TRIPLE = "t" # משולש מצוטט (RDF-star)
|
||||
|
||||
@dataclass
|
||||
class Term:
|
||||
type: str = "" # אחד מ: IRI, BLANK, LITERAL, TRIPLE
|
||||
|
||||
# עבור מונחי IRI (type == IRI)
|
||||
iri: str = ""
|
||||
|
||||
# עבור צמתים ריקים (type == BLANK)
|
||||
id: str = ""
|
||||
|
||||
# עבור מילויים (type == LITERAL)
|
||||
value: str = ""
|
||||
datatype: str = "" # טיפוס URI של XSD (בלעדי ל-language)
|
||||
language: str = "" # תגית שפה (בלעדי ל-datatype)
|
||||
|
||||
# עבור משולשות מצוטטות (type == TRIPLE)
|
||||
triple: "Triple | None" = None
|
||||
```
|
||||
|
||||
דוגמאות שימוש:
|
||||
|
||||
```python
|
||||
# מונח IRI
|
||||
node = Term(type=IRI, iri="http://example.org/Alice")
|
||||
|
||||
# מילול עם טיפוס נתונים
|
||||
age = Term(type=LITERAL, value="42", datatype="xsd:integer")
|
||||
|
||||
# מילול עם תגית שפה
|
||||
label = Term(type=LITERAL, value="Hello", language="en")
|
||||
|
||||
# צומת ריק
|
||||
anon = Term(type=BLANK, id="_:b1")
|
||||
|
||||
# משולש מצוטט (הצהרה על הצהרה)
|
||||
inner = Triple(
|
||||
s=Term(type=IRI, iri="http://example.org/Alice"),
|
||||
p=Term(type=IRI, iri="http://example.org/knows"),
|
||||
o=Term(type=IRI, iri="http://example.org/Bob"),
|
||||
)
|
||||
reified = Term(type=TRIPLE, triple=inner)
|
||||
```
|
||||
|
||||
##### אלטרנטיבות שנשקלו
|
||||
|
||||
**אפשרות B: איחוד של מחלקות מיוחדות** (`Term = IRI | BlankNode | Literal | QuotedTriple`)
|
||||
- נדחה: הסתרה עדיין תצטרך מפריד טיפוס, מה שמוסיף מורכבות
|
||||
|
||||
**אפשרות C: מחלקה בסיסית עם תת-מחלקה**
|
||||
- נדחה: אותה בעיית הסתרה, בנוסף לבעיות ירושה של dataclass
|
||||
|
||||
#### משולש / ארבעייה
|
||||
|
||||
המחלקת `Triple` רוכשת שדה גרף אופציונלי כדי להפוך לארבעייה:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Triple:
|
||||
s: Term | None = None # נושא
|
||||
p: Term | None = None # תכונה
|
||||
o: Term | None = None # אובייקט
|
||||
g: str | None = None # שם גרף (IRI), None = גרף ברירת מחדל
|
||||
```
|
||||
|
||||
החלטות עיצוב:
|
||||
- **שם שדה**: `g` לעקביות עם `s`, `p`, `o`
|
||||
- **אופציונלי**: `None` פירושו הגרף כברירת מחדל (חסר שם)
|
||||
- **סוג**: מחרוזת פשוטה (IRI) ולא Term
|
||||
- שמות גרפים הם תמיד IRIs
|
||||
- צמתים ריקים כשמות גרפים נשללו (מבלבלים)
|
||||
- אין צורך במכניקת ה-Term המלאה
|
||||
|
||||
שים לב: שם המחלקה נשאר `Triple` גם אם היא טכנית ארבעייה.
|
||||
זה מונע שינויים ו"משולש" הוא עדיין המונח הנפוץ. הקונטקסט של הגרף
|
||||
הוא מטא-נתונים לגבי היכן שוכנת השלישייה.
|
||||
|
||||
### תבניות שאילתות מועמדות
|
||||
|
||||
מנוע השאילתות הנוכחי מקבל שילובים של מונחי S, P, O. עם משולשות מצוטטות,
|
||||
משולש בעצמו הופך ל-term חוקי בעמדות אלה. להלן תבניות שאילתות מועמדות
|
||||
התומכות במטרות המקוריות.
|
||||
|
||||
#### סמנטיקת פרמטר גרף
|
||||
|
||||
בהתאם לקונבנציות SPARQL עבור תאימות לאחור:
|
||||
|
||||
- **`g` מושמט / None**: שאילתא רק את הגרף כברירת מחדל
|
||||
- **`g` = IRI ספציפי**: שאילתא רק את הגרף בעל השם הזה
|
||||
- **`g` = wildcard / `*`**: שאילתא על פני כל הגרפים (שווה ערך ל-SPARQL
|
||||
`GRAPH ?g { ... }`)
|
||||
|
||||
זה שומר על שאילתות פשוטות כפשוטות ומאפשר שאילתות על גרפים בעלי
|
||||
שמות כבחירה.
|
||||
|
||||
שאילתות חוצות גרפים (g=wildcard) נתמכות במלואן. סכימת Cassandra
|
||||
כוללת טבלאות ייעודיות (SPOG, POSG, OSPG) כאשר g הוא עמודת clustering
|
||||
ולא מפתח מחיצה, המאפשר שאילתות יעילות על פני כל הגרפים.
|
||||
|
||||
#### שאילתות זמניות
|
||||
|
||||
**מצא את כל העובדות שהתגלו בתאריך 2024-01-15:**
|
||||
```
|
||||
SELECT * FROM triples WHERE ?s p1 ?o1 .
|
||||
```
|
||||
|
||||
#### שיקולי ביצועים
|
||||
|
||||
- משולשות מצוטטות מוסיפות עומק קינון - עשויות להשפיע על ביצועי השאילתות
|
||||
- אסטרטגיות אינדוקס לגרפים בעלי שם נחוצות עבור שאילתות יעילות מבוססות גרפים
|
||||
- עיצוב סכימת Cassandra יצטרך להתאים אחסון ארבעיות ביעילות
|
||||
|
||||
### גבולת מאגר וקטורי
|
||||
|
||||
מאגרי וקטורים תמיד מתייחסים ל-IRIs בלבד:
|
||||
- לעולם לא קצוות (משולשות מצוטטות)
|
||||
- לעולם לא ערכים מילוליים
|
||||
- לעולם לא צמתים ריקים
|
||||
|
||||
זה שומר על מאגר הווקטורים פשוט - הוא מטפל בדמיון סמנטי של ישויות בעלות שם.
|
||||
המבנה של הגרף מטפל ביחסים, reification ומטא-נתונים. משולשות מצוטטות
|
||||
וגרפים בעלי שם אינם מסבכים פעולות וקטוריות.
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
גרפים בעלי שם אינם תכונה של אבטחה. משתמשים ואוספים הם גבולות האבטחה.
|
||||
גרפים בעלי שם הם אך ורק עבור ארגון נתונים ו-reification תמיכה.
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
- משולשות מצוטטות מוסיפות עומק קינון - עשויות להשפיע על ביצועי השאילתות
|
||||
- אסטרטגיות אינדוקס לגרפים בעלי שם נחוצות עבור שאילתות יעילות מבוססות גרפים
|
||||
- עיצוב סכימת Cassandra יצטרך להתאים אחסון ארבעיות ביעילות
|
||||
|
||||
### גבולת מאגר וקטורי
|
||||
|
||||
מאגרי וקטורים תמיד מתייחסים ל-IRIs בלבד:
|
||||
- לעולם לא קצוות (משולשות מצוטטות)
|
||||
- לעולם לא ערכים מילוליים
|
||||
- לעולם לא צמתים ריקים
|
||||
|
||||
זה שומר על מאגר הווקטורים פשוט - הוא מטפל בדמיון סמנטי של ישויות בעלות שם.
|
||||
המבנה של הגרף מטפל ביחסים, reification ומטא-נתונים. משולשות מצוטטות
|
||||
וגרפים בעלי שם אינם מסבכים פעולות וקטוריות.
|
||||
|
||||
## אסטרטגיית בדיקה
|
||||
|
||||
השתמש באסטרטגיית הבדיקה הקיימת. מכיוון שזוהי גרסה שבירה, יש להתמקד
|
||||
בבדיקות הקצה כדי לוודא שהמבנים החדשים עובדים כראוי בכל הרכיבים.
|
||||
|
||||
## תוכנית העברה
|
||||
|
||||
- 2.0 היא גרסה שבירה; אין צורך בתאימות לאחור
|
||||
- ייתכן שיהיה צורך להעביר נתונים קיימים לסכימה חדשה (בהתאם לעיצוב הסופי)
|
||||
- שקול כלי העברה להמרת משולשות קיימות
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
- **צמתים ריקים**: תמיכה מוגבלת אושרה. ייתכן שיהיה צורך להחליט על
|
||||
אסטרטגיית skolemization (ליצור IRIs בעת הטעינה, או לשמר מזהי צמתים ריקים).
|
||||
- **תחביר שאילתא**: מהו התחביר הקונקרטי לציין משולשות מצוטטות
|
||||
בשאלות? יש להגדיר את ממשק ה-API של השאילתא.
|
||||
- ~~**אוצר מילים של תכונות**~~: נפתר. כל תכונות RDF חוקיות מותרות,
|
||||
כולל מילים מוגדרות על ידי משתמש. הנחות מינימליות לגבי תוקף RDF.
|
||||
אסטרטגיה: הימנע מנעילה אלא אם הכרחי לחלוטין.
|
||||
- ~~**השפעה על מאגר הווקטורים**~~: נפתר. מאגרי וקטורים תמיד מצביעים על
|
||||
IRIs בלבד - לעולם לא קצוות, מילויים או צמתים ריקים. משולשות מצוטטות
|
||||
וגרפים בעלי שם אינם משפיעים על מאגר הווקטורים.
|
||||
- ~~**סמנטיקת גרפים בעלי שם**~~: נפתר. שאילתות כברירת מחדל לגרף
|
||||
כברירת מחדל (מתאים להתנהגות SPARQL, תואם לאחור). פרמטר גרף ספציפי
|
||||
נדרש לשאילתא על גרפים בעלי שם או כל הגרפים.
|
||||
|
||||
## הפניות
|
||||
|
||||
- [מושגים של RDF 1.2](https://www.w3.org/TR/rdf12-concepts/)
|
||||
- [RDF-star ו-SPARQL-star](https://w3c.github.io/rdf-star/)
|
||||
- [סט נתונים RDF](https://www.w3.org/TR/rdf11-concepts/#section-dataset)
|
||||
465
docs/tech-specs/he/graphql-query.he.md
Normal file
465
docs/tech-specs/he/graphql-query.he.md
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
---
|
||||
layout: default
|
||||
title: "GraphQL Query Technical Specification"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# GraphQL Query Technical Specification
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## Overview
|
||||
|
||||
<<<<<<< HEAD
|
||||
מפרט זה מתאר את יישום ממשק שאילתות GraphQL עבור אחסון נתונים מובנים של TrustGraph ב-Apache Cassandra. בהתבסס על יכולות הנתונים המובנים המתוארות במפרט structured-data.md, מסמך זה מפרט כיצד שאילתות GraphQL יבוצעו כנגד טבלאות Cassandra המכילות אובייקטים מובנים שחולצו והועברו.
|
||||
=======
|
||||
מפרט זה מתאר את יישום ממשק שאילתות GraphQL עבור אחסון נתונים מובנים של TrustGraph ב-Apache Cassandra. בהתבסס על יכולות הנתונים המובנים המתוארות במפרט structured-data.md, מסמך זה מפרט כיצד שאילתות GraphQL יבוצעו כנגד טבלאות Cassandra המכילות אובייקטים מובנים שחולצו ויועברו.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
שירות שאילתות GraphQL יספק ממשק גמיש ובטוח טיפוסית לשאילתות נתונים מובנים המאוחסנים ב-Cassandra. הוא יסתגל באופן דינמי לשינויים בסכימה, יתמוך בשאילתות מורכבות כולל קשרים בין אובייקטים, וישתלב בצורה חלקה עם ארכיטקטורת העברת הודעות הקיימת של TrustGraph.
|
||||
|
||||
## Goals
|
||||
|
||||
**תמיכה דינמית בסכימה**: הסתגלות אוטומטית לשינויים בסכימה בתצורה ללא אתחולים מחדש של השירות
|
||||
<<<<<<< HEAD
|
||||
**עמידה בתקני GraphQL**: מתן ממשק GraphQL סטנדרטי התואם לכלי לקוחות GraphQL קיימים
|
||||
**שאילתות Cassandra יעילות**: המרת שאילתות GraphQL לשאילתות CQL יעילות של Cassandra תוך כיבוד מפתחות מחיצה ואינדקסים
|
||||
**פתרון קשרים**: תמיכה במאפייני פותרים עבור קשרים בין סוגי אובייקטים שונים
|
||||
**בטיחות טיפוסים**: הבטחת ביצוע שאילתות ובניית תגובות בצורה בטוחה טיפוסית בהתבסס על הגדרות סכימה
|
||||
**ביצועים ניתנים להרחבה**: טיפול יעיל בשאילתות מקבילות עם ניהול חיבורים מתאים ואופטימיזציה של שאילתות
|
||||
=======
|
||||
**עמידה בתקני GraphQL**: מתן ממשק GraphQL סטנדרטי התואם לכלי ולקוחות GraphQL קיימים
|
||||
**שאילתות Cassandra יעילות**: המרת שאילתות GraphQL לשאילתות CQL יעילות של Cassandra תוך כיבוד מפתחות מחיצה ואינדקסים
|
||||
**פתרון קשרים**: תמיכה בפתרוני שדות עבור קשרים בין סוגי אובייקטים שונים
|
||||
**בטיחות טיפוסים**: הבטחת ביצוע שאילתות ובניית תגובות בצורה בטוחה טיפוסית בהתבסס על הגדרות סכימה
|
||||
**ביצועים ניתנים להרחבה**: טיפול יעיל בשאילתות מקבילות עם ניהול בריכת חיבורים ואופטימיזציה של שאילתות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**אינטגרציה של בקשות/תגובות**: שמירה על תאימות לדפוס בקשות/תגובות המבוסס על Pulsar של TrustGraph
|
||||
**טיפול בשגיאות**: מתן דיווח מקיף על שגיאות עבור חוסר התאמה בסכימה, שגיאות שאילתות ובעיות אימות נתונים
|
||||
|
||||
## Background
|
||||
|
||||
<<<<<<< HEAD
|
||||
יישום אחסון הנתונים המובנים (trustgraph-flow/trustgraph/storage/objects/cassandra/) כותב אובייקטים לטבלאות Cassandra בהתבסס על הגדרות סכימה המאוחסנות במערכת התצורה של TrustGraph. טבלאות אלה משתמשות במבנה מפתח מחיצה מורכב עם אוספים ומפתחות ראשיים המוגדרים בסכימה, המאפשרות שאילתות יעילות בתוך אוספים.
|
||||
|
||||
מגבלות קיימות שספציפיקציה זו מתייחסת אליהן:
|
||||
=======
|
||||
יישום אחסון הנתונים המובנים (trustgraph-flow/trustgraph/storage/objects/cassandra/) כותב אובייקטים לטבלאות Cassandra בהתבסס על הגדרות סכימה המאוחסנות במערכת התצורה של TrustGraph. טבלאות אלה משתמשות במבנה מפתח מחיצה מורכב עם אוספים ומפתחות ראשיים המוגדרים בסכימה, המאפשרים שאילתות יעילות בתוך אוספים.
|
||||
|
||||
מגבלות נוכחיות שמתפרט זה מטפל בהן:
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
אין ממשק שאילתות עבור הנתונים המובנים המאוחסנים ב-Cassandra
|
||||
חוסר יכולת לנצל את יכולות השאילתות החזקות של GraphQL עבור נתונים מובנים
|
||||
חוסר תמיכה במעבר על קשרים בין אובייקטים קשורים
|
||||
היעדר שפה סטנדרטית לגישה לנתונים מובנים
|
||||
|
||||
שירות שאילתות GraphQL יסגור את הפערים הללו על ידי:
|
||||
מתן ממשק GraphQL סטנדרטי לשאילתות של טבלאות Cassandra
|
||||
יצירת סכימות GraphQL באופן דינמי מתצורה של TrustGraph
|
||||
המרת יעילה של שאילתות GraphQL לשאילתות CQL של Cassandra
|
||||
<<<<<<< HEAD
|
||||
תמיכה בפתרון קשרים באמצעות פותרים של שדות
|
||||
=======
|
||||
תמיכה בפתרון קשרים באמצעות פתרוני שדות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## Technical Design
|
||||
|
||||
### Architecture
|
||||
|
||||
שירות שאילתות GraphQL ייושם כמעבד זרימה חדש של TrustGraph תוך שימוש בדפוסים מבוססים:
|
||||
|
||||
**מיקום מודול**: `trustgraph-flow/trustgraph/query/objects/cassandra/`
|
||||
|
||||
**רכיבים מרכזיים**:
|
||||
|
||||
1. **מעבד שירות שאילתות GraphQL**
|
||||
מרחיב את מחלקת FlowProcessor הבסיסית
|
||||
מיישם דפוס בקשה/תגובה הדומה לשירותי שאילתות קיימים
|
||||
מנטר את התצורה עבור עדכוני סכימה
|
||||
שומר על סכימת GraphQL מסונכרנת עם התצורה
|
||||
|
||||
<<<<<<< HEAD
|
||||
2. **מחולל סכימה דינמי**
|
||||
ממיר הגדרות RowSchema של TrustGraph לטיפוסי GraphQL
|
||||
יוצר טיפוסי אובייקטים של GraphQL עם הגדרות שדות מתאימות
|
||||
מייצר טיפוס שורש Query עם פותרים מבוססי אוספים
|
||||
=======
|
||||
2. **מחולל סכימה דינמית**
|
||||
ממיר הגדרות RowSchema של TrustGraph לסוגי GraphQL
|
||||
יוצר סוגי אובייקטים של GraphQL עם הגדרות שדות מתאימות
|
||||
מייצר סוג שאילתא ראשי עם פותרים מבוססי אוספים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
מעדכן את סכימת GraphQL כאשר התצורה משתנה
|
||||
|
||||
3. **מבצע שאילתות**
|
||||
מנתח שאילתות GraphQL נכנס באמצעות ספריית Strawberry
|
||||
מאמת שאילתות כנגד הסכימה הנוכחית
|
||||
מבצע שאילתות ומחזיר תגובות מובנות
|
||||
מטפל בשגיאות בצורה אלגנטית עם הודעות שגיאה מפורטות
|
||||
|
||||
4. **מתרגם שאילתות Cassandra**
|
||||
ממיר בחירות GraphQL לשאילתות CQL
|
||||
מייעל שאילתות בהתבסס על אינדקסים ומפתחות מחיצה זמינים
|
||||
מטפל בסינון, דפוס ומיון
|
||||
<<<<<<< HEAD
|
||||
מנהל ניהול חיבורים ומחזור חיים של סשן
|
||||
|
||||
5. **פותר קשרים**
|
||||
מיישם פותרים של שדות עבור קשרים בין אובייקטים
|
||||
=======
|
||||
מנהל ניהול בריכת חיבורים ומחזור חיים של סשן
|
||||
|
||||
5. **פתרון קשרים**
|
||||
מיישם פתרוני שדות עבור קשרים בין אובייקטים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
מבצע טעינה באצווה יעילה כדי למנוע שאילתות N+1
|
||||
שומר על קשרים פתורים בהקשר הבקשה
|
||||
תומך במעבר קשרים קדימה ואחורה
|
||||
|
||||
### ניטור סכימת תצורה
|
||||
|
||||
השירות יירשם למטפל תצורה כדי לקבל עדכוני סכימה:
|
||||
|
||||
```python
|
||||
self.register_config_handler(self.on_schema_config)
|
||||
```
|
||||
|
||||
כאשר סכימות משתנות:
|
||||
1. ניתוח הגדרות סכימה חדשות מקובץ התצורה
|
||||
2. יצירת סוגי GraphQL ופתרונות (resolvers) מחדש
|
||||
3. עדכון הסכימה הביצועית
|
||||
4. ניקוי מטמון כלשהו התלוי בסכימה
|
||||
|
||||
### יצירת סכימת GraphQL
|
||||
|
||||
עבור כל RowSchema בתצורה, יוצרים:
|
||||
|
||||
1. **סוג אובייקט GraphQL**:
|
||||
מיפוי סוגי שדות (string → String, integer → Int, float → Float, boolean → Boolean)
|
||||
סימון שדות חובה כלא-nullable ב-GraphQL
|
||||
הוספת תיאורי שדות מהסכימה
|
||||
|
||||
2. **שדות שאילתה ראשיים**:
|
||||
שאילתת אוסף (לדוגמה, `customers`, `transactions`)
|
||||
ארגומנטים לסינון המבוססים על שדות עם אינדקס
|
||||
תמיכה בדפוס של "paginate" (limit, offset)
|
||||
אפשרויות מיון עבור שדות הניתנים למיון
|
||||
|
||||
3. **שדות יחסים**:
|
||||
זיהוי יחסי מפתח זר מהסכימה
|
||||
יצירת פתרונות (resolvers) עבור אובייקטים קשורים
|
||||
תמיכה הן ביחסי אובייקט בודד והן ביחסי רשימה
|
||||
|
||||
### זרימת ביצוע שאילתות
|
||||
|
||||
1. **קבלת בקשה**:
|
||||
קבלת ObjectsQueryRequest מ-Pulsar
|
||||
חילוץ מחרוזת שאילתת GraphQL ומשתנים
|
||||
זיהוי משתמש והקשר של אוסף
|
||||
|
||||
2. **אימות שאילתה**:
|
||||
ניתוח שאילתת GraphQL באמצעות Strawberry
|
||||
אימות מול הסכימה הנוכחית
|
||||
בדיקת בחירות שדות וסוגי ארגומנטים
|
||||
|
||||
3. **יצירת CQL**:
|
||||
ניתוח בחירות GraphQL
|
||||
בניית שאילתת CQL עם סעיפי WHERE מתאימים
|
||||
הכללת האוסף במפתח מחיצה
|
||||
החלת פילטרים המבוססים על ארגומנטים של GraphQL
|
||||
|
||||
4. **ביצוע שאילתה**:
|
||||
ביצוע שאילתת CQL נגד Cassandra
|
||||
מיפוי תוצאות למבנה תגובת GraphQL
|
||||
פתרון כל שדות היחסים
|
||||
עיצוב התגובה בהתאם למפרט של GraphQL
|
||||
|
||||
5. **העברת תגובה**:
|
||||
יצירת ObjectsQueryResponse עם תוצאות
|
||||
הכללת כל שגיאות הביצוע
|
||||
שליחת תגובה דרך Pulsar עם מזהה מתאם
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
<<<<<<< HEAD
|
||||
> **הערה**: קיימת סכימת StructuredQueryRequest/Response קיימת ב-`trustgraph-base/trustgraph/schema/services/structured_query.py`. עם זאת, היא חסרה שדות קריטיים (משתמש, אוסף) ומשתמשת בסוגים לא אופטימליים. הסכימות שלהלן מייצגות את ההתפתחות המומלצת, שעליה להחליף את הסכימות הקיימות או ליצור סוגי ObjectsQueryRequest/Response חדשים.
|
||||
=======
|
||||
> **הערה**: קיימת סכימת StructuredQueryRequest/Response קיימת ב-`trustgraph-base/trustgraph/schema/services/structured_query.py`. עם זאת, היא חסרה שדות קריטיים (משתמש, אוסף) ומשתמשת בסוגים לא אופטימליים. הסכימות שלהלן מייצגות את ההתפתחות המומלצת, שעשויה להחליף את הסכימות הקיימות או ליצור סוגי ObjectsQueryRequest/Response חדשים.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### סכימת בקשה (ObjectsQueryRequest)
|
||||
|
||||
```python
|
||||
from pulsar.schema import Record, String, Map, Array
|
||||
|
||||
class ObjectsQueryRequest(Record):
|
||||
user = String() # Cassandra keyspace (follows pattern from TriplesQueryRequest)
|
||||
collection = String() # Data collection identifier (required for partition key)
|
||||
query = String() # GraphQL query string
|
||||
variables = Map(String()) # GraphQL variables (consider enhancing to support all JSON types)
|
||||
operation_name = String() # Operation to execute for multi-operation documents
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
**ההצדקה לשינויים מתוך בקשת StructuredQueryRequest קיימת:**
|
||||
הוספת השדות `user` ו-`collection` כדי להתאים לדפוס של שירותי שאילתות אחרים.
|
||||
שדות אלה חיוניים לזיהוי ה-keyspace והקולקציה של Cassandra.
|
||||
המשתנים נשארים מסוג Map(String()) כרגע, אך באופן אידיאלי צריכים לתמוך בכל סוגי ה-JSON.
|
||||
|
||||
#### סכימת תגובה (ObjectsQueryResponse)
|
||||
=======
|
||||
**ההצדקה לשינויים מהבקשה המובנית הקיימת (StructuredQueryRequest):**
|
||||
הוספת השדות `user` ו-`collection` כדי להתאים לדפוס של שירותי שאילתות אחרים.
|
||||
שדות אלה חיוניים לזיהוי מרחב המפתחות (keyspace) והאוסף (collection) של Cassandra.
|
||||
המשתנים נשארים מסוג Map(String()) כרגע, אך באופן אידיאלי צריכים לתמוך בכל סוגי ה-JSON.
|
||||
|
||||
#### סכימת התגובה (ObjectsQueryResponse)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```python
|
||||
from pulsar.schema import Record, String, Array
|
||||
from ..core.primitives import Error
|
||||
|
||||
class GraphQLError(Record):
|
||||
message = String()
|
||||
path = Array(String()) # Path to the field that caused the error
|
||||
extensions = Map(String()) # Additional error metadata
|
||||
|
||||
class ObjectsQueryResponse(Record):
|
||||
error = Error() # System-level error (connection, timeout, etc.)
|
||||
data = String() # JSON-encoded GraphQL response data
|
||||
errors = Array(GraphQLError) # GraphQL field-level errors
|
||||
extensions = Map(String()) # Query metadata (execution time, etc.)
|
||||
```
|
||||
|
||||
**ההצדקה לשינויים מ-StructuredQueryResponse הקיים:**
|
||||
מבחינה בין שגיאות מערכת (`error`) ושגיאות GraphQL (`errors`)
|
||||
משתמשת באובייקטי GraphQLError מובנים במקום מערך מחרוזות
|
||||
מוסיפה שדה `extensions` לצורך עמידה במפרט GraphQL
|
||||
שומרת על הנתונים כמחרוזת JSON לצורך תאימות, למרות שטיפוסים מקוריים היו עדיפים
|
||||
|
||||
### אופטימיזציה של שאילתות Cassandra
|
||||
|
||||
השירות יבצע אופטימיזציה של שאילתות Cassandra על ידי:
|
||||
|
||||
1. **כבוד למפתחות מחיצה:**
|
||||
תמיד לכלול אוסף בשאילתות
|
||||
להשתמש ביעילות במפתחות ראשיים המוגדרים בסכימה
|
||||
להימנע מסריקות טבלה מלאות
|
||||
|
||||
2. **ניצול אינדקסים:**
|
||||
להשתמש באינדקסים משניים לסינון
|
||||
לשלב מספר פילטרים במידת האפשר
|
||||
להזהיר כאשר שאילתות עשויות להיות לא יעילות
|
||||
|
||||
3. **טעינה באצווה:**
|
||||
לאסוף שאילתות קשר
|
||||
<<<<<<< HEAD
|
||||
לבצע אותן באצווה כדי להפחית את מספר הפעמים
|
||||
=======
|
||||
לבצע אותן באצווה כדי להפחית מעברים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
לשמור תוצאות בהקשר הבקשה
|
||||
|
||||
4. **ניהול חיבורים:**
|
||||
לשמור על סשנים קבועים של Cassandra
|
||||
להשתמש בבריכת חיבורים
|
||||
לטפל בחיבור מחדש במקרה של כשלים
|
||||
|
||||
### דוגמאות לשאילתות GraphQL
|
||||
|
||||
#### שאילתת אוסף פשוטה
|
||||
```graphql
|
||||
{
|
||||
customers(status: "active") {
|
||||
customer_id
|
||||
name
|
||||
email
|
||||
registration_date
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### שאילתה עם קשרים
|
||||
```graphql
|
||||
{
|
||||
orders(order_date_gt: "2024-01-01") {
|
||||
order_id
|
||||
total_amount
|
||||
customer {
|
||||
name
|
||||
email
|
||||
}
|
||||
items {
|
||||
product_name
|
||||
quantity
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### שאילתה מדורגת
|
||||
```graphql
|
||||
{
|
||||
products(limit: 20, offset: 40) {
|
||||
product_id
|
||||
name
|
||||
price
|
||||
category
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### תלותות יישום
|
||||
|
||||
**Strawberry GraphQL**: להגדרת סכימת GraphQL ולביצוע שאילתות
|
||||
**Cassandra Driver**: לחיבור למסד הנתונים (בשימוש כבר במודול האחסון)
|
||||
**TrustGraph Base**: עבור FlowProcessor והגדרות סכימה
|
||||
<<<<<<< HEAD
|
||||
**Configuration System**: לניטור ועדכון סכימות
|
||||
=======
|
||||
**Configuration System**: עבור ניטור ועדכון סכימות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### ממשק שורת הפקודה
|
||||
|
||||
השירות יספק פקודת CLI: `kg-query-objects-graphql-cassandra`
|
||||
|
||||
ארגומנטים:
|
||||
`--cassandra-host`: נקודת מגע של אשכול Cassandra
|
||||
`--cassandra-username`: שם משתמש לאימות
|
||||
`--cassandra-password`: סיסמה לאימות
|
||||
`--config-type`: סוג תצורה עבור סכימות (ברירת מחדל: "schema")
|
||||
ארגומנטים סטנדרטיים של FlowProcessor (תצורת Pulsar, וכו')
|
||||
|
||||
## אינטגרציה של API
|
||||
|
||||
### נושאים של Pulsar
|
||||
|
||||
**נושא קלט**: `objects-graphql-query-request`
|
||||
סכימה: ObjectsQueryRequest
|
||||
מקבל שאילתות GraphQL משירותי שער
|
||||
|
||||
**נושא פלט**: `objects-graphql-query-response`
|
||||
סכימה: ObjectsQueryResponse
|
||||
מחזיר תוצאות שאילתות ושגיאות
|
||||
|
||||
### אינטגרציה של שער
|
||||
|
||||
השער ושער הפוך יצטרכו נקודות קצה כדי:
|
||||
1. לקבל שאילתות GraphQL מלקוחות
|
||||
2. להעביר לשירות השאילתות דרך Pulsar
|
||||
3. להחזיר תגובות ללקוחות
|
||||
4. לתמוך בשאילתות אינטרוספקציה של GraphQL
|
||||
|
||||
### אינטגרציה של כלי סוכן
|
||||
|
||||
מחלקה חדשה של כלי סוכן תאפשר:
|
||||
יצירת שאילתות GraphQL משפה טבעית
|
||||
ביצוע ישיר של שאילתות GraphQL
|
||||
פרשנות ועיצוב תוצאות
|
||||
שילוב עם זרימות החלטה של סוכן
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
**הגבלת עומק שאילתה**: למנוע שאילתות מקוננות עמוקות שעלולות לגרום לבעיות ביצועים
|
||||
**ניתוח מורכבות שאילתה**: להגביל את מורכבות השאילתה כדי למנוע מיצוי משאבים
|
||||
**הרשאות ברמת השדה**: תמיכה עתידית בשליטה על גישה ברמת השדה בהתבסס על תפקידי משתמש
|
||||
**ניקוי קלט**: לאמת ולנקות את כל קלט השאילתה כדי למנוע התקפות הזרקה
|
||||
**הגבלת קצב**: ליישם הגבלת קצב שאילתות למשתמש/אוסף
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
**תכנון שאילתות**: לנתח שאילתות לפני ביצוע כדי לייעל יצירת CQL
|
||||
**מטמון תוצאות**: לשקול שמירת נתונים שנגישים אליהם לעתים קרובות ברמת פותר השדה
|
||||
**בריכת חיבורים**: לשמור על בריכות חיבורים יעילות ל-Cassandra
|
||||
**פעולות אצווה**: לשלב מספר שאילתות כאשר אפשר כדי להפחית השהיה
|
||||
**ניטור**: לעקוב אחר מדדי ביצועי שאילתות לצורך אופטימיזציה
|
||||
|
||||
## אסטרטגיית בדיקה
|
||||
|
||||
### בדיקות יחידה
|
||||
יצירת סכימה מתוך הגדרות RowSchema
|
||||
ניתוח ותיקוף שאילתות GraphQL
|
||||
לוגיקת יצירת שאילתות CQL
|
||||
יישומים של פותרים (resolvers) של שדות
|
||||
|
||||
### בדיקות חוזה
|
||||
עמידה בחוזה הודעות Pulsar
|
||||
תקינות סכימת GraphQL
|
||||
אימות פורמט תגובה
|
||||
אימות מבנה שגיאות
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
ביצוע שאילתות מקצה לקצה מול מופע בדיקת Cassandra
|
||||
טיפול בעדכוני סכימה
|
||||
פתרון קשרים
|
||||
דפוסים של דף אחרי דף וסינון
|
||||
<<<<<<< HEAD
|
||||
תרחישי שגיאות
|
||||
=======
|
||||
תרחישי שגיאה
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### בדיקות ביצועים
|
||||
תפוקת שאילתות תחת עומס
|
||||
זמן תגובה עבור מורכבויות שאילתות שונות
|
||||
שימוש בזיכרון עם קבוצות תוצאות גדולות
|
||||
יעילות של מאגר חיבורים
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
<<<<<<< HEAD
|
||||
אין צורך במעבר מכיוון שזו יכולת חדשה. השירות י:
|
||||
1. יקרא סכימות קיימות מהתצורה
|
||||
=======
|
||||
אין צורך במעבר מכיוון שזו יכולת חדשה. השירות יעשה את הפעולות הבאות:
|
||||
1. יקרא סכימות קיימות מהגדרות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
2. יתחבר לטבלאות Cassandra קיימות שנוצרו על ידי מודול האחסון
|
||||
3. יתחיל לקבל שאילתות מיד עם הפריסה
|
||||
|
||||
## ציר זמן
|
||||
|
||||
שבוע 1-2: יישום ליבת השירות ויצירת סכימה
|
||||
שבוע 3: ביצוע שאילתות ותרגום CQL
|
||||
שבוע 4: פתרון קשרים ואופטימיזציה
|
||||
<<<<<<< HEAD
|
||||
שבוע 5: בדיקות וכוונון ביצועים
|
||||
=======
|
||||
שבוע 5: בדיקות וכיוונון ביצועים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
שבוע 6: שילוב עם שער ותיעוד
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
1. **אבולוציה של סכימה**: כיצד השירות צריך להתמודד עם שאילתות במהלך מעברי סכימה?
|
||||
אפשרות: תזמון שאילתות במהלך עדכוני סכימה
|
||||
אפשרות: תמיכה במספר גרסאות סכימה בו זמנית
|
||||
|
||||
2. **אסטרטגיית אחסון במטמון**: האם יש לאחסן תוצאות שאילתות במטמון?
|
||||
לשקול: תפוגה מבוססת זמן
|
||||
לשקול: ביטול תוקף מבוסס אירועים
|
||||
|
||||
3. **תמיכה בפדרציה**: האם השירות צריך לתמוך בפדרציה של GraphQL לשילוב עם מקורות נתונים אחרים?
|
||||
יאפשר שאילתות מאוחדות על נתונים מובנים וגרפיים
|
||||
|
||||
4. **תמיכה במנויים**: האם השירות צריך לתמוך במנויים של GraphQL לעדכונים בזמן אמת?
|
||||
ידרוש תמיכה ב-WebSocket בשער
|
||||
|
||||
5. **סקלרים מותאמים אישית**: האם יש לתמוך בסקלרים מותאמים אישית עבור סוגי נתונים ספציפיים לתחום?
|
||||
דוגמאות: DateTime, UUID, שדות JSON
|
||||
|
||||
## הפניות
|
||||
|
||||
מפרט טכני של נתונים מובנים: `docs/tech-specs/structured-data.md`
|
||||
תיעוד Strawberry GraphQL: https://strawberry.rocks/
|
||||
מפרט GraphQL: https://spec.graphql.org/
|
||||
הפניה ל-Apache Cassandra CQL: https://cassandra.apache.org/doc/stable/cassandra/cql/
|
||||
<<<<<<< HEAD
|
||||
תיעוד מעבד זרימת נתונים TrustGraph: תיעוד פנימי
|
||||
=======
|
||||
תיעוד מעבד זרימה של TrustGraph: תיעוד פנימי
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
807
docs/tech-specs/he/graphrag-performance-optimization.he.md
Normal file
807
docs/tech-specs/he/graphrag-performance-optimization.he.md
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לשיפור ביצועי GraphRAG"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לשיפור ביצועי GraphRAG
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
<<<<<<< HEAD
|
||||
מפרט זה מתאר שיפורי ביצועים מקיפים עבור אלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מבעיות ביצועים משמעותיות המגבילות את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה:
|
||||
|
||||
1. **אופטימיזציה של מעבר גרפים**: ביטול שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים באצווה.
|
||||
2. **אופטימיזציה של פתרון תגיות**: החלפת אחזור תגיות רציף בפעולות מקבילות/באצווה.
|
||||
3. **שיפור אסטרטגיית אחסון במטמון**: יישום אחסון במטמון חכם עם פינוי LRU וטעינה מראש.
|
||||
4. **אופטימיזציה של שאילתות**: הוספת שמירת תוצאות במטמון ואחסון במטמון של הטמעות לשיפור זמני התגובה.
|
||||
|
||||
## מטרות
|
||||
|
||||
**הפחתת נפח שאילתות מסד הנתונים**: השגת הפחתה של 50-80% בסך כל שאילתות מסד הנתונים באמצעות אצווה ואחסון במטמון.
|
||||
**שיפור זמני תגובה**: יעד לבניית תת-גרפים מהירה פי 3-5 ופתרון תגיות מהיר פי 2-3.
|
||||
**שיפור יכולת הרחבה**: תמיכה בגרפי ידע גדולים יותר עם ניהול זיכרון טוב יותר.
|
||||
**שמירה על דיוק**: שמירה על פונקציונליות ואיכות תוצאות GraphRAG הקיימות.
|
||||
**אפשרות לעיבוד מקבילי**: שיפור יכולות עיבוד מקבילי עבור בקשות מרובות בו-זמנית.
|
||||
**הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים.
|
||||
**הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור.
|
||||
**הבטחת אמינות**: הוספת טיפול בשגיאות ומנגנוני תזמון מתאימים.
|
||||
=======
|
||||
מפרט זה מתאר שיפורים מקיפים בביצועים עבור אלגוריתם GraphRAG (Graph Retrieval-Augmented Generation) ב-TrustGraph. יישום הנוכחי סובל מבעיות ביצועים משמעותיות המגבילות את יכולת ההרחבה וזמני התגובה. מפרט זה מתייחס לארבעה תחומים עיקריים של אופטימיזציה:
|
||||
|
||||
1. **אופטימיזציה של מעבר גרפים**: ביטול שאילתות מסד נתונים רקורסיביות לא יעילות ויישום חקר גרפים בקבוצות
|
||||
2. **אופטימיזציה של פתרון תגיות**: החלפת שליפת תגיות רציפה בפעולות מקבילות/בקבוצות
|
||||
3. **שיפור אסטרטגיית אחסון במטמון**: יישום אחסון במטמון חכם עם פינוי LRU וטעינה מראש
|
||||
4. **אופטימיזציה של שאילתות**: הוספת שמירת תוצאות במטמון ואחסון במטמון של הטמעות לשיפור זמני התגובה
|
||||
|
||||
## מטרות
|
||||
|
||||
**הפחתת נפח שאילתות מסד הנתונים**: השגת הפחתה של 50-80% בסך כל שאילתות מסד הנתונים באמצעות קיבוץ ואחסון במטמון
|
||||
**שיפור זמני תגובה**: יעד לבניית תת-גרפים מהירה פי 3-5 ופתרון תגיות מהיר פי 2-3
|
||||
**שיפור יכולת הרחבה**: תמיכה בגרפי ידע גדולים יותר עם ניהול זיכרון טוב יותר
|
||||
**שמירה על דיוק**: שמירה על פונקציונליות ואיכות תוצאות GraphRAG הקיימות
|
||||
**אפשרות לעיבוד מקבילי**: שיפור יכולות עיבוד מקבילי עבור בקשות מרובות בו-זמנית
|
||||
**הפחתת טביעת רגל של זיכרון**: יישום מבני נתונים וניהול זיכרון יעילים
|
||||
**הוספת יכולת ניטור**: הכללת מדדי ביצועים ויכולות ניטור
|
||||
**הבטחת אמינות**: הוספת טיפול מתאים בשגיאות ומנגנוני תזמון
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## רקע
|
||||
|
||||
יישום GraphRAG הנוכחי ב-`trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` מציג מספר בעיות ביצועים קריטיות המשפיעות באופן משמעותי על יכולת ההרחבה של המערכת:
|
||||
|
||||
### בעיות ביצועים נוכחיות
|
||||
|
||||
**1. מעבר גרפים לא יעיל (פונקציה `follow_edges`, שורות 79-127)**
|
||||
<<<<<<< HEAD
|
||||
מבצע 3 שאילתות נפרדות למסד הנתונים עבור כל ישות בכל רמת עומק.
|
||||
תבנית שאילתה: שאילתות מבוססות נושא, מבוססות פרידיקט ומבוססות אובייקט עבור כל ישות.
|
||||
ללא אצווה: כל שאילתה מעבדת רק ישות אחת בכל פעם.
|
||||
ללא זיהוי מעגלים: ניתן לחזור על צמתים זהים מספר פעמים.
|
||||
יישום רקורסיבי ללא שמירה במטמון מוביל למורכבות אקספוננציאלית.
|
||||
מורכבות זמן: O(entities × max_path_length × triple_limit³)
|
||||
|
||||
**2. פתרון תגיות רציף (פונקציה `get_labelgraph`, שורות 144-171)**
|
||||
מעבד כל רכיב משולש (נושא, פרידיקט, אובייקט) ברצף.
|
||||
כל קריאה ל-`maybe_label` עלולה לגרום לשאילתה למסד הנתונים.
|
||||
ללא ביצוע מקבילי או אצווה של שאילתות תגיות.
|
||||
גורם עד ל-3 × קריאות אישיות למסד הנתונים עבור גודל תת-גרף.
|
||||
|
||||
**3. אסטרטגיית אחסון במטמון בסיסית (פונקציה `maybe_label`, שורות 62-77)**
|
||||
מטמון מילון פשוט ללא מגבלות גודל או TTL.
|
||||
מדיניות פינוי מטמון חסרת גבולות מובילה לצמיחה בלתי מוגבלת של זיכרון.
|
||||
החסרה במטמון גורמת לשאילתות נפרדות למסד הנתונים.
|
||||
ללא טעינה מראש או אחסון במטמון חכם.
|
||||
|
||||
**4. תבניות שאילתות לא אופטימליות**
|
||||
שאילתות דמיון וקטורי לישויות אינן מאוחסנות במטמון בין בקשות דומות.
|
||||
ללא שמירת תוצאות במטמון לתבניות שאילתות חוזרות.
|
||||
חסרים אופטימיזציות שאילתות לתבניות גישה נפוצות.
|
||||
|
||||
**5. בעיות קריטיות של חיי אובייקט (`rag.py:96-102`)**
|
||||
**אובייקט GraphRag נוצר מחדש עבור כל בקשה**: מופע חדש נוצר עבור כל שאילתה, תוך אובדן כל יתרונות המטמון.
|
||||
**אובייקט שאילתה בעל אורך חיים קצר ביותר**: נוצר ונהרס בתוך ביצוע שאילתה יחיד (שורות 201-207).
|
||||
**מטמון תגיות מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר אובדים בין בקשות.
|
||||
**תקורה של יצירת לקוח מחדש**: לקוחות מסד נתונים פוטנציאליים מוקמים מחדש עבור כל בקשה.
|
||||
**ללא אופטימיזציה חוצה בקשות**: לא ניתן להפיק תועלת מתבניות שאילתות או שיתוף תוצאות.
|
||||
=======
|
||||
מבצע 3 שאילתות נפרדות למסד הנתונים עבור כל ישות בכל רמת עומק
|
||||
תבנית שאילתה: שאילתות מבוססות נושא, שאילתות מבוססות פרידיקט ושאילתות מבוססות אובייקט עבור כל ישות
|
||||
ללא קיבוץ: כל שאילתה מעבדת רק ישות אחת בכל פעם
|
||||
ללא זיהוי מעגלים: ניתן לחזור על צמתים זהים מספר פעמים
|
||||
יישום רקורסיבי ללא שמירה במטמון מוביל למורכבות אקספוננציאלית
|
||||
מורכבות זמן: O(entities × max_path_length × triple_limit³)
|
||||
|
||||
**2. פתרון תגיות רציף (פונקציה `get_labelgraph`, שורות 144-171)**
|
||||
מעבד כל רכיב משולש (נושא, פרידיקט, אובייקט) ברצף
|
||||
כל קריאה ל-`maybe_label` עלולה לגרום לשאילתה למסד הנתונים
|
||||
ללא ביצוע מקבילי או קיבוץ של שאילתות תגיות
|
||||
גורם עד ל-3 × קריאות אישיות למסד הנתונים עבור גודל תת-גרף
|
||||
|
||||
**3. אסטרטגיית אחסון במטמון בסיסית (פונקציה `maybe_label`, שורות 62-77)**
|
||||
מטמון מילון פשוט ללא מגבלות גודל או TTL
|
||||
מדיניות פינוי מטמון חסרת גבולות מובילה לצמיחה בלתי מוגבלת של זיכרון
|
||||
החסרה במטמון גורמת לשאילתות נפרדות למסד הנתונים
|
||||
ללא טעינה מראש או אחסון במטמון חכם
|
||||
|
||||
**4. תבניות שאילתות לא אופטימליות**
|
||||
שאילתות דמיון וקטורי לישויות אינן מאוחסנות במטמון בין בקשות דומות
|
||||
ללא שמירת תוצאות במטמון לתבניות שאילתות חוזרות
|
||||
חסרים אופטימיזציות שאילתות לתבניות גישה נפוצות
|
||||
|
||||
**5. בעיות קריטיות של חיי אובייקט (`rag.py:96-102`)**
|
||||
**אובייקט GraphRag נוצר מחדש עבור כל בקשה**: מופע חדש נוצר עבור כל שאילתה, ומאבד את כל יתרונות האחסון במטמון
|
||||
**אובייקט שאילתה בעל אורך חיים קצר ביותר**: נוצר ונהרס בתוך ביצוע שאילתה יחידה (שורות 201-207)
|
||||
**מטמון תגיות מאופס עבור כל בקשה**: חימום מטמון וידע שנצבר הולכים לאיבוד בין בקשות
|
||||
**תקורה של יצירת לקוח**: לקוחות מסד נתונים פוטנציאליים נוצרים מחדש עבור כל בקשה
|
||||
**ללא אופטימיזציה חוצה בקשות**: לא ניתן להפיק תועלת מתבניות שאילתות או שיתוף תוצאות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### ניתוח השפעת ביצועים
|
||||
|
||||
תרחיש גרוע ביותר נוכחי עבור שאילתה טיפוסית:
|
||||
<<<<<<< HEAD
|
||||
**אחזור ישות**: שאילתת דמיון וקטורית אחת.
|
||||
**מעבר גרפים**: entities × max_path_length × 3 × שאילתות triple_limit.
|
||||
**פתרון תגיות**: 3 × שאילתות תגיות אישיות עבור גודל תת-גרף.
|
||||
פלט חוזה (יש לעקוב אחר הפורמט המדויק).
|
||||
עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת 30 משולשים, גודל תת-גרף 150):
|
||||
=======
|
||||
**שליפת ישות**: שאילתה אחת לדמיון וקטורי
|
||||
**מעבר גרפים**: entities × max_path_length × 3 × שאילתות triple_limit
|
||||
**פתרון תגיות**: 3 × שאילתות אישיות לגודל תת-גרף
|
||||
פלט חוזה (יש לעקוב אחר הפורמט המדויק).
|
||||
עבור פרמטרים ברירת מחדל (50 ישויות, אורך נתיב 2, מגבלת טריפל של 30, גודל תת-גרף של 150):
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**מספר שאילתות מינימלי**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9,451 שאילתות למסד נתונים**
|
||||
**זמן תגובה**: 15-30 שניות עבור גרפים בגודל בינוני
|
||||
**שימוש בזיכרון**: צמיחה בלתי מוגבלת של מטמון לאורך זמן
|
||||
**יעילות מטמון**: 0% - המטמון מאופס בכל בקשה
|
||||
**תקורה של יצירת אובייקטים**: אובייקטי GraphRag + שאילתה נוצרים/נמחקים עבור כל בקשה
|
||||
|
||||
מפרט זה מתייחס לפערים אלה על ידי יישום שאילתות באצווה, מטמון חכם ועיבוד מקבילי. על ידי אופטימיזציה של דפוסי שאילתות וגישה לנתונים, TrustGraph יכולה:
|
||||
לתמוך בגרפי ידע בקנה מידה ארגוני עם מיליוני ישויות
|
||||
לספק זמני תגובה של פחות משנייה עבור שאילתות טיפוסיות
|
||||
לטפל במאות בקשות GraphRAG מקבילות
|
||||
להתרחב ביעילות עם גודל ומורכבות הגרף
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
אופטימיזציית הביצועים של GraphRAG דורשת את הרכיבים הטכניים הבאים:
|
||||
|
||||
#### 1. **שינוי ארכיטקטורה של משך חיי אובייקטים**
|
||||
**הפוך את GraphRag לבעל חיים ארוך**: העבר את המופע של GraphRag לרמה של המעבד לצורך שמירה בין בקשות
|
||||
**שמור על מטמון**: שמור על מטמון תוויות, מטמון הטבעות ומטמון תוצאות שאילתה בין בקשות
|
||||
<<<<<<< HEAD
|
||||
**אופטימיזציה של אובייקט שאילתה**: שנה את מבנה אובייקט השאילתה כהקשר ביצוע קל משקל, ולא כמכל נתונים
|
||||
=======
|
||||
**אופטימיזציה של אובייקט שאילתה**: שנה את מבנה אובייקט השאילתה כך שיהיה הקשר ביצוע קל משקל, ולא מיכל נתונים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**שמירה על חיבורים**: שמור על חיבורי לקוח למסד הנתונים בין בקשות
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (עודכן)
|
||||
|
||||
#### 2. **מנוע מעבר גרפים מותאם**
|
||||
החלף את `follow_edges` רקורסיבי בחיפוש רוחב-ראשוני איטרטיבי
|
||||
<<<<<<< HEAD
|
||||
הטמעת עיבוד אצווה של ישויות בכל רמת מעבר
|
||||
הוסף זיהוי מעגלים באמצעות מעקב אחר צמתים מבקרים
|
||||
כלול סיום מוקדם כאשר מגיעים למגבלות
|
||||
=======
|
||||
הטמע עיבוד אצווה של ישויות בכל רמת מעבר
|
||||
הוסף זיהוי מעגלים באמצעות מעקב אחר צמתים שנצפו
|
||||
כלול סיום מוקדם כאשר מגיעים לגבולות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py`
|
||||
|
||||
#### 3. **מערכת פתרון תוויות מקבילה**
|
||||
שאילתות תוויות באצווה עבור מספר ישויות בו-זמנית
|
||||
<<<<<<< HEAD
|
||||
הטמעת דפוסי async/await לגישה מקבילה למסד הנתונים
|
||||
=======
|
||||
הטמע דפוסי async/await לגישה מקבילה למסד הנתונים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
הוסף אחזור מוקדם לדפוסי תוויות נפוצים
|
||||
כלול אסטרטגיות חימום מטמון תוויות
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py`
|
||||
|
||||
#### 4. **שכבת מטמון תוויות שמרנית**
|
||||
מטמון LRU עם TTL קצר עבור תוויות בלבד (5 דקות) כדי לאזן בין ביצועים ועקביות
|
||||
ניטור מדדי מטמון ויחס פגיעות
|
||||
**ללא מטמון הטבעות**: כבר שמורים עבור כל שאילתה, אין יתרון בין שאילתות
|
||||
**ללא מטמון תוצאות שאילתה**: עקב חששות לגבי עקביות שינוי גרף
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py`
|
||||
|
||||
#### 5. **מסגרת אופטימיזציה של שאילתות**
|
||||
ניתוח אופטימיזציה של דפוסי שאילתות והצעות
|
||||
מתאם שאילתות באצווה לגישה למסד הנתונים
|
||||
<<<<<<< HEAD
|
||||
ניהול בריכת חיבורים וזמן קצוב של שאילתות
|
||||
=======
|
||||
ניהול בריכת חיבורים ותזמון תפוגה של שאילתות
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
ניטור ביצועים ואיסוף מדדים
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py`
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### מצב מעבר גרפים מותאם
|
||||
|
||||
מנוע המעבר שומר על מצב כדי להימנע מפעולות מיותרות:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TraversalState:
|
||||
visited_entities: Set[str]
|
||||
current_level_entities: Set[str]
|
||||
next_level_entities: Set[str]
|
||||
subgraph: Set[Tuple[str, str, str]]
|
||||
depth: int
|
||||
query_batch: List[TripleQuery]
|
||||
```
|
||||
|
||||
גישה זו מאפשרת:
|
||||
<<<<<<< HEAD
|
||||
זיהוי יעיל של מעגלים באמצעות מעקב אחר ישויות שביקרו
|
||||
הכנת שאילתות באצווה בכל רמת מעבר
|
||||
ניהול מצב חסכוני בזיכרון
|
||||
סיום מוקדם כאשר מגיעים למגבלות גודל
|
||||
=======
|
||||
זיהוי יעיל של מעגלים באמצעות מעקב אחר ישויות שכבר נבדקו.
|
||||
הכנת שאילתות בקבוצות בכל רמת מעבר.
|
||||
ניהול מצב חסכוני בזיכרון.
|
||||
סיום מוקדם כאשר מגבלות גודל הושגו.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
#### מבנה מטמון משופר
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class CacheEntry:
|
||||
value: Any
|
||||
timestamp: float
|
||||
access_count: int
|
||||
ttl: Optional[float]
|
||||
|
||||
class CacheManager:
|
||||
label_cache: LRUCache[str, CacheEntry]
|
||||
embedding_cache: LRUCache[str, CacheEntry]
|
||||
query_result_cache: LRUCache[str, CacheEntry]
|
||||
cache_stats: CacheStatistics
|
||||
```
|
||||
|
||||
#### מבני שאילתות אצווה
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class BatchTripleQuery:
|
||||
entities: List[str]
|
||||
query_type: QueryType # SUBJECT, PREDICATE, OBJECT
|
||||
limit_per_entity: int
|
||||
|
||||
@dataclass
|
||||
class BatchLabelQuery:
|
||||
entities: List[str]
|
||||
predicate: str = LABEL
|
||||
```
|
||||
|
||||
### ממשקי API
|
||||
|
||||
#### ממשקי API חדשים:
|
||||
|
||||
**ממשק GraphTraversal API**
|
||||
```python
|
||||
async def optimized_follow_edges_batch(
|
||||
entities: List[str],
|
||||
max_depth: int,
|
||||
triple_limit: int,
|
||||
max_subgraph_size: int
|
||||
) -> Set[Tuple[str, str, str]]
|
||||
```
|
||||
|
||||
**ממשק API לפתרון תגיות אצווה**
|
||||
```python
|
||||
async def resolve_labels_batch(
|
||||
entities: List[str],
|
||||
cache_manager: CacheManager
|
||||
) -> Dict[str, str]
|
||||
```
|
||||
|
||||
**ממשק ניהול מטמון (Cache Management API)**
|
||||
```python
|
||||
class CacheManager:
|
||||
async def get_or_fetch_label(self, entity: str) -> str
|
||||
async def get_or_fetch_embeddings(self, query: str) -> List[float]
|
||||
async def cache_query_result(self, query_hash: str, result: Any, ttl: int)
|
||||
def get_cache_statistics(self) -> CacheStatistics
|
||||
```
|
||||
|
||||
#### ממשקי API שעודכנו:
|
||||
|
||||
**GraphRag.query()** - שופר עם אופטימיזציות ביצועים:
|
||||
הוסף פרמטר cache_manager לשליטה על המטמון
|
||||
הוסף ערך החזרה performance_metrics
|
||||
הוסף פרמטר query_timeout לאמינות
|
||||
|
||||
**מחלקה Query** - שופרה לעיבוד באצווה:
|
||||
החלף עיבוד ישויות בודדות בפעולות באצווה
|
||||
הוסף מנהלי הקשר אסינכרוניים לניקוי משאבים
|
||||
הוסף פונקציות החזרה (callbacks) להתקדמות עבור פעולות ארוכות
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
#### שלב 0: שינוי ארכיטקטורה קריטי
|
||||
|
||||
**יישום בעייתי נוכחי:**
|
||||
```python
|
||||
# INEFFICIENT: GraphRag recreated every request
|
||||
class Processor(FlowProcessor):
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
# PROBLEM: New GraphRag instance per request!
|
||||
self.rag = GraphRag(
|
||||
embeddings_client = flow("embeddings-request"),
|
||||
graph_embeddings_client = flow("graph-embeddings-request"),
|
||||
triples_client = flow("triples-request"),
|
||||
prompt_client = flow("prompt-request"),
|
||||
verbose=True,
|
||||
)
|
||||
# Cache starts empty every time - no benefit from previous requests
|
||||
response = await self.rag.query(...)
|
||||
|
||||
# VERY SHORT-LIVED: Query object created/destroyed per request
|
||||
class GraphRag:
|
||||
async def query(self, query, user="trustgraph", collection="default", ...):
|
||||
q = Query(rag=self, user=user, collection=collection, ...) # Created
|
||||
kg = await q.get_labelgraph(query) # Used briefly
|
||||
# q automatically destroyed when function exits
|
||||
```
|
||||
|
||||
**ארכיטקטורה ארוכת טווח ומותאמת:**
|
||||
```python
|
||||
class Processor(FlowProcessor):
|
||||
def __init__(self, **params):
|
||||
super().__init__(**params)
|
||||
self.rag_instance = None # Will be initialized once
|
||||
self.client_connections = {}
|
||||
|
||||
async def initialize_rag(self, flow):
|
||||
"""Initialize GraphRag once, reuse for all requests"""
|
||||
if self.rag_instance is None:
|
||||
self.rag_instance = LongLivedGraphRag(
|
||||
embeddings_client=flow("embeddings-request"),
|
||||
graph_embeddings_client=flow("graph-embeddings-request"),
|
||||
triples_client=flow("triples-request"),
|
||||
prompt_client=flow("prompt-request"),
|
||||
verbose=True,
|
||||
)
|
||||
return self.rag_instance
|
||||
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
# REUSE the same GraphRag instance - caches persist!
|
||||
rag = await self.initialize_rag(flow)
|
||||
|
||||
# Query object becomes lightweight execution context
|
||||
response = await rag.query_with_context(
|
||||
query=v.query,
|
||||
execution_context=QueryContext(
|
||||
user=v.user,
|
||||
collection=v.collection,
|
||||
entity_limit=entity_limit,
|
||||
# ... other params
|
||||
)
|
||||
)
|
||||
|
||||
class LongLivedGraphRag:
|
||||
def __init__(self, ...):
|
||||
# CONSERVATIVE caches - balance performance vs consistency
|
||||
self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness
|
||||
# Note: No embedding cache - already cached per-query, no cross-query benefit
|
||||
# Note: No query result cache due to consistency concerns
|
||||
self.performance_metrics = PerformanceTracker()
|
||||
|
||||
async def query_with_context(self, query: str, context: QueryContext):
|
||||
# Use lightweight QueryExecutor instead of heavyweight Query object
|
||||
executor = QueryExecutor(self, context) # Minimal object
|
||||
return await executor.execute(query)
|
||||
|
||||
@dataclass
|
||||
class QueryContext:
|
||||
"""Lightweight execution context - no heavy operations"""
|
||||
user: str
|
||||
collection: str
|
||||
entity_limit: int
|
||||
triple_limit: int
|
||||
max_subgraph_size: int
|
||||
max_path_length: int
|
||||
|
||||
class QueryExecutor:
|
||||
"""Lightweight execution context - replaces old Query class"""
|
||||
def __init__(self, rag: LongLivedGraphRag, context: QueryContext):
|
||||
self.rag = rag
|
||||
self.context = context
|
||||
# No heavy initialization - just references
|
||||
|
||||
async def execute(self, query: str):
|
||||
# All heavy lifting uses persistent rag caches
|
||||
return await self.rag.execute_optimized_query(query, self.context)
|
||||
```
|
||||
|
||||
שינוי ארכיטקטורה זה מספק:
|
||||
**הפחתת שאילתות מסד נתונים ב-10-20%** עבור גרפים עם קשרים נפוצים (בהשוואה ל-0% כיום)
|
||||
**ביטול תקורה של יצירת אובייקטים** עבור כל בקשה
|
||||
**בריכת חיבורים קבועה** ושימוש חוזר בלקוח
|
||||
**אופטימיזציה בין בקשות** בתוך חלונות TTL של מטמון
|
||||
|
||||
**מגבלה חשובה של עקביות מטמון:**
|
||||
אחסון מטמון לטווח ארוך מכניס סיכון של מידע מיושן כאשר ישויות/תוויות נמחקים או משתנים בגרף הבסיסי. מטמון LRU עם TTL מספק איזון בין שיפורי ביצועים ורעננות נתונים, אך אינו יכול לזהות שינויים בזמן אמת בגרף.
|
||||
|
||||
#### שלב 1: אופטימיזציה של מעבר גרפים
|
||||
|
||||
**בעיות ביישום הנוכחי:**
|
||||
```python
|
||||
# INEFFICIENT: 3 queries per entity per level
|
||||
async def follow_edges(self, ent, subgraph, path_length):
|
||||
# Query 1: s=ent, p=None, o=None
|
||||
res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit)
|
||||
# Query 2: s=None, p=ent, o=None
|
||||
res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit)
|
||||
# Query 3: s=None, p=None, o=ent
|
||||
res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit)
|
||||
```
|
||||
|
||||
**יישום אופטימלי:**
|
||||
```python
|
||||
async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]:
|
||||
visited = set()
|
||||
current_level = set(entities)
|
||||
subgraph = set()
|
||||
|
||||
for depth in range(max_depth):
|
||||
if not current_level or len(subgraph) >= self.max_subgraph_size:
|
||||
break
|
||||
|
||||
# Batch all queries for current level
|
||||
batch_queries = []
|
||||
for entity in current_level:
|
||||
if entity not in visited:
|
||||
batch_queries.extend([
|
||||
TripleQuery(s=entity, p=None, o=None),
|
||||
TripleQuery(s=None, p=entity, o=None),
|
||||
TripleQuery(s=None, p=None, o=entity)
|
||||
])
|
||||
|
||||
# Execute all queries concurrently
|
||||
results = await self.execute_batch_queries(batch_queries)
|
||||
|
||||
# Process results and prepare next level
|
||||
next_level = set()
|
||||
for result in results:
|
||||
subgraph.update(result.triples)
|
||||
next_level.update(result.new_entities)
|
||||
|
||||
visited.update(current_level)
|
||||
current_level = next_level - visited
|
||||
|
||||
return subgraph
|
||||
```
|
||||
|
||||
#### שלב 2: פתרון מקבילי של תגיות
|
||||
|
||||
**יישום סדרתי נוכחי:**
|
||||
```python
|
||||
# INEFFICIENT: Sequential processing
|
||||
for edge in subgraph:
|
||||
s = await self.maybe_label(edge[0]) # Individual query
|
||||
p = await self.maybe_label(edge[1]) # Individual query
|
||||
o = await self.maybe_label(edge[2]) # Individual query
|
||||
```
|
||||
|
||||
**יישום מקבילי אופטימלי:**
|
||||
```python
|
||||
async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]:
|
||||
# Collect all unique entities needing labels
|
||||
entities_to_resolve = set()
|
||||
for s, p, o in subgraph:
|
||||
entities_to_resolve.update([s, p, o])
|
||||
|
||||
# Remove already cached entities
|
||||
uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache]
|
||||
|
||||
# Batch query for all uncached labels
|
||||
if uncached_entities:
|
||||
label_results = await self.batch_label_query(uncached_entities)
|
||||
self.label_cache.update(label_results)
|
||||
|
||||
# Apply labels to subgraph
|
||||
return [
|
||||
(self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o))
|
||||
for s, p, o in subgraph
|
||||
]
|
||||
```
|
||||
|
||||
#### שלב 3: אסטרטגיית אחסון מטמון מתקדמת
|
||||
|
||||
**מטמון LRU עם TTL:**
|
||||
```python
|
||||
class LRUCacheWithTTL:
|
||||
def __init__(self, max_size: int, default_ttl: int = 3600):
|
||||
self.cache = OrderedDict()
|
||||
self.max_size = max_size
|
||||
self.default_ttl = default_ttl
|
||||
self.access_times = {}
|
||||
|
||||
async def get(self, key: str) -> Optional[Any]:
|
||||
if key in self.cache:
|
||||
# Check TTL expiration
|
||||
if time.time() - self.access_times[key] > self.default_ttl:
|
||||
del self.cache[key]
|
||||
del self.access_times[key]
|
||||
return None
|
||||
|
||||
# Move to end (most recently used)
|
||||
self.cache.move_to_end(key)
|
||||
return self.cache[key]
|
||||
return None
|
||||
|
||||
async def put(self, key: str, value: Any):
|
||||
if key in self.cache:
|
||||
self.cache.move_to_end(key)
|
||||
else:
|
||||
if len(self.cache) >= self.max_size:
|
||||
# Remove least recently used
|
||||
oldest_key = next(iter(self.cache))
|
||||
del self.cache[oldest_key]
|
||||
del self.access_times[oldest_key]
|
||||
|
||||
self.cache[key] = value
|
||||
self.access_times[key] = time.time()
|
||||
```
|
||||
|
||||
#### שלב 4: אופטימיזציה וניטור של שאילתות
|
||||
|
||||
**איסוף מדדי ביצועים:**
|
||||
```python
|
||||
@dataclass
|
||||
class PerformanceMetrics:
|
||||
total_queries: int
|
||||
cache_hits: int
|
||||
cache_misses: int
|
||||
avg_response_time: float
|
||||
subgraph_construction_time: float
|
||||
label_resolution_time: float
|
||||
total_entities_processed: int
|
||||
memory_usage_mb: float
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
**זמן תגובה מקסימלי ומנגנון ניתוב מחדש:**
|
||||
=======
|
||||
**מגבלת זמן שאילתה ומנגנון ניתוב:**
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
```python
|
||||
async def execute_with_timeout(self, query_func, timeout: int = 30):
|
||||
try:
|
||||
return await asyncio.wait_for(query_func(), timeout=timeout)
|
||||
except asyncio.TimeoutError:
|
||||
logger.error(f"Query timeout after {timeout}s")
|
||||
raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s")
|
||||
```
|
||||
|
||||
## שיקולים בנוגע לעקביות מטמון
|
||||
|
||||
<<<<<<< HEAD
|
||||
**פשרות בנוגע לרעננות נתונים:**
|
||||
**מטמון תוויות (TTL של 5 דקות)**: סיכון להצגת תוויות של ישויות שנמחקו/ששמותיהן שונו.
|
||||
**ללא שמירת מטמון של הטמעות (embeddings)**: לא נדרש - הטמעות כבר שמורות מטמון עבור כל שאילתה.
|
||||
**ללא שמירת מטמון של תוצאות**: מונע קבלת תוצאות תת-גרף לא עדכניות מישויות/קשרים שנמחקו.
|
||||
=======
|
||||
**פשרות בין רעננות נתונים:**
|
||||
**מטמון תוויות (TTL של 5 דקות)**: סיכון בהצגת תוויות של ישויות שנמחקו/ששמותיהן שונו.
|
||||
**ללא שמירת מטמון של הטמעות (embeddings)**: לא נדרש - הטמעות כבר שמורות מטמון עבור כל שאילתה.
|
||||
**ללא שמירת מטמון של תוצאות**: מונע תוצאות תת-גרף שגויות מישויות/קשרים שנמחקו.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**אסטרטגיות הפחתה:**
|
||||
**ערכי TTL שמרניים**: איזון בין שיפורי ביצועים (10-20%) לבין רעננות נתונים.
|
||||
**מנגנוני ביטול מטמון**: שילוב אופציונלי עם אירועי שינוי בגרף.
|
||||
<<<<<<< HEAD
|
||||
**לוחות מחוונים לניטור**: מעקב אחר אחוזי פגיעה במטמון (cache hit rates) לעומת מקרים של נתונים לא עדכניים.
|
||||
**מדיניות מטמון הניתנות לתצורה**: אפשרות לכוונון פר-פריסה בהתאם לתדירות השינויים.
|
||||
|
||||
**תצורת מטמון מומלצת בהתאם לקצב שינויים בגרף:**
|
||||
**קצב שינויים גבוה (>100 שינויים/שעה)**: TTL=60 שניות, גדלי מטמון קטנים יותר.
|
||||
**קצב שינויים בינוני (10-100 שינויים/שעה)**: TTL=300 שניות (ברירת מחדל).
|
||||
**קצב שינויים נמוך (<10 שינויים/שעה)**: TTL=600 שניות, גדלי מטמון גדולים יותר.
|
||||
|
||||
## שיקולים בנוגע לאבטחה
|
||||
|
||||
**מניעת הזרקת שאילתות:**
|
||||
אימות כל מזהי ישויות ופרמטרים של שאילתות.
|
||||
שימוש בשאילתות מפורמטות עבור כל אינטראקציות עם מסד הנתונים.
|
||||
יישום מגבלות על מורכבות השאילתות כדי למנוע התקפות מניעת שירות (DoS).
|
||||
|
||||
**הגנה על משאבים:**
|
||||
אכיפת מגבלות על גודל תת-גרף מקסימלי.
|
||||
יישום זמני קצבה לשאילתות כדי למנוע מיצוי משאבים.
|
||||
הוספת ניטור מגבלות לשימוש בזיכרון.
|
||||
=======
|
||||
**לוחות מחוונים לניטור**: מעקב אחר שיעורי פגיעות במטמון לעומת מקרים של נתונים לא מעודכנים.
|
||||
**מדיניות מטמון הניתנות לתצורה**: אפשרות לכוונון עדין בהתאם לתדירות השינויים בכל פריסה.
|
||||
|
||||
**תצורת מטמון מומלצת בהתאם לקצב שינויים בגרף:**
|
||||
**שינויים רבים (>100 שינויים/שעה)**: TTL=60 שניות, גדלי מטמון קטנים יותר.
|
||||
**שינויים בינוניים (10-100 שינויים/שעה)**: TTL=300 שניות (ברירת מחדל).
|
||||
**שינויים מעטים (<10 שינויים/שעה)**: TTL=600 שניות, גדלי מטמון גדולים יותר.
|
||||
|
||||
## שיקולים בנושא אבטחה
|
||||
|
||||
**מניעת הזרקת שאילתות:**
|
||||
אימות כל מזהי ישויות ופרמטרים של שאילתות.
|
||||
שימוש בשאילתות מפורטות עבור כל אינטראקציות עם מסד הנתונים.
|
||||
יישום מגבלות מורכבות שאילתות למניעת התקפות מניעת שירות (DoS).
|
||||
|
||||
**הגנה על משאבים:**
|
||||
אכיפת מגבלות גודל תת-גרף מקסימלי.
|
||||
יישום זמני קצבי שאילתות למניעת מיצוי משאבים.
|
||||
הוספת ניטור מגבלות שימוש בזיכרון.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**בקרת גישה:**
|
||||
שמירה על בידוד משתמשים ואוספים קיימים.
|
||||
הוספת רישום ביקורת עבור פעולות המשפיעות על הביצועים.
|
||||
יישום הגבלת קצב עבור פעולות יקרות.
|
||||
|
||||
<<<<<<< HEAD
|
||||
## שיקולים בנוגע לביצועים
|
||||
=======
|
||||
## שיקולים בנושא ביצועים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### שיפורי ביצועים צפויים
|
||||
|
||||
**הפחתת מספר שאילתות:**
|
||||
נוכחי: ~9,000+ שאילתות עבור בקשה טיפוסית.
|
||||
אופטימלי: ~50-100 שאילתות מקובצות (הפחתה של 98%).
|
||||
|
||||
**שיפורי זמן תגובה:**
|
||||
מעבר בגרף: 15-20 שניות → 3-5 שניות (מהיר פי 4-5).
|
||||
פתרון תוויות: 8-12 שניות → 2-4 שניות (מהיר פי 3).
|
||||
שאילתה כוללת: 25-35 שניות → 6-10 שניות (שיפור של פי 3-4).
|
||||
|
||||
**יעילות זיכרון:**
|
||||
גדלי מטמון מוגבלים מונעים דליפות זיכרון.
|
||||
מבני נתונים יעילים מפחיתים את טביעת הרגל של הזיכרון בערך ב-40%.
|
||||
איסוף אשפה טוב יותר באמצעות ניקוי משאבים נכון.
|
||||
|
||||
**ציפיות ריאליות בנוגע לביצועים:**
|
||||
<<<<<<< HEAD
|
||||
**מטמון תוויות**: הפחתה של 10-20% במספר השאילתות עבור גרפים עם קשרים נפוצים.
|
||||
**אופטימיזציה של קיבוץ**: הפחתה של 50-80% במספר השאילתות (אופטימיזציה עיקרית).
|
||||
=======
|
||||
**מטמון תוויות**: הפחתת שאילתות ב-10-20% עבור גרפים עם קשרים נפוצים.
|
||||
**אופטימיזציה של קיבוץ**: הפחתת שאילתות ב-50-80% (אופטימיזציה עיקרית).
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**אופטימיזציה של חיי אובייקט**: ביטול תקורה של יצירה מחדש בכל בקשה.
|
||||
**שיפור כולל**: שיפור של פי 3-4 בזמן התגובה בעיקר בזכות קיבוץ.
|
||||
|
||||
**שיפורי יכולת הרחבה:**
|
||||
תמיכה בגרפי ידע גדולים פי 3-5 (מוגבל על ידי צרכי עקביות מטמון).
|
||||
קיבולת גבוהה יותר פי 3-5 של בקשות מקבילות.
|
||||
ניצול טוב יותר של משאבים באמצעות שימוש חוזר בחיבורים.
|
||||
|
||||
### ניטור ביצועים
|
||||
|
||||
**מדדים בזמן אמת:**
|
||||
זמני ביצוע שאילתות לפי סוג פעולה.
|
||||
<<<<<<< HEAD
|
||||
אחוזי פגיעה במטמון ויעילות.
|
||||
שימוש בבריכת חיבורים למסד הנתונים.
|
||||
=======
|
||||
שיעורי פגיעה ויעילות של מטמון.
|
||||
שימוש בבריכת חיבורי מסד נתונים.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
שימוש בזיכרון והשפעת איסוף אשפה.
|
||||
|
||||
**בדיקות ביצועים:**
|
||||
בדיקות רגרסיה אוטומטיות לביצועים
|
||||
בדיקות עומסים עם נפחי נתונים ריאליים
|
||||
השוואות ביצועים מול המימוש הנוכחי
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות יחידה
|
||||
<<<<<<< HEAD
|
||||
בדיקת רכיבים בודדים עבור מעבר, אחסון במטמון ופתרון תגיות
|
||||
הדמיית אינטראקציות עם מסד נתונים לצורך בדיקות ביצועים
|
||||
בדיקת פינוי מטמון ותפוגה של זמן תפוגה (TTL)
|
||||
=======
|
||||
בדיקת רכיבים בודדים עבור מעבר, אחסון במטמון ופתרון תוויות
|
||||
הדמיית אינטראקציות עם מסד נתונים לצורך בדיקות ביצועים
|
||||
בדיקת פינוי מטמון ותפוגת זמן (TTL)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
בדיקת טיפול בשגיאות ותסריטי תזמון
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
בדיקות מקצה לקצה של שאילתות GraphRAG עם אופטימיזציות
|
||||
בדיקת אינטראקציות עם מסד נתונים עם נתונים אמיתיים
|
||||
טיפול בבקשות מקבילות וניהול משאבים
|
||||
<<<<<<< HEAD
|
||||
זיהוי דליפות זיכרון ואימות ניקוי משאבים
|
||||
=======
|
||||
זיהוי דליפות זיכרון ובדיקת ניקוי משאבים
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### בדיקות ביצועים
|
||||
בדיקות ביצועים מול המימוש הנוכחי
|
||||
בדיקות עומסים עם גדלים ומורכבויות גרף משתנים
|
||||
בדיקות לחץ עבור מגבלות זיכרון וחיבורים
|
||||
בדיקות רגרסיה לשיפורי ביצועים
|
||||
|
||||
### בדיקות תאימות
|
||||
אימות תאימות של ממשקי API קיימים של GraphRAG
|
||||
בדיקה עם מנועי גרפים שונים
|
||||
אימות דיוק התוצאות בהשוואה למימוש הנוכחי
|
||||
|
||||
## תוכנית יישום
|
||||
|
||||
### גישת יישום ישירה
|
||||
<<<<<<< HEAD
|
||||
מכיוון שמותר לשנות ממשקי API, ליישם אופטימיזציות ישירות ללא מורכבות של העברה:
|
||||
|
||||
1. **החלפת `follow_edges`:** כתיבה מחדש עם מעבר אצווה איטרטיבי
|
||||
2. **אופטימיזציה של `get_labelgraph`:** יישום פתרון תגיות מקבילי
|
||||
3. **הוספת GraphRag ארוך טווח:** שינוי של מעבד כדי לשמור על מופע קבוע
|
||||
4. **יישום אחסון במטמון של תגיות:** הוספת מטמון LRU עם TTL למחלקת GraphRag
|
||||
|
||||
### היקף השינויים
|
||||
**מחלקה של שאילתות:** החלפת כ-50 שורות ב-`follow_edges`, הוספת כ-30 שורות לטיפול באצווה
|
||||
**מחלקה של GraphRag:** הוספת שכבת אחסון במטמון (כ-40 שורות)
|
||||
**מחלקה של מעבד:** שינוי לשימוש במופע קבוע של GraphRag (כ-20 שורות)
|
||||
=======
|
||||
מכיוון שמותר לשנות ממשקי API, ליישם אופטימיזציות ישירות ללא מורכבות של מעבר:
|
||||
|
||||
1. **החלפת `follow_edges`:** כתיבה מחדש עם מעבר אצווה איטרטיבי
|
||||
2. **אופטימיזציה של `get_labelgraph`:** יישום פתרון תוויות מקבילי
|
||||
3. **הוספת GraphRag ארוך טווח:** שינוי של Processor לשמירה על מופע קבוע
|
||||
4. **יישום אחסון תוויות במטמון:** הוספת מטמון LRU עם TTL למחלקת GraphRag
|
||||
|
||||
### היקף השינויים
|
||||
**מחלקת שאילתה:** החלפת כ-50 שורות ב-`follow_edges`, הוספת כ-30 שורות לטיפול באצווה
|
||||
**מחלקת GraphRag:** הוספת שכבת אחסון במטמון (כ-40 שורות)
|
||||
**מחלקת Processor:** שינוי לשימוש במופע קבוע של GraphRag (כ-20 שורות)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**סה"כ:** כ-140 שורות של שינויים ממוקדים, בעיקר בתוך מחלקות קיימות
|
||||
|
||||
## ציר זמן
|
||||
|
||||
**שבוע 1: יישום ליבה**
|
||||
החלפת `follow_edges` עם מעבר אצווה איטרטיבי
|
||||
<<<<<<< HEAD
|
||||
יישום פתרון תגיות מקבילי ב-`get_labelgraph`
|
||||
הוספת מופע GraphRag ארוך טווח למעבד
|
||||
יישום שכבת אחסון במטמון של תגיות
|
||||
=======
|
||||
יישום פתרון תוויות מקבילי ב-`get_labelgraph`
|
||||
הוספת מופע GraphRag ארוך טווח ל-Processor
|
||||
יישום שכבת אחסון במטמון
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**שבוע 2: בדיקות ושילוב**
|
||||
בדיקות יחידה ללוגיקה חדשה של מעבר ואחסון במטמון
|
||||
בדיקות ביצועים מול המימוש הנוכחי
|
||||
בדיקות אינטגרציה עם נתוני גרף אמיתיים
|
||||
סקירת קוד ואופטימיזציה
|
||||
|
||||
**שבוע 3: פריסה**
|
||||
פריסת המימוש המותאם
|
||||
ניטור שיפורי ביצועים
|
||||
כוונון עדין של זמן תפוגה של מטמון וגדלי אצווה בהתבסס על שימוש אמיתי
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
**בריכת חיבורים למסד נתונים:** האם עלינו ליישם בריכת חיבורים מותאמת אישית או להסתמך על בריכת חיבורים קיימת של לקוח מסד נתונים?
|
||||
<<<<<<< HEAD
|
||||
**שימור מטמון:** האם מטמון התגיות וההטבעות צריך להתמיד בין הפעלות מחדש של השירות?
|
||||
**אחסון במטמון מבוזר:** עבור פריסות מרובות מופעים, האם עלינו ליישם אחסון במטמון מבוזר עם Redis/Memcached?
|
||||
**פורמט תוצאות שאילתה:** האם עלינו לייעל את הייצוג הפנימי של משולש לטובת יעילות זיכרון טובה יותר?
|
||||
**שילוב ניטור:** אילו מדדים יש לחשוף למערכות ניטור קיימות (Prometheus, וכו')?
|
||||
=======
|
||||
**שימור מטמון:** האם מטמון תוויות ו-embedding צריך להתמיד בין הפעלות מחדש של השירות?
|
||||
**אחסון מבוזר:** עבור פריסות מרובות מופעים, האם עלינו ליישם אחסון מבוזר עם Redis/Memcached?
|
||||
**פורמט תוצאות שאילתה:** האם עלינו לייעל את הייצוג הפנימי של משולש לטובת יעילות זיכרון טובה יותר?
|
||||
**שילוב ניטור:** אילו מדדים צריכים להיות חשופים למערכות ניטור קיימות (Prometheus, וכו')?
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## הפניות
|
||||
|
||||
[מימוש מקורי של GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py)
|
||||
[עקרונות ארכיטקטורה של TrustGraph](architecture-principles.md)
|
||||
[מפרט ניהול אוספים](collection-management.md)
|
||||
713
docs/tech-specs/he/import-export-graceful-shutdown.he.md
Normal file
713
docs/tech-specs/he/import-export-graceful-shutdown.he.md
Normal file
|
|
@ -0,0 +1,713 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לסגירה חלקה של ייבוא/יצוא"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לסגירה חלקה של ייבוא/יצוא
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## הצהרת בעיה
|
||||
|
||||
<<<<<<< HEAD
|
||||
שער TrustGraph חווה כרגע אובדן הודעות במהלך סגירת WebSocket בפעולות ייבוא ויצוא כאחד. זה קורה עקב מצבי מירוץ שבהם הודעות בתנועה נזרקות לפני שהן מגיעות ליעדים שלהן (תורי Pulsar לייבוא, לקוחות WebSocket לייצוא).
|
||||
=======
|
||||
שער TrustGraph חווה כרגע אובדן הודעות במהלך סגירת WebSocket בפעולות ייבוא ויצוא כאחד. זה קורה עקב מצבי מירוץ שבהם הודעות בתנועה נזרקות לפני שהן מגיעות ליעדים שלהן (תורי Pulsar עבור ייבוא, לקוחות WebSocket עבור יצוא).
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### בעיות בצד הייבוא
|
||||
1. מאגר ה-asyncio.Queue של המפרסם אינו מרוקן במהלך השבתה.
|
||||
2. WebSocket נסגר לפני הבטחה שהודעות בתור יגיעו ל-Pulsar.
|
||||
3. אין מנגנון אישור עבור מסירת הודעות מוצלחת.
|
||||
|
||||
### בעיות בצד היצוא
|
||||
1. הודעות מאושרות ב-Pulsar לפני מסירה מוצלחת ללקוחות.
|
||||
2. זמני תפוגה מוגדרים מראש גורמים לאובדן הודעות כאשר התורים מלאים.
|
||||
3. אין מנגנון לחץ נגדי לטיפול בצרכנים איטיים.
|
||||
4. נקודות מאגר מרובות שבהן ניתן לאבד נתונים.
|
||||
|
||||
## סקירה כללית של הארכיטקטורה
|
||||
|
||||
```
|
||||
Import Flow:
|
||||
Client -> Websocket -> TriplesImport -> Publisher -> Pulsar Queue
|
||||
|
||||
Export Flow:
|
||||
Pulsar Queue -> Subscriber -> TriplesExport -> Websocket -> Client
|
||||
```
|
||||
|
||||
## תיקונים מוצעים
|
||||
|
||||
### 1. שיפורים עבור מפרסמים (צד הייבוא)
|
||||
|
||||
#### א. ניקוז תור חלק
|
||||
|
||||
**קובץ:** `trustgraph-base/trustgraph/base/publisher.py`
|
||||
|
||||
```python
|
||||
class Publisher:
|
||||
def __init__(self, client, topic, schema=None, max_size=10,
|
||||
chunking_enabled=True, drain_timeout=5.0):
|
||||
self.client = client
|
||||
self.topic = topic
|
||||
self.schema = schema
|
||||
self.q = asyncio.Queue(maxsize=max_size)
|
||||
self.chunking_enabled = chunking_enabled
|
||||
self.running = True
|
||||
self.draining = False # New state for graceful shutdown
|
||||
self.task = None
|
||||
self.drain_timeout = drain_timeout
|
||||
|
||||
async def stop(self):
|
||||
"""Initiate graceful shutdown with draining"""
|
||||
self.running = False
|
||||
self.draining = True
|
||||
|
||||
if self.task:
|
||||
# Wait for run() to complete draining
|
||||
await self.task
|
||||
|
||||
async def run(self):
|
||||
"""Enhanced run method with integrated draining logic"""
|
||||
while self.running or self.draining:
|
||||
try:
|
||||
producer = self.client.create_producer(
|
||||
topic=self.topic,
|
||||
schema=JsonSchema(self.schema),
|
||||
chunking_enabled=self.chunking_enabled,
|
||||
)
|
||||
|
||||
drain_end_time = None
|
||||
|
||||
while self.running or self.draining:
|
||||
try:
|
||||
# Start drain timeout when entering drain mode
|
||||
if self.draining and drain_end_time is None:
|
||||
drain_end_time = time.time() + self.drain_timeout
|
||||
logger.info(f"Publisher entering drain mode, timeout={self.drain_timeout}s")
|
||||
|
||||
# Check drain timeout
|
||||
if self.draining and time.time() > drain_end_time:
|
||||
if not self.q.empty():
|
||||
logger.warning(f"Drain timeout reached with {self.q.qsize()} messages remaining")
|
||||
self.draining = False
|
||||
break
|
||||
|
||||
# Calculate wait timeout based on mode
|
||||
if self.draining:
|
||||
# Shorter timeout during draining to exit quickly when empty
|
||||
timeout = min(0.1, drain_end_time - time.time())
|
||||
else:
|
||||
# Normal operation timeout
|
||||
timeout = 0.25
|
||||
|
||||
# Get message from queue
|
||||
id, item = await asyncio.wait_for(
|
||||
self.q.get(),
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
# Send the message (single place for sending)
|
||||
if id:
|
||||
producer.send(item, { "id": id })
|
||||
else:
|
||||
producer.send(item)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
# If draining and queue is empty, we're done
|
||||
if self.draining and self.q.empty():
|
||||
logger.info("Publisher queue drained successfully")
|
||||
self.draining = False
|
||||
break
|
||||
continue
|
||||
|
||||
except asyncio.QueueEmpty:
|
||||
# If draining and queue is empty, we're done
|
||||
if self.draining and self.q.empty():
|
||||
logger.info("Publisher queue drained successfully")
|
||||
self.draining = False
|
||||
break
|
||||
continue
|
||||
|
||||
# Flush producer before closing
|
||||
if producer:
|
||||
producer.flush()
|
||||
producer.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Exception in publisher: {e}", exc_info=True)
|
||||
|
||||
if not self.running and not self.draining:
|
||||
return
|
||||
|
||||
# If handler drops out, sleep a retry
|
||||
await asyncio.sleep(1)
|
||||
|
||||
async def send(self, id, item):
|
||||
"""Send still works normally - just adds to queue"""
|
||||
if self.draining:
|
||||
# Optionally reject new messages during drain
|
||||
raise RuntimeError("Publisher is shutting down, not accepting new messages")
|
||||
await self.q.put((id, item))
|
||||
```
|
||||
|
||||
**יתרונות עיצוב מרכזיים:**
|
||||
**מיקום שליחה יחיד**: כל הקריאות ל-`producer.send()` מתרחשות במקום אחד בתוך השיטה `run()`.
|
||||
**מצב פעולה ברור:** שלושה מצבים ברורים - פעיל, ריקון, עצור.
|
||||
<<<<<<< HEAD
|
||||
**הגנה מפני תזמון מוגזם:** לא יימשך ללא הגבלת זמן במהלך הריקון.
|
||||
=======
|
||||
**הגנה מפני תזמון מוגזם:** לא יימשך ללא סוף במהלך הריקון.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**יכולת ניטור משופרת:** רישום ברור של התקדמות הריקון ומעברי מצב.
|
||||
**דחיית הודעות אופציונלית:** ניתן לדחות הודעות חדשות במהלך שלב השבתה.
|
||||
|
||||
#### ב. סדר השבתה משופר
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_import.py`
|
||||
|
||||
```python
|
||||
class TriplesImport:
|
||||
async def destroy(self):
|
||||
"""Enhanced destroy with proper shutdown order"""
|
||||
# Step 1: Stop accepting new messages
|
||||
self.running.stop()
|
||||
|
||||
# Step 2: Wait for publisher to drain its queue
|
||||
logger.info("Draining publisher queue...")
|
||||
await self.publisher.stop()
|
||||
|
||||
# Step 3: Close websocket only after queue is drained
|
||||
if self.ws:
|
||||
await self.ws.close()
|
||||
```
|
||||
|
||||
### 2. שיפורים למנויים (צד היצוא)
|
||||
|
||||
#### א. תבנית ניקוז משולבת
|
||||
|
||||
<<<<<<< HEAD
|
||||
**קובץ**: `trustgraph-base/trustgraph/base/subscriber.py`
|
||||
=======
|
||||
**קובץ:** `trustgraph-base/trustgraph/base/subscriber.py`
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```python
|
||||
class Subscriber:
|
||||
def __init__(self, client, topic, subscription, consumer_name,
|
||||
schema=None, max_size=100, metrics=None,
|
||||
backpressure_strategy="block", drain_timeout=5.0):
|
||||
# ... existing init ...
|
||||
self.backpressure_strategy = backpressure_strategy
|
||||
self.running = True
|
||||
self.draining = False # New state for graceful shutdown
|
||||
self.drain_timeout = drain_timeout
|
||||
self.pending_acks = {} # Track messages awaiting delivery
|
||||
|
||||
async def stop(self):
|
||||
"""Initiate graceful shutdown with draining"""
|
||||
self.running = False
|
||||
self.draining = True
|
||||
|
||||
if self.task:
|
||||
# Wait for run() to complete draining
|
||||
await self.task
|
||||
|
||||
async def run(self):
|
||||
"""Enhanced run method with integrated draining logic"""
|
||||
while self.running or self.draining:
|
||||
if self.metrics:
|
||||
self.metrics.state("stopped")
|
||||
|
||||
try:
|
||||
self.consumer = self.client.subscribe(
|
||||
topic = self.topic,
|
||||
subscription_name = self.subscription,
|
||||
consumer_name = self.consumer_name,
|
||||
schema = JsonSchema(self.schema),
|
||||
)
|
||||
|
||||
if self.metrics:
|
||||
self.metrics.state("running")
|
||||
|
||||
logger.info("Subscriber running...")
|
||||
drain_end_time = None
|
||||
|
||||
while self.running or self.draining:
|
||||
# Start drain timeout when entering drain mode
|
||||
if self.draining and drain_end_time is None:
|
||||
drain_end_time = time.time() + self.drain_timeout
|
||||
logger.info(f"Subscriber entering drain mode, timeout={self.drain_timeout}s")
|
||||
|
||||
# Stop accepting new messages from Pulsar during drain
|
||||
self.consumer.pause_message_listener()
|
||||
|
||||
# Check drain timeout
|
||||
if self.draining and time.time() > drain_end_time:
|
||||
async with self.lock:
|
||||
total_pending = sum(
|
||||
q.qsize() for q in
|
||||
list(self.q.values()) + list(self.full.values())
|
||||
)
|
||||
if total_pending > 0:
|
||||
logger.warning(f"Drain timeout reached with {total_pending} messages in queues")
|
||||
self.draining = False
|
||||
break
|
||||
|
||||
# Check if we can exit drain mode
|
||||
if self.draining:
|
||||
async with self.lock:
|
||||
all_empty = all(
|
||||
q.empty() for q in
|
||||
list(self.q.values()) + list(self.full.values())
|
||||
)
|
||||
if all_empty and len(self.pending_acks) == 0:
|
||||
logger.info("Subscriber queues drained successfully")
|
||||
self.draining = False
|
||||
break
|
||||
|
||||
# Process messages only if not draining
|
||||
if not self.draining:
|
||||
try:
|
||||
msg = await asyncio.to_thread(
|
||||
self.consumer.receive,
|
||||
timeout_millis=250
|
||||
)
|
||||
except _pulsar.Timeout:
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.error(f"Exception in subscriber receive: {e}", exc_info=True)
|
||||
raise e
|
||||
|
||||
if self.metrics:
|
||||
self.metrics.received()
|
||||
|
||||
# Process the message
|
||||
await self._process_message(msg)
|
||||
else:
|
||||
# During draining, just wait for queues to empty
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Subscriber exception: {e}", exc_info=True)
|
||||
|
||||
finally:
|
||||
# Negative acknowledge any pending messages
|
||||
for msg in self.pending_acks.values():
|
||||
self.consumer.negative_acknowledge(msg)
|
||||
self.pending_acks.clear()
|
||||
|
||||
if self.consumer:
|
||||
self.consumer.unsubscribe()
|
||||
self.consumer.close()
|
||||
self.consumer = None
|
||||
|
||||
if self.metrics:
|
||||
self.metrics.state("stopped")
|
||||
|
||||
if not self.running and not self.draining:
|
||||
return
|
||||
|
||||
# If handler drops out, sleep a retry
|
||||
await asyncio.sleep(1)
|
||||
|
||||
async def _process_message(self, msg):
|
||||
"""Process a single message with deferred acknowledgment"""
|
||||
# Store message for later acknowledgment
|
||||
msg_id = str(uuid.uuid4())
|
||||
self.pending_acks[msg_id] = msg
|
||||
|
||||
try:
|
||||
id = msg.properties()["id"]
|
||||
except:
|
||||
id = None
|
||||
|
||||
value = msg.value()
|
||||
delivery_success = False
|
||||
|
||||
async with self.lock:
|
||||
# Deliver to specific subscribers
|
||||
if id in self.q:
|
||||
delivery_success = await self._deliver_to_queue(
|
||||
self.q[id], value
|
||||
)
|
||||
|
||||
# Deliver to all subscribers
|
||||
for q in self.full.values():
|
||||
if await self._deliver_to_queue(q, value):
|
||||
delivery_success = True
|
||||
|
||||
# Acknowledge only on successful delivery
|
||||
if delivery_success:
|
||||
self.consumer.acknowledge(msg)
|
||||
del self.pending_acks[msg_id]
|
||||
else:
|
||||
# Negative acknowledge for retry
|
||||
self.consumer.negative_acknowledge(msg)
|
||||
del self.pending_acks[msg_id]
|
||||
|
||||
async def _deliver_to_queue(self, queue, value):
|
||||
"""Deliver message to queue with backpressure handling"""
|
||||
try:
|
||||
if self.backpressure_strategy == "block":
|
||||
# Block until space available (no timeout)
|
||||
await queue.put(value)
|
||||
return True
|
||||
|
||||
elif self.backpressure_strategy == "drop_oldest":
|
||||
# Drop oldest message if queue full
|
||||
if queue.full():
|
||||
try:
|
||||
queue.get_nowait()
|
||||
if self.metrics:
|
||||
self.metrics.dropped()
|
||||
except asyncio.QueueEmpty:
|
||||
pass
|
||||
await queue.put(value)
|
||||
return True
|
||||
|
||||
elif self.backpressure_strategy == "drop_new":
|
||||
# Drop new message if queue full
|
||||
if queue.full():
|
||||
if self.metrics:
|
||||
self.metrics.dropped()
|
||||
return False
|
||||
await queue.put(value)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to deliver message: {e}")
|
||||
return False
|
||||
```
|
||||
|
||||
**יתרונות עיצוב מרכזיים (התאמה לדפוס של המפרסם):**
|
||||
<<<<<<< HEAD
|
||||
**מיקום עיבוד יחיד**: כל עיבוד ההודעות מתבצע בשיטה `run()`.
|
||||
**מצב מכונה נקי**: שלושה מצבים ברורים - פעיל, ריקון, עצור.
|
||||
**השהיה במהלך ריקון**: מפסיק לקבל הודעות חדשות מ-Pulsar תוך כדי ריקון תורים קיימים.
|
||||
**הגנה מפני תזמון מוגזם**: לא ייקפא ללא סיבה במהלך הריקון.
|
||||
=======
|
||||
**מיקום עיבוד יחיד**: כל פעולות העיבוד של ההודעות מתבצעות בשיטה `run()`.
|
||||
**מצב מכונה נקי**: שלושה מצבים ברורים - פעיל, ריקון, עצור.
|
||||
**השהיה במהלך הריקון**: מפסיק לקבל הודעות חדשות מ-Pulsar תוך כדי ריקון תורים קיימים.
|
||||
**הגנה מפני תקיעות**: לא ייגרם תקיעה אינסופי במהלך הריקון.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**ניקוי תקין**: מודה בשלילה על כל הודעות שלא נמסרו בעת השבתה.
|
||||
|
||||
#### ב. שיפורים למטפל ייצוא
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/gateway/dispatch/triples_export.py`
|
||||
|
||||
```python
|
||||
class TriplesExport:
|
||||
async def destroy(self):
|
||||
"""Enhanced destroy with graceful shutdown"""
|
||||
# Step 1: Signal stop to prevent new messages
|
||||
self.running.stop()
|
||||
|
||||
# Step 2: Wait briefly for in-flight messages
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# Step 3: Unsubscribe and stop subscriber (triggers queue drain)
|
||||
if hasattr(self, 'subs'):
|
||||
await self.subs.unsubscribe_all(self.id)
|
||||
await self.subs.stop()
|
||||
|
||||
# Step 4: Close websocket last
|
||||
if self.ws and not self.ws.closed:
|
||||
await self.ws.close()
|
||||
|
||||
async def run(self):
|
||||
"""Enhanced run with better error handling"""
|
||||
self.subs = Subscriber(
|
||||
client = self.pulsar_client,
|
||||
topic = self.queue,
|
||||
consumer_name = self.consumer,
|
||||
subscription = self.subscriber,
|
||||
schema = Triples,
|
||||
backpressure_strategy = "block" # Configurable
|
||||
)
|
||||
|
||||
await self.subs.start()
|
||||
|
||||
self.id = str(uuid.uuid4())
|
||||
q = await self.subs.subscribe_all(self.id)
|
||||
|
||||
consecutive_errors = 0
|
||||
max_consecutive_errors = 5
|
||||
|
||||
while self.running.get():
|
||||
try:
|
||||
resp = await asyncio.wait_for(q.get(), timeout=0.5)
|
||||
await self.ws.send_json(serialize_triples(resp))
|
||||
consecutive_errors = 0 # Reset on success
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
|
||||
except queue.Empty:
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Exception sending to websocket: {str(e)}")
|
||||
consecutive_errors += 1
|
||||
|
||||
if consecutive_errors >= max_consecutive_errors:
|
||||
logger.error("Too many consecutive errors, shutting down")
|
||||
break
|
||||
|
||||
# Brief pause before retry
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# Graceful cleanup handled in destroy()
|
||||
```
|
||||
|
||||
### 3. שיפורים ברמת החיבור (Socket)
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/gateway/endpoint/socket.py`
|
||||
|
||||
```python
|
||||
class SocketEndpoint:
|
||||
async def listener(self, ws, dispatcher, running):
|
||||
"""Enhanced listener with graceful shutdown"""
|
||||
async for msg in ws:
|
||||
if msg.type == WSMsgType.TEXT:
|
||||
await dispatcher.receive(msg)
|
||||
continue
|
||||
elif msg.type == WSMsgType.BINARY:
|
||||
await dispatcher.receive(msg)
|
||||
continue
|
||||
else:
|
||||
# Graceful shutdown on close
|
||||
logger.info("Websocket closing, initiating graceful shutdown")
|
||||
running.stop()
|
||||
|
||||
# Allow time for dispatcher cleanup
|
||||
await asyncio.sleep(1.0)
|
||||
break
|
||||
|
||||
async def handle(self, request):
|
||||
"""Enhanced handler with better cleanup"""
|
||||
# ... existing setup code ...
|
||||
|
||||
try:
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
running = Running()
|
||||
|
||||
dispatcher = await self.dispatcher(
|
||||
ws, running, request.match_info
|
||||
)
|
||||
|
||||
worker_task = tg.create_task(
|
||||
self.worker(ws, dispatcher, running)
|
||||
)
|
||||
|
||||
lsnr_task = tg.create_task(
|
||||
self.listener(ws, dispatcher, running)
|
||||
)
|
||||
|
||||
except ExceptionGroup as e:
|
||||
logger.error("Exception group occurred:", exc_info=True)
|
||||
|
||||
# Attempt graceful dispatcher shutdown
|
||||
try:
|
||||
await asyncio.wait_for(
|
||||
dispatcher.destroy(),
|
||||
timeout=5.0
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning("Dispatcher shutdown timed out")
|
||||
except Exception as de:
|
||||
logger.error(f"Error during dispatcher cleanup: {de}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Socket exception: {e}", exc_info=True)
|
||||
|
||||
finally:
|
||||
# Ensure dispatcher cleanup
|
||||
if dispatcher and hasattr(dispatcher, 'destroy'):
|
||||
try:
|
||||
await dispatcher.destroy()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Ensure websocket is closed
|
||||
if ws and not ws.closed:
|
||||
await ws.close()
|
||||
|
||||
return ws
|
||||
```
|
||||
|
||||
## אפשרויות תצורה
|
||||
|
||||
הוספת תמיכה בתצורה לשינוי התנהגות:
|
||||
|
||||
```python
|
||||
# config.py
|
||||
class GracefulShutdownConfig:
|
||||
# Publisher settings
|
||||
PUBLISHER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain
|
||||
PUBLISHER_FLUSH_TIMEOUT = 2.0 # Producer flush timeout
|
||||
|
||||
# Subscriber settings
|
||||
SUBSCRIBER_DRAIN_TIMEOUT = 5.0 # Seconds to wait for queue drain
|
||||
BACKPRESSURE_STRATEGY = "block" # Options: "block", "drop_oldest", "drop_new"
|
||||
SUBSCRIBER_MAX_QUEUE_SIZE = 100 # Maximum queue size before backpressure
|
||||
|
||||
# Socket settings
|
||||
SHUTDOWN_GRACE_PERIOD = 1.0 # Seconds to wait for graceful shutdown
|
||||
MAX_CONSECUTIVE_ERRORS = 5 # Maximum errors before forced shutdown
|
||||
|
||||
# Monitoring
|
||||
LOG_QUEUE_STATS = True # Log queue statistics on shutdown
|
||||
METRICS_ENABLED = True # Enable metrics collection
|
||||
```
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות יחידה
|
||||
|
||||
```python
|
||||
async def test_publisher_queue_drain():
|
||||
"""Verify Publisher drains queue on shutdown"""
|
||||
publisher = Publisher(...)
|
||||
|
||||
# Fill queue with messages
|
||||
for i in range(10):
|
||||
await publisher.send(f"id-{i}", {"data": i})
|
||||
|
||||
# Stop publisher
|
||||
await publisher.stop()
|
||||
|
||||
# Verify all messages were sent
|
||||
assert publisher.q.empty()
|
||||
assert mock_producer.send.call_count == 10
|
||||
|
||||
async def test_subscriber_deferred_ack():
|
||||
"""Verify Subscriber only acks on successful delivery"""
|
||||
subscriber = Subscriber(..., backpressure_strategy="drop_new")
|
||||
|
||||
# Fill queue to capacity
|
||||
queue = await subscriber.subscribe("test")
|
||||
for i in range(100):
|
||||
await queue.put({"data": i})
|
||||
|
||||
# Try to add message when full
|
||||
msg = create_mock_message()
|
||||
await subscriber._process_message(msg)
|
||||
|
||||
# Verify negative acknowledgment
|
||||
assert msg.negative_acknowledge.called
|
||||
assert not msg.acknowledge.called
|
||||
```
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
|
||||
```python
|
||||
async def test_import_graceful_shutdown():
|
||||
"""Test import path handles shutdown gracefully"""
|
||||
# Setup
|
||||
import_handler = TriplesImport(...)
|
||||
await import_handler.start()
|
||||
|
||||
# Send messages
|
||||
messages = []
|
||||
for i in range(100):
|
||||
msg = {"metadata": {...}, "triples": [...]}
|
||||
await import_handler.receive(msg)
|
||||
messages.append(msg)
|
||||
|
||||
# Shutdown while messages in flight
|
||||
await import_handler.destroy()
|
||||
|
||||
# Verify all messages reached Pulsar
|
||||
received = await pulsar_consumer.receive_all()
|
||||
assert len(received) == 100
|
||||
|
||||
async def test_export_no_message_loss():
|
||||
"""Test export path doesn't lose acknowledged messages"""
|
||||
# Setup Pulsar with test messages
|
||||
for i in range(100):
|
||||
await pulsar_producer.send({"data": i})
|
||||
|
||||
# Start export handler
|
||||
export_handler = TriplesExport(...)
|
||||
export_task = asyncio.create_task(export_handler.run())
|
||||
|
||||
# Receive some messages
|
||||
received = []
|
||||
for _ in range(50):
|
||||
msg = await websocket.receive()
|
||||
received.append(msg)
|
||||
|
||||
# Force shutdown
|
||||
await export_handler.destroy()
|
||||
|
||||
# Continue receiving until websocket closes
|
||||
while not websocket.closed:
|
||||
try:
|
||||
msg = await websocket.receive()
|
||||
received.append(msg)
|
||||
except:
|
||||
break
|
||||
|
||||
# Verify no acknowledged messages were lost
|
||||
assert len(received) >= 50
|
||||
```
|
||||
|
||||
## תוכנית הטמעה
|
||||
|
||||
### שלב 1: תיקונים קריטיים (שבוע 1)
|
||||
תיקון תזמון אישור מנויים (מניעת אובדן הודעות)
|
||||
הוספת ניקוז תור משדר
|
||||
הטמעה בסביבת בדיקות
|
||||
|
||||
### שלב 2: השבתה חלקה (שבוע 2)
|
||||
הטמעת תיאום השבתה
|
||||
הוספת אסטרטגיות לחץ נגדי
|
||||
בדיקות ביצועים
|
||||
|
||||
### שלב 3: ניטור וכוונון (שבוע 3)
|
||||
הוספת מדדים לעומק תורים
|
||||
הוספת התראות לאובדן הודעות
|
||||
כוונון ערכי זמן קצוב בהתבסס על נתוני ייצור
|
||||
|
||||
## ניטור והתראות
|
||||
|
||||
### מדדים שיש לעקוב אחריהם
|
||||
`publisher.queue.depth` - גודל נוכחי של תור המשדר
|
||||
`publisher.messages.dropped` - הודעות שאבדו במהלך השבתה
|
||||
`subscriber.messages.negatively_acknowledged` - משלוחים שנכשלו
|
||||
`websocket.graceful_shutdowns` - השבתות חלקות מוצלחות
|
||||
`websocket.forced_shutdowns` - השבתות בכוח/עקב חריגה מהזמן הקצוב
|
||||
|
||||
### התראות
|
||||
עומק תור המשדר > 80% מהקיבולת
|
||||
כל אובדן הודעות במהלך השבתה
|
||||
קצב אישור שלילי של מנויים > 1%
|
||||
חריגה מהזמן הקצוב להשבתה
|
||||
|
||||
## תאימות לאחור
|
||||
|
||||
כל השינויים שומרים על תאימות לאחור:
|
||||
התנהגות ברירת המחדל לא משתנה ללא תצורה
|
||||
הטמעות קיימות ממשיכות לתפקד
|
||||
ירידה הדרגתית בפעולה אם תכונות חדשות אינן זמינות
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
לא הוצגו וקטורי תקיפה חדשים
|
||||
לחץ נגדי מונע התקפות של התעמקות זיכרון
|
||||
מגבלות הניתנות לתצורה מונעות ניצול משאבים
|
||||
|
||||
## השפעה על הביצועים
|
||||
|
||||
תקורה מינימלית במהלך פעולה רגילה
|
||||
השבתה עשויה לקחת עד 5 שניות נוספות (ניתן להגדרה)
|
||||
השימוש בזיכרון מוגבל על ידי מגבלות גודל התור
|
||||
<<<<<<< HEAD
|
||||
השפעה על ה-CPU זניחה (<1% עלייה)
|
||||
=======
|
||||
השפעה על מעבד זניחה (<1% עלייה)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
548
docs/tech-specs/he/jsonl-prompt-output.he.md
Normal file
548
docs/tech-specs/he/jsonl-prompt-output.he.md
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של פלט JSONL"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של פלט JSONL
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר את יישום פורמט הפלט JSONL (JSON Lines)
|
||||
עבור תשובות לשאילתות ב-TrustGraph. JSONL מאפשר חילוץ עמיד לקיטוע
|
||||
של נתונים מובנים מתשובות של מודלי שפה גדולים (LLM), תוך התמודדות עם בעיות
|
||||
<<<<<<< HEAD
|
||||
קריטיות שבהן פלט מערך JSON נפגע כאשר תשובות ה-LLM מגיעות למגבלות
|
||||
של מספר הטוקנים.
|
||||
=======
|
||||
קריטיות שבהן מערכי JSON יוצאים מכלל שימוש כאשר תשובות ה-LLM מגיעות
|
||||
למגבלות מספר הטוקנים.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
יישום זה תומך בתרחישי שימוש הבאים:
|
||||
|
||||
1. **חילוץ עמיד לקיטוע**: חילוץ תוצאות חלקיות ותקינות גם כאשר
|
||||
פלט ה-LLM מקוטע באמצע התגובה.
|
||||
2. **חילוץ בקנה מידה גדול**: טיפול בחילוץ של פריטים רבים מבלי
|
||||
<<<<<<< HEAD
|
||||
להסתכן בכשל מוחלט עקב מגבלות טוקנים.
|
||||
=======
|
||||
להסתכן בכשל מוחלט עקב מגבלות מספר הטוקנים.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
3. **חילוץ מסוגים מעורבים**: תמיכה בחילוץ של סוגי ישויות מרובים
|
||||
(הגדרות, קשרים, ישויות, תכונות) בשאילתה אחת.
|
||||
4. **פלט תואם לסטרימינג**: אפשור עיבוד עתידי של תוצאות החילוץ
|
||||
בצורה של סטרימינג/הדרגתית.
|
||||
|
||||
## מטרות
|
||||
|
||||
**תאימות לאחור**: שאילתות קיימות המשתמשות ב-`response-type: "text"` ו-
|
||||
`response-type: "json"` ממשיכות לעבוד ללא שינוי.
|
||||
**עמידות לקיטוע**: פלטים חלקיים של LLM מניבים תוצאות חלקיות ותקינות
|
||||
במקום כשל מוחלט.
|
||||
**אימות סכימה**: תמיכה באימות סכימה של JSON עבור אובייקטים בודדים.
|
||||
**איחודים מובחנים**: תמיכה בפלטים מסוגים מעורבים באמצעות שדה `type`
|
||||
מפריד.
|
||||
**שינויים מינימליים ב-API**: הרחבת תצורת השאילתה הקיימת עם סוג
|
||||
תגובה חדש ומפתח סכימה.
|
||||
|
||||
## רקע
|
||||
|
||||
### ארכיטקטורה נוכחית
|
||||
|
||||
<<<<<<< HEAD
|
||||
שירות השאילתות תומך בשני סוגי תגובה:
|
||||
|
||||
1. `response-type: "text"` - תגובה טקסטואלית גולמית המוחזרת כפי שהיא.
|
||||
2. `response-type: "json"` - JSON המנותח מהתגובה, ומאומת כנגד
|
||||
=======
|
||||
שירות השאילתות תומך בשני סוגי תגובות:
|
||||
|
||||
1. `response-type: "text"` - תגובה טקסטואלית גולמית המוחזרת כפי שהיא.
|
||||
2. `response-type: "json"` - JSON המנותח מהתגובה, ומאומת מול
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
`schema` אופציונלי.
|
||||
|
||||
יישום נוכחי ב-`trustgraph-flow/trustgraph/template/prompt_manager.py`:
|
||||
|
||||
```python
|
||||
class Prompt:
|
||||
def __init__(self, template, response_type = "text", terms=None, schema=None):
|
||||
self.template = template
|
||||
self.response_type = response_type
|
||||
self.terms = terms
|
||||
self.schema = schema
|
||||
```
|
||||
|
||||
### מגבלות נוכחיות
|
||||
|
||||
כאשר הנחיות החילוץ מבקשות פלט כמערכים מסוג JSON (`[{...}, {...}, ...]`):
|
||||
|
||||
<<<<<<< HEAD
|
||||
**שחיתות עקב קיטום**: אם מודל השפה (LLM) מגיע למגבלת מספר הטוקנים במהלך יצירת המערך,
|
||||
=======
|
||||
**שחיתות עקב קיטוע:** אם מודל השפה (LLM) מגיע למגבלת מספר הטוקנים במהלך יצירת המערך,
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
התגובה כולה הופכת ל-JSON לא חוקי ואי אפשר לנתח אותה.
|
||||
**ניתוח "הכל או כלום":** יש לקבל את הפלט השלם לפני הניתוח.
|
||||
**אין תוצאות חלקיות:** תגובה מקוטעת מניבה אפס נתונים שניתן להשתמש בהם.
|
||||
**לא אמין עבור חילוצים גדולים:** ככל שיותר פריטים מחולצים, כך גדל הסיכון לכישלון.
|
||||
|
||||
מפרט זה מתייחס למגבלות אלה על ידי הצגת פורמט JSONL עבור
|
||||
הנחיות חילוץ, כאשר כל פריט מחולץ הוא אובייקט JSON שלם בשורה
|
||||
משלו.
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### הרחבת סוג התגובה
|
||||
|
||||
הוסף סוג תגובה חדש `"jsonl"` לצד סוגי `"text"` ו-`"json"` הקיימים.
|
||||
|
||||
#### שינויי תצורה
|
||||
|
||||
<<<<<<< HEAD
|
||||
**ערך חדש עבור סוג התגובה:**
|
||||
=======
|
||||
**ערך סוג תגובה חדש:**
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```
|
||||
"response-type": "jsonl"
|
||||
```
|
||||
|
||||
**פרשנות של הסכימה:**
|
||||
|
||||
המפתח הקיים `"schema"` משמש הן עבור סוג התגובה `"json"` והן עבור סוג התגובה `"jsonl"`.
|
||||
הפרשנות תלויה בסוג התגובה:
|
||||
|
||||
`"json"`: הסכימה מתארת את כל התגובה (בדרך כלל מערך או אובייקט).
|
||||
`"jsonl"`: הסכימה מתארת כל שורה/אובייקט בנפרד.
|
||||
|
||||
```json
|
||||
{
|
||||
"response-type": "jsonl",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"entity": { "type": "string" },
|
||||
"definition": { "type": "string" }
|
||||
},
|
||||
"required": ["entity", "definition"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
זה מונע שינויים בכלי התצורה ובתוכנות העריכה.
|
||||
|
||||
### מפרט פורמט JSONL
|
||||
|
||||
#### חילוץ פשוט
|
||||
|
||||
עבור שאילתות המפיקות סוג אחד של אובייקט (הגדרות, קשרים,
|
||||
נושאים, שורות), הפלט הוא אובייקט JSON אחד בכל שורה, ללא עטיפה:
|
||||
|
||||
**פורמט פלט של השאילתה:**
|
||||
```
|
||||
{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}
|
||||
{"entity": "chlorophyll", "definition": "Green pigment in plants"}
|
||||
{"entity": "mitochondria", "definition": "Powerhouse of the cell"}
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
**ניגוד לפורמט מערך JSON הקודם:**
|
||||
=======
|
||||
**השוואה לפורמט מערך JSON הקודם:**
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
```json
|
||||
[
|
||||
{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"},
|
||||
{"entity": "chlorophyll", "definition": "Green pigment in plants"},
|
||||
{"entity": "mitochondria", "definition": "Powerhouse of the cell"}
|
||||
]
|
||||
```
|
||||
|
||||
אם מודל השפה הגדול (LLM) מקצר אחרי השורה 2, פורמט מערך ה-JSON ייתן JSON לא תקין,
|
||||
בעוד ש-JSONL ייתן שני אובייקטים תקינים.
|
||||
|
||||
<<<<<<< HEAD
|
||||
#### חילוץ של טיפוסים מעורבים (איחודים מובחנים)
|
||||
|
||||
עבור הנחיות המפיקות מספר סוגים של אובייקטים (לדוגמה, גם הגדרות וגם
|
||||
קשרים, או ישויות, קשרים ומאפיינים), השתמש בשדה `"type"`
|
||||
=======
|
||||
#### חילוץ מסוגים מעורבים (איחודים מובחנים)
|
||||
|
||||
עבור הנחיות המפיקות סוגים מרובים של אובייקטים (לדוגמה, גם הגדרות וגם
|
||||
קשרים, או ישויות, קשרים ומאפיינים), השתמשו בשדה `"type"`
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
כמבחין:
|
||||
|
||||
**פורמט פלט של ההנחיה:**
|
||||
```
|
||||
{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"}
|
||||
{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true}
|
||||
{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"}
|
||||
{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true}
|
||||
```
|
||||
|
||||
**הסכימה עבור איחודים מובחנים משתמשת ב-`oneOf`:**
|
||||
```json
|
||||
{
|
||||
"response-type": "jsonl",
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "definition" },
|
||||
"entity": { "type": "string" },
|
||||
"definition": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "entity", "definition"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "relationship" },
|
||||
"subject": { "type": "string" },
|
||||
"predicate": { "type": "string" },
|
||||
"object": { "type": "string" },
|
||||
"object-entity": { "type": "boolean" }
|
||||
},
|
||||
"required": ["type", "subject", "predicate", "object", "object-entity"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### חילוץ אונטולוגיה
|
||||
|
||||
עבור חילוץ המבוסס על אונטולוגיה, הכולל ישויות, קשרים ומאפיינים:
|
||||
|
||||
**פורמט פלט של ההנחיה:**
|
||||
```
|
||||
{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"}
|
||||
{"type": "entity", "entity": "beef", "entity_type": "fo/Food"}
|
||||
{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"}
|
||||
{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"}
|
||||
```
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
#### מחלקת Prompt
|
||||
|
||||
המחלקה הקיימת `Prompt` אינה דורשת שינויים. השדה `schema` משמש מחדש
|
||||
עבור JSONL, והפרשנות שלו נקבעת על ידי `response_type`:
|
||||
|
||||
```python
|
||||
class Prompt:
|
||||
def __init__(self, template, response_type="text", terms=None, schema=None):
|
||||
self.template = template
|
||||
self.response_type = response_type
|
||||
self.terms = terms
|
||||
self.schema = schema # Interpretation depends on response_type
|
||||
```
|
||||
|
||||
#### PromptManager.load_config
|
||||
|
||||
אין צורך בשינויים - הטעינה הקיימת של התצורה כבר מטפלת במפתח
|
||||
`schema`.
|
||||
|
||||
#### ניתוח JSONL
|
||||
|
||||
הוסף שיטת ניתוח חדשה לתגובות JSONL:
|
||||
|
||||
```python
|
||||
def parse_jsonl(self, text):
|
||||
"""
|
||||
Parse JSONL response, returning list of valid objects.
|
||||
|
||||
Invalid lines (malformed JSON, empty lines) are skipped with warnings.
|
||||
This provides truncation resilience - partial output yields partial results.
|
||||
"""
|
||||
results = []
|
||||
|
||||
for line_num, line in enumerate(text.strip().split('\n'), 1):
|
||||
line = line.strip()
|
||||
|
||||
# Skip empty lines
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Skip markdown code fence markers if present
|
||||
if line.startswith('```'):
|
||||
continue
|
||||
|
||||
try:
|
||||
obj = json.loads(line)
|
||||
results.append(obj)
|
||||
except json.JSONDecodeError as e:
|
||||
# Log warning but continue - this provides truncation resilience
|
||||
logger.warning(f"JSONL parse error on line {line_num}: {e}")
|
||||
|
||||
return results
|
||||
```
|
||||
|
||||
#### שינויים ב-PromptManager.invoke
|
||||
|
||||
<<<<<<< HEAD
|
||||
הרחב את השיטה invoke כדי לטפל בסוג התגובה החדש:
|
||||
=======
|
||||
הרחב את המיפעל invoke כדי לטפל בסוג התגובה החדש:
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
```python
|
||||
async def invoke(self, id, input, llm):
|
||||
logger.debug("Invoking prompt template...")
|
||||
|
||||
terms = self.terms | self.prompts[id].terms | input
|
||||
resp_type = self.prompts[id].response_type
|
||||
|
||||
prompt = {
|
||||
"system": self.system_template.render(terms),
|
||||
"prompt": self.render(id, input)
|
||||
}
|
||||
|
||||
resp = await llm(**prompt)
|
||||
|
||||
if resp_type == "text":
|
||||
return resp
|
||||
|
||||
if resp_type == "json":
|
||||
try:
|
||||
obj = self.parse_json(resp)
|
||||
except:
|
||||
logger.error(f"JSON parse failed: {resp}")
|
||||
raise RuntimeError("JSON parse fail")
|
||||
|
||||
if self.prompts[id].schema:
|
||||
try:
|
||||
validate(instance=obj, schema=self.prompts[id].schema)
|
||||
logger.debug("Schema validation successful")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Schema validation fail: {e}")
|
||||
|
||||
return obj
|
||||
|
||||
if resp_type == "jsonl":
|
||||
objects = self.parse_jsonl(resp)
|
||||
|
||||
if not objects:
|
||||
logger.warning("JSONL parse returned no valid objects")
|
||||
return []
|
||||
|
||||
# Validate each object against schema if provided
|
||||
if self.prompts[id].schema:
|
||||
validated = []
|
||||
for i, obj in enumerate(objects):
|
||||
try:
|
||||
validate(instance=obj, schema=self.prompts[id].schema)
|
||||
validated.append(obj)
|
||||
except Exception as e:
|
||||
logger.warning(f"Object {i} failed schema validation: {e}")
|
||||
return validated
|
||||
|
||||
return objects
|
||||
|
||||
raise RuntimeError(f"Response type {resp_type} not known")
|
||||
```
|
||||
|
||||
### הנחיות מושפעות
|
||||
|
||||
ההנחיות הבאות צריכות להיות מועברות לפורמט JSONL:
|
||||
|
||||
| מזהה הנחיה | תיאור | שדה סוג |
|
||||
|-----------|-------------|------------|
|
||||
| `extract-definitions` | חילוץ ישויות/הגדרות | לא (סוג בודד) |
|
||||
| `extract-relationships` | חילוץ קשרים | לא (סוג בודד) |
|
||||
| `extract-topics` | חילוץ נושא/הגדרה | לא (סוג בודד) |
|
||||
| `extract-rows` | חילוץ שורה מובנית | לא (סוג בודד) |
|
||||
| `agent-kg-extract` | חילוץ משולב של הגדרה + קשר | כן: `"definition"`, `"relationship"` |
|
||||
| `extract-with-ontologies` / `ontology-extract` | חילוץ מבוסס אונטולוגיה | כן: `"entity"`, `"relationship"`, `"attribute"` |
|
||||
|
||||
### שינויים ב-API
|
||||
|
||||
#### נקודת מבט של הלקוח
|
||||
|
||||
ניתוח JSONL שקוף למשתמשי ה-API של שירות ההנחיות. הניתוח מתבצע
|
||||
<<<<<<< HEAD
|
||||
בצד השרת בשירות ההנחיות, והתגובה מוחזרת באמצעות השדה הסטנדרטי
|
||||
=======
|
||||
בצד השרת בשירות ההנחיות, והתגובה מוחזרת דרך השדה הסטנדרטי
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
`PromptResponse.object` כמערך JSON מוסרי.
|
||||
|
||||
כאשר לקוחות קוראים לשירות ההנחיות (דרך `PromptClient.prompt()` או דומה):
|
||||
|
||||
**`response-type: "json"`** עם סכימת מערך → הלקוח מקבל `list` בפייתון
|
||||
**`response-type: "jsonl"`** → הלקוח מקבל `list` בפייתון
|
||||
|
||||
מנקודת מבטו של הלקוח, שתי השיטות מחזירות מבני נתונים זהים. ההבדל
|
||||
<<<<<<< HEAD
|
||||
הוא אך ורק באופן שבו פלט ה-LLM מנותח בצד השרת:
|
||||
|
||||
פורמט מערך JSON: קריאה אחת ל-`json.loads()`; נכשל לחלוטין אם הוא חתוך
|
||||
פורמט JSONL: ניתוח שורה אחר שורה; מייצר תוצאות חלקיות אם הוא חתוך
|
||||
=======
|
||||
הוא אך ורק באופן שבו הפלט של מודל השפה הגדול (LLM) מנותח בצד השרת:
|
||||
|
||||
פורמט מערך JSON: קריאה אחת ל-`json.loads()`; נכשל לחלוטין אם הוא חתוך.
|
||||
פורמט JSONL: ניתוח שורה אחר שורה; מייצר תוצאות חלקיות אם הוא חתוך.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
המשמעות היא שקוד לקוח קיים שמצפה לרשימה מהנחיות חילוץ
|
||||
אינו דורש שינויים בעת העברת הנחיות מפורמט JSON לפורמט JSONL.
|
||||
|
||||
#### ערך החזרה של השרת
|
||||
|
||||
עבור `response-type: "jsonl"`, השיטה `PromptManager.invoke()` מחזירה
|
||||
`list[dict]` המכיל את כל האובייקטים שנותחו ואומתו בהצלחה.
|
||||
רשימה זו מוסרת אז ל-JSON עבור השדה `PromptResponse.object`.
|
||||
|
||||
#### טיפול בשגיאות
|
||||
|
||||
<<<<<<< HEAD
|
||||
תוצאות ריקות: מחזיר רשימה ריקה `[]` עם רישום אזהרה
|
||||
כשל חלקי בניתוח: מחזיר רשימה של אובייקטים שנותחו בהצלחה עם
|
||||
רישומי אזהרה עבור כשלים
|
||||
כשל מוחלט בניתוח: מחזיר רשימה ריקה `[]` עם רישומי אזהרה
|
||||
=======
|
||||
תוצאות ריקות: מחזיר רשימה ריקה `[]` עם רישום אזהרה.
|
||||
כשל חלקי בניתוח: מחזיר רשימה של אובייקטים שנותחו בהצלחה עם
|
||||
רישומי אזהרה עבור כשלים.
|
||||
כשל מוחלט בניתוח: מחזיר רשימה ריקה `[]` עם רישומי אזהרה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
זה שונה מ-`response-type: "json"` שמגביר `RuntimeError`
|
||||
בעת כשל בניתוח. ההתנהגות הסלחנית עבור JSONL היא מכוונת כדי לספק
|
||||
עמידות לחיתוך.
|
||||
|
||||
### דוגמה לתצורה
|
||||
|
||||
דוגמה מלאה לתצורה של הנחיה:
|
||||
|
||||
```json
|
||||
{
|
||||
"prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"<name>\", \"definition\": \"<definition>\"}",
|
||||
"response-type": "jsonl",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"entity": {
|
||||
"type": "string",
|
||||
"description": "The entity name"
|
||||
},
|
||||
"definition": {
|
||||
"type": "string",
|
||||
"description": "A clear definition of the entity"
|
||||
}
|
||||
},
|
||||
"required": ["entity", "definition"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
<<<<<<< HEAD
|
||||
**בדיקת תקינות קלט**: ניתוח JSON משתמש ב-`json.loads()` הסטנדרטי, שהוא בטוח
|
||||
מפני התקפות הזרקה.
|
||||
**בדיקת תאימות סכימה**: משתמש ב-`jsonschema.validate()` לאכיפת סכימה.
|
||||
**ללא משטח תקיפה חדש**: ניתוח JSONL בטוח יותר מניתוח מערך JSON
|
||||
=======
|
||||
**בדיקת קלט**: ניתוח JSON משתמש ב-`json.loads()` הסטנדרטי, שהוא בטוח
|
||||
מפני התקפות הזרקה.
|
||||
**בדיקת סכימה**: משתמש ב-`jsonschema.validate()` לאכיפת סכימה.
|
||||
**ללא נקודות תורפה חדשות**: ניתוח JSONL בטוח יותר מניתוח מערך JSON
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
בשל עיבוד שורה אחר שורה.
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
<<<<<<< HEAD
|
||||
**זיכרון**: ניתוח שורה אחר שורה משתמש בפחות זיכרון שיא בהשוואה לטעינת מערכי JSON שלמים.
|
||||
|
||||
**השהיה**: ביצועי הניתוח דומים לניתוח מערך JSON.
|
||||
**בדיקת תאימות**: בדיקת תאימות סכימה מתבצעת עבור כל אובייקט, מה שמוסיף תקורה אך
|
||||
מאפשר תוצאות חלקיות במקרה של כשל בבדיקת התאימות.
|
||||
=======
|
||||
**זיכרון**: ניתוח שורה אחר שורה משתמש בפחות זיכרון שיא בהשוואה לטעינת
|
||||
מערכי JSON שלמים.
|
||||
**השהיה**: ביצועי הניתוח דומים לניתוח מערך JSON.
|
||||
**בדיקה**: בדיקת סכימה מתבצעת עבור כל אובייקט, מה שמוסיף תקורה אך
|
||||
מאפשר תוצאות חלקיות במקרה של כשל בבדיקה.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות יחידה
|
||||
|
||||
ניתוח JSONL עם קלט תקין.
|
||||
ניתוח JSONL עם שורות ריקות.
|
||||
ניתוח JSONL עם גדרות קוד Markdown.
|
||||
ניתוח JSONL עם שורה אחרונה חתוכה.
|
||||
ניתוח JSONL עם שורות JSON לא תקינות המפוזרות.
|
||||
<<<<<<< HEAD
|
||||
בדיקת תאימות סכימה עם איחודים מובחנים של `oneOf`.
|
||||
=======
|
||||
בדיקת סכימה עם איחודים מובחנים של `oneOf`.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
תאימות לאחור: הנחיות `"text"` ו-`"json"` קיימות אינן משתנות.
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
|
||||
חילוץ מקצה לקצה עם הנחיות JSONL.
|
||||
חילוץ עם קיצוץ מדומם (תגובה מוגבלת באופן מלאכותי).
|
||||
חילוץ מסוגים מעורבים עם מפריד סוגים.
|
||||
חילוץ אונטולוגיה עם שלושת הסוגים.
|
||||
|
||||
### בדיקות איכות חילוץ
|
||||
|
||||
השוואת תוצאות חילוץ: פורמט JSONL לעומת מערך JSON.
|
||||
<<<<<<< HEAD
|
||||
בדיקת עמידות בפני קיטוע: JSONL מניב תוצאות חלקיות כאשר JSON נכשל.
|
||||
=======
|
||||
בדיקת עמידות בפני קיטוע: פורמט JSONL מספק תוצאות חלקיות כאשר פורמט JSON נכשל.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
### שלב 1: הטמעה
|
||||
|
||||
1. הטמעת שיטה `parse_jsonl()` ב-`PromptManager`.
|
||||
2. הרחבת `invoke()` כדי לטפל ב-`response-type: "jsonl"`.
|
||||
3. הוספת בדיקות יחידה.
|
||||
|
||||
### שלב 2: מעבר להנחיות
|
||||
|
||||
1. עדכון ההנחיה והתצורה של `extract-definitions`.
|
||||
2. עדכון ההנחיה והתצורה של `extract-relationships`.
|
||||
3. עדכון ההנחיה והתצורה של `extract-topics`.
|
||||
4. עדכון ההנחיה והתצורה של `extract-rows`.
|
||||
5. עדכון ההנחיה והתצורה של `agent-kg-extract`.
|
||||
6. עדכון ההנחיה והתצורה של `extract-with-ontologies`.
|
||||
|
||||
### שלב 3: עדכונים במערכות משימתיות
|
||||
|
||||
<<<<<<< HEAD
|
||||
1. עדכון כל קוד המשתמש בתוצאות החילוץ כדי לטפל בסוג החזרה של רשימה.
|
||||
2. עדכון קוד המקטלג חילוצים מסוגים מעורבים לפי שדה `type`.
|
||||
=======
|
||||
1. עדכון כל קוד הצורך בתוצאות החילוץ כדי לטפל בסוג החזרה של רשימה.
|
||||
2. עדכון קוד שמקטלג חילוצים מסוגים מעורבים לפי שדה `type`.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
3. עדכון בדיקות המאמתות את פורמט הפלט של החילוץ.
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
אין כרגע.
|
||||
|
||||
## הפניות
|
||||
|
||||
יישום נוכחי: `trustgraph-flow/trustgraph/template/prompt_manager.py`.
|
||||
מפרט JSON Lines: https://jsonlines.org/.
|
||||
סכימת JSON `oneOf`: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof.
|
||||
מפרט קשור: Streaming LLM Responses (`docs/tech-specs/streaming-llm-responses.md`).
|
||||
992
docs/tech-specs/he/large-document-loading.he.md
Normal file
992
docs/tech-specs/he/large-document-loading.he.md
Normal file
|
|
@ -0,0 +1,992 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לטעינת מסמכים גדולים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לטעינת מסמכים גדולים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה עוסק בבעיות של יכולת התרחבות וחוויית משתמש כאשר טוענים
|
||||
מסמכים גדולים ל-TrustGraph. הארכיטקטורה הנוכחית מתייחסת להעלאת מסמכים
|
||||
כפעולה אטומית אחת, דבר הגורם ללחץ זיכרון במספר נקודות במערכת
|
||||
ואינו מספק משוב או אפשרויות התאוששות למשתמשים.
|
||||
|
||||
יישום זה מכוון למקרים הבאים:
|
||||
|
||||
1. **עיבוד PDF גדול**: העלאה ועיבוד של קבצי PDF בגודל מאות מגה-בייטים
|
||||
מבלי למצות את הזיכרון
|
||||
2. **העלאות ניתנות לחידוש**: אפשרות להמשיך העלאות שהופסקו מאותה נקודה
|
||||
במקום להתחיל מחדש
|
||||
3. **משוב התקדמות**: מתן למשתמשים תצוגה חיה של התקדמות ההעלאה
|
||||
והעיבוד
|
||||
4. **עיבוד חסכוני בזיכרון**: עיבוד מסמכים בצורה רציפה
|
||||
מבלי לשמור את כל הקבצים בזיכרון
|
||||
|
||||
## מטרות
|
||||
|
||||
**העלאה הדרגתית**: תמיכה בהעלאה מקוטעת של מסמכים באמצעות REST ו-WebSocket
|
||||
**העברות ניתנות לחידוש**: אפשרות להתאושש מהעלאות שהופסקו
|
||||
**נראות של התקדמות**: מתן משוב על התקדמות ההעלאה/עיבוד ללקוחות
|
||||
**יעילות זיכרון**: ביטול אחסון מלא של מסמכים לאורך כל המערכת
|
||||
**תאימות לאחור**: זרימות עבודה קיימות עבור מסמכים קטנים ממשיכות לפעול ללא שינוי
|
||||
**עיבוד רציף**: פענוח PDF וחלוקת טקסט מתבצעות על זרמים
|
||||
|
||||
## רקע
|
||||
|
||||
### ארכיטקטורה נוכחית
|
||||
|
||||
זרימת הגשת מסמכים עוברת דרך הנתיב הבא:
|
||||
|
||||
1. **לקוח** מגיש מסמך באמצעות REST (`POST /api/v1/librarian`) או WebSocket
|
||||
2. **שער API** מקבל בקשה שלמה עם תוכן המסמך מקודד ב-base64
|
||||
3. **LibrarianRequestor** מתרגם את הבקשה להודעת Pulsar
|
||||
4. **שירות Librarian** מקבל את ההודעה, מפענח את המסמך לזיכרון
|
||||
5. **BlobStore** מעלה את המסמך ל-Garage/S3
|
||||
6. **Cassandra** שומר מטא-דאטה עם הפניה לאובייקט
|
||||
7. לצורך עיבוד: המסמך נשלף מ-S3, מפענח, מחולק - הכל בזיכרון
|
||||
|
||||
קבצים מרכזיים:
|
||||
נקודת כניסה REST/WebSocket: `trustgraph-flow/trustgraph/gateway/service.py`
|
||||
ליבה של Librarian: `trustgraph-flow/trustgraph/librarian/librarian.py`
|
||||
אחסון Blob: `trustgraph-flow/trustgraph/librarian/blob_store.py`
|
||||
טבלאות Cassandra: `trustgraph-flow/trustgraph/tables/library.py`
|
||||
סכימת API: `trustgraph-base/trustgraph/schema/services/library.py`
|
||||
|
||||
### מגבלות נוכחיות
|
||||
|
||||
לעיצוב הנוכחי יש מספר בעיות מורכבות של זיכרון וחוויית משתמש:
|
||||
|
||||
1. **פעולת העלאה אטומית**: יש להעביר את כל המסמך בבקשה אחת.
|
||||
מסמכים גדולים דורשים בקשות ארוכות עם אינדיקציה מועטה להתקדמות
|
||||
וללא מנגנון ניסיון חוזר אם החיבור נכשל.
|
||||
|
||||
2. **עיצוב API**: גם ממשקי REST וגם WebSocket מצפים לקבל את כל המסמך
|
||||
בהודעה אחת. הסכימה (`LibrarianRequest`) כוללת שדה `content`
|
||||
יחיד המכיל את תוכן המסמך המקודד ב-base64.
|
||||
|
||||
3. **זיכרון של Librarian**: שירות ה-librarian מפענח את כל המסמך
|
||||
לזיכרון לפני העלאתו ל-S3. עבור קובץ PDF בגודל 500 מגה-בייטים,
|
||||
זה אומר שמירת 500 מגה-בייטים+ בזיכרון התהליך.
|
||||
|
||||
4. **זיכרון של מפענח PDF**: כאשר העיבוד מתחיל, מפענח ה-PDF טוען את
|
||||
ה-PDF כולו לזיכרון כדי לחלץ טקסט. ספריות כמו PyPDF דורשות
|
||||
בדרך כלל גישה מלאה למסמך.
|
||||
|
||||
5. **זיכרון של חולק הטקסט**: החולק של הטקסט מקבל את הטקסט
|
||||
שחולץ ומחזיק אותו בזיכרון תוך יצירת חלקים.
|
||||
|
||||
**דוגמה להשפעה על הזיכרון** (PDF בגודל 500 מגה-בייטים):
|
||||
Gateway: ~700 מגה-בייטים (עקב קידוד base64)
|
||||
Librarian: ~500 מגה-בייטים (בייטים מפוענחים)
|
||||
מפענח PDF: ~500 מגה-בייטים + חוצצים לחילוץ
|
||||
חולק: טקסט שחולץ (משתנה, פוטנציאלית 100 מגה-בייטים+)
|
||||
|
||||
הזיכרון המקסימלי יכול לעלות על 2 ג'יגה-בייטים עבור מסמך גדול יחיד.
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### עקרונות עיצוב
|
||||
|
||||
1. **ממשק API**: כל האינטראקציות עם הלקוח עוברות דרך ה-API של ה-librarian.
|
||||
ללקוחות אין גישה ישירה או ידע לגבי אחסון S3/Garage הבסיסי.
|
||||
|
||||
2. **העלאה מרובת חלקים של S3**: שימוש בהעלאה מרובת חלקים סטנדרטית של S3.
|
||||
זה נתמך באופן נרחב במערכות התואמות ל-S3 (AWS S3, MinIO, Garage,
|
||||
Ceph, DigitalOcean Spaces, Backblaze B2 וכו') ומבטיח ניידות.
|
||||
|
||||
3. **השלמה אטומית**: העלאות מרובות חלקים של S3 הן מטבען אטומיות - חלקים שהועלו
|
||||
אינם גלויים עד ש-`CompleteMultipartUpload` נקרא. אין צורך בקבצים זמניים או פעולות
|
||||
שינוי שם.
|
||||
|
||||
4. **מצב הניתן למעקב**: סשנים של העלאה נרשמים ב-Cassandra ומאפשרים
|
||||
התאוששות במקרה של כשל.
|
||||
|
||||
|
||||
|
||||
```
|
||||
Client Librarian API S3/Garage
|
||||
│ │ │
|
||||
│── begin-upload ───────────►│ │
|
||||
│ (metadata, size) │── CreateMultipartUpload ────►│
|
||||
│ │◄── s3_upload_id ─────────────│
|
||||
│◄── upload_id ──────────────│ (store session in │
|
||||
│ │ Cassandra) │
|
||||
│ │ │
|
||||
│── upload-chunk ───────────►│ │
|
||||
│ (upload_id, index, data) │── UploadPart ───────────────►│
|
||||
│ │◄── etag ─────────────────────│
|
||||
│◄── ack + progress ─────────│ (store etag in session) │
|
||||
│ ⋮ │ ⋮ │
|
||||
│ (repeat for all chunks) │ │
|
||||
│ │ │
|
||||
│── complete-upload ────────►│ │
|
||||
│ (upload_id) │── CompleteMultipartUpload ──►│
|
||||
│ │ (parts coalesced by S3) │
|
||||
│ │── store doc metadata ───────►│ Cassandra
|
||||
│◄── document_id ────────────│ (delete session) │
|
||||
```
|
||||
|
||||
הלקוח לעולם אינו מתקשר ישירות עם S3. הספרן מתרגם בין
|
||||
ממשק ההעלאה המקוטעת שלנו לפעולות ה-multipart של S3 באופן פנימי.
|
||||
|
||||
### פעולות ממשק ה-API של הספרן
|
||||
|
||||
#### `begin-upload`
|
||||
|
||||
אתחול סשן העלאה מקוטעת.
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "begin-upload",
|
||||
"document-metadata": {
|
||||
"id": "doc-123",
|
||||
"kind": "application/pdf",
|
||||
"title": "Large Document",
|
||||
"user": "user-id",
|
||||
"tags": ["tag1", "tag2"]
|
||||
},
|
||||
"total-size": 524288000,
|
||||
"chunk-size": 5242880
|
||||
}
|
||||
```
|
||||
|
||||
תגובה:
|
||||
```json
|
||||
{
|
||||
"upload-id": "upload-abc-123",
|
||||
"chunk-size": 5242880,
|
||||
"total-chunks": 100
|
||||
}
|
||||
```
|
||||
|
||||
הספרן:
|
||||
1. מייצר `upload_id` ו-`object_id` ייחודיים (UUID עבור אחסון בלובים).
|
||||
2. קורא ל-S3 `CreateMultipartUpload`, מקבל `s3_upload_id`.
|
||||
3. יוצר רשומת סשן ב-Cassandra.
|
||||
4. מחזיר `upload_id` ללקוח.
|
||||
|
||||
#### `upload-chunk`
|
||||
|
||||
העלאת מקטע בודד.
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "upload-chunk",
|
||||
"upload-id": "upload-abc-123",
|
||||
"chunk-index": 0,
|
||||
"content": "<base64-encoded-chunk>"
|
||||
}
|
||||
```
|
||||
|
||||
תגובה:
|
||||
```json
|
||||
{
|
||||
"upload-id": "upload-abc-123",
|
||||
"chunk-index": 0,
|
||||
"chunks-received": 1,
|
||||
"total-chunks": 100,
|
||||
"bytes-received": 5242880,
|
||||
"total-bytes": 524288000
|
||||
}
|
||||
```
|
||||
|
||||
הספרן:
|
||||
1. מחפש את הסשן לפי `upload_id`
|
||||
2. מאמת בעלות (המשתמש חייב להתאים ליוצר הסשן)
|
||||
3. קורא ל-S3 `UploadPart` עם נתוני החלק, מקבל `etag`
|
||||
4. מעדכן את רשומת הסשן עם אינדקס החלק ו-etag
|
||||
5. מחזיר התקדמות ללקוח
|
||||
|
||||
חלקים שנכשלו ניתנים לניסיון חוזר - פשוט שלחו שוב את `chunk-index`.
|
||||
|
||||
#### `complete-upload`
|
||||
|
||||
השלמת ההעלאה ויצירת המסמך.
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "complete-upload",
|
||||
"upload-id": "upload-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
תגובה:
|
||||
```json
|
||||
{
|
||||
"document-id": "doc-123",
|
||||
"object-id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
הספרן:
|
||||
1. מחפש את הסשן, מוודא שכל החלקים התקבלו.
|
||||
2. קורא ל-S3 `CompleteMultipartUpload` עם תגיות חלק (S3 ממזגת חלקים
|
||||
באופן פנימי - אין עלות זיכרון לספרן).
|
||||
3. יוצר רשומת מסמך ב-Cassandra עם מטא-דאטה והפניה לאובייקט.
|
||||
4. מוחק את רשומת סשן ההעלאה.
|
||||
5. מחזיר את מזהה המסמך ללקוח.
|
||||
|
||||
#### `abort-upload`
|
||||
|
||||
ביטול העלאה בתהליך.
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "abort-upload",
|
||||
"upload-id": "upload-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
הספרן:
|
||||
1. מתקשר ל-S3 `AbortMultipartUpload` כדי לנקות חלקים.
|
||||
2. מוחק את רשומת הסשן מ-Cassandra.
|
||||
|
||||
#### `get-upload-status`
|
||||
|
||||
בדיקת סטטוס של העלאה (לצורך אפשרות המשך).
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "get-upload-status",
|
||||
"upload-id": "upload-abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
תגובה:
|
||||
```json
|
||||
{
|
||||
"upload-id": "upload-abc-123",
|
||||
"state": "in-progress",
|
||||
"chunks-received": [0, 1, 2, 5, 6],
|
||||
"missing-chunks": [3, 4, 7, 8],
|
||||
"total-chunks": 100,
|
||||
"bytes-received": 36700160,
|
||||
"total-bytes": 524288000
|
||||
}
|
||||
```
|
||||
|
||||
#### `list-uploads`
|
||||
|
||||
הצגת רשימה של העלאות חסרות השלמה עבור משתמש.
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "list-uploads"
|
||||
}
|
||||
```
|
||||
|
||||
תגובה:
|
||||
```json
|
||||
{
|
||||
"uploads": [
|
||||
{
|
||||
"upload-id": "upload-abc-123",
|
||||
"document-metadata": { "title": "Large Document", ... },
|
||||
"progress": { "chunks-received": 43, "total-chunks": 100 },
|
||||
"created-at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### אחסון סשן העלאה
|
||||
|
||||
מעקב אחר העלאות בתהליך ב-Cassandra:
|
||||
|
||||
```sql
|
||||
CREATE TABLE upload_session (
|
||||
upload_id text PRIMARY KEY,
|
||||
user text,
|
||||
document_id text,
|
||||
document_metadata text, -- JSON: title, kind, tags, comments, etc.
|
||||
s3_upload_id text, -- internal, for S3 operations
|
||||
object_id uuid, -- target blob ID
|
||||
total_size bigint,
|
||||
chunk_size int,
|
||||
total_chunks int,
|
||||
chunks_received map<int, text>, -- chunk_index → etag
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
) WITH default_time_to_live = 86400; -- 24 hour TTL
|
||||
|
||||
CREATE INDEX upload_session_user ON upload_session (user);
|
||||
```
|
||||
|
||||
**התנהגות TTL:**
|
||||
סשנים פוקעים לאחר 24 שעות אם לא הושלמו.
|
||||
כאשר TTL של Cassandra פוקע, רשומת הסשן נמחקת.
|
||||
חלקים של S3 שנותרו מאחור מנוקים על ידי מדיניות מחזור חיים של S3 (יש להגדיר על ה-bucket).
|
||||
|
||||
### טיפול בכשלים ואטומיות
|
||||
|
||||
**כשל בהעלאת חלק:**
|
||||
הלקוח מנסה שוב את החלק שנכשל (באמצעות אותו `upload_id` ו-`chunk-index`).
|
||||
`UploadPart` של S3 היא פעולה אידempotent עבור אותו מספר חלק.
|
||||
הסשן עוקב אחר אילו חלקים הצליחו.
|
||||
|
||||
**ניתוק לקוח במהלך העלאה:**
|
||||
הסשן נשאר ב-Cassandra עם החלקים שהתקבלו.
|
||||
הלקוח יכול לקרוא ל-`get-upload-status` כדי לראות מה חסר.
|
||||
ניתן לחדש על ידי העלאת רק החלקים החסרים, ולאחר מכן `complete-upload`.
|
||||
|
||||
**כשל בהעלאה מלאה:**
|
||||
`CompleteMultipartUpload` של S3 היא פעולה אטומית - או מצליחה לחלוטין או נכשלת.
|
||||
במקרה של כשל, החלקים נשארים והלקוח יכול לנסות שוב את `complete-upload`.
|
||||
לא ניתן לראות מסמך חלקי.
|
||||
|
||||
**תפוגת הסשן:**
|
||||
TTL של Cassandra מוחקת את רשומת הסשן לאחר 24 שעות.
|
||||
מדיניות מחזור חיים של bucket ב-S3 מנקה העלאות מרובות חלקים לא שלמות.
|
||||
אין צורך בניקוי ידני.
|
||||
|
||||
### אטומיות של העלאות מרובות חלקים ב-S3
|
||||
|
||||
העלאות מרובות חלקים ב-S3 מספקות אטומיות מובנית:
|
||||
|
||||
1. **חלקים אינם גלויים**: חלקים שהועלו לא ניתנים לגישה כאובייקטים.
|
||||
הם קיימים רק כחלקים של העלאה מרובת חלקים לא שלמה.
|
||||
|
||||
2. **השלמה אטומית**: `CompleteMultipartUpload` מצליחה (האובייקט
|
||||
מופיע באופן אטומי) או נכשלת (לא נוצר אובייקט). אין מצב חלקי.
|
||||
|
||||
3. **אין צורך בשינוי שם**: המפתח של האובייקט הסופי מצוין בזמן
|
||||
`CreateMultipartUpload`. החלקים משולבים ישירות למפתח זה.
|
||||
|
||||
4. **שילוב בצד השרת**: S3 משלבת חלקים באופן פנימי. ה-librarian
|
||||
לעולם לא קורא בחזרה חלקים - אין עומס זיכרון ללא קשר לגודל המסמך.
|
||||
|
||||
### הרחבות BlobStore
|
||||
|
||||
**קובץ:** `trustgraph-flow/trustgraph/librarian/blob_store.py`
|
||||
|
||||
הוספת שיטות העלאה מרובות חלקים:
|
||||
|
||||
```python
|
||||
class BlobStore:
|
||||
# Existing methods...
|
||||
|
||||
def create_multipart_upload(self, object_id: UUID, kind: str) -> str:
|
||||
"""Initialize multipart upload, return s3_upload_id."""
|
||||
# minio client: create_multipart_upload()
|
||||
|
||||
def upload_part(
|
||||
self, object_id: UUID, s3_upload_id: str,
|
||||
part_number: int, data: bytes
|
||||
) -> str:
|
||||
"""Upload a single part, return etag."""
|
||||
# minio client: upload_part()
|
||||
# Note: S3 part numbers are 1-indexed
|
||||
|
||||
def complete_multipart_upload(
|
||||
self, object_id: UUID, s3_upload_id: str,
|
||||
parts: List[Tuple[int, str]] # [(part_number, etag), ...]
|
||||
) -> None:
|
||||
"""Finalize multipart upload."""
|
||||
# minio client: complete_multipart_upload()
|
||||
|
||||
def abort_multipart_upload(
|
||||
self, object_id: UUID, s3_upload_id: str
|
||||
) -> None:
|
||||
"""Cancel multipart upload, clean up parts."""
|
||||
# minio client: abort_multipart_upload()
|
||||
```
|
||||
|
||||
### שיקולי גודל מקטע
|
||||
|
||||
**מינימום עבור S3**: 5MB לכל חלק (למעט החלק האחרון)
|
||||
**מקסימום עבור S3**: 10,000 חלקים לכל העלאה
|
||||
**ערך ברירת מחדל מעשי**: מקטעים בגודל 5MB
|
||||
מסמך בגודל 500MB = 100 מקטעים
|
||||
מסמך בגודל 5GB = 1,000 מקטעים
|
||||
**גרנולריות של התקדמות**: מקטעים קטנים יותר = עדכוני התקדמות מדויקים יותר
|
||||
**יעילות רשת**: מקטעים גדולים יותר = פחות מעברים
|
||||
|
||||
גודל המקטע יכול להיות מוגדר על ידי הלקוח בטווח מסוים (5MB - 100MB).
|
||||
|
||||
### עיבוד מסמכים: אחזור סטרימינג
|
||||
|
||||
זרימת ההעלאה מטפלת בהעברת מסמכים לאחסון בצורה יעילה. זרימת העיבוד מטפלת בחילוץ ופיצול מסמכים מבלי לטעון
|
||||
אותם כולם לזיכרון.
|
||||
|
||||
|
||||
#### עקרון עיצוב: מזהה, לא תוכן
|
||||
|
||||
כיום, כאשר עיבוד מופעל, תוכן המסמך זורם באמצעות הודעות Pulsar. זה טוען מסמכים שלמים לזיכרון. במקום זאת:
|
||||
|
||||
|
||||
הודעות Pulsar נושאות רק את **מזהה המסמך**
|
||||
מעבדים שולפים תוכן מסמך ישירות מהספרן (librarian)
|
||||
השליפה מתבצעת כ**זרם לקובץ זמני**
|
||||
ניתוח ספציפי למסמך (PDF, טקסט, וכו') עובד עם קבצים, ולא עם מאגרי זיכרון
|
||||
|
||||
זה שומר על כך שהספרן אינו תלוי במבנה המסמך. ניתוח PDF, חילוץ טקסט, ולוגיקה ספציפית אחרת לפורמט נשארים בדקודינג המתאים.
|
||||
|
||||
|
||||
#### זרימת עיבוד
|
||||
|
||||
```
|
||||
Pulsar PDF Decoder Librarian S3
|
||||
│ │ │ │
|
||||
│── doc-id ───────────►│ │ │
|
||||
│ (processing msg) │ │ │
|
||||
│ │ │ │
|
||||
│ │── stream-document ──────►│ │
|
||||
│ │ (doc-id) │── GetObject ────►│
|
||||
│ │ │ │
|
||||
│ │◄── chunk ────────────────│◄── stream ───────│
|
||||
│ │ (write to temp file) │ │
|
||||
│ │◄── chunk ────────────────│◄── stream ───────│
|
||||
│ │ (append to temp file) │ │
|
||||
│ │ ⋮ │ ⋮ │
|
||||
│ │◄── EOF ──────────────────│ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────────────────────────┐ │
|
||||
│ │ │ temp file on disk │ │
|
||||
│ │ │ (memory stays bounded) │ │
|
||||
│ │ └────────────┬─────────────┘ │
|
||||
│ │ │ │
|
||||
│ │ PDF library opens file │
|
||||
│ │ extract page 1 text ──► chunker │
|
||||
│ │ extract page 2 text ──► chunker │
|
||||
│ │ ⋮ │
|
||||
│ │ close file │
|
||||
│ │ delete temp file │
|
||||
```
|
||||
|
||||
#### ממשק API של ספריות
|
||||
|
||||
הוספת פעולת שליפה של מסמכים בסטרימינג:
|
||||
|
||||
**`stream-document`**
|
||||
|
||||
בקשה:
|
||||
```json
|
||||
{
|
||||
"operation": "stream-document",
|
||||
"document-id": "doc-123"
|
||||
}
|
||||
```
|
||||
|
||||
תגובה: מקטעי נתונים בינאריים (ולא תגובה יחידה).
|
||||
|
||||
עבור ממשק API REST, זה מחזיר תגובה סטרימינג עם `Transfer-Encoding: chunked`.
|
||||
|
||||
עבור שיחות פנימיות בין שירותים (ממעבד לספרן), זה יכול להיות:
|
||||
סטרימינג ישיר מ-S3 באמצעות כתובת URL חתומה מראש (אם רשת פנימית מאפשרת זאת).
|
||||
תגובות מחולקות באמצעות פרוטוקול השירות.
|
||||
נקודת קצה ייעודית לסטרימינג.
|
||||
|
||||
הדרישה העיקרית: הנתונים זורמים במקטעים, ואינם מאוחסנים באופן מלא בזיכרון בספרן.
|
||||
|
||||
#### שינויים במפענח PDF
|
||||
|
||||
**יישום נוכחי** (דורש משאבים רבים בזיכרון):
|
||||
|
||||
```python
|
||||
def decode_pdf(document_content: bytes) -> str:
|
||||
reader = PdfReader(BytesIO(document_content)) # full doc in memory
|
||||
text = ""
|
||||
for page in reader.pages:
|
||||
text += page.extract_text() # accumulating
|
||||
return text # full text in memory
|
||||
```
|
||||
|
||||
**יישום חדש** (קובץ זמני, מצטבר):
|
||||
|
||||
```python
|
||||
def decode_pdf_streaming(doc_id: str, librarian_client) -> Iterator[str]:
|
||||
"""Yield extracted text page by page."""
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp:
|
||||
# Stream document to temp file
|
||||
for chunk in librarian_client.stream_document(doc_id):
|
||||
tmp.write(chunk)
|
||||
tmp.flush()
|
||||
|
||||
# Open PDF from file (not memory)
|
||||
reader = PdfReader(tmp.name)
|
||||
|
||||
# Yield pages incrementally
|
||||
for page in reader.pages:
|
||||
yield page.extract_text()
|
||||
|
||||
# tmp file auto-deleted on context exit
|
||||
```
|
||||
|
||||
פרופיל זיכרון:
|
||||
קובץ זמני בדיסק: גודל קובץ ה-PDF (דיסק זול).
|
||||
בזיכרון: עמוד טקסט אחד בכל פעם.
|
||||
שיא זיכרון: מוגבל, בלתי תלוי בגודל המסמך.
|
||||
|
||||
#### שינויים במפענח מסמכי טקסט
|
||||
|
||||
עבור מסמכי טקסט רגילים, זה אפילו פשוט יותר - אין צורך בקובץ זמני:
|
||||
|
||||
```python
|
||||
def decode_text_streaming(doc_id: str, librarian_client) -> Iterator[str]:
|
||||
"""Yield text in chunks as it streams from storage."""
|
||||
|
||||
buffer = ""
|
||||
for chunk in librarian_client.stream_document(doc_id):
|
||||
buffer += chunk.decode('utf-8')
|
||||
|
||||
# Yield complete lines/paragraphs as they arrive
|
||||
while '\n\n' in buffer:
|
||||
paragraph, buffer = buffer.split('\n\n', 1)
|
||||
yield paragraph + '\n\n'
|
||||
|
||||
# Yield remaining buffer
|
||||
if buffer:
|
||||
yield buffer
|
||||
```
|
||||
|
||||
מסמכי טקסט יכולים לעבור סטרימינג ישירות ללא קובץ זמני מכיוון שהם
|
||||
בנויים בצורה ליניארית.
|
||||
|
||||
#### שילוב עם מודול חלוקה (Chunker)
|
||||
|
||||
המודול חלוקה מקבל איטרטור של טקסט (עמודים או פסקאות) ומייצר
|
||||
חלקים באופן הדרגתי:
|
||||
|
||||
```python
|
||||
class StreamingChunker:
|
||||
def __init__(self, chunk_size: int, overlap: int):
|
||||
self.chunk_size = chunk_size
|
||||
self.overlap = overlap
|
||||
|
||||
def process(self, text_stream: Iterator[str]) -> Iterator[str]:
|
||||
"""Yield chunks as text arrives."""
|
||||
buffer = ""
|
||||
|
||||
for text_segment in text_stream:
|
||||
buffer += text_segment
|
||||
|
||||
while len(buffer) >= self.chunk_size:
|
||||
chunk = buffer[:self.chunk_size]
|
||||
yield chunk
|
||||
# Keep overlap for context continuity
|
||||
buffer = buffer[self.chunk_size - self.overlap:]
|
||||
|
||||
# Yield remaining buffer as final chunk
|
||||
if buffer.strip():
|
||||
yield buffer
|
||||
```
|
||||
|
||||
#### צינור עיבוד מקצה לקצה
|
||||
|
||||
```python
|
||||
async def process_document(doc_id: str, librarian_client, embedder):
|
||||
"""Process document with bounded memory."""
|
||||
|
||||
# Get document metadata to determine type
|
||||
metadata = await librarian_client.get_document_metadata(doc_id)
|
||||
|
||||
# Select decoder based on document type
|
||||
if metadata.kind == 'application/pdf':
|
||||
text_stream = decode_pdf_streaming(doc_id, librarian_client)
|
||||
elif metadata.kind == 'text/plain':
|
||||
text_stream = decode_text_streaming(doc_id, librarian_client)
|
||||
else:
|
||||
raise UnsupportedDocumentType(metadata.kind)
|
||||
|
||||
# Chunk incrementally
|
||||
chunker = StreamingChunker(chunk_size=1000, overlap=100)
|
||||
|
||||
# Process each chunk as it's produced
|
||||
for chunk in chunker.process(text_stream):
|
||||
# Generate embeddings, store in vector DB, etc.
|
||||
embedding = await embedder.embed(chunk)
|
||||
await store_chunk(doc_id, chunk, embedding)
|
||||
```
|
||||
|
||||
בשום שלב לא נשמר המסמך השלם או הטקסט החלץ בזיכרון.
|
||||
|
||||
#### שיקולים לגבי קבצי זמניים
|
||||
|
||||
**מיקום**: יש להשתמש בספריית הזמנים של המערכת (`/tmp` או מקביל). עבור
|
||||
פריסות מבוססות קונטיינרים, ודאו שספריית הזמנים מכילה מספיק מקום
|
||||
ושנמצאת באחסון מהיר (לא מחובר לרשת, אם אפשר).
|
||||
|
||||
**ניקוי**: יש להשתמש במנהלי הקשר (context managers) (`with tempfile...`) כדי להבטיח ניקוי
|
||||
גם במקרה של חריגות.
|
||||
|
||||
**עיבוד מקבילי**: כל משימת עיבוד מקבלת קובץ זמני משלה.
|
||||
אין התנגשויות בין עיבוד מקבילי של מסמכים.
|
||||
|
||||
**שטח דיסק**: קבצים זמניים הם קצרי טווח (משך העיבוד). עבור
|
||||
קובץ PDF בגודל 500MB, נדרש שטח זמני של 500MB במהלך העיבוד. ניתן
|
||||
לאכוף מגבלת גודל בזמן ההעלאה אם יש מגבלות על שטח הדיסק.
|
||||
|
||||
### ממשק עיבוד מאוחד: מסמכים משניים
|
||||
|
||||
חילוץ PDF ועיבוד מסמכי טקסט צריכים להזין לאותו
|
||||
צינור עיבוד המשכיות (chunker → embeddings → storage). כדי להשיג זאת עם
|
||||
ממשק "שליפה לפי מזהה" עקבי, חלקי טקסט חלצים מאוחסנים בחזרה
|
||||
ל-librarian כמסמכים משניים.
|
||||
|
||||
#### זרימת עיבוד עם מסמכים משניים
|
||||
|
||||
```
|
||||
PDF Document Text Document
|
||||
│ │
|
||||
▼ │
|
||||
pdf-extractor │
|
||||
│ │
|
||||
│ (stream PDF from librarian) │
|
||||
│ (extract page 1 text) │
|
||||
│ (store as child doc → librarian) │
|
||||
│ (extract page 2 text) │
|
||||
│ (store as child doc → librarian) │
|
||||
│ ⋮ │
|
||||
▼ ▼
|
||||
[child-doc-id, child-doc-id, ...] [doc-id]
|
||||
│ │
|
||||
└─────────────────────┬───────────────────────────────┘
|
||||
▼
|
||||
chunker
|
||||
│
|
||||
│ (receives document ID)
|
||||
│ (streams content from librarian)
|
||||
│ (chunks incrementally)
|
||||
▼
|
||||
[chunks → embedding → storage]
|
||||
```
|
||||
|
||||
למודול החלוקה יש ממשק אחיד אחד:
|
||||
קבלת מזהה מסמך (דרך Pulsar)
|
||||
קבלת תוכן מהספרן
|
||||
חלוקת התוכן לחלקים
|
||||
|
||||
הוא לא יודע או אכפת לו האם המזהה מתייחס ל:
|
||||
מסמך טקסט שהועלה על ידי משתמש
|
||||
פיסת טקסט שחולצה מעמוד PDF
|
||||
כל סוג מסמך עתידי
|
||||
|
||||
#### מטא-נתונים של מסמכים משניים
|
||||
|
||||
הרחבת הסכימה של המסמך כדי לעקוב אחר קשרים הוריים/משניים:
|
||||
|
||||
```sql
|
||||
-- Add columns to document table
|
||||
ALTER TABLE document ADD parent_id text;
|
||||
ALTER TABLE document ADD document_type text;
|
||||
|
||||
-- Index for finding children of a parent
|
||||
CREATE INDEX document_parent ON document (parent_id);
|
||||
```
|
||||
|
||||
**סוגי מסמכים:**
|
||||
|
||||
| `document_type` | תיאור |
|
||||
|-----------------|-------------|
|
||||
| `source` | מסמך שהועלה על ידי משתמש (PDF, טקסט, וכו') |
|
||||
| `extracted` | נגזר ממסמך מקור (לדוגמה, טקסט של עמוד PDF) |
|
||||
|
||||
**שדות מטא-דאטה:**
|
||||
|
||||
| שדה | מסמך מקור | מסמך משני |
|
||||
|-------|-----------------|-----------------|
|
||||
| `id` | שסופק על ידי המשתמש או נוצר | נוצר (לדוגמה, `{parent-id}-page-{n}`) |
|
||||
| `parent_id` | `NULL` | מזהה מסמך הורה |
|
||||
| `document_type` | `source` | `extracted` |
|
||||
| `kind` | `application/pdf`, וכו' | `text/plain` |
|
||||
| `title` | שסופק על ידי המשתמש | נוצר (לדוגמה, "עמוד 3 של Report.pdf") |
|
||||
| `user` | משתמש מאומת | זהה למסמך הורה |
|
||||
|
||||
#### ממשק API של הספרן עבור מסמכים משניים
|
||||
|
||||
**יצירת מסמכים משניים** (פנימי, בשימוש על ידי pdf-extractor):
|
||||
|
||||
```json
|
||||
{
|
||||
"operation": "add-child-document",
|
||||
"parent-id": "doc-123",
|
||||
"document-metadata": {
|
||||
"id": "doc-123-page-1",
|
||||
"kind": "text/plain",
|
||||
"title": "Page 1"
|
||||
},
|
||||
"content": "<base64-encoded-text>"
|
||||
}
|
||||
```
|
||||
|
||||
עבור טקסט קצר שחולץ (טקסט עמוד טיפוסי הוא פחות מ-100KB), העלאה בפעולה אחת מקובלת. עבור חילוצי טקסט גדולים מאוד, ניתן להשתמש בהעלאה מחולקת.
|
||||
|
||||
**רשימת מסמכים משניים** (לצרכי ניפוי באגים/ניהול):
|
||||
|
||||
**הצגת מסמכים משניים** (לצרכי ניפוי באגים/ניהול):
|
||||
|
||||
```json
|
||||
{
|
||||
"operation": "list-children",
|
||||
"parent-id": "doc-123"
|
||||
}
|
||||
```
|
||||
|
||||
תגובה:
|
||||
```json
|
||||
{
|
||||
"children": [
|
||||
{ "id": "doc-123-page-1", "title": "Page 1", "kind": "text/plain" },
|
||||
{ "id": "doc-123-page-2", "title": "Page 2", "kind": "text/plain" },
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### התנהגות מול המשתמש
|
||||
|
||||
**התנהגות ברירת מחדל `list-documents`:**
|
||||
|
||||
```sql
|
||||
SELECT * FROM document WHERE user = ? AND parent_id IS NULL;
|
||||
```
|
||||
|
||||
רק מסמכים ברמה העליונה (מקור) מופיעים ברשימת המסמכים של המשתמש.
|
||||
מסמכים משניים מסוננים כברירת מחדל.
|
||||
|
||||
**דגל "הכללה של תת-מסמכים" אופציונלי** (למנהל/דיבוג):
|
||||
|
||||
```json
|
||||
{
|
||||
"operation": "list-documents",
|
||||
"include-children": true
|
||||
}
|
||||
```
|
||||
|
||||
#### מחיקה מדורגת
|
||||
|
||||
כאשר מסמך הורה נמחק, יש למחוק את כל הצאצאים:
|
||||
|
||||
```python
|
||||
def delete_document(doc_id: str):
|
||||
# Find all children
|
||||
children = query("SELECT id, object_id FROM document WHERE parent_id = ?", doc_id)
|
||||
|
||||
# Delete child blobs from S3
|
||||
for child in children:
|
||||
blob_store.delete(child.object_id)
|
||||
|
||||
# Delete child metadata from Cassandra
|
||||
execute("DELETE FROM document WHERE parent_id = ?", doc_id)
|
||||
|
||||
# Delete parent blob and metadata
|
||||
parent = get_document(doc_id)
|
||||
blob_store.delete(parent.object_id)
|
||||
execute("DELETE FROM document WHERE id = ? AND user = ?", doc_id, user)
|
||||
```
|
||||
|
||||
#### שיקולי אחסון
|
||||
|
||||
קטעי טקסט שחולצו מכפילים תוכן:
|
||||
קובץ PDF מקורי מאוחסן ב-"Garage"
|
||||
טקסט שחולץ לכל עמוד מאוחסן גם ב-"Garage"
|
||||
|
||||
פשרה זו מאפשרת:
|
||||
**ממשק "חיתוך" אחיד**: "חיתוך" תמיד שולף לפי מזהה
|
||||
**התחלה מחדש/ניסיון חוזר**: ניתן להתחיל בשלב ה-"חיתוך" מבלי לחלץ מחדש את קובץ ה-PDF
|
||||
**ניפוי שגיאות**: ניתן לבדוק את הטקסט שחולץ
|
||||
**הפרדת אחריות**: שירות חילוץ ה-PDF ושירות ה-"חיתוך" הם שירותים עצמאיים
|
||||
|
||||
עבור קובץ PDF בגודל 500MB עם 200 עמודים, כאשר בממוצע יש 5KB טקסט לעמוד:
|
||||
אחסון קובץ PDF: 500MB
|
||||
אחסון טקסט שחולץ: כ-1MB בסך הכל
|
||||
תקורה: זניחה
|
||||
|
||||
#### פלט של מופע חילוץ PDF
|
||||
|
||||
מופע חילוץ ה-PDF, לאחר עיבוד מסמך:
|
||||
|
||||
1. מוריד את קובץ ה-PDF מה-"librarian" לקובץ זמני
|
||||
2. מחלץ טקסט עמוד אחר עמוד
|
||||
3. עבור כל עמוד, שומר את הטקסט שחולץ כמסמך משני דרך ה-"librarian"
|
||||
4. שולח מזהי מסמכים משניים לתור ה-"chunker"
|
||||
פלט חוזה (יש לעקוב אחר הפורמט המדויק).
|
||||
```python
|
||||
async def extract_pdf(doc_id: str, librarian_client, output_queue):
|
||||
"""Extract PDF pages and store as child documents."""
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=True, suffix='.pdf') as tmp:
|
||||
# Stream PDF to temp file
|
||||
for chunk in librarian_client.stream_document(doc_id):
|
||||
tmp.write(chunk)
|
||||
tmp.flush()
|
||||
|
||||
# Extract pages
|
||||
reader = PdfReader(tmp.name)
|
||||
for page_num, page in enumerate(reader.pages, start=1):
|
||||
text = page.extract_text()
|
||||
|
||||
# Store as child document
|
||||
child_id = f"{doc_id}-page-{page_num}"
|
||||
await librarian_client.add_child_document(
|
||||
parent_id=doc_id,
|
||||
document_id=child_id,
|
||||
kind="text/plain",
|
||||
title=f"Page {page_num}",
|
||||
content=text.encode('utf-8')
|
||||
)
|
||||
|
||||
# Send to chunker queue
|
||||
await output_queue.send(child_id)
|
||||
```
|
||||
|
||||
המודול שמחלק את הטקסט מקבל את מזהי הילדים הללו ומעבד אותם באופן זהה
|
||||
לאופן שבו הוא היה מעבד מסמך טקסט שהועלה על ידי משתמש.
|
||||
|
||||
### עדכונים עבור הלקוח
|
||||
|
||||
#### ערכת פיתוח תוכנה (SDK) עבור Python
|
||||
|
||||
ערכת הפיתוח תוכנה (`trustgraph-base/trustgraph/api/library.py`) עבור Python צריכה לטפל
|
||||
בהעלאות מחולקות בצורה שקופה. הממשק הציבורי נשאר ללא שינוי:
|
||||
|
||||
```python
|
||||
# Existing interface - no change for users
|
||||
library.add_document(
|
||||
id="doc-123",
|
||||
title="Large Report",
|
||||
kind="application/pdf",
|
||||
content=large_pdf_bytes, # Can be hundreds of MB
|
||||
tags=["reports"]
|
||||
)
|
||||
```
|
||||
|
||||
מבפנים, ה-SDK מזהה את גודל המסמך ועובר לאסטרטגיה אחרת:
|
||||
|
||||
```python
|
||||
class Library:
|
||||
CHUNKED_UPLOAD_THRESHOLD = 2 * 1024 * 1024 # 2MB
|
||||
|
||||
def add_document(self, id, title, kind, content, tags=None, ...):
|
||||
if len(content) < self.CHUNKED_UPLOAD_THRESHOLD:
|
||||
# Small document: single operation (existing behavior)
|
||||
return self._add_document_single(id, title, kind, content, tags)
|
||||
else:
|
||||
# Large document: chunked upload
|
||||
return self._add_document_chunked(id, title, kind, content, tags)
|
||||
|
||||
def _add_document_chunked(self, id, title, kind, content, tags):
|
||||
# 1. begin-upload
|
||||
session = self._begin_upload(
|
||||
document_metadata={...},
|
||||
total_size=len(content),
|
||||
chunk_size=5 * 1024 * 1024
|
||||
)
|
||||
|
||||
# 2. upload-chunk for each chunk
|
||||
for i, chunk in enumerate(self._chunk_bytes(content, session.chunk_size)):
|
||||
self._upload_chunk(session.upload_id, i, chunk)
|
||||
|
||||
# 3. complete-upload
|
||||
return self._complete_upload(session.upload_id)
|
||||
```
|
||||
|
||||
**החזרות התקדמות** (שיפור אופציונלי):
|
||||
|
||||
```python
|
||||
def add_document(self, ..., on_progress=None):
|
||||
"""
|
||||
on_progress: Optional callback(bytes_sent, total_bytes)
|
||||
"""
|
||||
```
|
||||
|
||||
זה מאפשר לממשקים גרפיים להציג את התקדמות ההעלאה מבלי לשנות את ממשק ה-API הבסיסי.
|
||||
|
||||
#### כלים עבור שורת הפקודה
|
||||
|
||||
**`tg-add-library-document`** ממשיך לעבוד ללא שינוי:
|
||||
|
||||
```bash
|
||||
# Works transparently for any size - SDK handles chunking internally
|
||||
tg-add-library-document --file large-report.pdf --title "Large Report"
|
||||
```
|
||||
|
||||
ניתן להוסיף תצוגת התקדמות אופציונלית:
|
||||
|
||||
```bash
|
||||
tg-add-library-document --file large-report.pdf --title "Large Report" --progress
|
||||
# Output:
|
||||
# Uploading: 45% (225MB / 500MB)
|
||||
```
|
||||
|
||||
**כלים מיושנים הוסרו:**
|
||||
|
||||
`tg-load-pdf` - מיושן, השתמשו ב-`tg-add-library-document`
|
||||
`tg-load-text` - מיושן, השתמשו ב-`tg-add-library-document`
|
||||
|
||||
**פקודות ניהול/דיבוג** (אופציונלי, בעדיפות נמוכה):
|
||||
|
||||
```bash
|
||||
# List incomplete uploads (admin troubleshooting)
|
||||
tg-add-library-document --list-pending
|
||||
|
||||
# Resume specific upload (recovery scenario)
|
||||
tg-add-library-document --resume upload-abc-123 --file large-report.pdf
|
||||
```
|
||||
|
||||
אלו יכולות להיות דגלים בפקודה הקיימת ולא כלים נפרדים.
|
||||
|
||||
#### עדכוני מפרט API
|
||||
|
||||
יש לעדכן את מפרט OpenAPI (`specs/api/paths/librarian.yaml`) עבור:
|
||||
|
||||
**פעולות חדשות:**
|
||||
|
||||
`begin-upload` - אתחול סשן העלאה מקוטעת
|
||||
`upload-chunk` - העלאת חלק בודד
|
||||
`complete-upload` - השלמת העלאה
|
||||
`abort-upload` - ביטול העלאה
|
||||
`get-upload-status` - שאילתת התקדמות העלאה
|
||||
`list-uploads` - הצגת רשימת העלאות חלקיות עבור משתמש
|
||||
`stream-document` - אחזור מסמך בסטרימינג
|
||||
`add-child-document` - אחסון טקסט חילוץ (פנימי)
|
||||
`list-children` - הצגת רשימת מסמכים ילדים (מנהל מערכת)
|
||||
|
||||
**פעולות ששונו:**
|
||||
|
||||
`list-documents` - הוספת פרמטר `include-children`
|
||||
|
||||
**סכימות חדשות:**
|
||||
|
||||
`ChunkedUploadBeginRequest`
|
||||
`ChunkedUploadBeginResponse`
|
||||
`ChunkedUploadChunkRequest`
|
||||
`ChunkedUploadChunkResponse`
|
||||
`UploadSession`
|
||||
`UploadProgress`
|
||||
|
||||
**עדכוני מפרט WebSocket** (`specs/websocket/`):
|
||||
|
||||
שכפול הפעולות REST עבור לקוחות WebSocket, המאפשר עדכונים בזמן אמת
|
||||
במהלך ההעלאה.
|
||||
|
||||
#### שיקולי UX
|
||||
|
||||
עדכוני מפרט ה-API מאפשרים שיפורים בחזית המשתמש:
|
||||
|
||||
**ממשק התקדמות העלאה:**
|
||||
סרגל התקדמות המציג חלקים שהועלו
|
||||
זמן משוער שנותר
|
||||
אפשרות השהיה/המשך
|
||||
|
||||
**התאוששות משגיאות:**
|
||||
אפשרות "המשך העלאה" עבור העלאות שהופרעו
|
||||
רשימת העלאות תלויות לאחר חיבור מחדש
|
||||
|
||||
**טיפול בקבצים גדולים:**
|
||||
זיהוי גודל קובץ בצד הלקוח
|
||||
העלאה מקוטעת אוטומטית עבור קבצים גדולים
|
||||
משוב ברור במהלך העלאות ארוכות
|
||||
|
||||
שיפורי UX אלו דורשים עבודה בצד החזית המשתמש, המונחית על ידי מפרט ה-API המעודכן.
|
||||
358
docs/tech-specs/he/logging-strategy.he.md
Normal file
358
docs/tech-specs/he/logging-strategy.he.md
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
---
|
||||
layout: default
|
||||
title: "אסטרטגיית רישום (לוגינג) של TrustGraph"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# אסטרטגיית רישום (לוגינג) של TrustGraph
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
TrustGraph משתמש במודול `logging` המובנה של Python עבור כל פעולות הרישום, עם תצורה מרכזית ושילוב אופציונלי של Loki לאיסוף יומנים. זה מספק גישה סטנדרטית וגמישה לרישום בכל רכיבי המערכת.
|
||||
|
||||
## תצורה ברירת מחדל
|
||||
|
||||
### רמת רישום
|
||||
**רמה ברירת מחדל**: `INFO`
|
||||
**ניתן להגדרה באמצעות**: ארגומנט שורת הפקודה `--log-level`
|
||||
**אפשרויות**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
|
||||
|
||||
### יעדי פלט
|
||||
1. **קונסולה (stdout)**: תמיד מופעלת - מבטיחה תאימות עם סביבות מבוססות קונטיינרים
|
||||
2. **Loki**: איסוף יומנים מרכזי אופציונלי (מופעל כברירת מחדל, ניתן לביטול)
|
||||
|
||||
## מודול רישום מרכזי
|
||||
|
||||
כל תצורת הרישום מנוהלת על ידי המודול `trustgraph.base.logging`, המספק:
|
||||
`add_logging_args(parser)` - מוסיף ארגומנטי שורת פקודה סטנדרטיים לרישום
|
||||
`setup_logging(args)` - מגדיר רישום מארגומנטים מנותחים
|
||||
|
||||
מודול זה משמש את כל רכיבי הצד-שרת:
|
||||
שירותים מבוססי AsyncProcessor
|
||||
API Gateway
|
||||
MCP Server
|
||||
|
||||
## הנחיות יישום
|
||||
|
||||
### 1. אתחול רשומות
|
||||
|
||||
כל מודול צריך ליצור את הרשומות שלו באמצעות המודול `__name__`:
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
```
|
||||
|
||||
שם ה-logger משמש באופן אוטומטי כתווית ב-Loki לצורך סינון וחיפוש.
|
||||
|
||||
### 2. אתחול שירות
|
||||
|
||||
כל השירותים בצד השרת מקבלים באופן אוטומטי הגדרות רישום דרך המודול המרכזי:
|
||||
|
||||
```python
|
||||
from trustgraph.base import add_logging_args, setup_logging
|
||||
import argparse
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
# Add standard logging arguments (includes Loki configuration)
|
||||
add_logging_args(parser)
|
||||
|
||||
# Add your service-specific arguments
|
||||
parser.add_argument('--port', type=int, default=8080)
|
||||
|
||||
args = parser.parse_args()
|
||||
args = vars(args)
|
||||
|
||||
# Setup logging early in startup
|
||||
setup_logging(args)
|
||||
|
||||
# Rest of your service initialization
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info("Service starting...")
|
||||
```
|
||||
|
||||
### 3. ארגומנטים של שורת הפקודה
|
||||
|
||||
כל השירותים תומכים בארגומנטים אלה של רישום:
|
||||
|
||||
**רמת רישום:**
|
||||
```bash
|
||||
--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}
|
||||
```
|
||||
|
||||
**תצורת לוקי:**
|
||||
```bash
|
||||
--loki-enabled # Enable Loki (default)
|
||||
--no-loki-enabled # Disable Loki
|
||||
--loki-url URL # Loki push URL (default: http://loki:3100/loki/api/v1/push)
|
||||
--loki-username USERNAME # Optional authentication
|
||||
--loki-password PASSWORD # Optional authentication
|
||||
```
|
||||
|
||||
**דוגמאות:**
|
||||
```bash
|
||||
# Default - INFO level, Loki enabled
|
||||
./my-service
|
||||
|
||||
# Debug mode, console only
|
||||
./my-service --log-level DEBUG --no-loki-enabled
|
||||
|
||||
# Custom Loki server with auth
|
||||
./my-service --loki-url http://loki.prod:3100/loki/api/v1/push \
|
||||
--loki-username admin --loki-password secret
|
||||
```
|
||||
|
||||
### 4. משתני סביבה
|
||||
|
||||
תצורת Loki תומכת באפשרויות ברירת מחדל עבור משתני סביבה:
|
||||
|
||||
```bash
|
||||
export LOKI_URL=http://loki.prod:3100/loki/api/v1/push
|
||||
export LOKI_USERNAME=admin
|
||||
export LOKI_PASSWORD=secret
|
||||
```
|
||||
|
||||
ארגומנטים משורת הפקודה גוברים על משתני סביבה.
|
||||
|
||||
### 5. שיטות עבודה מומלצות לרישום נתונים
|
||||
|
||||
#### שימוש ברמות רישום
|
||||
**DEBUG**: מידע מפורט לצורך אבחון בעיות (ערכי משתנים, כניסה/יציאה מפונקציות)
|
||||
**INFO**: הודעות מידע כלליות (השירות התחיל, תצורה נטענה, נקודות ציון בעיבוד)
|
||||
**WARNING**: הודעות אזהרה למצבים שעלולים להיות מזיקים (תכונות מיושנות, שגיאות שניתן להתאושש מהן)
|
||||
**ERROR**: הודעות שגיאה לבעיות חמורות (פעולות שנכשלו, חריגות)
|
||||
**CRITICAL**: הודעות קריטיות לכשלים במערכת הדורשים התייחסות מיידית
|
||||
|
||||
#### פורמט ההודעה
|
||||
```python
|
||||
# Good - includes context
|
||||
logger.info(f"Processing document: {doc_id}, size: {doc_size} bytes")
|
||||
logger.error(f"Failed to connect to database: {error}", exc_info=True)
|
||||
|
||||
# Avoid - lacks context
|
||||
logger.info("Processing document")
|
||||
logger.error("Connection failed")
|
||||
```
|
||||
|
||||
#### שיקולי ביצועים
|
||||
```python
|
||||
# Use lazy formatting for expensive operations
|
||||
logger.debug("Expensive operation result: %s", expensive_function())
|
||||
|
||||
# Check log level for very expensive debug operations
|
||||
if logger.isEnabledFor(logging.DEBUG):
|
||||
debug_data = compute_expensive_debug_info()
|
||||
logger.debug(f"Debug data: {debug_data}")
|
||||
```
|
||||
|
||||
### 6. רישום מובנה עם לוקי
|
||||
|
||||
עבור נתונים מורכבים, השתמש ברישום מובנה עם תגיות נוספות עבור לוקי:
|
||||
|
||||
```python
|
||||
logger.info("Request processed", extra={
|
||||
'tags': {
|
||||
'request_id': request_id,
|
||||
'user_id': user_id,
|
||||
'status': 'success'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
תגיות אלו הופכות לתויות הניתנות לחיפוש ב-Loki, בנוסף לתויות אוטומטיות:
|
||||
`severity` - רמת לוג (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
`logger` - שם מודול (מתוך `__name__`)
|
||||
|
||||
### 7. רישום חריגות
|
||||
|
||||
תמיד כללו עקבות מחסנית עבור חריגות:
|
||||
|
||||
```python
|
||||
try:
|
||||
process_data()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to process data: {e}", exc_info=True)
|
||||
raise
|
||||
```
|
||||
|
||||
### 8. שיקולים בנושא רישום אסינכרוני
|
||||
|
||||
מערכת הרישום משתמשת במטפלים (handlers) בתור לא חוסמים עבור Loki:
|
||||
פלט לקונסולה הוא סינכרוני (מהיר)
|
||||
פלט ל-Loki מוצג בתור עם מאגר של 500 הודעות
|
||||
ניתוב רקע מטפל בהעברת נתונים ל-Loki
|
||||
אין חסימה של קוד האפליקציה הראשי
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
async def async_operation():
|
||||
logger = logging.getLogger(__name__)
|
||||
# Logging is thread-safe and won't block async operations
|
||||
logger.info(f"Starting async operation in task: {asyncio.current_task().get_name()}")
|
||||
```
|
||||
|
||||
## אינטגרציה עם לוקי
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
מערכת הרישום משתמשת בפונקציות המובנות של Python, `QueueHandler` ו-`QueueListener`, עבור אינטגרציה לא חוסמת עם לוקי:
|
||||
|
||||
1. **QueueHandler**: הודעות רישום מוכנסות לתור של 500 הודעות (לא חוסם).
|
||||
2. **Background Thread**: QueueListener שולח הודעות רישום ללוקי באופן אסינכרוני.
|
||||
3. **Graceful Degradation**: אם לוקי אינו זמין, רישום לקונסולה ממשיך.
|
||||
|
||||
### תגיות אוטומטיות
|
||||
|
||||
כל הודעת רישום שנשלחת ללוקי כוללת:
|
||||
`processor`: זהות המעבד (לדוגמה, `config-svc`, `text-completion`, `embeddings`).
|
||||
`severity`: רמת הרישום (DEBUG, INFO, וכו').
|
||||
`logger`: שם המודול (לדוגמה, `trustgraph.gateway.service`, `trustgraph.agent.react.service`).
|
||||
|
||||
### תגיות מותאמות אישית
|
||||
|
||||
הוספת תגיות מותאמות אישית באמצעות הפרמטר `extra`:
|
||||
|
||||
```python
|
||||
logger.info("User action", extra={
|
||||
'tags': {
|
||||
'user_id': user_id,
|
||||
'action': 'document_upload',
|
||||
'collection': collection_name
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### שאילתת יומנים ב-Loki
|
||||
|
||||
```logql
|
||||
# All logs from a specific processor (recommended - matches Prometheus metrics)
|
||||
{processor="config-svc"}
|
||||
{processor="text-completion"}
|
||||
{processor="embeddings"}
|
||||
|
||||
# Error logs from a specific processor
|
||||
{processor="config-svc", severity="ERROR"}
|
||||
|
||||
# Error logs from all processors
|
||||
{severity="ERROR"}
|
||||
|
||||
# Logs from a specific processor with text filter
|
||||
{processor="text-completion"} |= "Processing"
|
||||
|
||||
# All logs from API gateway
|
||||
{processor="api-gateway"}
|
||||
|
||||
# Logs from processors matching pattern
|
||||
{processor=~".*-completion"}
|
||||
|
||||
# Logs with custom tags
|
||||
{processor="api-gateway"} | json | user_id="12345"
|
||||
```
|
||||
|
||||
### ניוון מבוקר (Graceful Degradation)
|
||||
|
||||
אם Loki אינו זמין או `python-logging-loki` אינו מותקן:
|
||||
הודעת אזהרה מוצגת לקונסולה
|
||||
רישום לקונסולה ממשיך כרגיל
|
||||
היישום ממשיך לפעול
|
||||
אין לוגיקה של ניסיון חוזר לחיבור ל-Loki (כשל מהיר, ניוון מבוקר)
|
||||
|
||||
## בדיקות (Testing)
|
||||
|
||||
במהלך הבדיקות, שקלו להשתמש בתצורת רישום שונה:
|
||||
|
||||
```python
|
||||
# In test setup
|
||||
import logging
|
||||
|
||||
# Reduce noise during tests
|
||||
logging.getLogger().setLevel(logging.WARNING)
|
||||
|
||||
# Or disable Loki for tests
|
||||
setup_logging({'log_level': 'WARNING', 'loki_enabled': False})
|
||||
```
|
||||
|
||||
## אינטגרציה של ניטור
|
||||
|
||||
### פורמט סטנדרטי
|
||||
כל הרישומים משתמשים בפורמט עקבי:
|
||||
```
|
||||
2025-01-09 10:30:45,123 - trustgraph.gateway.service - INFO - Request processed
|
||||
```
|
||||
|
||||
מרכיבי פורמט:
|
||||
חותמת זמן (פורמט ISO עם מילישניות)
|
||||
שם הלוגר (נתיב מודול)
|
||||
רמת לוג
|
||||
הודעה
|
||||
|
||||
### שאילתות לוקי לניטור
|
||||
|
||||
שאילתות ניטור נפוצות:
|
||||
|
||||
```logql
|
||||
# Error rate by processor
|
||||
rate({severity="ERROR"}[5m]) by (processor)
|
||||
|
||||
# Top error-producing processors
|
||||
topk(5, count_over_time({severity="ERROR"}[1h]) by (processor))
|
||||
|
||||
# Recent errors with processor name
|
||||
{severity="ERROR"} | line_format "{{.processor}}: {{.message}}"
|
||||
|
||||
# All agent processors
|
||||
{processor=~".*agent.*"} |= "exception"
|
||||
|
||||
# Specific processor error count
|
||||
count_over_time({processor="config-svc", severity="ERROR"}[1h])
|
||||
```
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
**לעולם אין לרשום מידע רגיש** (סיסמאות, מפתחות API, נתונים אישיים, טוקנים)
|
||||
**לנקות קלט משתמש** לפני רישום
|
||||
**להשתמש במחזירי מקום** עבור שדות רגישים: `user_id=****1234`
|
||||
**אימות לוקי:** השתמשו ב-`--loki-username` ו-`--loki-password` עבור פריסות מאובטחות
|
||||
**העברה מאובטחת:** השתמשו ב-HTTPS עבור כתובת ה-URL של לוקי בסביבת ייצור: `https://loki.prod:3100/loki/api/v1/push`
|
||||
|
||||
## תלויות
|
||||
|
||||
מודול הרישום המרכזי דורש:
|
||||
`python-logging-loki` - עבור אינטגרציה עם לוקי (אופציונלי, ירידה הדרגתית אם חסר)
|
||||
|
||||
כלול כבר ב-`trustgraph-base/pyproject.toml` ו-`requirements.txt`.
|
||||
|
||||
## נתיב מעבר
|
||||
|
||||
עבור קוד קיים:
|
||||
|
||||
1. **שירותים שכבר משתמשים ב-AsyncProcessor:** אין צורך בשינויים, תמיכה בלוקי היא אוטומטית
|
||||
2. **שירותים שאינם משתמשים ב-AsyncProcessor** (api-gateway, mcp-server): כבר עודכנו
|
||||
3. **כלי שורת פקודה:** מחוץ לתחום - המשיכו להשתמש ב-print() או ברישום פשוט
|
||||
|
||||
### מ-print() לרישום:
|
||||
```python
|
||||
# Before
|
||||
print(f"Processing document {doc_id}")
|
||||
|
||||
# After
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(f"Processing document {doc_id}")
|
||||
```
|
||||
|
||||
## סיכום הגדרות
|
||||
|
||||
| ארגומנט | ברירת מחדל | משתנה סביבה | תיאור |
|
||||
|----------|---------|---------------------|-------------|
|
||||
| `--log-level` | `INFO` | - | רמת רישום עבור קונסולה ו-Loki |
|
||||
| `--loki-enabled` | `True` | - | הפעלת רישום Loki |
|
||||
| `--loki-url` | `http://loki:3100/loki/api/v1/push` | `LOKI_URL` | נקודת קצה (endpoint) של Loki לשליחה |
|
||||
| `--loki-username` | `None` | `LOKI_USERNAME` | שם משתמש לאימות ב-Loki |
|
||||
| `--loki-password` | `None` | `LOKI_PASSWORD` | סיסמה לאימות ב-Loki |
|
||||
126
docs/tech-specs/he/mcp-tool-arguments.he.md
Normal file
126
docs/tech-specs/he/mcp-tool-arguments.he.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט ארגומנטים של כלי MCP"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט ארגומנטים של כלי MCP
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
**שם פיצ'ר**: תמיכה בארגומנטים של כלי MCP
|
||||
**מחבר**: עוזר קוד של Claude
|
||||
**תאריך**: 2025-08-21
|
||||
**סטטוס**: סופי
|
||||
|
||||
### סיכום מנהלים
|
||||
|
||||
לאפשר למייצגי ReACT להפעיל כלי MCP (פרוטוקול הקשר של מודל) עם
|
||||
ארגומנטים מוגדרים כראוי, על ידי הוספת תמיכה במפרט ארגומנטים
|
||||
ליצור הגדרות כלי MCP, בדומה לאופן שבו כלי תבנית הנחייה
|
||||
פועלים כיום.
|
||||
|
||||
### הצגת הבעיה
|
||||
|
||||
כרגע, כלי MCP בתוך מסגרת ה-ReACT אינם יכולים לציין את
|
||||
הארגומנטים הצפויים שלהם. מתודת `McpToolImpl.get_arguments()`
|
||||
מחזירה רשימה ריקה, ולכן LLMs חייבים לנחש את המבנה של הפרמטרים
|
||||
רק על סמך שמות וכותרות כלים. זה גורם ל:
|
||||
- קריאות כלים לא אמינות עקב ניחוש פרמטרים
|
||||
- חוויית משתמש גרועה כאשר כלים נכשלים עקב ארגומנטים שגויים
|
||||
- אי אימות של פרמטרי כלים לפני ביצוע
|
||||
- אי עליית תיעוד פרמטרים בהנחיית הסוכן
|
||||
|
||||
### מטרות
|
||||
|
||||
- [ ] לאפשר להגדרות כלי MCP לציין ארגומנטים צפויים (שם, סוג, תיאור)
|
||||
- [ ] לעדכן את מנהל הסוכן כדי לחשוף ארגומנטי כלי MCP ל-LLMs באמצעות הנחיה
|
||||
- [ ] לשמור על תאימות לאחור להגדרות כלי MCP קיימות
|
||||
- [ ] לתמוך באימות ארגומנטים בדומה לכלי תבנית הנחיה
|
||||
|
||||
### מטרות לא
|
||||
- גילוי דינמי של ארגומנטים מהשרתים של MCP (שיפור עתידי)
|
||||
- אימות סוגי ארגומנט מעבר למבנה בסיסי
|
||||
- סכימות ארגומנטים מורכבות (אובייקטים מקובצים, מערכים)
|
||||
|
||||
## רקע והקשר
|
||||
|
||||
### מצב נוכחי
|
||||
כלי MCP מוגדרים במערכת ה-ReACT עם מידע מינימלי:
|
||||
```json
|
||||
{
|
||||
"type": "mcp-tool",
|
||||
"name": "get_bank_balance",
|
||||
"description": "Get bank account balance",
|
||||
"mcp-tool": "get_bank_balance"
|
||||
}
|
||||
```
|
||||
|
||||
המתודת `McpToolImpl.get_arguments()` מחזירה `[]`, ולכן LLMs לא מקבלים הדרכה לגבי ארגומנטים בהנחייתם.
|
||||
|
||||
### מגבלות
|
||||
1. **אין מפרט ארגומנטים**: כלי MCP אינם יכולים להגדיר פרמטרים צפויים
|
||||
2. **ניחוש פרמטרים על ידי LLM**: הסוכן חייב להסיק פרמטרים משמות/תיאורים של כלים
|
||||
3. **מידע הנחיה חסר**: הנחיות הסוכן אינן מציגות פרטים לגבי ארגומנטים של כלי MCP
|
||||
4. **אין אימות**: פרמטרים לא חוקיים מתגלים רק בזמן ביצוע כלי MCP
|
||||
|
||||
### רכיבים קשורים
|
||||
- **trustgraph-flow/agent/react/service.py**: טעינת הגדרות כלי וליצירת מנהל סוכן
|
||||
- **trustgraph-flow/agent/react/tools.py**: יישום של McpToolImpl
|
||||
- **trustgraph-flow/agent/react/agent_manager.py**: יצירת הנחיה עם ארגומנטי כלי
|
||||
- **trustgraph-cli**: כלים של שורת פקודה לניהול כלי MCP
|
||||
- **Workbench**: ממשק משתמש חיצוני להגדרת כלי סוכן
|
||||
|
||||
## דרישות
|
||||
|
||||
### דרישות פונקציונליות
|
||||
1. **הגדרות ארגומנטים של כלי MCP**: הגדרות כלי MCP חייבות לתמוך במערך אופציונלי של `arguments` עם שדות שם, סוג ותיאור
|
||||
2. **חשיפת ארגומנטים**: `McpToolImpl.get_arguments()` חייב להחזיר את הארגומנטים המוגדרים במקום רשימה ריקה
|
||||
3. **אינטגרציה עם הנחיה**: הנחיית הסוכן חייבת לכלול פרטים של ארגומנטי כלי MCP כאשר הם מוגדרים
|
||||
4. **תאימות לאחור**: הגדרות כלי MCP קיימות ללא ארגומנטים חייבות להמשיך לעבוד
|
||||
5. **תמיכה ב-CLI**: כלי ה-CLI הקיים `tg-invoke-mcp-tool` תומך בארגומנטים (כבר מיושם)
|
||||
|
||||
### דרישות לא פונקציונליות
|
||||
1. **תאימות לאחור**: ללא שינויים שמשבשים בהגדרות כלי MCP קיימות
|
||||
2. **ביצועים**: ללא השפעה משמעותית על יצירת הנחיות סוכן
|
||||
3. **עקביות**: טיפול בארגומנטים חייב להתאים לתבניות של כלי תבנית הנחיה
|
||||
|
||||
### סיפורי משתמש
|
||||
1. כ**מפתח סוכן**, אני רוצה לציין ארגומנטים של כלי MCP בהגדרות, כך ש-LLMs יוכלו להפעיל כלים עם פרמטרים נכונים
|
||||
2. כ**משתמש ב-Workbench**, אני רוצה להגדיר ארגומנטים של כלי MCP בממשק ה-UI, כך שהסוכן ישתמש בכלים כראוי
|
||||
3. כ**LLM בסוכן ReACT**, אני רוצה לראות את המפרט של ארגומנטי כלי בהנחיות, כך שאוכל לספק פרמטרים נכונים
|
||||
|
||||
## עיצוב
|
||||
|
||||
### ארכיטקטורה ברמה גבוהה
|
||||
להרחיב את הגדרת כלי MCP כך שתתאים לתבנית כלי תבנית הנחיה על ידי:
|
||||
1. הוספת מערך אופציונלי של `arguments` להגדרות כלי MCP
|
||||
2. שינוי המחלקה `McpToolImpl` כדי לקבל את הארגומנטים
|
||||
3. לשמור על התאמה לאחור להגדרות כלי MCP קיימות
|
||||
|
||||
### דוגמה
|
||||
```python
|
||||
class McpToolImpl:
|
||||
def get_arguments(self):
|
||||
# ... קוד לקבלת ארגומנטים ...
|
||||
return arguments
|
||||
```
|
||||
|
||||
## שאלות פתוחות
|
||||
1. **אימות ארגומנטים**: האם אמור להיות אימות סוגים/פורמטים של ארגומנט מעבר לבדיקות מבני בסיסיות?
|
||||
2. **גילוי דינמי**: האם עדיף לשאול את שרתי ה-MCP עבור סכימות כלי באופן אוטומטי?
|
||||
3. **מבנה ארגומנטים**: האם הארגומנטים צריכים להיות בפורמט מובנה (לדוגמה, JSON)?
|
||||
|
||||
## אפשרויות שנשקלו
|
||||
1. **גילוי דינמי של סכימת MCP**: לשאול את שרתי ה-MCP עבור סכימות של כלי בזמן ריצה - נדחה עקב מורכבות וחששות לגבי אמינות
|
||||
2. **רשום ארגומנטים נפרד**: לאחסן את ארגומנטי הכלי בפרטי הגדרה נפרדים - נדחה עקב עקביות עם הגישה של תבנית הנחיה
|
||||
3. **אימות סוג**: אימות JSON מלא של ארגומנטים - מוחזר כשיפור עתידי כדי לשמור על היישום הראשוני פשוט
|
||||
|
||||
## מקורות
|
||||
- [מפרט פרוטוקול MCP](https://github.com/modelcontextprotocol/spec)
|
||||
- [יישום כלי תבנית הנחיה](./trustgraph-flow/trustgraph/agent/react/service.py#L114-129)
|
||||
- [יישום כלי MCP נוכחי](./trustgraph-flow/trustgraph/agent/react/tools.py#L58-86)
|
||||
|
||||
## נספחים
|
||||
[כל מידע, דיאגרמות או דוגמאות נוספות]
|
||||
562
docs/tech-specs/he/mcp-tool-bearer-token.he.md
Normal file
562
docs/tech-specs/he/mcp-tool-bearer-token.he.md
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט אימות טוקן עבור כלי MCP"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט אימות טוקן עבור כלי MCP
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
> **⚠️ חשוב: רק עבור סביבות עם משתמש יחיד**
|
||||
>
|
||||
> מפרט זה מתאר מנגנון אימות בסיסי ברמת השירות עבור כלי MCP. זה **אינו** פתרון אימות שלם ו**אינו מתאים** עבור:
|
||||
> - סביבות מרובות משתמשים
|
||||
> - פריסות מרובות דיירים
|
||||
> - אימות פדרטיבי
|
||||
> - העברת הקשר משתמש
|
||||
> - הרשאה ברמת המשתמש
|
||||
>
|
||||
> תכונה זו מספקת **טוקן סטטי אחד לכל כלי MCP**, המשותף לכל המשתמשים והסשנים. אם אתם זקוקים לאימות ברמת המשתמש או הדייר, זו אינה הפתרון הנכון.
|
||||
|
||||
## סקירה כללית
|
||||
**שם התכונה**: תמיכה באימות טוקן עבור כלי MCP
|
||||
**כותב**: Claude Code Assistant
|
||||
**תאריך**: 2025-11-11
|
||||
**סטטוס**: בפיתוח
|
||||
|
||||
### תקציר
|
||||
|
||||
אפשר תצורות של כלי MCP לציין טוקנים סטטיים אופציונליים לאימות עם שרתי MCP מוגנים. זה מאפשר ל-TrustGraph להפעיל כלי MCP המאוחסנים בשרתים הדורשים אימות, מבלי לשנות את סוכן או ממשקי הפעלה של הכלי.
|
||||
|
||||
**חשוב**: זוהי מנגנון אימות בסיסי המיועדת לתסריטי אימות בין שירותים בסביבות עם משתמש יחיד. זה **אינו** מתאים עבור:
|
||||
סביבות מרובות משתמשים שבהן משתמשים שונים צריכים אישורים שונים
|
||||
פריסות מרובות דיירים הדורשות בידוד לדייר
|
||||
תרחישי אימות פדרטיביים
|
||||
אימות או הרשאה ברמת המשתמש
|
||||
ניהול או רענון אישורים דינמיים
|
||||
|
||||
תכונה זו מספקת טוקן סטטי, ברמת המערכת, עבור כל תצורת כלי MCP, המשותף לכל המשתמשים וההפעלה של כלי זה.
|
||||
|
||||
### הצגת הבעיה
|
||||
|
||||
כיום, כלי MCP יכולים להתחבר רק לשרתי MCP נגישים לציבור. פריסות MCP רבות בייצור דורשות אימות באמצעות טוקנים עבור אבטחה. ללא תמיכה באימות:
|
||||
כלי MCP לא יכולים להתחבר לשרתי MCP מאובטחים
|
||||
משתמשים חייבים או לחשוף שרתי MCP לציבור או ליישם שרתי הפוך
|
||||
אין דרך סטנדרטית להעביר אישורים לחיבורי MCP
|
||||
לא ניתן לאכוף שיטות עבודה מומלצות לאבטחה בקצוות MCP
|
||||
|
||||
### מטרות
|
||||
|
||||
[ ] לאפשר לתצורות של כלי MCP לציין פרמטר אופציונלי `auth-token`
|
||||
[ ] לעדכן את שירות כלי MCP כדי להשתמש בטוקנים בעת חיבור לשרתי MCP
|
||||
[ ] לעדכן כלים בשורת הפקודה לתמיכה בהגדרת/הצגת טוקני אימות
|
||||
[ ] לשמור על תאימות לאחור עם תצורות MCP ללא אימות
|
||||
[ ] לתעד שיקולים אבטחתיים עבור אחסון טוקנים
|
||||
|
||||
### לא מטרות
|
||||
רענון טוקנים דינמי או זרימות OAuth (רק טוקנים סטטיים)
|
||||
הצפנה של טוקנים המאוחסנים (אבטחת מערכת התצורה אינה בתחום)
|
||||
שיטות אימות חלופיות (אימות בסיסי, מפתחות API, וכו')
|
||||
אימות או בדיקת תפוגה של טוקנים
|
||||
**אימות ברמת המשתמש**: תכונה זו **אינה** תומכת באישורים ספציפיים למשתמש
|
||||
**בידוד מרובה דיירים**: תכונה זו **אינה** מספקת ניהול טוקנים ברמת הדייר
|
||||
**אימות פדרטיבי**: תכונה זו **אינה** משתלבת עם ספקי זהות (SSO, OAuth, SAML, וכו')
|
||||
**אימות מודע הקשר**: טוקנים אינם מועברים בהתבסס על הקשר משתמש או סשן
|
||||
|
||||
## רקע והקשר
|
||||
|
||||
### מצב נוכחי
|
||||
תצורות של כלי MCP מאוחסנות בקבוצת התצורה `mcp` עם המבנה הבא:
|
||||
```json
|
||||
{
|
||||
"remote-name": "tool_name",
|
||||
"url": "http://mcp-server:3000/api"
|
||||
}
|
||||
```
|
||||
|
||||
שירות הכלי MCP מתחבר לשרתים באמצעות `streamablehttp_client(url)` ללא כותרות אימות.
|
||||
|
||||
### מגבלות
|
||||
|
||||
**מגבלות מערכת נוכחיות:**
|
||||
1. **ללא תמיכה באימות:** לא ניתן להתחבר לשרתי MCP מאובטחים.
|
||||
2. **חשיפה אבטחתיות:** שרתי MCP חייבים להיות נגישים לציבור או להשתמש באבטחה ברמת הרשת בלבד.
|
||||
3. **בעיות פריסה בסביבת ייצור:** לא ניתן לעקוב אחר שיטות עבודה מומלצות לאבטחת נקודות קצה של API.
|
||||
|
||||
**מגבלות של פתרון זה:**
|
||||
1. **מתאים רק למערכת משתמש יחיד:** טוקן סטטי אחד לכל כלי MCP, משותף לכל המשתמשים.
|
||||
2. **ללא אישורים מבוססי משתמש:** לא ניתן לאמת כמשתמשים שונים או להעביר הקשר משתמש.
|
||||
3. **ללא תמיכה בריבוי משתמשים:** לא ניתן לבודד אישורים לפי משתמש או ארגון.
|
||||
4. **טוקנים סטטיים בלבד:** ללא תמיכה בחידוש טוקנים, רוטציה או טיפול בתפוגה.
|
||||
5. **אימות ברמת השירות:** מאמת את שירות TrustGraph, ולא משתמשים בודדים.
|
||||
6. **הקשר אבטחה משותף:** כל שימוש בכלי MCP משתמש באותו אישור.
|
||||
|
||||
### התאמת מקרי שימוש
|
||||
|
||||
**✅ מקרי שימוש מתאימים:**
|
||||
פריסות TrustGraph עם משתמש יחיד.
|
||||
אימות בין שירותים (TrustGraph → שרת MCP).
|
||||
סביבות פיתוח ובדיקה.
|
||||
כלי MCP פנימיים שאליהם ניגש מערכת TrustGraph.
|
||||
תרחישים שבהם כל המשתמשים חולקים את אותו רמת גישה לכלי MCP.
|
||||
אישורים שירותיים סטטיים, בעלי אורך חיים ארוך.
|
||||
|
||||
**❌ מקרי שימוש לא מתאימים:**
|
||||
מערכות מרובות משתמשים הדורשות אימות מבוסס משתמש.
|
||||
פריסות SaaS מרובות משתמשים עם דרישות בידוד משתמשים.
|
||||
תרחישי אימות מאוחדים (SSO, OAuth, SAML).
|
||||
מערכות הדורשות העברת הקשר משתמש לשרתי MCP.
|
||||
סביבות הזקוקות לחידוש טוקנים דינמי או טוקנים בעלי אורך חיים קצר.
|
||||
יישומים שבהם משתמשים שונים צריכים רמות הרשאות שונות.
|
||||
דרישות תאימות לרישומי ביקורת ברמת המשתמש.
|
||||
|
||||
**תרחיש מתאים לדוגמה:**
|
||||
פריסה של TrustGraph עבור ארגון יחיד שבהם כל העובדים משתמשים באותו כלי MCP פנימי (לדוגמה, שאילתת מסד נתונים של החברה). שרת ה-MCP דורש אימות כדי למנוע גישה חיצונית, אך לכל המשתמשים הפנימיים יש את אותו רמת גישה.
|
||||
|
||||
**תרחיש לא מתאים לדוגמה:**
|
||||
פלטפורמת SaaS מרובת משתמשים של TrustGraph שבה כל אחד מ-Tenant A ו-Tenant B צריך לגשת לשרתי MCP מבודדים משלהם עם אישורים נפרדים. תכונה זו אינה תומכת בניהול טוקנים ברמת ה-Tenant.
|
||||
|
||||
### רכיבים קשורים
|
||||
**trustgraph-flow/trustgraph/agent/mcp_tool/service.py**: שירות הפעלת כלי MCP.
|
||||
**trustgraph-cli/trustgraph/cli/set_mcp_tool.py**: כלי שורת פקודה ליצירת/עדכון תצורות MCP.
|
||||
**trustgraph-cli/trustgraph/cli/show_mcp_tools.py**: כלי שורת פקודה להצגת תצורות MCP.
|
||||
**MCP Python SDK**: `streamablehttp_client` מ- `mcp.client.streamable_http`
|
||||
|
||||
## דרישות
|
||||
|
||||
### דרישות פונקציונליות
|
||||
|
||||
1. **טוקן אימות לתצורה של MCP:** תצורות כלי MCP חייבות לתמוך בשדה אופציונלי `auth-token`.
|
||||
2. **שימוש בטוקן Bearer:** שירות כלי MCP חייב לשלוח כותרת `Authorization: Bearer {token}` כאשר טוקן אימות מוגדר.
|
||||
3. **תמיכה בשורת הפקודה:** `tg-set-mcp-tool` חייב לקבל פרמטר אופציונלי `--auth-token`.
|
||||
4. **הצגת טוקן:** `tg-show-mcp-tools` חייב לציין מתי טוקן אימות מוגדר (מוסתר מטעמי אבטחה).
|
||||
5. **תאימות לאחור:** תצורות כלי MCP קיימות ללא טוקן אימות חייבות להמשיך לעבוד.
|
||||
|
||||
### דרישות לא פונקציונליות
|
||||
1. **תאימות לאחור:** ללא שינויים משמעותיים עבור תצורות כלי MCP קיימות.
|
||||
2. **ביצועים:** ללא השפעה משמעותית על ביצועי הפעלת כלי MCP.
|
||||
3. **אבטחה:** טוקנים המאוחסנים בתצורה (יש להבין את השלכות האבטחה).
|
||||
|
||||
### סיפורי משתמש
|
||||
|
||||
1. כ-**מהנדס DevOps**, אני רוצה להגדיר טוקני Bearer עבור כלי MCP כך שאוכל לאבטח נקודות קצה של שרתי MCP.
|
||||
2. כ-**משתמש שורת פקודה**, אני רוצה להגדיר טוקני אימות בעת יצירת כלי MCP כך שאוכל להתחבר לשרתים מוגנים.
|
||||
3. כ-**מנהל מערכת**, אני רוצה לראות אילו כלי MCP מוגדרים עם אימות כך שאוכל לבדוק הגדרות אבטחה.
|
||||
|
||||
## עיצוב
|
||||
|
||||
### ארכיטקטורה ברמה גבוהה
|
||||
הרחבת תצורת כלי MCP ושירות כדי לתמוך באימות טוקן Bearer:
|
||||
1. הוספת שדה אופציונלי `auth-token` לתבנית תצורה של כלי MCP.
|
||||
2. שנה את שירות הכלי MCP כדי לקרוא את הטוקן האימות ולהעביר אותו ללקוח HTTP.
|
||||
3. עדכן את כלי שורת הפקודה (CLI) כדי לתמוך בהגדרת והצגת טוקני אימות.
|
||||
4. תעד שיקולי אבטחה ושיטות עבודה מומלצות.
|
||||
|
||||
### סכימת תצורה
|
||||
|
||||
**הסכימה הנוכחית**:
|
||||
```json
|
||||
{
|
||||
"remote-name": "tool_name",
|
||||
"url": "http://mcp-server:3000/api"
|
||||
}
|
||||
```
|
||||
|
||||
**סכימה חדשה** (עם טוקן אימות אופציונלי):
|
||||
```json
|
||||
{
|
||||
"remote-name": "tool_name",
|
||||
"url": "http://mcp-server:3000/api",
|
||||
"auth-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
```
|
||||
|
||||
**תיאורי שדות**:
|
||||
`remote-name` (אופציונלי): שם המשמש את שרת ה-MCP (ברירת מחדל היא מפתח התצורה)
|
||||
`url` (חובה): כתובת URL של נקודת הקצה של שרת ה-MCP
|
||||
`auth-token` (אופציונלי): טוקן Bearer לאימות
|
||||
|
||||
### זרימת נתונים
|
||||
|
||||
1. **אחסון תצורה**: המשתמש מריץ את `tg-set-mcp-tool --id my-tool --tool-url http://server/api --auth-token xyz123`
|
||||
2. **טעינת תצורה**: שירות הכלי ה-MCP מקבל עדכון תצורה באמצעות קריאה חוזרת (callback) של `on_mcp_config()`
|
||||
3. **הפעלת כלי**: כאשר הכלי מופעל:
|
||||
השירות קורא את `auth-token` מהתצורה (אם קיים)
|
||||
יוצר מילון כותרות: `{"Authorization": "Bearer {token}"}`
|
||||
מעביר את הכותרות ל-`streamablehttp_client(url, headers=headers)`
|
||||
שרת ה-MCP מאמת את הטוקן ומעבד את הבקשה
|
||||
|
||||
### שינויי API
|
||||
אין שינויי API חיצוניים - רק הרחבת סכימת התצורה.
|
||||
|
||||
### פרטי רכיב
|
||||
|
||||
#### רכיב 1: service.py (שירות כלי MCP)
|
||||
**קובץ**: `trustgraph-flow/trustgraph/agent/mcp_tool/service.py`
|
||||
|
||||
**מטרה**: הפעלת כלי MCP על שרתים מרוחקים
|
||||
|
||||
**שינויים נדרשים** (בשיטה `invoke_tool()`):
|
||||
1. בדוק אם קיים `auth-token` בתצורת `self.mcp_services[name]`
|
||||
2. בנה מילון כותרות עם כותרת Authorization אם קיים טוקן
|
||||
3. העבר את הכותרות ל-`streamablehttp_client(url, headers=headers)`
|
||||
|
||||
**קוד נוכחי** (שורות 42-89):
|
||||
```python
|
||||
async def invoke_tool(self, name, parameters):
|
||||
try:
|
||||
if name not in self.mcp_services:
|
||||
raise RuntimeError(f"MCP service {name} not known")
|
||||
if "url" not in self.mcp_services[name]:
|
||||
raise RuntimeError(f"MCP service {name} URL not defined")
|
||||
|
||||
url = self.mcp_services[name]["url"]
|
||||
|
||||
if "remote-name" in self.mcp_services[name]:
|
||||
remote_name = self.mcp_services[name]["remote-name"]
|
||||
else:
|
||||
remote_name = name
|
||||
|
||||
logger.info(f"Invoking {remote_name} at {url}")
|
||||
|
||||
# Connect to a streamable HTTP server
|
||||
async with streamablehttp_client(url) as (
|
||||
read_stream,
|
||||
write_stream,
|
||||
_,
|
||||
):
|
||||
# ... rest of method
|
||||
```
|
||||
|
||||
**קוד שעבר שינוי:**
|
||||
```python
|
||||
async def invoke_tool(self, name, parameters):
|
||||
try:
|
||||
if name not in self.mcp_services:
|
||||
raise RuntimeError(f"MCP service {name} not known")
|
||||
if "url" not in self.mcp_services[name]:
|
||||
raise RuntimeError(f"MCP service {name} URL not defined")
|
||||
|
||||
url = self.mcp_services[name]["url"]
|
||||
|
||||
if "remote-name" in self.mcp_services[name]:
|
||||
remote_name = self.mcp_services[name]["remote-name"]
|
||||
else:
|
||||
remote_name = name
|
||||
|
||||
# Build headers with optional bearer token
|
||||
headers = {}
|
||||
if "auth-token" in self.mcp_services[name]:
|
||||
token = self.mcp_services[name]["auth-token"]
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
|
||||
logger.info(f"Invoking {remote_name} at {url}")
|
||||
|
||||
# Connect to a streamable HTTP server with headers
|
||||
async with streamablehttp_client(url, headers=headers) as (
|
||||
read_stream,
|
||||
write_stream,
|
||||
_,
|
||||
):
|
||||
# ... rest of method (unchanged)
|
||||
```
|
||||
|
||||
#### רכיב 2: set_mcp_tool.py (כלי תצורה דרך שורת הפקודה)
|
||||
**קובץ**: `trustgraph-cli/trustgraph/cli/set_mcp_tool.py`
|
||||
|
||||
**מטרה**: יצירת/עדכון תצורות לכלי MCP
|
||||
|
||||
**שינויים נדרשים**:
|
||||
1. הוספת ארגומנט אופציונלי `--auth-token` ל-argparse
|
||||
2. הכללת `auth-token` בקובץ JSON של התצורה כאשר הוא מסופק
|
||||
|
||||
**ארגומנטים נוכחיים**:
|
||||
`--id` (חובה): מזהה של כלי MCP
|
||||
`--remote-name` (אופציונלי): שם של כלי MCP מרוחק
|
||||
`--tool-url` (חובה): נקודת קצה של כתובת URL של כלי MCP
|
||||
`-u, --api-url` (אופציונלי): כתובת URL של ממשק API של TrustGraph
|
||||
|
||||
**ארגומנט חדש**:
|
||||
`--auth-token` (אופציונלי): טוקן bearer לאימות
|
||||
|
||||
**שינוי בבניית התצורה**:
|
||||
```python
|
||||
# Build configuration object
|
||||
config = {
|
||||
"url": args.tool_url,
|
||||
}
|
||||
|
||||
if args.remote_name:
|
||||
config["remote-name"] = args.remote_name
|
||||
|
||||
if args.auth_token:
|
||||
config["auth-token"] = args.auth_token
|
||||
|
||||
# Store configuration
|
||||
api.config().put([
|
||||
ConfigValue(type="mcp", key=args.id, value=json.dumps(config))
|
||||
])
|
||||
```
|
||||
|
||||
#### רכיב 3: show_mcp_tools.py (כלי תצוגה בשורת הפקודה)
|
||||
**קובץ**: `trustgraph-cli/trustgraph/cli/show_mcp_tools.py`
|
||||
|
||||
**מטרה**: הצגת תצורות של כלי MCP
|
||||
|
||||
**שינויים נדרשים**:
|
||||
1. הוספת עמודה "אימות" (Auth) לטבלת הפלט
|
||||
2. הצגת "כן" או "לא" בהתאם לנוכחות של טוקן אימות
|
||||
3. אין להציג את ערך הטוקן בפועל (אבטחה)
|
||||
|
||||
**פלט נוכחי**:
|
||||
```
|
||||
ID Remote Name URL
|
||||
---------- ------------- ------------------------
|
||||
my-tool my-tool http://server:3000/api
|
||||
```
|
||||
|
||||
**פלט חדש**:
|
||||
```
|
||||
ID Remote Name URL Auth
|
||||
---------- ------------- ------------------------ ------
|
||||
my-tool my-tool http://server:3000/api Yes
|
||||
other-tool other-tool http://other:3000/api No
|
||||
```
|
||||
|
||||
#### רכיב 4: תיעוד
|
||||
**קובץ**: `docs/cli/tg-set-mcp-tool.md`
|
||||
|
||||
**שינויים נדרשים**:
|
||||
1. לתעד את הפרמטר החדש `--auth-token`
|
||||
2. לספק דוגמה לשימוש עם אימות
|
||||
3. לתעד שיקולי אבטחה
|
||||
|
||||
## תוכנית יישום
|
||||
|
||||
### שלב 1: יצירת מפרט טכני
|
||||
[x] לכתוב מפרט טכני מקיף המתעד את כל השינויים
|
||||
|
||||
### שלב 2: עדכון שירות כלי MCP
|
||||
[ ] לשנות את `invoke_tool()` ב-`service.py` כדי לקרוא את auth-token מקובץ התצורה
|
||||
[ ] לבנות מילון כותרות ולהעביר ל-`streamablehttp_client`
|
||||
[ ] לבדוק עם שרת MCP מאומת
|
||||
|
||||
### שלב 3: עדכון כלי שורת הפקודה
|
||||
[ ] להוסיף את הארגומנט `--auth-token` ל-`set_mcp_tool.py`
|
||||
[ ] לכלול את auth-token בקובץ JSON של התצורה
|
||||
[ ] להוסיף עמודה "אימות" לפלט של `show_mcp_tools.py`
|
||||
[ ] לבדוק את השינויים בכלי שורת הפקודה
|
||||
|
||||
### שלב 4: עדכון תיעוד
|
||||
[ ] לתעד את הפרמטר `--auth-token` ב-`tg-set-mcp-tool.md`
|
||||
[ ] להוסיף סעיף של שיקולי אבטחה
|
||||
[ ] לספק דוגמה לשימוש
|
||||
|
||||
### שלב 5: בדיקות
|
||||
[ ] לבדוק שכלי ה-MCP מתחבר בהצלחה עם auth-token
|
||||
[ ] לבדוק תאימות לאחור (כלים ללא auth-token עדיין עובדים)
|
||||
[ ] לבדוק שכלי שורת הפקודה מקבלים ושומרים את auth-token כראוי
|
||||
[ ] לבדוק שפקודת ה-show מציגה את סטטוס האימות כראוי
|
||||
|
||||
### סיכום שינויים בקוד
|
||||
| קובץ | סוג שינוי | שורות | תיאור |
|
||||
|------|------------|-------|-------------|
|
||||
| `service.py` | שינוי | ~52-66 | הוספת קריאת auth-token ובניית כותרות |
|
||||
| `set_mcp_tool.py` | שינוי | ~30-60 | הוספת ארגומנט --auth-token ואחסון בתצורה |
|
||||
| `show_mcp_tools.py` | שינוי | ~40-70 | הוספת עמודה "אימות" לתצוגה |
|
||||
| `tg-set-mcp-tool.md` | שינוי | שונות | תיעוד פרמטר חדש |
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות יחידה
|
||||
**קריאת סיסמת אימות**: לבדוק ש-`invoke_tool()` קורא כראוי את סיסמת האימות מקובץ התצורה
|
||||
**בניית כותרות**: לבדוק שכותרת ה-Authorization נבנית כראוי עם הקידומת Bearer
|
||||
**תאימות לאחור**: לבדוק שכלי ללא סיסמת אימות עובדים ללא שינוי
|
||||
**ניתוח ארגומנטים בשורת הפקודה**: לבדוק שהארגומנט `--auth-token` מנותח כראוי
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
**חיבור מאומת**: בדיקת חיבור שירות כלי MCP לשרת מאומת
|
||||
**מקיף (End-to-End)**: בדיקת CLI → אחסון תצורה → הפעלת שירות עם טוקן אימות
|
||||
**טוקן לא נדרש**: בדיקת חיבור לשרת לא מאומת עדיין עובד
|
||||
|
||||
### בדיקות ידניות
|
||||
**שרת MCP אמיתי**: בדיקה עם שרת MCP אמיתי הדורש אימות באמצעות טוקן
|
||||
**זרימת עבודה של CLI**: בדיקת זרימת עבודה מלאה: הגדרת כלי עם אימות → הפעלת כלי → אימות הצלחה
|
||||
**הסתרת תצוגה**: ודאו שמצב האימות מוצג אך ערך הטוקן אינו נחשף
|
||||
|
||||
## מעבר ושילוב
|
||||
|
||||
### אסטרטגיית מעבר
|
||||
אין צורך במעבר - זו פונקציונליות נוספת בלבד:
|
||||
תצורות כלי MCP קיימות ללא `auth-token` ממשיכות לעבוד ללא שינוי
|
||||
ניתן לכלול את השדה `auth-token` בתצורות חדשות, אופציונלית
|
||||
כלי CLI מקבלים אך אינם דורשים את הפרמטר `--auth-token`
|
||||
|
||||
### תוכנית שילוב
|
||||
1. **שלב 1**: פריסת שינויים בסיסיים בשירות לסביבות פיתוח/בדיקות
|
||||
2. **שלב 2**: פריסת עדכוני כלי CLI
|
||||
3. **שלב 3**: עדכון תיעוד
|
||||
4. **שלב 4**: שילוב בסביבת ייצור עם ניטור
|
||||
|
||||
### תוכנית חזרה אחורה
|
||||
השינויים הבסיסיים תואמים לאחור - כלים קיימים אינם מושפעים
|
||||
אם מתעוררות בעיות, ניתן להשבית את הטיפול בטוקן אימות על ידי הסרת הלוגיקה לבניית כותרות
|
||||
שינויים ב-CLI הם עצמאיים וניתן לבטל אותם בנפרד
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
### ⚠️ מגבלה קריטית: אימות רק עבור לקוח יחיד
|
||||
|
||||
**מנגנון אימות זה אינו מתאים לסביבות מרובות משתמשים או מרובות לקוחות.**
|
||||
|
||||
**אישורים משותפים**: כל המשתמשים וההפעלה חולקים את אותו טוקן עבור כל כלי MCP
|
||||
**ללא הקשר משתמש**: שרת ה-MCP אינו יכול להבחין בין משתמשי TrustGraph שונים
|
||||
**ללא בידוד לקוחות**: כל הלקוחות חולקים את אותו אישור עבור כל כלי MCP
|
||||
**מגבלת מעקב**: שרת ה-MCP רושם את כל הבקשות מאותו אישור
|
||||
**היקף הרשאות**: לא ניתן לאכוף רמות הרשאות שונות עבור משתמשים שונים
|
||||
|
||||
**אל תשתמשו בתכונה זו אם:**
|
||||
הפריסה של TrustGraph שלכם משרתת מספר ארגונים (מרובת לקוחות)
|
||||
אתם צריכים לעקוב אילו משתמשים גשו לאילו כלי MCP
|
||||
משתמשים שונים דורשים רמות הרשאות שונות
|
||||
אתם צריכים לעמוד בדרישות מעקב ברמת המשתמש
|
||||
שרת ה-MCP שלכם מאכף מגבלות קצב או מכסות ברמת המשתמש
|
||||
|
||||
**פתרונות חלופיים עבור תרחישי משתמשים/לקוחות מרובים:**
|
||||
הטמעת העברת הקשר משתמש באמצעות כותרות מותאמות אישית
|
||||
פריסת מופעי TrustGraph נפרדים עבור כל לקוח
|
||||
שימוש בבידוד ברמת הרשת (VPCs, רשתות שירות)
|
||||
הטמעת שכבת פרוקסי המטפלת באימות מבוסס משתמש
|
||||
|
||||
### אחסון טוקנים
|
||||
**סיכון**: טוקנים של אימות מאוחסנים בטקסט רגיל במערכת התצורה
|
||||
|
||||
**הפחתה**:
|
||||
תיעוד העובדה שטוקנים מאוחסנים ללא הצפנה
|
||||
המלצה על שימוש בטוקנים קצרי טווח במידת האפשר
|
||||
המלצה על בקרת גישה מתאימה לאחסון התצורה
|
||||
שקילת שיפור עתידי לאחסון מוצפן של טוקנים
|
||||
|
||||
### חשיפת טוקנים
|
||||
**סיכון**: טוקנים עלולים להיחשף ביומני רישום או בפלט של שורת הפקודה
|
||||
|
||||
**הפחתה**:
|
||||
אין לרשום ערכי טוקנים (לרשום רק "אימות מוגדר: כן/לא")
|
||||
פקודת ה-CLI להצגה מציגה סטטוס מוסתר בלבד, ולא את הטוקן בפועל
|
||||
אין לכלול טוקנים בהודעות שגיאה
|
||||
|
||||
### אבטחת רשת
|
||||
**סיכון**: טוקנים מועברים על גבי חיבורים לא מוצפנים
|
||||
|
||||
**הפחתה**:
|
||||
המלצה לשימוש בכתובות URL של HTTPS עבור שרתי MCP
|
||||
אזהרת משתמשים לגבי סיכון השידור בטקסט רגיל עם HTTP
|
||||
|
||||
### גישה לתצורה
|
||||
**סיכון**: גישה לא מורשית למערכת התצורה חושפת טוקנים
|
||||
|
||||
**הפחתה**:
|
||||
תיעוד החשיבות של אבטחת גישה למערכת התצורה
|
||||
המלצה על עקרון ההרשאה המינימלית לגישה לתצורה
|
||||
שקילת רישום ביקורת עבור שינויים בתצורה (שיפור עתידי)
|
||||
|
||||
### סביבות מרובות משתמשים
|
||||
**סיכון**: בסביבות מרובות משתמשים, כל המשתמשים חולקים את אותם פרטי כניסה של MCP
|
||||
|
||||
**הבנת הסיכון**:
|
||||
משתמש א' ומשתמש ב' משתמשים באותו טוקן בעת גישה לכלי MCP
|
||||
שרת ה-MCP אינו יכול להבחין בין משתמשי TrustGraph שונים
|
||||
אין דרך לאכוף הרשאות או מגבלות קצב מבוססות משתמש
|
||||
יומני רישום בשרת ה-MCP מציגים את כל הבקשות מאותה פרטי כניסה
|
||||
אם הסשן של משתמש אחד נפגע, לתוקף יש את אותה גישה ל-MCP כמו לכל המשתמשים
|
||||
|
||||
**זהו לא באג - זהו מגבלה יסודית של עיצוב זה.**
|
||||
|
||||
## השפעה על ביצועים
|
||||
**תקורה מינימלית**: בניית כותרת מוסיפה זמן עיבוד זניח
|
||||
**השפעה על הרשת**: כותרת HTTP נוספת מוסיפה ~50-200 בתים לכל בקשה
|
||||
**שימוש בזיכרון**: עלייה זניחה עבור אחסון מחרוזת הטוקן בתצורה
|
||||
|
||||
## תיעוד
|
||||
|
||||
### תיעוד למשתמש
|
||||
[ ] עדכון `tg-set-mcp-tool.md` עם פרמטר `--auth-token`
|
||||
[ ] הוספת סעיף שיקולי אבטחה
|
||||
[ ] מתן דוגמה לשימוש עם טוקן bearer
|
||||
[ ] תיעוד השלכות אחסון טוקנים
|
||||
|
||||
### תיעוד למפתחים
|
||||
[ ] הוספת הערות שורה לטיפול בטוקן אימות ב-`service.py`
|
||||
[ ] תיעוד לוגיקת בניית כותרות
|
||||
[ ] עדכון תיעוד סכימת התצורה של כלי MCP
|
||||
|
||||
## שאלות פתוחות
|
||||
1. **הצפנת טוקנים**: האם עלינו ליישם אחסון מוצפן של טוקנים במערכת התצורה?
|
||||
2. **רענון טוקנים**: תמיכה עתידית בזרמי רענון OAuth או סיבוב טוקנים?
|
||||
3. **שיטות אימות חלופיות**: האם עלינו לתמוך באימות בסיסי, מפתחות API או שיטות אחרות?
|
||||
|
||||
## חלופות שנשקלו
|
||||
|
||||
1. **משתני סביבה עבור טוקנים**: אחסון טוקנים במשתני סביבה במקום בתצורה
|
||||
**נדחה**: מסבך פריסה וניהול תצורה
|
||||
|
||||
2. **מאגר סודות נפרד**: שימוש במערכת ניהול סודות ייעודית
|
||||
**נדחה**: מחוץ להיקף היישום הראשוני, לשקול שיפור עתידי
|
||||
|
||||
3. **שיטות אימות מרובות**: תמיכה בסיסי, מפתח API, OAuth וכו'.
|
||||
**נדחה**: טוקני bearer מכסים את רוב מקרי השימוש, לשמור על יישום ראשוני פשוט
|
||||
|
||||
4. **אחסון מוצפן של טוקנים**: הצפנת טוקנים במערכת התצורה
|
||||
**נדחה**: אבטחת מערכת התצורה היא דאגה רחבה יותר, לדחות לעבודה עתידית
|
||||
|
||||
5. **טוקנים לכל קריאה**: לאפשר העברת טוקנים בזמן ההפעלה
|
||||
**נדחה**: מפר את הפרדת האחריות, סוכן לא צריך לטפל באישורים
|
||||
|
||||
## הפניות
|
||||
[מפרט פרוטוקול MCP](https://github.com/modelcontextprotocol/spec)
|
||||
[אימות Bearer HTTP (RFC 6750)](https://tools.ietf.org/html/rfc6750)
|
||||
[כלי שירות MCP נוכחי](../trustgraph-flow/trustgraph/agent/mcp_tool/service.py)
|
||||
[מפרט ארגומנטים של כלי MCP](./mcp-tool-arguments.md)
|
||||
|
||||
## נספח
|
||||
|
||||
### שימוש לדוגמה
|
||||
פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא).
|
||||
**הגדרת כלי MCP עם אימות:**
|
||||
```bash
|
||||
tg-set-mcp-tool \
|
||||
--id secure-tool \
|
||||
--tool-url https://secure-server.example.com/mcp \
|
||||
--auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
**הצגת כלי MCP:**
|
||||
```bash
|
||||
tg-show-mcp-tools
|
||||
|
||||
ID Remote Name URL Auth
|
||||
----------- ----------- ------------------------------------ ------
|
||||
secure-tool secure-tool https://secure-server.example.com/mcp Yes
|
||||
public-tool public-tool http://localhost:3000/mcp No
|
||||
```
|
||||
|
||||
### דוגמה לתצורה
|
||||
|
||||
**מאוחסן במערכת התצורה:**
|
||||
```json
|
||||
{
|
||||
"type": "mcp",
|
||||
"key": "secure-tool",
|
||||
"value": "{\"url\": \"https://secure-server.example.com/mcp\", \"auth-token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"}"
|
||||
}
|
||||
```
|
||||
|
||||
### שיטות עבודה מומלצות לאבטחה
|
||||
|
||||
1. **שימוש ב-HTTPS**: השתמשו תמיד בכתובות HTTPS עבור שרתי MCP עם אימות.
|
||||
2. **אסימונים קצרי טווח**: השתמשו באסימונים עם תאריך תפוגה כאשר אפשר.
|
||||
3. **הרשאות מינימליות**: העניקו לאסימונים את ההרשאות המינימליות הנדרשות.
|
||||
4. **בקרת גישה**: הגבילו את הגישה למערכת התצורה.
|
||||
5. **החלפת אסימונים**: החליפו אסימונים באופן קבוע.
|
||||
6. **רישום ביקורת**: עקבו אחר שינויים בתצורה לאירועי אבטחה.
|
||||
266
docs/tech-specs/he/minio-to-s3-migration.he.md
Normal file
266
docs/tech-specs/he/minio-to-s3-migration.he.md
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
---
|
||||
layout: default
|
||||
title: "Tech Spec: S3-Compatible Storage Backend Support"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# Tech Spec: S3-Compatible Storage Backend Support
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## Overview
|
||||
|
||||
השירות Librarian משתמש באחסון אובייקטים תואם ל-S3 לאחסון קבצים. מסמך זה מתאר את היישום המאפשר תמיכה בכל אחסון תואם ל-S3, כולל MinIO, Ceph RADOS Gateway (RGW), AWS S3, Cloudflare R2, DigitalOcean Spaces, ואחרים.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Storage Components
|
||||
**Blob Storage**: אחסון אובייקטים תואם ל-S3 באמצעות `minio` ספריית לקוח Python
|
||||
**Metadata Storage**: Cassandra (מאחסן מיפוי object_id ונתוני מטא-דאטה של מסמכים)
|
||||
**Affected Component**: רק השירות Librarian
|
||||
**Storage Pattern**: אחסון היברידי עם מטא-דאטה ב-Cassandra ותוכן באחסון תואם ל-S3
|
||||
|
||||
### Implementation
|
||||
**Library**: `minio` לקוח Python (תומך בכל API תואם ל-S3)
|
||||
**Location**: `trustgraph-flow/trustgraph/librarian/blob_store.py`
|
||||
**Operations**:
|
||||
`add()` - שמירת קובץ עם מזהה אובייקט UUID
|
||||
`get()` - שליפת קובץ לפי מזהה אובייקט
|
||||
`remove()` - מחיקת קובץ לפי מזהה אובייקט
|
||||
`ensure_bucket()` - יצירת תיקייה אם היא לא קיימת
|
||||
**Bucket**: `library`
|
||||
**Object Path**: `doc/{object_id}`
|
||||
**Supported MIME Types**: `text/plain`, `application/pdf`
|
||||
|
||||
### Key Files
|
||||
1. `trustgraph-flow/trustgraph/librarian/blob_store.py` - יישום BlobStore
|
||||
2. `trustgraph-flow/trustgraph/librarian/librarian.py` - אתחול BlobStore
|
||||
3. `trustgraph-flow/trustgraph/librarian/service.py` - תצורת שירות
|
||||
4. `trustgraph-flow/pyproject.toml` - תלויות (חבילת `minio`)
|
||||
5. `docs/apis/api-librarian.md` - תיעוד API
|
||||
|
||||
## Supported Storage Backends
|
||||
|
||||
היישום עובד עם כל מערכת אחסון אובייקטים תואמת ל-S3:
|
||||
|
||||
### Tested/Supported
|
||||
**Ceph RADOS Gateway (RGW)** - מערכת אחסון מבוזרת עם API של S3 (תצורת ברירת מחדל)
|
||||
**MinIO** - אחסון אובייקטים קל משקל, הניתן לאירוח עצמי
|
||||
**Garage** - אחסון S3-תואם, מבוזר גיאוגרפית, קל משקל
|
||||
|
||||
### Should Work (S3-Compatible)
|
||||
**AWS S3** - אחסון אובייקטים בענן של Amazon
|
||||
**Cloudflare R2** - אחסון S3-תואם של Cloudflare
|
||||
**DigitalOcean Spaces** - אחסון אובייקטים של DigitalOcean
|
||||
**Wasabi** - אחסון בענן S3-תואם
|
||||
**Backblaze B2** - אחסון גיבוי S3-תואם
|
||||
כל שירות אחר המיישם את ממשק ה-API של S3
|
||||
|
||||
## Configuration
|
||||
|
||||
### CLI Arguments
|
||||
|
||||
```bash
|
||||
librarian \
|
||||
--object-store-endpoint <hostname:port> \
|
||||
--object-store-access-key <access_key> \
|
||||
--object-store-secret-key <secret_key> \
|
||||
[--object-store-use-ssl] \
|
||||
[--object-store-region <region>]
|
||||
```
|
||||
|
||||
**הערה:** אל תכללו את `http://` או `https://` בסוף. השתמשו ב-`--object-store-use-ssl` כדי להפעיל HTTPS.
|
||||
|
||||
### משתני סביבה (חלופי)
|
||||
|
||||
```bash
|
||||
OBJECT_STORE_ENDPOINT=<hostname:port>
|
||||
OBJECT_STORE_ACCESS_KEY=<access_key>
|
||||
OBJECT_STORE_SECRET_KEY=<secret_key>
|
||||
OBJECT_STORE_USE_SSL=true|false # Optional, default: false
|
||||
OBJECT_STORE_REGION=<region> # Optional
|
||||
```
|
||||
|
||||
### דוגמאות
|
||||
|
||||
**שער Ceph RADOS (ברירת מחדל):**
|
||||
```bash
|
||||
--object-store-endpoint ceph-rgw:7480 \
|
||||
--object-store-access-key object-user \
|
||||
--object-store-secret-key object-password
|
||||
```
|
||||
|
||||
**MinIO:**
|
||||
```bash
|
||||
--object-store-endpoint minio:9000 \
|
||||
--object-store-access-key minioadmin \
|
||||
--object-store-secret-key minioadmin
|
||||
```
|
||||
|
||||
**מחסן (תואם S3):**
|
||||
```bash
|
||||
--object-store-endpoint garage:3900 \
|
||||
--object-store-access-key GK000000000000000000000001 \
|
||||
--object-store-secret-key b171f00be9be4c32c734f4c05fe64c527a8ab5eb823b376cfa8c2531f70fc427
|
||||
```
|
||||
|
||||
**AWS S3 עם SSL:**
|
||||
```bash
|
||||
--object-store-endpoint s3.amazonaws.com \
|
||||
--object-store-access-key AKIAIOSFODNN7EXAMPLE \
|
||||
--object-store-secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
|
||||
--object-store-use-ssl \
|
||||
--object-store-region us-east-1
|
||||
```
|
||||
|
||||
## אימות
|
||||
|
||||
כל השרתים התומכים ב-S3 דורשים אימות AWS Signature Version 4 (או v2):
|
||||
|
||||
**מפתח גישה (Access Key)** - מזהה ציבורי (כמו שם משתמש)
|
||||
**מפתח סודי (Secret Key)** - מפתח חתימה פרטי (כמו סיסמה)
|
||||
|
||||
לקוח ה-Python של MinIO מטפל בכל חישוב החתימה באופן אוטומטי.
|
||||
|
||||
### יצירת פרטי גישה
|
||||
|
||||
**עבור MinIO:**
|
||||
```bash
|
||||
# Use default credentials or create user via MinIO Console
|
||||
minioadmin / minioadmin
|
||||
```
|
||||
|
||||
**עבור Ceph RGW:**
|
||||
```bash
|
||||
radosgw-admin user create --uid="trustgraph" --display-name="TrustGraph Service"
|
||||
# Returns access_key and secret_key
|
||||
```
|
||||
|
||||
**עבור AWS S3:**
|
||||
צור משתמש IAM עם הרשאות S3
|
||||
צור מפתח גישה בלוח הבקרה של AWS
|
||||
|
||||
## בחירת ספרייה: לקוח Python של MinIO
|
||||
|
||||
**ההצדקה:**
|
||||
קל משקל (~500KB לעומת ~50MB של boto3)
|
||||
תואם ל-S3 - עובד עם כל נקודת קצה של ממשק API של S3
|
||||
ממשק API פשוט יותר מ-boto3 עבור פעולות בסיסיות
|
||||
כבר בשימוש, אין צורך בהעברה
|
||||
נבדק היטב עם MinIO ומערכות S3 אחרות
|
||||
|
||||
## יישום BlobStore
|
||||
|
||||
**מיקום:** `trustgraph-flow/trustgraph/librarian/blob_store.py`
|
||||
|
||||
```python
|
||||
from minio import Minio
|
||||
import io
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class BlobStore:
|
||||
"""
|
||||
S3-compatible blob storage for document content.
|
||||
Supports MinIO, Ceph RGW, AWS S3, and other S3-compatible backends.
|
||||
"""
|
||||
|
||||
def __init__(self, endpoint, access_key, secret_key, bucket_name,
|
||||
use_ssl=False, region=None):
|
||||
"""
|
||||
Initialize S3-compatible blob storage.
|
||||
|
||||
Args:
|
||||
endpoint: S3 endpoint (e.g., "minio:9000", "ceph-rgw:7480")
|
||||
access_key: S3 access key
|
||||
secret_key: S3 secret key
|
||||
bucket_name: Bucket name for storage
|
||||
use_ssl: Use HTTPS instead of HTTP (default: False)
|
||||
region: S3 region (optional, e.g., "us-east-1")
|
||||
"""
|
||||
self.client = Minio(
|
||||
endpoint=endpoint,
|
||||
access_key=access_key,
|
||||
secret_key=secret_key,
|
||||
secure=use_ssl,
|
||||
region=region,
|
||||
)
|
||||
|
||||
self.bucket_name = bucket_name
|
||||
|
||||
protocol = "https" if use_ssl else "http"
|
||||
logger.info(f"Connected to S3-compatible storage at {protocol}://{endpoint}")
|
||||
|
||||
self.ensure_bucket()
|
||||
|
||||
def ensure_bucket(self):
|
||||
"""Create bucket if it doesn't exist"""
|
||||
found = self.client.bucket_exists(bucket_name=self.bucket_name)
|
||||
if not found:
|
||||
self.client.make_bucket(bucket_name=self.bucket_name)
|
||||
logger.info(f"Created bucket {self.bucket_name}")
|
||||
else:
|
||||
logger.debug(f"Bucket {self.bucket_name} already exists")
|
||||
|
||||
async def add(self, object_id, blob, kind):
|
||||
"""Store blob in S3-compatible storage"""
|
||||
self.client.put_object(
|
||||
bucket_name=self.bucket_name,
|
||||
object_name=f"doc/{object_id}",
|
||||
length=len(blob),
|
||||
data=io.BytesIO(blob),
|
||||
content_type=kind,
|
||||
)
|
||||
logger.debug("Add blob complete")
|
||||
|
||||
async def remove(self, object_id):
|
||||
"""Delete blob from S3-compatible storage"""
|
||||
self.client.remove_object(
|
||||
bucket_name=self.bucket_name,
|
||||
object_name=f"doc/{object_id}",
|
||||
)
|
||||
logger.debug("Remove blob complete")
|
||||
|
||||
async def get(self, object_id):
|
||||
"""Retrieve blob from S3-compatible storage"""
|
||||
resp = self.client.get_object(
|
||||
bucket_name=self.bucket_name,
|
||||
object_name=f"doc/{object_id}",
|
||||
)
|
||||
return resp.read()
|
||||
```
|
||||
|
||||
## יתרונות מרכזיים
|
||||
|
||||
1. **ללא תלות בספק** - עובד עם כל אחסון התומך ב-S3
|
||||
2. **קל משקל** - הלקוח של MinIO הוא בגודל של כ-500KB בלבד
|
||||
3. **הגדרות פשוטות** - רק נקודת קצה (endpoint) ואישורים
|
||||
4. **ללא העברת נתונים** - החלפה ישירה בין מערכות אחסון שונות
|
||||
5. **נבדק ביסודיות** - לקוח MinIO עובד עם כל המימושים העיקריים של S3
|
||||
|
||||
## סטטוס יישום
|
||||
|
||||
כל הקוד עודכן לשימוש בשמות פרמטרים גנריים של S3:
|
||||
|
||||
✅ `blob_store.py` - עודכן כדי לקבל `endpoint`, `access_key`, `secret_key`
|
||||
✅ `librarian.py` - עודכנו שמות הפרמטרים
|
||||
✅ `service.py` - עודכנו ארגומנטים של שורת הפקודה והגדרות
|
||||
✅ תיעוד עודכן
|
||||
|
||||
## שיפורים עתידיים
|
||||
|
||||
1. **תמיכה ב-SSL/TLS** - הוספת דגל `--s3-use-ssl` עבור HTTPS
|
||||
2. **לוגיקת ניסיונות חוזרים** - יישום של דחייה אקספוננציאלית עבור כשלים זמניים
|
||||
3. **כתובות URL חתומות** - יצירת כתובות URL זמניות להעלאה/הורדה
|
||||
4. **תמיכה בריבוי אזורים** - שכפול קבצים בין אזורים
|
||||
5. **אינטגרציה עם CDN** - שירות קבצים באמצעות CDN
|
||||
6. **מדרגי אחסון** - שימוש במדרגי אחסון של S3 למיטוב עלויות
|
||||
7. **מדיניות מחזור חיים** - ארכיון/מחיקה אוטומטיים
|
||||
8. **גרסאות** - שמירת גרסאות מרובות של קבצים
|
||||
|
||||
## הפניות
|
||||
|
||||
לקוח MinIO לפייתון: https://min.io/docs/minio/linux/developers/python/API.html
|
||||
Ceph RGW S3 API: https://docs.ceph.com/en/latest/radosgw/s3/
|
||||
מדריך API של S3: https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html
|
||||
151
docs/tech-specs/he/more-config-cli.he.md
Normal file
151
docs/tech-specs/he/more-config-cli.he.md
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של שורת הפקודה עבור תצורות"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של שורת הפקודה עבור תצורות
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מתאר יכולות תצורה משופרות של שורת הפקודה עבור TrustGraph, ומאפשר למשתמשים לנהל פריטי תצורה בודדים באמצעות פקודות שורת פקודה מפורטות. האינטגרציה תומכת ברשיות שימושיות עיקריות:
|
||||
|
||||
1. **רשימת פריטי תצורה**: הצגת מפתחות התצורה של סוג מסוים
|
||||
2. **קבלת פריט תצורה**: שליפת ערכי התצורה הספציפיים
|
||||
3. **הגדרת פריט תצורה**: הגדרת או עדכון פריטי תצורה בודדים
|
||||
4. **מחיקת פריט תצורה**: הסרת פריטי תצורה ספציפיים
|
||||
|
||||
## יעדים
|
||||
|
||||
- **שליטה מפורטת**: אפשר ניהול של פריטי תצורה בודדים ולא פעולות מקובצות
|
||||
- **רשימה לפי סוג**: לאפשר למשתמשים לחקור פריטי תצורה לפי סוג
|
||||
- **פעולות על פריט בודד**: לספק פקודות לקבלת/הגדרה/מחיקה של פריטי תצורה בודדים
|
||||
- **אינטגרציה של API**: לנצל את ה-API הקיים של התצורה עבור כל הפעולות
|
||||
- **תבנית שורת פקודה עקבית**: לעקוב אחר התקנות והתבניות הסטנדרטיות של TrustGraph
|
||||
- **טיפול בשגיאות**: לספק הודעות שגיאה ברורות עבור פעולות לא חוקיות
|
||||
- **פלט JSON**: תמיכה בפלט מובנה לשימוש תכנותי
|
||||
- **תיעוד**: לכלול עזרה מקיפה ודוגמאות שימוש
|
||||
|
||||
## רקע
|
||||
|
||||
TrustGraph מספקת כיום ניהול תצורה באמצעות ה-API של התצורה ופקודה בודדת בשם `tg-show-config` המציגה את כל התצורה. אמנם זה עובד לצורך הצגת התצורה, אך הוא חסר יכולות ניהול מפורטות.
|
||||
|
||||
הגבלות נוכחיות כוללות:
|
||||
- אין דרך לרשום פריטי תצורה לפי סוג מתוך שורת הפקודה
|
||||
- אין פקודה בשורת הפקודה לקבלת ערכי תצורה ספציפיים
|
||||
- אין פקודה בשורת הפקודה להגדרת פריטי תצורה בודדים
|
||||
- אין פקודה בשורת הפקודה למחיקת פריטי תצורה ספציפיים
|
||||
|
||||
מסמך זה מטפל בחוסרים אלה על ידי הוספת ארבע פקודות שורת פקודה חדשות המספקות ניהול תצורה מפורט. על ידי חשיפת פעולות API של התצורה הבודדות דרך פקודות שורת פקודה, TrustGraph יכול:
|
||||
- לאפשר ניהול תצורה מבוסס תסריט
|
||||
- לאפשר חקירה של מבנה התצורה לפי סוג
|
||||
- לתמוך בעדכונים ממוקדי תצורה
|
||||
- לספק שליטה מפורטת על התצורה
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
התצורה המשופרת של שורת הפקודה דורשת את הרכיבים הטכניים הבאים:
|
||||
|
||||
1. **tg-list-config-items**
|
||||
- רשימת מפתחות תצורה עבור סוג ספציפי
|
||||
- קוראת לשיטת ה-API `Config.list(type)`
|
||||
- פלט של רשימת מפתחות התצורה
|
||||
|
||||
מודול: `trustgraph.cli.list_config_items`
|
||||
|
||||
2. **tg-get-config-item**
|
||||
- השגת פריט תצורה ספציפי(ים)
|
||||
- קוראת לשיטת ה-API `Config.get(keys)`
|
||||
- פלט של ערכי התצורה בפורמט JSON
|
||||
|
||||
מודול: `trustgraph.cli.get_config_item`
|
||||
|
||||
3. **tg-put-config-item**
|
||||
- הגדרת או עדכון פריט תצורה
|
||||
- קוראת לשיטת ה-API `Config.put(values)`
|
||||
- מקבל את פרמטרי הטיפוס, המפתח והערך
|
||||
|
||||
מודול: `trustgraph.cli.put_config_item`
|
||||
|
||||
4. **tg-delete-config-item**
|
||||
- הסרת פריט תצורה
|
||||
- קוראת לשיטת ה-API `Config.delete(keys)`
|
||||
- מקבל את פרמטרי הטיפוס והמפתח
|
||||
|
||||
מודול: `trustgraph.cli.delete_config_item`
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### ConfigKey ו-ConfigValue
|
||||
|
||||
הפקודות משתמשות במבני נתונים הקיימים מ-`trustgraph.api.types`:
|
||||
|
||||
```python
|
||||
@dataclasses.dataclass
|
||||
class ConfigKey:
|
||||
type : str
|
||||
key : str
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ConfigValue:
|
||||
type : str
|
||||
key : str
|
||||
value : str
|
||||
```
|
||||
|
||||
גישה זו מאפשרת:
|
||||
- טיפול עקבי בנתונים בכל ה-CLI וה-API
|
||||
- פעולות תצורה מסוג-יציבות
|
||||
- פורמטי קלט/פלט מובנים
|
||||
- שילוב עם ה-API של התצורה הקיים
|
||||
|
||||
### מפרטי פקודות שורת הפקודה
|
||||
|
||||
#### tg-list-config-items
|
||||
```bash
|
||||
tg-list-config-items --type <config-type> [--format text|json] [--api-url <url>]
|
||||
```
|
||||
- **מטרה**: רשימת מפתחות התצורה עבור סוג נתון
|
||||
- **קריאה ל-API**: `Config.list(type)`
|
||||
- **פלט**:
|
||||
- `text` (ברירת מחדל): מפתחות התצורה מופרדים ברווחים
|
||||
- `json`: מערך JSON של מפתחות התצורה
|
||||
|
||||
#### tg-get-config-item
|
||||
```bash
|
||||
tg-get-config-item --type <type> --key <key> [--format text|json] [--api-url <url>]
|
||||
```
|
||||
- **מטרה**: השגת פריט תצורה ספציפי
|
||||
- **קריאה ל-API**: `Config.get([ConfigKey(type, key)])`
|
||||
- **פלט**: ערך התצורה
|
||||
|
||||
#### הגדרת פריט תצורה
|
||||
```bash
|
||||
tg-put-config-item --type <type> --key <key> --value <value>
|
||||
```
|
||||
- **מטרה**: הגדרת או עדכון פריט תצורה
|
||||
- **קריאה ל-API**: `Config.put(key, value)`
|
||||
- **פרמטרים**:
|
||||
- `<type>`: סוג פריט התצורה (לדוגמה, "prompt", "system-prompt")
|
||||
- `<key>`: המפתח של פריט התצורה
|
||||
- `<value>`: הערך של פריט התצורה
|
||||
|
||||
#### מחיקת פריט תצורה
|
||||
```bash
|
||||
tg-delete-config-item --type <type> --key <key>
|
||||
```
|
||||
- **מטרה**: הסרת פריט תצורה
|
||||
- **קריאה ל-API**: `Config.delete(key)`
|
||||
- **פרמטרים**:
|
||||
- `<type>`: סוג פריט התצורה
|
||||
- `<key>`: המפתח של פריט התצורה
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
- האם יש לשנות את הפקודות לתמוך בפעולות מקובצות (מפתחות מרובים) בנוסף לפריטים בודדים?
|
||||
- איזה פורמט פלט צריך להיות בשימוש עבור אישור הצלחה?
|
||||
- איך המשתמשים יכולים לגלות או לתעד את סוגי התצורה?
|
||||
780
docs/tech-specs/he/multi-tenant-support.he.md
Normal file
780
docs/tech-specs/he/multi-tenant-support.he.md
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני: תמיכה בריבוי דיירים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני: תמיכה בריבוי דיירים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
אפשר ריבוי פריסות דיירים על ידי תיקון חוסר התאמות בשמות הפרמטרים שמונע התאמה אישית של תורים, והוספת פרמטריזציה של מרחבי מפתחות Cassandra.
|
||||
|
||||
## הקשר ארכיטקטוני
|
||||
|
||||
### פתרון תורים מבוסס זרימה
|
||||
|
||||
מערכת TrustGraph משתמשת בארכיטקטורה **מבוססת זרימה** לפתרון דינמי של תורים, התומכת באופן מובנה בריבוי דיירים:
|
||||
|
||||
**הגדרות זרימה** מאוחסנות ב-Cassandra ומציינות שמות תורים באמצעות הגדרות ממשק.
|
||||
**שמות התורים משתמשים בתבניות** עם משתנים `{id}` שמוחלפים במזהי מופעי זרימה.
|
||||
**השירותים פותרים באופן דינמי את התורים** על ידי חיפוש תצורות זרימה בזמן בקשה.
|
||||
**לכל דייר יכולות להיות זרימות ייחודיות** עם שמות תורים שונים, המספקות בידוד.
|
||||
|
||||
דוגמה להגדרת ממשק זרימה:
|
||||
```json
|
||||
{
|
||||
"interfaces": {
|
||||
"triples-store": "persistent://tg/flow/triples-store:{id}",
|
||||
"graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
כאשר שוכר א מתחיל זרימה `tenant-a-prod` ושוכר ב מתחיל זרימה `tenant-b-prod`, הם באופן אוטומטי מקבלים תורים מבודדים:
|
||||
`persistent://tg/flow/triples-store:tenant-a-prod`
|
||||
`persistent://tg/flow/triples-store:tenant-b-prod`
|
||||
|
||||
**שירותים המעוצבים כראוי עבור ריבוי שוכרים:**
|
||||
✅ **ניהול ידע (ליבה)** - פותר באופן דינמי תורים מהגדרת הזרימה המועברת בבקשות
|
||||
|
||||
**שירותים הדורשים תיקונים:**
|
||||
🔴 **שירות תצורה** - חוסר התאמה בשם הפרמטר מונע התאמה אישית של תורים
|
||||
🔴 **שירות ספרית** - נושאים של ניהול אחסון מקודדים (נדון בהמשך)
|
||||
🔴 **כל השירותים** - לא ניתן להתאים אישית את מרחב המפתחות של Cassandra
|
||||
|
||||
## הצהרת בעיה
|
||||
|
||||
### בעיה #1: חוסר התאמה בשם פרמטר ב-AsyncProcessor
|
||||
**הגדרות CLI:** `--config-queue` (שם לא ברור)
|
||||
**Argparse ממיר ל:** `config_queue` (במילון הפרמטרים)
|
||||
**הקוד מחפש:** `config_push_queue`
|
||||
**תוצאה:** הפרמטר מתעלם, ברירת מחדל ל-`persistent://tg/config/config`
|
||||
**השפעה:** משפיע על כל 32+ שירותים היורשים מ-AsyncProcessor
|
||||
**חוסם:** פריסות מרובות שוכרים לא יכולות להשתמש בתורי תצורה ספציפיים לשוכר
|
||||
**פתרון:** לשנות את שם הפרמטר ב-CLI ל-`--config-push-queue` לצורך בהירות (שינוי שבירה מקובל מכיוון שהתכונה שבורה כרגע)
|
||||
|
||||
### בעיה #2: חוסר התאמה בשם פרמטר בשירות התצורה
|
||||
**הגדרות CLI:** `--push-queue` (שם מעורפל)
|
||||
**Argparse ממיר ל:** `push_queue` (במילון הפרמטרים)
|
||||
**הקוד מחפש:** `config_push_queue`
|
||||
**תוצאה:** הפרמטר מתעלם
|
||||
**השפעה:** שירות התצורה לא יכול להשתמש בתור דחיפה מותאם אישית
|
||||
**פתרון:** לשנות את שם הפרמטר ב-CLI ל-`--config-push-queue` לצורך עקביות ובהירות (שינוי שבירה מקובל)
|
||||
|
||||
### בעיה #3: מרחב מפתחות Cassandra מקודד
|
||||
**נוכחי:** מרחב המפתחות מקודד כ-`"config"`, `"knowledge"`, `"librarian"` בשירותים שונים
|
||||
**תוצאה:** לא ניתן להתאים אישית את מרחב המפתחות עבור פריסות מרובות שוכרים
|
||||
**השפעה:** שירותי תצורה, ליבה וספריה
|
||||
**חוסם:** מספר שוכרים לא יכולים להשתמש במרחבי מפתחות Cassandra נפרדים
|
||||
|
||||
### בעיה #4: ארכיטקטורת ניהול אוספים ✅ הושלם
|
||||
**קודם:** אוספים שמורים במרחב המפתחות של Cassandra של הספריה באמצעות טבלת אוספים נפרדת
|
||||
**קודם:** הספריה השתמשה ב-4 נושאים מקודדים לניהול אחסון לתאם יצירה/מחיקה של אוספים:
|
||||
`vector_storage_management_topic`
|
||||
`object_storage_management_topic`
|
||||
`triples_storage_management_topic`
|
||||
`storage_management_response_topic`
|
||||
**בעיות (טופלו):**
|
||||
נושאים מקודדים לא ניתן להתאים אישית עבור פריסות מרובות שוכרים
|
||||
תיאום אסינכרוני מורכב בין הספריה לבין 4+ שירותי אחסון
|
||||
טבלה נפרדת ותשתית ניהול
|
||||
תורי בקשה/תגובה לא מתמידים עבור פעולות קריטיות
|
||||
**פתרון מיושם:** העברנו אוספים לשירות האחסון של התצורה, השתמשנו בדחיפה של תצורה להפצה
|
||||
**סטטוס:** כל בסיסי האחסון עברו לדפוס `CollectionConfigHandler`
|
||||
|
||||
## פתרון
|
||||
|
||||
מפרט זה מתייחס לבעיות #1, #2, #3 ו-#4.
|
||||
|
||||
### חלק 1: תיקון חוסר התאמה בשמות פרמטרים
|
||||
|
||||
#### שינוי 1: מחלקת בסיס AsyncProcessor - שינוי שם פרמטר CLI
|
||||
**קובץ:** `trustgraph-base/trustgraph/base/async_processor.py`
|
||||
**שורה:** 260-264
|
||||
|
||||
**נוכחי:**
|
||||
```python
|
||||
parser.add_argument(
|
||||
'--config-queue',
|
||||
default=default_config_queue,
|
||||
help=f'Config push queue {default_config_queue}',
|
||||
)
|
||||
```
|
||||
|
||||
**קבוע:**
|
||||
```python
|
||||
parser.add_argument(
|
||||
'--config-push-queue',
|
||||
default=default_config_queue,
|
||||
help=f'Config push queue (default: {default_config_queue})',
|
||||
)
|
||||
```
|
||||
|
||||
**הסבר:**
|
||||
שם ברור וחד יותר
|
||||
תואם לשם המשתנה הפנימי `config_push_queue`
|
||||
שינוי משמעותי מקובל מכיוון שהפיצ'ר אינו פעיל כרגע
|
||||
אין צורך בשינוי קוד בפונקציה params.get() - היא כבר מחפשת את השם הנכון
|
||||
|
||||
#### שינוי 2: שירות תצורה - שינוי שם פרמטר שורת הפקודה
|
||||
**קובץ:** `trustgraph-flow/trustgraph/config/service/service.py`
|
||||
**שורה:** 276-279
|
||||
|
||||
**נוכחי:**
|
||||
```python
|
||||
parser.add_argument(
|
||||
'--push-queue',
|
||||
default=default_config_push_queue,
|
||||
help=f'Config push queue (default: {default_config_push_queue})'
|
||||
)
|
||||
```
|
||||
|
||||
**קבוע:**
|
||||
```python
|
||||
parser.add_argument(
|
||||
'--config-push-queue',
|
||||
default=default_config_push_queue,
|
||||
help=f'Config push queue (default: {default_config_push_queue})'
|
||||
)
|
||||
```
|
||||
|
||||
**הסבר:**
|
||||
שמות ברורים יותר - "config-push-queue" מפורט יותר מ-"push-queue" בלבד.
|
||||
תואם לשם המשתנה הפנימי `config_push_queue`.
|
||||
עקבי עם הפרמטר `--config-push-queue` של AsyncProcessor.
|
||||
שינוי שעלול לשבור תאימות מקובל מכיוון שהפיצ'ר אינו פונקציונלי כרגע.
|
||||
אין צורך בשינוי קוד בפונקציה params.get() - היא כבר מחפשת את השם הנכון.
|
||||
|
||||
### חלק 2: הוספת פרמטריזציה של Keyspace של Cassandra
|
||||
|
||||
#### שינוי 3: הוספת פרמטר Keyspace למודול cassandra_config
|
||||
**קובץ:** `trustgraph-base/trustgraph/base/cassandra_config.py`
|
||||
|
||||
**הוספת ארגומנט שורת פקודה** (בפונקציה `add_cassandra_args()`):
|
||||
```python
|
||||
parser.add_argument(
|
||||
'--cassandra-keyspace',
|
||||
default=None,
|
||||
help='Cassandra keyspace (default: service-specific)'
|
||||
)
|
||||
```
|
||||
|
||||
**הוספת תמיכה במשתני סביבה** (בפונקציה `resolve_cassandra_config()`):
|
||||
```python
|
||||
keyspace = params.get(
|
||||
"cassandra_keyspace",
|
||||
os.environ.get("CASSANDRA_KEYSPACE")
|
||||
)
|
||||
```
|
||||
|
||||
**עדכון ערך ההחזרה** של `resolve_cassandra_config()`:
|
||||
כרגע מחזיר: `(hosts, username, password)`
|
||||
לשנות כך שיחזיר: `(hosts, username, password, keyspace)`
|
||||
|
||||
**הצדקה:**
|
||||
עקבי עם תבנית התצורה הקיימת של Cassandra
|
||||
זמין לכל השירותים דרך `add_cassandra_args()`
|
||||
תומך בתצורה הן דרך שורת הפקודה והן דרך משתני סביבה
|
||||
|
||||
#### שינוי 4: שירות תצורה - שימוש במפתחות מרחב (Keyspace) מוגדרים
|
||||
**קובץ:** `trustgraph-flow/trustgraph/config/service/service.py`
|
||||
|
||||
**שורה 30** - הסרת שם מרחב (Keyspace) מקודד:
|
||||
```python
|
||||
# DELETE THIS LINE:
|
||||
keyspace = "config"
|
||||
```
|
||||
|
||||
**שורות 69-73** - עדכון פתרון תצורת Cassandra:
|
||||
|
||||
**נוכחי:**
|
||||
```python
|
||||
cassandra_host, cassandra_username, cassandra_password = \
|
||||
resolve_cassandra_config(params)
|
||||
```
|
||||
|
||||
**קבוע:**
|
||||
```python
|
||||
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
||||
resolve_cassandra_config(params, default_keyspace="config")
|
||||
```
|
||||
|
||||
**הסבר:**
|
||||
שומר על תאימות לאחור עם "config" כברירת מחדל.
|
||||
מאפשר ביטול באמצעות `--cassandra-keyspace` או `CASSANDRA_KEYSPACE`.
|
||||
|
||||
#### שינוי 5: שירות ליבה/ידע - שימוש במרחבי מפתחות מוגדרים
|
||||
**קובץ:** `trustgraph-flow/trustgraph/cores/service.py`
|
||||
|
||||
**שורה 37** - הסרת מרחב מפתחות מקודד:
|
||||
```python
|
||||
# DELETE THIS LINE:
|
||||
keyspace = "knowledge"
|
||||
```
|
||||
|
||||
**עדכון פתרון תצורת Cassandra** (במיקום דומה לשירות התצורה):
|
||||
```python
|
||||
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
||||
resolve_cassandra_config(params, default_keyspace="knowledge")
|
||||
```
|
||||
|
||||
#### שינוי 6: שירות סוכן מידע - שימוש במפתחות פרמטריים
|
||||
**קובץ:** `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
|
||||
**שורה 51** - הסרת מרחב מפתחות מקודד:
|
||||
```python
|
||||
# DELETE THIS LINE:
|
||||
keyspace = "librarian"
|
||||
```
|
||||
|
||||
**עדכון פתרון תצורת Cassandra** (במיקום דומה לשירות התצורה):
|
||||
```python
|
||||
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
||||
resolve_cassandra_config(params, default_keyspace="librarian")
|
||||
```
|
||||
|
||||
### חלק 3: העברת ניהול אוספים לשירות התצורה
|
||||
|
||||
#### סקירה כללית
|
||||
העברת אוספים ממערכת ה-Cassandra librarian keyspace לאחסון בשירות התצורה. פעולה זו מבטלת נושאים מובנים לניהול אחסון ומפשטת את הארכיטקטורה על ידי שימוש במנגנון הדחיפה הקיים של התצורה לצורך הפצה.
|
||||
|
||||
#### ארכיטקטורה נוכחית
|
||||
```
|
||||
API Request → Gateway → Librarian Service
|
||||
↓
|
||||
CollectionManager
|
||||
↓
|
||||
Cassandra Collections Table (librarian keyspace)
|
||||
↓
|
||||
Broadcast to 4 Storage Management Topics (hardcoded)
|
||||
↓
|
||||
Wait for 4+ Storage Service Responses
|
||||
↓
|
||||
Response to Gateway
|
||||
```
|
||||
|
||||
#### ארכיטקטורה חדשה
|
||||
```
|
||||
API Request → Gateway → Librarian Service
|
||||
↓
|
||||
CollectionManager
|
||||
↓
|
||||
Config Service API (put/delete/getvalues)
|
||||
↓
|
||||
Cassandra Config Table (class='collections', key='user:collection')
|
||||
↓
|
||||
Config Push (to all subscribers on config-push-queue)
|
||||
↓
|
||||
All Storage Services receive config update independently
|
||||
```
|
||||
|
||||
#### שינוי 7: מנהל אוספים - שימוש ב-API של שירות התצורה
|
||||
**קובץ:** `trustgraph-flow/trustgraph/librarian/collection_manager.py`
|
||||
|
||||
**הסרה:**
|
||||
שימוש ב-`LibraryTableStore` (שורות 33, 40-41)
|
||||
אתחול מפיקי ניהול אחסון (שורות 86-140)
|
||||
שיטה `on_storage_response` (שורות 400-430)
|
||||
מעקב `pending_deletions` (שורות 57, 90-96 ושימוש לאורך כל הקוד)
|
||||
|
||||
**הוספה:**
|
||||
לקוח שירות תצורה עבור קריאות API (תבנית בקשה/תגובה)
|
||||
|
||||
**הגדרת לקוח תצורה:**
|
||||
```python
|
||||
# In __init__, add config request/response producers/consumers
|
||||
from trustgraph.schema.services.config import ConfigRequest, ConfigResponse
|
||||
|
||||
# Producer for config requests
|
||||
self.config_request_producer = Producer(
|
||||
client=pulsar_client,
|
||||
topic=config_request_queue,
|
||||
schema=ConfigRequest,
|
||||
)
|
||||
|
||||
# Consumer for config responses (with correlation ID)
|
||||
self.config_response_consumer = Consumer(
|
||||
taskgroup=taskgroup,
|
||||
client=pulsar_client,
|
||||
flow=None,
|
||||
topic=config_response_queue,
|
||||
subscriber=f"{id}-config",
|
||||
schema=ConfigResponse,
|
||||
handler=self.on_config_response,
|
||||
)
|
||||
|
||||
# Tracking for pending config requests
|
||||
self.pending_config_requests = {} # request_id -> asyncio.Event
|
||||
```
|
||||
|
||||
**שנה את `list_collections` (שורות 145-180):**
|
||||
```python
|
||||
async def list_collections(self, user, tag_filter=None, limit=None):
|
||||
"""List collections from config service"""
|
||||
# Send getvalues request to config service
|
||||
request = ConfigRequest(
|
||||
id=str(uuid.uuid4()),
|
||||
operation='getvalues',
|
||||
type='collections',
|
||||
)
|
||||
|
||||
# Send request and wait for response
|
||||
response = await self.send_config_request(request)
|
||||
|
||||
# Parse collections from response
|
||||
collections = []
|
||||
for key, value_json in response.values.items():
|
||||
if ":" in key:
|
||||
coll_user, collection = key.split(":", 1)
|
||||
if coll_user == user:
|
||||
metadata = json.loads(value_json)
|
||||
collections.append(CollectionMetadata(**metadata))
|
||||
|
||||
# Apply tag filtering in-memory (as before)
|
||||
if tag_filter:
|
||||
collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)]
|
||||
|
||||
# Apply limit
|
||||
if limit:
|
||||
collections = collections[:limit]
|
||||
|
||||
return collections
|
||||
|
||||
async def send_config_request(self, request):
|
||||
"""Send config request and wait for response"""
|
||||
event = asyncio.Event()
|
||||
self.pending_config_requests[request.id] = event
|
||||
|
||||
await self.config_request_producer.send(request)
|
||||
await event.wait()
|
||||
|
||||
return self.pending_config_requests.pop(request.id + "_response")
|
||||
|
||||
async def on_config_response(self, message, consumer, flow):
|
||||
"""Handle config response"""
|
||||
response = message.value()
|
||||
if response.id in self.pending_config_requests:
|
||||
self.pending_config_requests[response.id + "_response"] = response
|
||||
self.pending_config_requests[response.id].set()
|
||||
```
|
||||
|
||||
**שנה את `update_collection` (שורות 182-312):**
|
||||
```python
|
||||
async def update_collection(self, user, collection, name, description, tags):
|
||||
"""Update collection via config service"""
|
||||
# Create metadata
|
||||
metadata = CollectionMetadata(
|
||||
user=user,
|
||||
collection=collection,
|
||||
name=name,
|
||||
description=description,
|
||||
tags=tags,
|
||||
)
|
||||
|
||||
# Send put request to config service
|
||||
request = ConfigRequest(
|
||||
id=str(uuid.uuid4()),
|
||||
operation='put',
|
||||
type='collections',
|
||||
key=f'{user}:{collection}',
|
||||
value=json.dumps(metadata.to_dict()),
|
||||
)
|
||||
|
||||
response = await self.send_config_request(request)
|
||||
|
||||
if response.error:
|
||||
raise RuntimeError(f"Config update failed: {response.error.message}")
|
||||
|
||||
# Config service will trigger config push automatically
|
||||
# Storage services will receive update and create collections
|
||||
```
|
||||
|
||||
**שנה את `delete_collection` (שורות 314-398):**
|
||||
```python
|
||||
async def delete_collection(self, user, collection):
|
||||
"""Delete collection via config service"""
|
||||
# Send delete request to config service
|
||||
request = ConfigRequest(
|
||||
id=str(uuid.uuid4()),
|
||||
operation='delete',
|
||||
type='collections',
|
||||
key=f'{user}:{collection}',
|
||||
)
|
||||
|
||||
response = await self.send_config_request(request)
|
||||
|
||||
if response.error:
|
||||
raise RuntimeError(f"Config delete failed: {response.error.message}")
|
||||
|
||||
# Config service will trigger config push automatically
|
||||
# Storage services will receive update and delete collections
|
||||
```
|
||||
|
||||
**פורמט מטא-דאטה לאוספים:**
|
||||
נשמר בטבלת התצורה כ: `class='collections', key='user:collection'`
|
||||
הערך הוא CollectionMetadata ממוין ב-JSON (ללא שדות תאריך ושעה)
|
||||
שדות: `user`, `collection`, `name`, `description`, `tags`
|
||||
דוגמה: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'`
|
||||
|
||||
#### שינוי 8: שירות הספרייה - הסרת תשתית ניהול אחסון
|
||||
**קובץ:** `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
|
||||
**הסרה:**
|
||||
מפיקי ניהול אחסון (שורות 173-190):
|
||||
`vector_storage_management_producer`
|
||||
`object_storage_management_producer`
|
||||
`triples_storage_management_producer`
|
||||
צרכן תגובות אחסון (שורות 192-201)
|
||||
מטפל `on_storage_response` (שורות 467-473)
|
||||
|
||||
**שינוי:**
|
||||
אתחול CollectionManager (שורות 215-224) - הסרת פרמטרים של מפיק אחסון
|
||||
|
||||
**הערה:** ממשק ה-API החיצוני לאוספים נשאר ללא שינוי:
|
||||
`list-collections`
|
||||
`update-collection`
|
||||
`delete-collection`
|
||||
|
||||
#### שינוי 9: הסרת טבלת האוספים מ-LibraryTableStore
|
||||
**קובץ:** `trustgraph-flow/trustgraph/tables/library.py`
|
||||
|
||||
**מחיקה:**
|
||||
הצהרת CREATE של טבלת האוספים (שורות 114-127)
|
||||
הצהרות מוכנות של האוספים (שורות 205-240)
|
||||
כל שיטות האוספים (שורות 578-717):
|
||||
`ensure_collection_exists`
|
||||
`list_collections`
|
||||
`update_collection`
|
||||
`delete_collection`
|
||||
`get_collection`
|
||||
`create_collection`
|
||||
|
||||
**הצדקה:**
|
||||
האוספים כעת מאוחסנים בטבלת התצורה
|
||||
שינוי שמשפיע על השינויים - אין צורך בהעברת נתונים
|
||||
מפשט את שירות הספרייה באופן משמעותי
|
||||
|
||||
#### שינוי 10: שירותי אחסון - ניהול אוספים מבוסס תצורה ✅ הושלם
|
||||
|
||||
**סטטוס:** כל 11 ה-backends של האחסון עברו לשימוש ב-`CollectionConfigHandler`.
|
||||
|
||||
**שירותים מושפעים (סה"כ 11):**
|
||||
הטמעות מסמכים: milvus, pinecone, qdrant
|
||||
הטמעות גרפים: milvus, pinecone, qdrant
|
||||
אחסון אובייקטים: cassandra
|
||||
אחסון משולשות: cassandra, falkordb, memgraph, neo4j
|
||||
|
||||
**קבצים:**
|
||||
`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py`
|
||||
`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py`
|
||||
|
||||
**תבנית יישום (לכל השירותים):**
|
||||
|
||||
1. **רישום מטפל תצורה ב-`__init__`:**
|
||||
```python
|
||||
# Add after AsyncProcessor initialization
|
||||
self.register_config_handler(self.on_collection_config)
|
||||
self.known_collections = set() # Track (user, collection) tuples
|
||||
```
|
||||
|
||||
2. **יישום מנהל תצורה:**
|
||||
```python
|
||||
async def on_collection_config(self, config, version):
|
||||
"""Handle collection configuration updates"""
|
||||
logger.info(f"Collection config version: {version}")
|
||||
|
||||
if "collections" not in config:
|
||||
return
|
||||
|
||||
# Parse collections from config
|
||||
# Key format: "user:collection" in config["collections"]
|
||||
config_collections = set()
|
||||
for key in config["collections"].keys():
|
||||
if ":" in key:
|
||||
user, collection = key.split(":", 1)
|
||||
config_collections.add((user, collection))
|
||||
|
||||
# Determine changes
|
||||
to_create = config_collections - self.known_collections
|
||||
to_delete = self.known_collections - config_collections
|
||||
|
||||
# Create new collections (idempotent)
|
||||
for user, collection in to_create:
|
||||
try:
|
||||
await self.create_collection_internal(user, collection)
|
||||
self.known_collections.add((user, collection))
|
||||
logger.info(f"Created collection: {user}/{collection}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create {user}/{collection}: {e}")
|
||||
|
||||
# Delete removed collections (idempotent)
|
||||
for user, collection in to_delete:
|
||||
try:
|
||||
await self.delete_collection_internal(user, collection)
|
||||
self.known_collections.discard((user, collection))
|
||||
logger.info(f"Deleted collection: {user}/{collection}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to delete {user}/{collection}: {e}")
|
||||
```
|
||||
|
||||
3. **אתחול אוספים ידועים בעת ההפעלה:**
|
||||
```python
|
||||
async def start(self):
|
||||
"""Start the processor"""
|
||||
await super().start()
|
||||
await self.sync_known_collections()
|
||||
|
||||
async def sync_known_collections(self):
|
||||
"""Query backend to populate known_collections set"""
|
||||
# Backend-specific implementation:
|
||||
# - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern
|
||||
# - Cassandra: Query keyspaces or collection metadata
|
||||
# - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes
|
||||
pass
|
||||
```
|
||||
|
||||
4. **שכתוב של שיטות טיפול קיימות:**
|
||||
```python
|
||||
# Rename and remove response sending:
|
||||
# handle_create_collection → create_collection_internal
|
||||
# handle_delete_collection → delete_collection_internal
|
||||
|
||||
async def create_collection_internal(self, user, collection):
|
||||
"""Create collection (idempotent)"""
|
||||
# Same logic as current handle_create_collection
|
||||
# But remove response producer calls
|
||||
# Handle "already exists" gracefully
|
||||
pass
|
||||
|
||||
async def delete_collection_internal(self, user, collection):
|
||||
"""Delete collection (idempotent)"""
|
||||
# Same logic as current handle_delete_collection
|
||||
# But remove response producer calls
|
||||
# Handle "not found" gracefully
|
||||
pass
|
||||
```
|
||||
|
||||
5. **הסרת תשתית ניהול אחסון:**
|
||||
הסרת הגדרות והתחלה של `self.storage_request_consumer`
|
||||
הסרת הגדרות של `self.storage_response_producer`
|
||||
הסרת שיטת ה-dispatcher של `on_storage_management`
|
||||
הסרת מדדים לניהול אחסון
|
||||
הסרת יבוא: `StorageManagementRequest`, `StorageManagementResponse`
|
||||
|
||||
**שיקולים ספציפיים ל-Backend:**
|
||||
|
||||
**מאגרי וקטורים (Milvus, Pinecone, Qdrant):** לעקוב אחר `(user, collection)` לוגי ב-`known_collections`, אך ייתכן שייווצרו מספר אוספים ב-backend עבור כל מימד. להמשיך בדפוס היצירה המאוחרת. פעולות מחיקה חייבות להסיר את כל הווריאציות של המימד.
|
||||
|
||||
**Cassandra Objects:** אוספים הם מאפייני שורות, ולא מבנים. לעקוב אחר מידע ברמת ה-keyspace.
|
||||
|
||||
**מאגרי גרפים (Neo4j, Memgraph, FalkorDB):** לשאול צמתים של `CollectionMetadata` בעת ההפעלה. ליצור/למחוק צמתי מטא-נתונים בעת הסנכרון.
|
||||
|
||||
**Cassandra Triples:** להשתמש ב-API של `KnowledgeGraph` עבור פעולות אוסף.
|
||||
|
||||
**נקודות עיצוב מרכזיות:**
|
||||
|
||||
**עקביות בסופו של דבר:** אין מנגנון בקשה/תגובה, דחיפת תצורה משודרת
|
||||
**אידמפוטנטיות:** כל פעולות היצירה/מחיקה חייבות להיות בטוחות לניסיון חוזר
|
||||
**טיפול בשגיאות:** לרשום שגיאות אך לא לחסום עדכוני תצורה
|
||||
**ריפוי עצמי:** פעולות שנכשלו ינסו שוב בדחיפת התצורה הבאה
|
||||
**פורמט מפתח אוסף:** `"user:collection"` ב-`config["collections"]`
|
||||
|
||||
#### שינוי 11: עדכון סכימת האוסף - הסרת חותמות זמן
|
||||
**קובץ:** `trustgraph-base/trustgraph/schema/services/collection.py`
|
||||
|
||||
**שינוי CollectionMetadata (שורות 13-21):**
|
||||
להסיר את השדות `created_at` ו-`updated_at`:
|
||||
```python
|
||||
class CollectionMetadata(Record):
|
||||
user = String()
|
||||
collection = String()
|
||||
name = String()
|
||||
description = String()
|
||||
tags = Array(String())
|
||||
# Remove: created_at = String()
|
||||
# Remove: updated_at = String()
|
||||
```
|
||||
|
||||
**שינוי ב-CollectionManagementRequest (שורות 25-47):**
|
||||
הסרת שדות חותמת זמן:
|
||||
```python
|
||||
class CollectionManagementRequest(Record):
|
||||
operation = String()
|
||||
user = String()
|
||||
collection = String()
|
||||
timestamp = String()
|
||||
name = String()
|
||||
description = String()
|
||||
tags = Array(String())
|
||||
# Remove: created_at = String()
|
||||
# Remove: updated_at = String()
|
||||
tag_filter = Array(String())
|
||||
limit = Integer()
|
||||
```
|
||||
|
||||
**ההצדקה:**
|
||||
חותמות זמן אינן מוסיפות ערך לאוספים
|
||||
שירות התצורה שומר על מעקב גרסאות משלו
|
||||
מפשט את הסכימה ומקטין את נפח האחסון
|
||||
|
||||
#### יתרונות של מעבר לשירות התצורה
|
||||
|
||||
1. ✅ **מבטל נושאים של ניהול אחסון מקודדים קשות** - פותר את החסימה של ריבוי דיירים
|
||||
2. ✅ **תיאום פשוט יותר** - אין המתנה אסינכרונית מורכבת לתגובות של 4+ שירותי אחסון
|
||||
3. ✅ **עקביות בסופו של דבר** - שירותי האחסון מתעדכנים באופן עצמאי באמצעות דחיפה של תצורה
|
||||
4. ✅ **אמינות טובה יותר** - דחיפה קבועה של תצורה לעומת בקשה/תגובה לא קבועה
|
||||
5. ✅ **מודל תצורה מאוחד** - אוספים מטופלים כתצורה
|
||||
6. ✅ **מפחית מורכבות** - מסיר כ-300 שורות של קוד תיאום
|
||||
7. ✅ **מוכן לריבוי דיירים** - התצורה כבר תומכת בבידוד דיירים באמצעות מרחבי מפתחות
|
||||
8. ✅ **מעקב גרסאות** - מנגנון גרסאות של שירות התצורה מספק תיעוד ביקורת
|
||||
|
||||
## הערות יישום
|
||||
|
||||
### תאימות לאחור
|
||||
|
||||
**שינויים בפרמטרים:**
|
||||
שינויי שמות של פרמטרים בשורת הפקודה הם שינויים שוברים אך מקובלים (התכונה אינה פונקציונלית כרגע)
|
||||
השירותים עובדים ללא פרמטרים (משתמשים בברירות המחדל)
|
||||
מרחבי מפתחות ברירת מחדל נשמרו: "config", "knowledge", "librarian"
|
||||
תור ברירת מחדל: `persistent://tg/config/config`
|
||||
|
||||
**ניהול אוספים:**
|
||||
**שינוי שובר:** הטבלה של האוספים הוסרה מממרחב המפתחות של librarian
|
||||
**לא סופקה העברת נתונים** - מקובל לשלב זה
|
||||
ממשק API חיצוני לאוספים לא השתנה (פעולות רשימה/עדכון/מחיקה)
|
||||
פורמט מטא-נתונים של אוספים פושט (הוסרו חותמות זמן)
|
||||
|
||||
### דרישות בדיקה
|
||||
|
||||
**בדיקת פרמטרים:**
|
||||
1. ודאו שהפרמטר `--config-push-queue` עובד בשירות graph-embeddings
|
||||
2. ודאו שהפרמטר `--config-push-queue` עובד בשירות text-completion
|
||||
3. ודאו שהפרמטר `--config-push-queue` עובד בשירות התצורה
|
||||
4. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות התצורה
|
||||
5. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות cores
|
||||
6. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות librarian
|
||||
7. ודאו שהשירותים עובדים ללא פרמטרים (משתמשים בברירות המחדל)
|
||||
8. ודאו פריסה מרובת דיירים עם שמות תורים ומרחבי מפתחות מותאמים אישית
|
||||
|
||||
**בדיקת ניהול אוספים:**
|
||||
9. ודאו את הפעולה `list-collections` באמצעות שירות התצורה
|
||||
10. ודאו ש-`update-collection` יוצר/מעדכן בטבלת התצורה
|
||||
11. ודאו ש-`delete-collection` מסיר מטבלת התצורה
|
||||
12. ודאו שדחיפה של תצורה מופעלת בעת עדכונים של אוספים
|
||||
13. ודאו שסינון תגים עובד עם אחסון מבוסס תצורה
|
||||
14. ודאו שפעולות על אוספים עובדות ללא שדות חותמות זמן
|
||||
|
||||
### דוגמה לפריסה מרובת דיירים
|
||||
```bash
|
||||
# Tenant: tg-dev
|
||||
graph-embeddings \
|
||||
-p pulsar+ssl://broker:6651 \
|
||||
--pulsar-api-key <KEY> \
|
||||
--config-push-queue persistent://tg-dev/config/config
|
||||
|
||||
config-service \
|
||||
-p pulsar+ssl://broker:6651 \
|
||||
--pulsar-api-key <KEY> \
|
||||
--config-push-queue persistent://tg-dev/config/config \
|
||||
--cassandra-keyspace tg_dev_config
|
||||
```
|
||||
|
||||
## ניתוח השפעה
|
||||
|
||||
### שירותים המושפעים משינוי 1-2 (שינוי שם פרמטר CLI)
|
||||
כל השירותים היורשים מ-AsyncProcessor או FlowProcessor:
|
||||
config-service
|
||||
cores-service
|
||||
librarian-service
|
||||
graph-embeddings
|
||||
document-embeddings
|
||||
text-completion-* (כל הספקיות)
|
||||
extract-* (כל ה-extractors)
|
||||
query-* (כל שירותי השאילתות)
|
||||
retrieval-* (כל שירותי ה-RAG)
|
||||
storage-* (כל שירותי האחסון)
|
||||
ועוד 20+ שירותים
|
||||
|
||||
### שירותים המושפעים משינויים 3-6 (Keyspace של Cassandra)
|
||||
config-service
|
||||
cores-service
|
||||
librarian-service
|
||||
|
||||
### שירותים המושפעים משינויים 7-11 (ניהול אוספים)
|
||||
|
||||
**שינויים מיידיים:**
|
||||
librarian-service (collection_manager.py, service.py)
|
||||
tables/library.py (הסרת טבלת אוספים)
|
||||
schema/services/collection.py (הסרת חותמת זמן)
|
||||
|
||||
**שינויים שהושלמו (שינוי 10):** ✅
|
||||
כל שירותי האחסון (11 בסך הכל) - עברו ל-config push לעדכוני אוספים דרך `CollectionConfigHandler`
|
||||
סכימת ניהול האחסון הוסרה מ-`storage.py`
|
||||
|
||||
## שיקולים עתידיים
|
||||
|
||||
### מודל Keyspace מבוסס משתמש
|
||||
|
||||
חלק מהשירותים משתמשים באופן דינמי ב-**keyspace מבוסס משתמש**, כאשר לכל משתמש יש את ה-keyspace של Cassandra שלו:
|
||||
|
||||
**שירותים עם keyspace מבוסס משתמש:**
|
||||
1. **Triples Query Service** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`)
|
||||
משתמש ב-`keyspace=query.user`
|
||||
2. **Objects Query Service** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`)
|
||||
משתמש ב-`keyspace=self.sanitize_name(user)`
|
||||
3. **KnowledgeGraph Direct Access** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`)
|
||||
פרמטר ברירת מחדל `keyspace="trustgraph"`
|
||||
|
||||
**סטטוס:** אלה **לא משתנים** במפרט זה.
|
||||
|
||||
**נדרשת בדיקה עתידית:**
|
||||
להעריך האם מודל ה-keyspace מבוסס משתמש יוצר בעיות בידוד שוכרים
|
||||
לשקול האם פריסות מרובות שוכרים צריכות דפוסי קידומת keyspace (לדוגמה, `tenant_a_user1`)
|
||||
לבדוק לגבי התנגשות פוטנציאלית של מזהי משתמש בין שוכרים
|
||||
להעריך האם keyspace משותף יחיד לכל שוכר עם בידוד שורות מבוסס משתמש עדיף
|
||||
|
||||
**הערה:** זה לא חוסם את יישום הריבוי שוכרים הנוכחי, אך יש לבדוק אותו לפני פריסות ריבוי שוכרים לייצור.
|
||||
|
||||
## שלבי יישום
|
||||
|
||||
### שלב 1: תיקוני פרמטרים (שינויים 1-6)
|
||||
לתקן את שם הפרמטר `--config-push-queue`
|
||||
להוסיף תמיכה בפרמטר `--cassandra-keyspace`
|
||||
**תוצאה:** תצורה של תור ו-keyspace מרובי שוכרים מופעלת
|
||||
|
||||
### שלב 2: הגירת ניהול אוספים (שינויים 7-9, 11)
|
||||
להגר את אחסון האוספים לשירות התצורה
|
||||
להסיר את טבלת האוספים מ-librarian
|
||||
לעדכן את סכימת האוספים (להסיר חותמות זמן)
|
||||
**תוצאה:** מבטלת את נושאי ניהול האחסון המקודדים קשות, מפשטת את librarian
|
||||
|
||||
### שלב 3: עדכוני שירותי אחסון (שינוי 10) ✅ הושלם
|
||||
עדכנו את כל שירותי האחסון להשתמש ב-config push עבור אוספים דרך `CollectionConfigHandler`
|
||||
הסרנו את תשתית הבקשות/תגובות לניהול אחסון
|
||||
הסרנו הגדרות סכימה מיושנות
|
||||
**תוצאה:** השגת ניהול אוספים מבוסס תצורה מלא
|
||||
|
||||
## הפניות
|
||||
GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582
|
||||
קבצים קשורים:
|
||||
`trustgraph-base/trustgraph/base/async_processor.py`
|
||||
`trustgraph-base/trustgraph/base/cassandra_config.py`
|
||||
`trustgraph-base/trustgraph/schema/core/topic.py`
|
||||
`trustgraph-base/trustgraph/schema/services/collection.py`
|
||||
`trustgraph-flow/trustgraph/config/service/service.py`
|
||||
`trustgraph-flow/trustgraph/cores/service.py`
|
||||
`trustgraph-flow/trustgraph/librarian/service.py`
|
||||
`trustgraph-flow/trustgraph/librarian/collection_manager.py`
|
||||
`trustgraph-flow/trustgraph/tables/library.py`
|
||||
196
docs/tech-specs/he/neo4j-user-collection-isolation.he.md
Normal file
196
docs/tech-specs/he/neo4j-user-collection-isolation.he.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
---
|
||||
layout: default
|
||||
title: "תמיכה ביסודות משתמשים/מערכות ב-Neo4j"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# תמיכה ביסודות משתמשים/מערכות ב-Neo4j
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## הצגת הבעיה
|
||||
|
||||
המימוש הנוכחי של אחסון שאילתות ב-Neo4j סובל מחוסר ביסודות משתמשים/מערכות, מה שיוצר בעיות אבטחה במצב רב-משתמשים. כל השלישים מאוחסנים במרחב גרף אחד ללא מנגנון למניעת משתמשים מגישה לנתונים של משתמשים אחרים או מיזוג מערכות.
|
||||
|
||||
בניגוד למערכות אחסון אחרות ב-TrustGraph:
|
||||
- **Cassandra**: משתמשת במרחבי מפתחות נפרדים לכל משתמש וטבלאות לכל מערכת
|
||||
- **אחסון וקטורי** (Milvus, Qdrant, Pinecone): משתמשים בשמות מרחבים ספציפיים למערכות
|
||||
- **Neo4j**: כיום, משתמשת בכל הנתונים במרחב גרף אחד (פגיעות אבטחה)
|
||||
|
||||
## ארכיטקטורה נוכחית
|
||||
|
||||
### מודל נתונים
|
||||
- **צמתים**: תוויות `:Node` עם תכונה `uri`, תוויות `:Literal` עם תכונה `value`
|
||||
- **קשרים**: תוויות `:Rel` עם תכונת `uri`
|
||||
- **אינדקסים**: `Node.uri`, `Literal.value`, `Rel.uri`
|
||||
|
||||
### זרימת הודעות
|
||||
- הודעות `Triples` מכילות שדות `metadata.user` ו-`metadata.collection`
|
||||
- שירות האחסון מקבל מידע על משתמשים/מערכות אך מתעלם ממנו
|
||||
- שירות השאילתות מצפה לשדות `user` ו-`collection` בבקשת `TriplesQueryRequest` אך מתעלם מהם
|
||||
|
||||
### בעיית אבטחה נוכחית
|
||||
```cypher
|
||||
# כל משתמש יכול לשאול כל נתונים - אין ביסודות
|
||||
MATCH (src:Node)-[rel:Rel]->(dest:Node)
|
||||
RETURN src.uri, rel.uri, dest.uri
|
||||
```
|
||||
|
||||
## פתרון מוצע: סינון מבוסס תכונות (מומלץ)
|
||||
|
||||
### סקירה כללית
|
||||
הוסף תכונות `user` ו-`collection` לכל הצמתים והקשרים, ואז לסנן את כל הפעולות לפי התכונות הללו. גישה זו מספקת ביסודות חזקות תוך שמירה על גמישות שאילתות והתאמה לגרסאות קודמות.
|
||||
|
||||
### שינויים במודל נתונים
|
||||
|
||||
#### מבנה צומת משופר
|
||||
```cypher
|
||||
// ישויות צומת
|
||||
CREATE (n:Node {
|
||||
uri: "http://example.com/entity1",
|
||||
user: "john_doe",
|
||||
collection: "production_v1"
|
||||
})
|
||||
|
||||
// ישויות Literal
|
||||
CREATE (n:Literal {
|
||||
value: "literal value",
|
||||
user: "john_doe",
|
||||
collection: "production_v1"
|
||||
})
|
||||
```
|
||||
|
||||
#### מבנה קשר משופר
|
||||
```cypher
|
||||
// קשרים עם תכונות משתמש/מערכת
|
||||
CREATE (src)-[:Rel {
|
||||
uri: "http://example.com/predicate1",
|
||||
user: "john_doe",
|
||||
collection: "production_v1"
|
||||
}]->(dest)
|
||||
```
|
||||
|
||||
#### אינדקסים מעודכנים
|
||||
```cypher
|
||||
// אינדקסים משולבים לסינון יעיל
|
||||
CREATE INDEX node_user_collection_uri FOR (n:Node) ON (n.user, n.collection, n.uri);
|
||||
CREATE INDEX literal_user_collection_value FOR (n:Literal) ON (n.user, n.collection, n.value);
|
||||
CREATE INDEX rel_user_collection_uri FOR ()-[r:Rel]-() ON (r.user, r.collection, r.uri);
|
||||
|
||||
// שמירה על אינדקסים קיימים לאחור התאמה (אופציונלי)
|
||||
```
|
||||
|
||||
## תוכנית יישום
|
||||
|
||||
### שלב 1: יסודות (שבוע 1)
|
||||
1. [ ] עדכן את שירות האחסון לקבל ולשמור תכונות משתמש/מערכת
|
||||
2. [ ] הוסף אינדקסים משולבים לביצוע שאילתות מיטבי
|
||||
3. [ ] יישם שכבת התאמה לגרסאות קודמות
|
||||
4. [ ] צור בדיקות יחידה לפונקציונליות החדשה
|
||||
|
||||
### שלב 2: עדכוני שאילתות (שבוע 2)
|
||||
1. [ ] עדכן את כל דפוסי השאילתות כדי לכלול סינון משתמש/מערכת
|
||||
2. [ ] הוסף אימות שאילתות ובקרת אבטחה
|
||||
3. [ ] עדכן בדיקות אינטגרציה
|
||||
4. [ ] בדיקות ביצוע עם שאילתות מסוננות
|
||||
|
||||
### שלב 3: העברה והפצה (שבוע 3)
|
||||
1. [ ] צור סקריפטים להעברת נתונים עבור מופעי Neo4j קיימים
|
||||
2. [ ] תיעוד והוראות הפעלה
|
||||
3. [ ] ניטור והתראות על הפרות ביסודות
|
||||
4. [ ] בדיקות סיום עם מספר משתמשים/מערכות
|
||||
|
||||
### שלב 4: חיזוק (שבוע 4)
|
||||
1. [ ] הסר את מצב ההתאמה לגרסאות קודמות
|
||||
2. [ ] הוסף רישום ביקורת מקיף
|
||||
3. [ ] ביקורת אבטחה וגישה
|
||||
4. [ ] בדיקות ביצוע
|
||||
|
||||
## אסטרטגיית בדיקה
|
||||
|
||||
### בדיקות יחידה
|
||||
```python
|
||||
def test_user_collection_isolation():
|
||||
# שמור שליש עבור משתמש1/מערכת1
|
||||
processor.store_triples(triples_user1_coll1)
|
||||
|
||||
# שמור שליש עבור משתמש2/מערכת2
|
||||
processor.store_triples(triples_user2_coll2)
|
||||
|
||||
# שאילת משתמש1 צריך רק להחזיר את הנתונים של משתמש1
|
||||
results = processor.query_triples(query_user1_coll1)
|
||||
assert all_results_belong_to_user1_coll1(results)
|
||||
|
||||
# שאילת משתמש2 צריך רק להחזיר את הנתונים של משתמש2
|
||||
results = processor.query_triples(query_user2_coll2)
|
||||
assert all_results_belong_to_user2_coll2(results)
|
||||
```
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
- תרחישים רב-משתמשים עם נתונים חופפים
|
||||
- שאילתות בין מערכות (צריכות להיכשל)
|
||||
- בדיקות העברה עם נתונים קיימים
|
||||
- ביצועים - שורה עם מערכות נתונים גדולות
|
||||
|
||||
### בדיקות אבטחה
|
||||
- ניסיון לשאול נתונים של משתמשים אחרים
|
||||
- התקפות SQL על פרמטרים של משתמש/מערכת
|
||||
- אימות של ביסודות תחת דפוסי שאילתות שונים
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
### אסטרטגיית אינדקס
|
||||
- אינדקסים משולבים על `(user, collection, uri)` לביצוע שאילתות מיטבי
|
||||
- שקול אינדקסים חלקיים אם יש למערכות רבות יותר גודל גדול
|
||||
- עקוב אחר שימוש באינדקס וביצוע שאילתות
|
||||
|
||||
### אופטימיזציה של שאילתות
|
||||
- השתמש ב-EXPLAIN כדי לוודא שימוש באינדקס בשאילתות מסוננות
|
||||
- שקול אחסון תוצאות שאילתות לשימוש חוזר
|
||||
- פרופיל שימוש בזיכרון עם מספר משתמשים/מערכות גדולים
|
||||
|
||||
### סקלאביליות
|
||||
- כל מערכת משתמשים/מערכת יוצרת איזולציה נפרדת של נתונים
|
||||
- עקוב אחר גודל מסד הנתונים ושימוש בבריאת חיבורים
|
||||
- שקול אסטרטגיות סקלאביליות אופקיות במידת הצורך
|
||||
|
||||
## אבטחה ותאימות
|
||||
|
||||
### ביסודות נתונים
|
||||
- **פיזי**: כל הנתונים של משתמש מאוחסנים עם תכונות משתמש/מערכת ספציפיות
|
||||
- **לוגי**: כל השאילתות מסוננות על ידי הקשר משתמש/מערכת
|
||||
- **בקרה**: שכבת שירות מאמתת גישה
|
||||
|
||||
### דרישות ביקורת
|
||||
- רשום את כל גישה לנתונים עם הקשר משתמש/מערכת
|
||||
- עקוב אחר פעילויות העברה
|
||||
- עקוב אחר ניסיונות הפרות ביסודות
|
||||
|
||||
### שיקולים תאימות
|
||||
- GDPR: יכולת טובה יותר למצוא ולמחוק נתונים ספציפיים למשתמשים
|
||||
- SOC2: בקרה בסיסית וגישה של משתמשים
|
||||
- HIPAA: ביסודות חזקים עבור נתונים בתחום הבריאות
|
||||
|
||||
## סיכונים ותיקונים
|
||||
|
||||
| סיכון | השפעה | הסתברות | תיקון |
|
||||
|------|--------|------------|------------|
|
||||
| שאילתות חסרות סינון משתמש/מערכת | גבוה | בינונית | אימות חובה, בדיקות מקיפות |
|
||||
| ירידה בביצועים | בינונית | נמוכה | אופטימיזציה של אינדקס, פרופיל שאילתות |
|
||||
| אובדן נתונים בהעברה | גבוה | נמוכה | אסטרטגיית גיבוי, פרוצדורות שלבים אחורה |
|
||||
| קשיים בהתאמה לגרסאות קודמות | בינונית | בינונית | תוכנית יישום, תיעוד |
|
||||
| קשיים בביצוע שאילתות מורכבות | בינונית | בינונית | תיעוד דפוסי שאילתות |
|
||||
|
||||
## קריטריוני הצלחה
|
||||
|
||||
1. **אבטחה**: אין גישה בין משתמשים בייצור
|
||||
2. **ביצועים**: <10% השפעה על ביצועי השאילתות בהשוואה לשאילתות לא מסוננות
|
||||
3. **העברה**: 100% נתונים קיימים מוצלחים בהעברה ללא אובדן
|
||||
4. **שימושיות**: כל דפוסי השאילתות הקיימים עובדים עם הקשר משתמש/מערכת
|
||||
5. **תאימות**: תיעוד מלא של גישה לנתונים מבוסס משתמש/מערכת
|
||||
|
||||
## מסקנה
|
||||
|
||||
הגישה המבוססת על תכונות מספקת את האיזון הטוב ביותר של אבטחה, ביצועים וקלות תחזוקה להוספת ביסודות משתמשים/מערכות ב-Neo4j. היא תואמת עם דפוסי הרב-משתמשים הקיימים ב-TrustGraph תוך ניצול החוזקות של Neo4j בשאילתות גרפים ואינדקסים.
|
||||
|
||||
פתרון זה מבטיח שהבסיס של ה-Neo4j ב-TrustGraph עומד בסטנדרטים אבטחיים כמו מערכות אחסון אחרות, ומספק ביסודות תוך שמירה על גמישות וגודל שאילתות.
|
||||
769
docs/tech-specs/he/ontology-extract-phase-2.he.md
Normal file
769
docs/tech-specs/he/ontology-extract-phase-2.he.md
Normal file
|
|
@ -0,0 +1,769 @@
|
|||
---
|
||||
layout: default
|
||||
title: "חילוץ ידע מתוך אונטולוגיות - שלב 2, שיפור מחדש"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# חילוץ ידע מתוך אונטולוגיות - שלב 2, שיפור מחדש
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
**סטטוס**: טיוטה
|
||||
**מחבר**: מפגש ניתוח 2025-12-03
|
||||
**קשור**: `ontology.md`, `ontorag.md`
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מזהה אי-התאמות במערכת הנוכחית לחילוץ ידע המבוססת על אונטולוגיות, ומציע שיפור מחדש כדי לשפר את הביצועים של מודלי שפה גדולים (LLM) ולהפחית אובדן מידע.
|
||||
|
||||
## יישום נוכחי
|
||||
|
||||
### איך זה עובד כרגע
|
||||
|
||||
1. **טעינת אונטולוגיה** (`ontology_loader.py`)
|
||||
טוען קובץ JSON של אונטולוגיה עם מפתחות כמו `"fo/Recipe"`, `"fo/Food"`, `"fo/produces"`
|
||||
מזהי מחלקות כוללים את הקידומת של מרחב השמות במפתח עצמו
|
||||
דוגמה מ-`food.ontology`:
|
||||
```json
|
||||
"classes": {
|
||||
"fo/Recipe": {
|
||||
"uri": "http://purl.org/ontology/fo/Recipe",
|
||||
"rdfs:comment": "A Recipe is a combination..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **בניית הנחיה** (`extract.py:299-307`, `ontology-prompt.md`)
|
||||
התבנית מקבלת מילונים `classes`, `object_properties`, `datatype_properties`
|
||||
התבנית חוזרת: `{% for class_id, class_def in classes.items() %}`
|
||||
מודל השפה (LLM) רואה: `**fo/Recipe**: A Recipe is a combination...`
|
||||
פורמט פלט לדוגמה מציג:
|
||||
```json
|
||||
{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"}
|
||||
{"subject": "recipe:cornish-pasty", "predicate": "has_ingredient", "object": "ingredient:flour"}
|
||||
```
|
||||
|
||||
3. **ניתוח תגובה** (`extract.py:382-428`)
|
||||
מצפה למערך JSON: `[{"subject": "...", "predicate": "...", "object": "..."}]`
|
||||
מאמת מול תת-אונטולוגיה
|
||||
מרחיב URI באמצעות `expand_uri()` (extract.py:473-521)
|
||||
|
||||
4. **הרחבת URI** (`extract.py:473-521`)
|
||||
בודק אם הערך נמצא במילון `ontology_subset.classes`
|
||||
אם נמצא, מחלץ את ה-URI מההגדרה של המחלקה
|
||||
אם לא נמצא, בונה את ה-URI: `f"https://trustgraph.ai/ontology/{ontology_id}#{value}"`
|
||||
|
||||
### דוגמה לזרימת נתונים
|
||||
|
||||
**JSON של אונטולוגיה → Loader → Prompt:**
|
||||
```
|
||||
"fo/Recipe" → classes["fo/Recipe"] → LLM sees "**fo/Recipe**"
|
||||
```
|
||||
|
||||
**מודל שפה גדול → מנתח → פלט:**
|
||||
```
|
||||
"Recipe" → not in classes["fo/Recipe"] → constructs URI → LOSES original URI
|
||||
"fo/Recipe" → found in classes → uses original URI → PRESERVES URI
|
||||
```
|
||||
|
||||
## בעיות שזוהו
|
||||
|
||||
### 1. **דוגמאות לא עקביות בהנחיה**
|
||||
|
||||
**בעיה**: תבנית ההנחיה מציגה מזהי מחלקות עם קידומות (`fo/Recipe`) אך הפלט לדוגמה משתמש בשמות מחלקות ללא קידומות (`Recipe`).
|
||||
|
||||
**מיקום**: `ontology-prompt.md:5-52`
|
||||
|
||||
```markdown
|
||||
## Ontology Classes:
|
||||
- **fo/Recipe**: A Recipe is...
|
||||
|
||||
## Example Output:
|
||||
{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "Recipe"}
|
||||
```
|
||||
|
||||
**השפעה**: מודל השפה הגדול (LLM) מקבל אותות סותרים לגבי הפורמט שיש להשתמש בו.
|
||||
|
||||
### 2. **אובדן מידע בהרחבת כתובות URL**
|
||||
|
||||
**בעיה**: כאשר מודל השפה הגדול (LLM) מחזיר שמות מחלקות ללא קידומת, בהתאם לדוגמה, `expand_uri()` לא יכול למצוא אותם במילון האונטולוגיה ויוצר כתובות URL חלופיות, ובכך מאבד את כתובות ה-URL המקוריות הנכונות.
|
||||
|
||||
**מיקום**: `extract.py:494-500`
|
||||
|
||||
```python
|
||||
if value in ontology_subset.classes: # Looks for "Recipe"
|
||||
class_def = ontology_subset.classes[value] # But key is "fo/Recipe"
|
||||
if isinstance(class_def, dict) and 'uri' in class_def:
|
||||
return class_def['uri'] # Never reached!
|
||||
return f"https://trustgraph.ai/ontology/{ontology_id}#{value}" # Fallback
|
||||
```
|
||||
|
||||
**השפעה:**
|
||||
URI מקורי: `http://purl.org/ontology/fo/Recipe`
|
||||
URI שנוצר: `https://trustgraph.ai/ontology/food#Recipe`
|
||||
אובדן משמעות סמנטית, פוגע בתאימות.
|
||||
|
||||
### 3. **פורמט לא ברור של מופעי ישויות**
|
||||
|
||||
**בעיה:** אין הנחיות ברורות לגבי פורמט ה-URI של מופעי ישויות.
|
||||
|
||||
**דוגמאות בהנחיה:**
|
||||
`"recipe:cornish-pasty"` (קידומת הדומה לשם מרחב)
|
||||
`"ingredient:flour"` (קידומת שונה)
|
||||
|
||||
**התנהגות בפועל** (extract.py:517-520):
|
||||
```python
|
||||
# Treat as entity instance - construct unique URI
|
||||
normalized = value.replace(" ", "-").lower()
|
||||
return f"https://trustgraph.ai/{ontology_id}/{normalized}"
|
||||
```
|
||||
|
||||
**השפעה**: מודל שפה גדול (LLM) חייב לנחש את מוסכמות הקידומת ללא הקשר אונטולוגי.
|
||||
|
||||
### 4. **הנחיות לגבי קידומות מרחבי שמות חסרות**
|
||||
|
||||
**בעיה**: קובץ ה-JSON של האונטולוגיה מכיל הגדרות מרחבי שמות (שורות 10-25 בקובץ food.ontology):
|
||||
```json
|
||||
"namespaces": {
|
||||
"fo": "http://purl.org/ontology/fo/",
|
||||
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
אבל השורות האלה לעולם אינן מוצגות למודל השפה הגדול (LLM). מודל השפה הגדול אינו יודע:
|
||||
מה המשמעות של "fo"
|
||||
איזה קידומת להשתמש עבור ישויות
|
||||
לאיזה מרחב שם מתייחס כל אלמנט
|
||||
|
||||
### 5. **תוויות שאינן משמשות בפרומפט**
|
||||
|
||||
**בעיה**: לכל מחלקה יש שדות `rdfs:label` (לדוגמה, `{"value": "Recipe", "lang": "en-gb"}`), אבל תבנית הפרומפט אינה משתמשת בהם.
|
||||
|
||||
**מצב נוכחי**: מציג רק `class_id` ו-`comment`
|
||||
```jinja
|
||||
- **{{class_id}}**{% if class_def.comment %}: {{class_def.comment}}{% endif %}
|
||||
```
|
||||
|
||||
**זמין אך לא בשימוש:**
|
||||
```python
|
||||
"rdfs:label": [{"value": "Recipe", "lang": "en-gb"}]
|
||||
```
|
||||
|
||||
**השפעה:** יכול לספק שמות קריאים לבני אדם לצד מזהים טכניים.
|
||||
|
||||
## פתרונות מוצעים
|
||||
|
||||
### אפשרות א': נרמול למזהים ללא קידומת
|
||||
|
||||
**גישה:** הסרת קידומות ממזהי מחלקות לפני הצגתם למודל LLM.
|
||||
|
||||
**שינויים:**
|
||||
1. שנה את `build_extraction_variables()` כדי לשנות מפתחות:
|
||||
```python
|
||||
classes_for_prompt = {
|
||||
k.split('/')[-1]: v # "fo/Recipe" → "Recipe"
|
||||
for k, v in ontology_subset.classes.items()
|
||||
}
|
||||
```
|
||||
|
||||
2. עדכון דוגמת ההנחיה כך שתתאים (כבר משתמשת בשמות ללא קידומת).
|
||||
|
||||
3. שינוי `expand_uri()` כדי לטפל בשני הפורמטים:
|
||||
```python
|
||||
# Try exact match first
|
||||
if value in ontology_subset.classes:
|
||||
return ontology_subset.classes[value]['uri']
|
||||
|
||||
# Try with prefix
|
||||
for prefix in ['fo/', 'rdf:', 'rdfs:']:
|
||||
prefixed = f"{prefix}{value}"
|
||||
if prefixed in ontology_subset.classes:
|
||||
return ontology_subset.classes[prefixed]['uri']
|
||||
```
|
||||
|
||||
**יתרונות:**
|
||||
נקי יותר, קריא יותר לבני אדם
|
||||
תואם לדוגמאות קיימות של הנחיות
|
||||
מודלי שפה גדולים (LLMs) עובדים טוב יותר עם טוקנים פשוטים יותר
|
||||
|
||||
**חסרונות:**
|
||||
התנגשויות בשמות מחלקות אם למספר אונטולוגיות יש אותו שם מחלקה
|
||||
מאבד מידע על מרחב השמות
|
||||
דורש לוגיקה חלופית עבור חיפושים
|
||||
|
||||
### אפשרות ב': שימוש עקבי במזהים עם קידומת מלאה
|
||||
|
||||
**גישה:** עדכון הדוגמאות לשימוש במזהים עם קידומת התואמים למה שמוצג ברשימת המחלקות.
|
||||
|
||||
**שינויים:**
|
||||
1. עדכון דוגמת הנחיה (ontology-prompt.md:46-52):
|
||||
```json
|
||||
[
|
||||
{"subject": "recipe:cornish-pasty", "predicate": "rdf:type", "object": "fo/Recipe"},
|
||||
{"subject": "recipe:cornish-pasty", "predicate": "rdfs:label", "object": "Cornish Pasty"},
|
||||
{"subject": "recipe:cornish-pasty", "predicate": "fo/produces", "object": "food:cornish-pasty"},
|
||||
{"subject": "food:cornish-pasty", "predicate": "rdf:type", "object": "fo/Food"}
|
||||
]
|
||||
```
|
||||
|
||||
2. הוספת הסבר על מרחב הnamespaces להנחיה:
|
||||
```markdown
|
||||
## Namespace Prefixes:
|
||||
- **fo/**: Food Ontology (http://purl.org/ontology/fo/)
|
||||
- **rdf:**: RDF Schema
|
||||
- **rdfs:**: RDF Schema
|
||||
|
||||
Use these prefixes exactly as shown when referencing classes and properties.
|
||||
```
|
||||
|
||||
3. שמרו על `expand_uri()` כפי שהוא (עובד כראוי כאשר נמצאו התאמות).
|
||||
|
||||
**יתרונות:**
|
||||
עקביות בין קלט לפלט.
|
||||
ללא אובדן מידע.
|
||||
שומר על סמנטיקת מרחבי השמות.
|
||||
עובד עם מרובות אונטולוגיות.
|
||||
|
||||
**חסרונות:**
|
||||
טוקנים מילוליים יותר עבור מודל שפה גדול (LLM).
|
||||
דורש ממודל השפה הגדול (LLM) לעקוב אחר קידומות.
|
||||
|
||||
### אפשרות ג': היברידית - הצגת תווית ומזהה כאחד.
|
||||
|
||||
**גישה:** שיפור ההנחיה להצגת תוויות קריאות אנוש ומזהים טכניים.
|
||||
|
||||
**שינויים:**
|
||||
1. עדכון תבנית ההנחיה:
|
||||
```jinja
|
||||
{% for class_id, class_def in classes.items() %}
|
||||
- **{{class_id}}** (label: "{{class_def.labels[0].value if class_def.labels else class_id}}"){% if class_def.comment %}: {{class_def.comment}}{% endif %}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
פלט לדוגמה:
|
||||
```markdown
|
||||
- **fo/Recipe** (label: "Recipe"): A Recipe is a combination...
|
||||
```
|
||||
|
||||
2. הוראות עדכון:
|
||||
```markdown
|
||||
When referencing classes:
|
||||
- Use the full prefixed ID (e.g., "fo/Recipe") in JSON output
|
||||
- The label (e.g., "Recipe") is for human understanding only
|
||||
```
|
||||
|
||||
**יתרונות:**
|
||||
הבהרה עבור מודלי שפה גדולים (LLM)
|
||||
שומר על כל המידע
|
||||
מפרט במפורש מה להשתמש
|
||||
|
||||
**חסרונות:**
|
||||
הנחיה ארוכה יותר
|
||||
תבנית מורכבת יותר
|
||||
|
||||
## גישה מיושמת
|
||||
|
||||
**פורמט פשוט של ישות-קשר-תכונה** - מחליף לחלוטין את הפורמט המבוסס על שלישיות הישן.
|
||||
|
||||
הגישה החדשה נבחרה מכיוון:
|
||||
|
||||
1. **ללא אובדן מידע:** כתובות URI מקוריות נשמרות כהלכה
|
||||
2. **לוגיקה פשוטה יותר:** אין צורך בטרנספורמציה, חיפושים ישירים במילון עובדים
|
||||
3. **בטיחות מרחבי שמות:** מטפל במספר אונטולוגיות ללא התנגשויות
|
||||
4. **נכונות סמנטית:** שומר על סמנטיקה של RDF/OWL
|
||||
|
||||
## יישום הושלם
|
||||
|
||||
### מה נבנה:
|
||||
|
||||
1. **תבנית הנחיה חדשה** (`prompts/ontology-extract-v2.txt`)
|
||||
✅ חלקים ברורים: סוגי ישויות, קשרים, תכונות
|
||||
✅ דוגמה תוך שימוש במזהים מלאים של סוגים (`fo/Recipe`, `fo/has_ingredient`)
|
||||
✅ הוראות לשימוש במזהים מדויקים מהסכימה
|
||||
✅ פורמט JSON חדש עם מערכים של ישויות/קשרים/תכונות
|
||||
|
||||
2. **נרמול ישויות** (`entity_normalizer.py`)
|
||||
✅ `normalize_entity_name()` - ממיר שמות לפורמט בטוח ל-URI
|
||||
✅ `normalize_type_identifier()` - מטפל בסלאשים בסוגים (`fo/Recipe` → `fo-recipe`)
|
||||
✅ `build_entity_uri()` - יוצר כתובות URI ייחודיות באמצעות טאפל (שם, סוג)
|
||||
✅ `EntityRegistry` - עוקב אחר ישויות לצורך הסרה כפולה
|
||||
|
||||
3. **מנתח JSON** (`simplified_parser.py`)
|
||||
✅ מנתח את הפורמט החדש: `{entities: [...], relationships: [...], attributes: [...]}`
|
||||
✅ תומך בשמות שדות בפורמט kebab-case ו-snake_case
|
||||
✅ מחזיר מחלקות נתונים מובנות
|
||||
✅ טיפול בשגיאות בצורה חלקה עם רישום
|
||||
|
||||
4. **ממיר שלישיות** (`triple_converter.py`)
|
||||
✅ `convert_entity()` - מייצר באופן אוטומטי שלישיות של סוג + תווית
|
||||
✅ `convert_relationship()` - מחבר כתובות URI של ישויות באמצעות מאפיינים
|
||||
✅ `convert_attribute()` - מוסיף ערכים מילוליים
|
||||
✅ מחפש כתובות URI מלאות מהגדרות האונטולוגיה
|
||||
|
||||
5. **מעבד ראשי מעודכן** (`extract.py`)
|
||||
✅ הסר קוד חילוץ ישן מבוסס על שלישיות
|
||||
✅ הוסף שיטה `extract_with_simplified_format()`
|
||||
✅ משתמש כעת אך ורק בפורמט הפשוט החדש
|
||||
✅ קורא להנחיה עם מזהה `extract-with-ontologies-v2`
|
||||
|
||||
## מקרי בדיקה
|
||||
|
||||
### בדיקה 1: שימור כתובות URI
|
||||
```python
|
||||
# Given ontology class
|
||||
classes = {"fo/Recipe": {"uri": "http://purl.org/ontology/fo/Recipe", ...}}
|
||||
|
||||
# When LLM returns
|
||||
llm_output = {"subject": "x", "predicate": "rdf:type", "object": "fo/Recipe"}
|
||||
|
||||
# Then expanded URI should be
|
||||
assert expanded == "http://purl.org/ontology/fo/Recipe"
|
||||
# Not: "https://trustgraph.ai/ontology/food#Recipe"
|
||||
```
|
||||
|
||||
### מבחן 2: התנגשות בין מרובי אונטולוגיות
|
||||
```python
|
||||
# Given two ontologies
|
||||
ont1 = {"fo/Recipe": {...}}
|
||||
ont2 = {"cooking/Recipe": {...}}
|
||||
|
||||
# LLM should use full prefix to disambiguate
|
||||
llm_output = {"object": "fo/Recipe"} # Not just "Recipe"
|
||||
```
|
||||
|
||||
### מבחן 3: פורמט של מופע ישות
|
||||
```python
|
||||
# Given prompt with food ontology
|
||||
# LLM should create instances like
|
||||
{"subject": "recipe:cornish-pasty"} # Namespace-style
|
||||
{"subject": "food:beef"} # Consistent prefix
|
||||
```
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
1. **האם יש להשתמש בתוספות מרחב שם עבור מופעי ישויות?**
|
||||
נוכחי: `"recipe:cornish-pasty"` (שרירותי)
|
||||
חלופה: להשתמש בתוסף אוֹנוֹטוֹלוֹגיה `"fo:cornish-pasty"`?
|
||||
חלופה: ללא תוסף, להרחיב ב-URI `"cornish-pasty"` → URI מלא?
|
||||
|
||||
2. **כיצד לטפל בתחום/טווח בפרומפט?**
|
||||
מוצג כעת: `(Recipe → Food)`
|
||||
האם זה צריך להיות: `(fo/Recipe → fo/Food)`?
|
||||
|
||||
3. **האם עלינו לאמת אילוצי תחום/טווח?**
|
||||
הערה TODO ב-extract.py:470
|
||||
יתפוס יותר שגיאות אך מורכב יותר
|
||||
|
||||
4. **מה לגבי תכונות הפוכות ושקילות?**
|
||||
לאוֹנוֹטוֹלוֹגיה יש `owl:inverseOf`, `owl:equivalentClass`
|
||||
לא בשימוש כרגע בחילוץ
|
||||
האם הם צריכים להיות בשימוש?
|
||||
|
||||
## מדדי הצלחה
|
||||
|
||||
✅ אפס אובדן מידע URI (שימור של 100% מה-URIs המקוריים)
|
||||
✅ פורמט הפלט של ה-LLM תואם לפורמט הקלט
|
||||
✅ אין דוגמאות מעורפלות בפרומפט
|
||||
✅ הבדיקות עוברות עם אוֹנוֹטוֹלוֹגיות מרובות
|
||||
✅ שיפור באיכות החילוץ (נמדד על ידי אחוז משולשות חוקיות)
|
||||
|
||||
## גישה חלופית: פורמט חילוץ מפושט
|
||||
|
||||
### פילוסופיה
|
||||
|
||||
במקום לבקש מה-LLM להבין סמנטיקה של RDF/OWL, לבקש ממנו לעשות את מה שהוא טוב בו: **למצוא ישויות ויחסים בטקסט**.
|
||||
|
||||
תן לקוד לטפל בבניית URI, המרת RDF ופורמליות של רשת סמנטית.
|
||||
|
||||
### דוגמה: סיווג ישויות
|
||||
|
||||
**טקסט קלט:**
|
||||
```
|
||||
Cornish pasty is a traditional British pastry filled with meat and vegetables.
|
||||
```
|
||||
|
||||
**סכימת אונטולוגיה (מוצגת למודל שפה גדול):**
|
||||
```markdown
|
||||
## Entity Types:
|
||||
- Recipe: A recipe is a combination of ingredients and a method
|
||||
- Food: A food is something that can be eaten
|
||||
- Ingredient: An ingredient combines a quantity and a food
|
||||
```
|
||||
|
||||
**מה שהמודל השפה הגדול מחזיר (JSON פשוט):**
|
||||
```json
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"entity": "Cornish pasty",
|
||||
"type": "Recipe"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**מה הקוד מייצר (משולשי RDF):**
|
||||
```python
|
||||
# 1. Normalize entity name + type to ID (type prevents collisions)
|
||||
entity_id = "recipe-cornish-pasty" # normalize("Cornish pasty", "Recipe")
|
||||
entity_uri = "https://trustgraph.ai/food/recipe-cornish-pasty"
|
||||
|
||||
# Note: Same name, different type = different URI
|
||||
# "Cornish pasty" (Recipe) → recipe-cornish-pasty
|
||||
# "Cornish pasty" (Food) → food-cornish-pasty
|
||||
|
||||
# 2. Generate triples
|
||||
triples = [
|
||||
# Type triple
|
||||
Triple(
|
||||
s=Value(value=entity_uri, is_uri=True),
|
||||
p=Value(value="http://www.w3.org/1999/02/22-rdf-syntax-ns#type", is_uri=True),
|
||||
o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True)
|
||||
),
|
||||
# Label triple (automatic)
|
||||
Triple(
|
||||
s=Value(value=entity_uri, is_uri=True),
|
||||
p=Value(value="http://www.w3.org/2000/01/rdf-schema#label", is_uri=True),
|
||||
o=Value(value="Cornish pasty", is_uri=False)
|
||||
)
|
||||
]
|
||||
```
|
||||
|
||||
### יתרונות
|
||||
|
||||
1. **מודל שפה גדול (LLM) לא צריך:**
|
||||
להבין תחביר URI
|
||||
להמציא קידומות מזהות (`recipe:`, `ingredient:`)
|
||||
לדעת על `rdf:type` או `rdfs:label`
|
||||
לבנות מזהי רשת סמנטית
|
||||
|
||||
2. **מודל שפה גדול (LLM) צריך רק:**
|
||||
למצוא ישויות בטקסט
|
||||
למפות אותן למחלקות אונטולוגיה
|
||||
לחלץ קשרים ומאפיינים
|
||||
|
||||
3. **הקוד מטפל ב:**
|
||||
נרמול ובניית URI
|
||||
יצירת משולשות RDF
|
||||
הקצאת תוויות אוטומטית
|
||||
ניהול מרחבי שמות
|
||||
|
||||
### למה זה עובד טוב יותר
|
||||
|
||||
**שאילתה פשוטה יותר** = פחות בלבול = פחות שגיאות
|
||||
**מזהים עקביים** = הקוד שולט בכללי הנרמול
|
||||
**תוויות שנוצרו אוטומטית** = אין משולשות rdfs:label חסרות
|
||||
**מודל שפה גדול מתמקד בחילוץ** = במה שהוא באמת טוב
|
||||
|
||||
### דוגמה: קשרי ישויות
|
||||
|
||||
**טקסט קלט:**
|
||||
```
|
||||
Cornish pasty is a traditional British pastry filled with beef and potatoes.
|
||||
```
|
||||
|
||||
**סכימת אונטולוגיה (מוצגת למודל שפה גדול):**
|
||||
```markdown
|
||||
## Entity Types:
|
||||
- Recipe: A recipe is a combination of ingredients and a method
|
||||
- Food: A food is something that can be eaten
|
||||
- Ingredient: An ingredient combines a quantity and a food
|
||||
|
||||
## Relationships:
|
||||
- has_ingredient: Relates a recipe to an ingredient it uses (Recipe → Ingredient)
|
||||
- food: Relates an ingredient to the food that is required (Ingredient → Food)
|
||||
```
|
||||
|
||||
**מה שהמודל השפה הגדול מחזיר (JSON פשוט):**
|
||||
```json
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"entity": "Cornish pasty",
|
||||
"type": "Recipe"
|
||||
},
|
||||
{
|
||||
"entity": "beef",
|
||||
"type": "Food"
|
||||
},
|
||||
{
|
||||
"entity": "potatoes",
|
||||
"type": "Food"
|
||||
}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"subject": "Cornish pasty",
|
||||
"subject-type": "Recipe",
|
||||
"relation": "has_ingredient",
|
||||
"object": "beef",
|
||||
"object-type": "Food"
|
||||
},
|
||||
{
|
||||
"subject": "Cornish pasty",
|
||||
"subject-type": "Recipe",
|
||||
"relation": "has_ingredient",
|
||||
"object": "potatoes",
|
||||
"object-type": "Food"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**מה הקוד מייצר (משולשי RDF):**
|
||||
```python
|
||||
# Normalize entity names to URIs
|
||||
cornish_pasty_uri = "https://trustgraph.ai/food/cornish-pasty"
|
||||
beef_uri = "https://trustgraph.ai/food/beef"
|
||||
potatoes_uri = "https://trustgraph.ai/food/potatoes"
|
||||
|
||||
# Look up relation URI from ontology
|
||||
has_ingredient_uri = "http://purl.org/ontology/fo/ingredients" # from fo/has_ingredient
|
||||
|
||||
triples = [
|
||||
# Entity type triples (as before)
|
||||
Triple(s=cornish_pasty_uri, p=rdf_type, o="http://purl.org/ontology/fo/Recipe"),
|
||||
Triple(s=cornish_pasty_uri, p=rdfs_label, o="Cornish pasty"),
|
||||
|
||||
Triple(s=beef_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"),
|
||||
Triple(s=beef_uri, p=rdfs_label, o="beef"),
|
||||
|
||||
Triple(s=potatoes_uri, p=rdf_type, o="http://purl.org/ontology/fo/Food"),
|
||||
Triple(s=potatoes_uri, p=rdfs_label, o="potatoes"),
|
||||
|
||||
# Relationship triples
|
||||
Triple(
|
||||
s=Value(value=cornish_pasty_uri, is_uri=True),
|
||||
p=Value(value=has_ingredient_uri, is_uri=True),
|
||||
o=Value(value=beef_uri, is_uri=True)
|
||||
),
|
||||
Triple(
|
||||
s=Value(value=cornish_pasty_uri, is_uri=True),
|
||||
p=Value(value=has_ingredient_uri, is_uri=True),
|
||||
o=Value(value=potatoes_uri, is_uri=True)
|
||||
)
|
||||
]
|
||||
```
|
||||
|
||||
**נקודות עיקריות:**
|
||||
מודל שפה גדול (LLM) מחזיר שמות של ישויות בשפה טבעית: `"Cornish pasty"`, `"beef"`, `"potatoes"`
|
||||
מודל שפה גדול (LLM) כולל סוגים כדי להבהיר: `subject-type`, `object-type`
|
||||
מודל שפה גדול (LLM) משתמש בשם היחס מהסכימה: `"has_ingredient"`
|
||||
הקוד מייצר מזהים עקביים באמצעות (שם, סוג): `("Cornish pasty", "Recipe")` → `recipe-cornish-pasty`
|
||||
הקוד מחפש את ה-URI של היחס מהאונטולוגיה: `fo/has_ingredient` → URI מלא
|
||||
אותה טופל (שם, סוג) תמיד מקבל את אותו ה-URI (הסרה כפילות)
|
||||
|
||||
### דוגמה: הבחנה בין שמות של ישויות
|
||||
|
||||
**בעיה:** אותו שם יכול להתייחס לסוגי ישויות שונים.
|
||||
|
||||
**מקרה אמיתי:**
|
||||
```
|
||||
"Cornish pasty" can be:
|
||||
- A Recipe (instructions for making it)
|
||||
- A Food (the dish itself)
|
||||
```
|
||||
|
||||
**כיצד זה מטופל:**
|
||||
|
||||
מודל שפה גדול (LLM) מחזיר את שניהם כיחידות נפרדות:
|
||||
```json
|
||||
{
|
||||
"entities": [
|
||||
{"entity": "Cornish pasty", "type": "Recipe"},
|
||||
{"entity": "Cornish pasty", "type": "Food"}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"subject": "Cornish pasty",
|
||||
"subject-type": "Recipe",
|
||||
"relation": "produces",
|
||||
"object": "Cornish pasty",
|
||||
"object-type": "Food"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**פתרון קוד:**
|
||||
```python
|
||||
# Different types → different URIs
|
||||
recipe_uri = normalize("Cornish pasty", "Recipe")
|
||||
# → "https://trustgraph.ai/food/recipe-cornish-pasty"
|
||||
|
||||
food_uri = normalize("Cornish pasty", "Food")
|
||||
# → "https://trustgraph.ai/food/food-cornish-pasty"
|
||||
|
||||
# Relationship connects them correctly
|
||||
triple = Triple(
|
||||
s=recipe_uri, # The Recipe
|
||||
p="http://purl.org/ontology/fo/produces",
|
||||
o=food_uri # The Food
|
||||
)
|
||||
```
|
||||
|
||||
**מדוע זה עובד:**
|
||||
הסוג כלול בכל ההפניות (ישויות, קשרים, תכונות)
|
||||
הקוד משתמש בטופל `(name, type)` כמפתח חיפוש
|
||||
אין דו-משמעות, אין התנגשויות
|
||||
|
||||
### דוגמה: תכונות של ישויות
|
||||
|
||||
**טקסט קלט:**
|
||||
```
|
||||
This Cornish pasty recipe serves 4-6 people and takes 45 minutes to prepare.
|
||||
```
|
||||
|
||||
**סכימת אונטולוגיה (מוצגת למודל שפה גדול):**
|
||||
```markdown
|
||||
## Entity Types:
|
||||
- Recipe: A recipe is a combination of ingredients and a method
|
||||
|
||||
## Attributes:
|
||||
- serves: Indicates what the recipe is intended to serve (Recipe → text)
|
||||
- preparation_time: Time needed to prepare the recipe (Recipe → text)
|
||||
```
|
||||
|
||||
**מה שהמודל השפה הגדול מחזיר (JSON פשוט):**
|
||||
```json
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"entity": "Cornish pasty recipe",
|
||||
"type": "Recipe"
|
||||
}
|
||||
],
|
||||
"attributes": [
|
||||
{
|
||||
"entity": "Cornish pasty recipe",
|
||||
"entity-type": "Recipe",
|
||||
"attribute": "serves",
|
||||
"value": "4-6 people"
|
||||
},
|
||||
{
|
||||
"entity": "Cornish pasty recipe",
|
||||
"entity-type": "Recipe",
|
||||
"attribute": "preparation_time",
|
||||
"value": "45 minutes"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**מה הקוד מייצר (משולשים RDF):**
|
||||
```python
|
||||
# Normalize entity name to URI
|
||||
recipe_uri = "https://trustgraph.ai/food/cornish-pasty-recipe"
|
||||
|
||||
# Look up attribute URIs from ontology
|
||||
serves_uri = "http://purl.org/ontology/fo/serves" # from fo/serves
|
||||
prep_time_uri = "http://purl.org/ontology/fo/preparation_time" # from fo/preparation_time
|
||||
|
||||
triples = [
|
||||
# Entity type triple
|
||||
Triple(
|
||||
s=Value(value=recipe_uri, is_uri=True),
|
||||
p=Value(value=rdf_type, is_uri=True),
|
||||
o=Value(value="http://purl.org/ontology/fo/Recipe", is_uri=True)
|
||||
),
|
||||
|
||||
# Label triple (automatic)
|
||||
Triple(
|
||||
s=Value(value=recipe_uri, is_uri=True),
|
||||
p=Value(value=rdfs_label, is_uri=True),
|
||||
o=Value(value="Cornish pasty recipe", is_uri=False)
|
||||
),
|
||||
|
||||
# Attribute triples (objects are literals, not URIs)
|
||||
Triple(
|
||||
s=Value(value=recipe_uri, is_uri=True),
|
||||
p=Value(value=serves_uri, is_uri=True),
|
||||
o=Value(value="4-6 people", is_uri=False) # Literal value!
|
||||
),
|
||||
Triple(
|
||||
s=Value(value=recipe_uri, is_uri=True),
|
||||
p=Value(value=prep_time_uri, is_uri=True),
|
||||
o=Value(value="45 minutes", is_uri=False) # Literal value!
|
||||
)
|
||||
]
|
||||
```
|
||||
|
||||
**נקודות עיקריות:**
|
||||
מודל שפה גדול (LLM) מחלץ ערכים מילוליים: `"4-6 people"`, `"45 minutes"`
|
||||
מודל שפה גדול (LLM) כולל סוג ישות לצורך הבחנה: `entity-type`
|
||||
מודל שפה גדול (LLM) משתמש בשם תכונה מהסכימה: `"serves"`, `"preparation_time"`
|
||||
הקוד מחפש את ה-URI של התכונה ממאפייני סוג הנתונים של האונטולוגיה
|
||||
**האובייקט הוא מילולי** (`is_uri=False`), ולא הפניה ל-URI
|
||||
הערכים נשארים כטקסט רגיל, אין צורך בנרמול
|
||||
|
||||
**ההבדל מיחסים:**
|
||||
יחסים: גם הנושא וגם האובייקט הם ישויות (URIs)
|
||||
תכונות: הנושא הוא ישות (URI), האובייקט הוא ערך מילולי (מחרוזת/מספר)
|
||||
|
||||
### דוגמה מלאה: ישויות + יחסים + תכונות
|
||||
|
||||
**טקסט קלט:**
|
||||
```
|
||||
Cornish pasty is a savory pastry filled with beef and potatoes.
|
||||
This recipe serves 4 people.
|
||||
```
|
||||
|
||||
**מה מודל שפה גדול מחזיר:**
|
||||
```json
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"entity": "Cornish pasty",
|
||||
"type": "Recipe"
|
||||
},
|
||||
{
|
||||
"entity": "beef",
|
||||
"type": "Food"
|
||||
},
|
||||
{
|
||||
"entity": "potatoes",
|
||||
"type": "Food"
|
||||
}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"subject": "Cornish pasty",
|
||||
"subject-type": "Recipe",
|
||||
"relation": "has_ingredient",
|
||||
"object": "beef",
|
||||
"object-type": "Food"
|
||||
},
|
||||
{
|
||||
"subject": "Cornish pasty",
|
||||
"subject-type": "Recipe",
|
||||
"relation": "has_ingredient",
|
||||
"object": "potatoes",
|
||||
"object-type": "Food"
|
||||
}
|
||||
],
|
||||
"attributes": [
|
||||
{
|
||||
"entity": "Cornish pasty",
|
||||
"entity-type": "Recipe",
|
||||
"attribute": "serves",
|
||||
"value": "4 people"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**תוצאה:** נוצרו 11 משולשים של RDF:
|
||||
3 משולשים מסוג ישות (rdf:type)
|
||||
3 משולשים של תווית ישות (rdfs:label) - אוטומטי
|
||||
2 משולשים של קשר (has_ingredient)
|
||||
משולש אחד של תכונה (serves)
|
||||
|
||||
הכל נוצר מחילוץ פשוט משפה טבעית על ידי מודל השפה הגדול!
|
||||
|
||||
## הפניות
|
||||
|
||||
יישום נוכחי: `trustgraph-flow/trustgraph/extract/kg/ontology/extract.py`
|
||||
תבנית הנחיה: `ontology-prompt.md`
|
||||
מקרים בדיקה: `tests/unit/test_extract/test_ontology/`
|
||||
אונטולוגיה לדוגמה: `e2e/test-data/food.ontology`
|
||||
208
docs/tech-specs/he/ontology.he.md
Normal file
208
docs/tech-specs/he/ontology.he.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מבנה אונטולוגי - מפרט טכני"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מבנה אונטולוגי - מפרט טכני
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר את המבנה והפורמט של אונטולוגיות במערכת TrustGraph. אונטולוגיות מספקות מודלים פורמליים של ידע המגדירים מחלקות, תכונות ויחסים, ומאפשרים יכולות של הסקה והסקת מסקנות. המערכת משתמשת בפורמט תצורה השואב השראה מ-OWL, ומייצג באופן כללי מושגי OWL/RDFS תוך התאמה לדרישות של TrustGraph.
|
||||
|
||||
**נוהל שמות:** הפרויקט משתמש בפורמט "קאב-קייז" (kebab-case) לכל המזהים (מפתחות תצורה, נקודות קצה של API, שמות מודולים, וכו') במקום "סנקה_קייז" (snake_case).
|
||||
|
||||
## מטרות
|
||||
|
||||
- **ניהול מחלקות ותכונות:** הגדרת מחלקות "דו-צורתיות" עם תכונות, תחומים, טווחי ערכים ומגבלות סוג
|
||||
- **תמיכה סמנטית עשירה:** אפשרות לתכונות RDFS/OWL מקיפות, כולל תוויות, תמיכה רב-לשונית ומגבלות פורמליות
|
||||
- **תמיכה באונטולוגיות מרובות:** אפשרות לאונטולוגיות מרובות להתקיים ולפעול יחד
|
||||
- **אימות והסקה:** הבטחת עמידה של האונטולוגיות בתקנים דמויי-OWL תוך בדיקות עקביות ותמיכה בהסקה
|
||||
- **תאימות לתקנים:** תמיכה בייבוא/ייצוא בפורמטים סטנדרטיים (Turtle, RDF/XML, OWL/XML) תוך שמירה על אופטימיזציה פנימית
|
||||
|
||||
## רקע
|
||||
|
||||
TrustGraph מאחסן אונטולוגיות כפריטים תצורה במערכת מבוססת מפתח-ערך גמישה. למרות שהפורמט מושפע מ-OWL (שפת אונטולוגיה ווב), הוא מותאם במיוחד לשימושים הספציפיים של TrustGraph ואינו עומד במלואן בכל המפרטים של OWL.
|
||||
|
||||
אונטולוגיות ב-TrustGraph מאפשרות:
|
||||
- הגדרה של סוגי אובייקט פורמליים והתכונות שלהם
|
||||
- הגדרה של תחומים, טווחי ערכים ומגבלות סוג
|
||||
- הסקה וסקת מסקנות
|
||||
- יחסים מורכבים ומגבלות כמותיות
|
||||
- תמיכה רב-לשונית לבינלאומיות
|
||||
|
||||
## מבנה אונטולוגי
|
||||
|
||||
### אחסון תצורה
|
||||
|
||||
אונטולוגיות מאוחסנות כפריטי תצורה עם התבנית הבאה:
|
||||
- **סוג:** `ontology`
|
||||
- **מפתח:** מזהה אונטולוגי ייחודי (למשל, `natural-world`, `domain-model`)
|
||||
- **ערך:** האונטולוגיה השלמה בפורמט JSON
|
||||
|
||||
### מבנה JSON
|
||||
|
||||
פורמט ה-JSON של האונטולוגיה מורכב מארבעה חלקים עיקריים:
|
||||
|
||||
#### 1. מטא-נתונים
|
||||
|
||||
מכיל מידע ניהולי ותיאורי על האונטולוגיה:
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"name": "העולם הטבעי",
|
||||
"description": "אונטולוגיה המכסה את הסדר הטבעי",
|
||||
"version": "1.0.0",
|
||||
"created": "2025-09-20T12:07:37.068Z",
|
||||
"modified": "2025-09-20T12:12:20.725Z",
|
||||
"creator": "משתמש נוכחי",
|
||||
"namespace": "http://trustgraph.ai/ontologies/natural-world",
|
||||
"imports": ["http://www.w3.org/2002/07/owl#"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**שדות:**
|
||||
- `name`: שם אנושי של האונטולוגיה
|
||||
- `description`: תיאור קצר של מטרת האונטולוגיה
|
||||
- `version`: מספר גרסה סמנטי
|
||||
- `created`: תאריך ושעה של יצירה בפורמט ISO 8601
|
||||
- `modified`: תאריך ושעה של העדכון האחרון בפורמט ISO 8601
|
||||
- `creator`: מזהה המשתמש/מערכת שיוצרת
|
||||
- `namespace`: URI בסיסי עבור אלמנטי האונטולוגיה
|
||||
- `imports`: מערך של URI של אונטולוגיות ייבוא
|
||||
|
||||
#### 2. מחלקות
|
||||
|
||||
מגדיר סוגי אובייקט ויחסים היררכיים:
|
||||
|
||||
```json
|
||||
{
|
||||
"classes": {
|
||||
"animal": {
|
||||
"uri": "http://trustgraph.ai/ontologies/natural-world#animal",
|
||||
"type": "owl:Class",
|
||||
"rdfs:label": [{"value": "Animal", "lang": "en"}],
|
||||
"rdfs:comment": "בעל חיים",
|
||||
"rdfs:subClassOf": "lifeform"
|
||||
},
|
||||
"cat": {
|
||||
"uri": "http://trustgraph.ai/ontologies/natural-world#cat",
|
||||
"type": "owl:Class",
|
||||
"rdfs:label": [{"value": "Cat", "lang": "en"}],
|
||||
"rdfs:comment": "חתול",
|
||||
"rdfs:subClassOf": "animal"
|
||||
},
|
||||
"dog": {
|
||||
"uri": "http://trustgraph.ai/ontologies/natural-world#dog",
|
||||
"type": "owl:Class",
|
||||
"rdfs:label": [{"value": "Dog", "lang": "en"}],
|
||||
"rdfs:comment": "כלב",
|
||||
"rdfs:subClassOf": "animal",
|
||||
"owl:disjointWith": ["cat"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. תכונות
|
||||
|
||||
מגדיר יחסים בין מחלקות:
|
||||
|
||||
```json
|
||||
{
|
||||
"objectProperties": {},
|
||||
"datatypeProperties": {
|
||||
"number-of-legs": {
|
||||
"uri": "http://trustgraph.ai/ontologies/natural-world#number-of-legs",
|
||||
"type": "owl:DatatypeProperty",
|
||||
"rdfs:label": [{"value": "number-of-legs", "lang": "en"}],
|
||||
"rdfs:comment": "ספירת הרגלי הבעל חיים",
|
||||
"rdfs:range": "xsd:nonNegativeInteger",
|
||||
"rdfs:domain": "animal"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. קובץ JSON לדוגמה (סגנון)
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"name": "אונטולוגיית בעלי חיים",
|
||||
"version": "1.0",
|
||||
"description": "אונטולוגיה המגדירה סוגי בעלי חיים",
|
||||
"created": "2024-01-01T00:00:00Z",
|
||||
"modified": "2024-01-01T00:00:00Z",
|
||||
"creator": "המשתמש"
|
||||
},
|
||||
"classes": {
|
||||
"בעל חיים": {
|
||||
"uri": "http://example.com/animals#Animal",
|
||||
"type": "owl:Class",
|
||||
"rdfs:label": {
|
||||
"value": "בעל חיים",
|
||||
"lang": "en"
|
||||
}
|
||||
},
|
||||
"חתול": {
|
||||
"uri": "http://example.com/animals#Cat",
|
||||
"type": "owl:Class",
|
||||
"rdfs:label": {
|
||||
"value": "חתול",
|
||||
"lang": "en"
|
||||
},
|
||||
"rdfs:subClassOf": "בעל חיים"
|
||||
},
|
||||
"כלב": {
|
||||
"uri": "http://example.com/animals#Dog",
|
||||
"type": "owl:Class",
|
||||
"rdfs:label": {
|
||||
"value": "כלב",
|
||||
"lang": "en"
|
||||
},
|
||||
"rdfs:subClassOf": "בעל חיים",
|
||||
"owl:disjointWith": [
|
||||
"חתול"
|
||||
]
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"hasBody": {
|
||||
"type": "owl:ObjectProperty",
|
||||
"domain": "בעל חיים",
|
||||
"range": "http://example.com/things#Body"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## כללי אימות
|
||||
|
||||
### אימות מבני
|
||||
|
||||
1. **עקביות URI:** כל ה-URI צריכים להיות בפורמט `{namespace}#{identifier}`
|
||||
2. **היררכיית מחלקות:** אין ירושה מעגלית ב-`rdfs:subClassOf`
|
||||
3. **תחומים/טווח תכונות:** צריכים להתייחס למחלקות קיימות או לסוגי XSD תקינים
|
||||
4. **מחלקות חופפות:** לא יכולות להיות תחת מחלקות אחרות
|
||||
5. **תכונות דו-כיוניות:** אם מצוינות, חייבות להיות דו-כיוניות
|
||||
|
||||
### אימות סמנטי
|
||||
|
||||
1. **מזהים ייחודיים:** מזהי מחלקות ותכונות צריכים להיות ייחודיים באונטולוגיה
|
||||
2. **תוויות שפה:** צריכות להיות בפורמט BCP 47
|
||||
3. **מגבלות כמותיות:** `minCardinality` ≤ `maxCardinality` כאשר שניהם מצוינים
|
||||
4. **תכונות פונקציונליות:** לא צריכות להכיל `maxCardinality` > 1
|
||||
|
||||
## תמיכה בפורמט ייבוא/ייצוא
|
||||
|
||||
למרות שהפורמט הפנימי הוא JSON, המערכת תומכת בהמרה בין פורמטים סטנדרטיים של אונטולוגיות:
|
||||
|
||||
- **Turtle (.ttl)** - פורמט RDF קומפקטי
|
||||
- **RDF/XML (.rdf, .owl)** - פורמט W3C סטנדרטי
|
||||
- **OWL/XML (.owx)** - פורמט OWL ספציפי ל-XML
|
||||
- **JSON-LD (.jsonld)** - JSON עבור נתונים מקושרים
|
||||
1075
docs/tech-specs/he/ontorag.he.md
Normal file
1075
docs/tech-specs/he/ontorag.he.md
Normal file
File diff suppressed because it is too large
Load diff
239
docs/tech-specs/he/openapi-spec.he.md
Normal file
239
docs/tech-specs/he/openapi-spec.he.md
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט OpenAPI - מפרט טכני"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט OpenAPI - מפרט טכני
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## מטרה
|
||||
|
||||
ליצור מפרט OpenAPI 3.1 מקיף ומודולרי עבור שער ה-API של TrustGraph REST, אשר:
|
||||
מתעד את כל נקודות הקצה של REST
|
||||
משתמש בקוד חיצוני `$ref` לצורך מודולריות ותחזוקה
|
||||
מתאים ישירות לקוד מתרגם ההודעות
|
||||
מספק סכימות מדויקות של בקשות/תגובות
|
||||
|
||||
## מקור האמת
|
||||
|
||||
ה-API מוגדר על ידי:
|
||||
**מתרגמי הודעות**: `trustgraph-base/trustgraph/messaging/translators/*.py`
|
||||
**מנהל ה-Dispatcher**: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py`
|
||||
**מנהל נקודות הקצה**: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py`
|
||||
|
||||
## מבנה תיקיות
|
||||
|
||||
```
|
||||
openapi/
|
||||
├── openapi.yaml # Main entry point
|
||||
├── paths/
|
||||
│ ├── config.yaml # Global services
|
||||
│ ├── flow.yaml
|
||||
│ ├── librarian.yaml
|
||||
│ ├── knowledge.yaml
|
||||
│ ├── collection-management.yaml
|
||||
│ ├── flow-services/ # Flow-hosted services
|
||||
│ │ ├── agent.yaml
|
||||
│ │ ├── document-rag.yaml
|
||||
│ │ ├── graph-rag.yaml
|
||||
│ │ ├── text-completion.yaml
|
||||
│ │ ├── prompt.yaml
|
||||
│ │ ├── embeddings.yaml
|
||||
│ │ ├── mcp-tool.yaml
|
||||
│ │ ├── triples.yaml
|
||||
│ │ ├── objects.yaml
|
||||
│ │ ├── nlp-query.yaml
|
||||
│ │ ├── structured-query.yaml
|
||||
│ │ ├── structured-diag.yaml
|
||||
│ │ ├── graph-embeddings.yaml
|
||||
│ │ ├── document-embeddings.yaml
|
||||
│ │ ├── text-load.yaml
|
||||
│ │ └── document-load.yaml
|
||||
│ ├── import-export/
|
||||
│ │ ├── core-import.yaml
|
||||
│ │ ├── core-export.yaml
|
||||
│ │ └── flow-import-export.yaml # WebSocket import/export
|
||||
│ ├── websocket.yaml
|
||||
│ └── metrics.yaml
|
||||
├── components/
|
||||
│ ├── schemas/
|
||||
│ │ ├── config/
|
||||
│ │ ├── flow/
|
||||
│ │ ├── librarian/
|
||||
│ │ ├── knowledge/
|
||||
│ │ ├── collection/
|
||||
│ │ ├── ai-services/
|
||||
│ │ ├── common/
|
||||
│ │ └── errors/
|
||||
│ ├── parameters/
|
||||
│ ├── responses/
|
||||
│ └── examples/
|
||||
└── security/
|
||||
└── bearerAuth.yaml
|
||||
```
|
||||
|
||||
## מיפוי שירותים
|
||||
|
||||
### שירותים גלובליים (`/api/v1/{kind}`)
|
||||
`config` - ניהול תצורה
|
||||
`flow` - מחזור חיים של זרימה
|
||||
`librarian` - ספריית מסמכים
|
||||
`knowledge` - ליבות ידע
|
||||
`collection-management` - מטא-דאטה של אוסף
|
||||
|
||||
### שירותים המאוחסנים בתוך זרימה (Flow-Hosted Services) (`/api/v1/flow/{flow}/service/{kind}`)
|
||||
|
||||
**בקשה/תגובה:**
|
||||
`agent`, `text-completion`, `prompt`, `mcp-tool`
|
||||
`graph-rag`, `document-rag`
|
||||
`embeddings`, `graph-embeddings`, `document-embeddings`
|
||||
`triples`, `objects`, `nlp-query`, `structured-query`, `structured-diag`
|
||||
|
||||
**שליחה והתעלמות (Fire-and-Forget):**
|
||||
`text-load`, `document-load`
|
||||
|
||||
### ייבוא/ייצוא
|
||||
`/api/v1/import-core` (POST)
|
||||
`/api/v1/export-core` (GET)
|
||||
`/api/v1/flow/{flow}/import/{kind}` (WebSocket)
|
||||
`/api/v1/flow/{flow}/export/{kind}` (WebSocket)
|
||||
|
||||
### אחר
|
||||
`/api/v1/socket` (WebSocket מרובה)
|
||||
`/api/metrics` (Prometheus)
|
||||
|
||||
## גישה
|
||||
|
||||
### שלב 1: הגדרה
|
||||
1. צור מבנה תיקיות
|
||||
2. צור את הקובץ הראשי `openapi.yaml` עם מטא-דאטה, שרתים, אבטחה
|
||||
3. צור רכיבים שניתנים לשימוש חוזר (שגיאות, פרמטרים נפוצים, סכימות אבטחה)
|
||||
|
||||
### שלב 2: סכימות נפוצות
|
||||
צור סכימות משותפות המשמשות בכל השירותים:
|
||||
`RdfValue`, `Triple` - מבני RDF/טריפל
|
||||
`ErrorObject` - תגובת שגיאה
|
||||
`DocumentMetadata`, `ProcessingMetadata` - מבני מטא-דאטה
|
||||
פרמטרים נפוצים: `FlowId`, `User`, `Collection`
|
||||
|
||||
### שלב 3: שירותים גלובליים
|
||||
עבור כל שירות גלובלי (תצורה, זרימה, ספרן, ידע, ניהול אוסף):
|
||||
1. צור קובץ נתיב ב-`paths/`
|
||||
2. צור סכימת בקשה ב-`components/schemas/{service}/`
|
||||
3. צור סכימת תגובה
|
||||
4. הוסף דוגמאות
|
||||
5. הפנה מהקובץ הראשי `openapi.yaml`
|
||||
|
||||
### שלב 4: שירותים המאוחסנים בתוך זרימה
|
||||
עבור כל שירות המאוחסן בתוך זרימה:
|
||||
1. צור קובץ נתיב ב-`paths/flow-services/`
|
||||
2. צור סכימות בקשה/תגובה ב-`components/schemas/ai-services/`
|
||||
3. הוסף תיעוד לדגל סטרימינג במידת הצורך
|
||||
4. הפנה מהקובץ הראשי `openapi.yaml`
|
||||
|
||||
### שלב 5: ייבוא/ייצוא ו-WebSocket
|
||||
1. תעד נקודות קצה מרכזיות לייבוא/ייצוא
|
||||
2. תעד תבניות פרוטוקול WebSocket
|
||||
3. תעד נקודות קצה של ייבוא/ייצוא ברמת הזרימה של WebSocket
|
||||
|
||||
### שלב 6: אימות
|
||||
1. אמת באמצעות כלי אימות OpenAPI
|
||||
2. בדוק באמצעות Swagger UI
|
||||
3. ודא שכל המתרגמים מכוסים
|
||||
|
||||
## מוסכמות מתן שמות לשדות
|
||||
|
||||
כל השדות ב-JSON משתמשים בפורמט **kebab-case**:
|
||||
`flow-id`, `blueprint-name`, `doc-limit`, `entity-limit`, וכו'.
|
||||
|
||||
## יצירת קבצי סכימה
|
||||
|
||||
עבור כל מתרגם ב-`trustgraph-base/trustgraph/messaging/translators/`:
|
||||
|
||||
1. **קרא את שיטת המתרגם `to_pulsar()`** - מגדיר סכימת בקשה
|
||||
2. **קרא את שיטת המתרגם `from_pulsar()`** - מגדיר סכימת תגובה
|
||||
3. **חלץ שמות שדות וסוגים**
|
||||
4. **צור סכימה של OpenAPI** עם:
|
||||
שמות שדות (kebab-case)
|
||||
סוגים (string, integer, boolean, object, array)
|
||||
שדות חובה
|
||||
ערכי ברירת מחדל
|
||||
תיאורים
|
||||
|
||||
### תהליך מיפוי לדוגמה
|
||||
|
||||
```python
|
||||
# From retrieval.py DocumentRagRequestTranslator
|
||||
def to_pulsar(self, data: Dict[str, Any]) -> DocumentRagQuery:
|
||||
return DocumentRagQuery(
|
||||
query=data["query"], # required string
|
||||
user=data.get("user", "trustgraph"), # optional string, default "trustgraph"
|
||||
collection=data.get("collection", "default"), # optional string, default "default"
|
||||
doc_limit=int(data.get("doc-limit", 20)), # optional integer, default 20
|
||||
streaming=data.get("streaming", False) # optional boolean, default false
|
||||
)
|
||||
```
|
||||
|
||||
מתורגם ל:
|
||||
|
||||
```yaml
|
||||
# components/schemas/ai-services/DocumentRagRequest.yaml
|
||||
type: object
|
||||
required:
|
||||
- query
|
||||
properties:
|
||||
query:
|
||||
type: string
|
||||
description: Search query
|
||||
user:
|
||||
type: string
|
||||
default: trustgraph
|
||||
collection:
|
||||
type: string
|
||||
default: default
|
||||
doc-limit:
|
||||
type: integer
|
||||
default: 20
|
||||
description: Maximum number of documents to retrieve
|
||||
streaming:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Enable streaming responses
|
||||
```
|
||||
|
||||
## תגובות סטרימינג
|
||||
|
||||
שירותים התומכים בסטרימינג מחזירים מספר תגובות עם הדגל `end_of_stream`:
|
||||
`agent`, `text-completion`, `prompt`
|
||||
`document-rag`, `graph-rag`
|
||||
|
||||
יש לתעד דפוס זה בסכימת התגובות של כל שירות.
|
||||
|
||||
## תגובות שגיאה
|
||||
|
||||
כל השירותים יכולים להחזיר:
|
||||
```yaml
|
||||
error:
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: '#/components/schemas/ErrorObject'
|
||||
```
|
||||
|
||||
היכן ש-`ErrorObject` נמצא:
|
||||
```yaml
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
```
|
||||
|
||||
## הפניות
|
||||
|
||||
מתרגמים: `trustgraph-base/trustgraph/messaging/translators/`
|
||||
מיפוי מפיץ: `trustgraph-flow/trustgraph/gateway/dispatch/manager.py`
|
||||
ניתוב נקודת קצה: `trustgraph-flow/trustgraph/gateway/endpoint/manager.py`
|
||||
תקציר שירות: `API_SERVICES_SUMMARY.md`
|
||||
965
docs/tech-specs/he/pubsub.he.md
Normal file
965
docs/tech-specs/he/pubsub.he.md
Normal file
|
|
@ -0,0 +1,965 @@
|
|||
---
|
||||
layout: default
|
||||
title: "תשתית Pub/Sub"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# תשתית Pub/Sub
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מפרט את כל החיבורים בין בסיס הקוד של TrustGraph לתשתית ה-pub/sub. כיום, המערכת מקודדת בצורה קבועה לשימוש ב-Apache Pulsar. ניתוח זה מזהה את כל נקודות האינטגרציה כדי ליידע שינויים עתידיים לכיוון הפשטה של pub/sub הניתנת לתצורה.
|
||||
|
||||
## מצב נוכחי: נקודות אינטגרציה של Pulsar
|
||||
|
||||
### 1. שימוש ישיר בלקוח Pulsar
|
||||
|
||||
**מיקום:** `trustgraph-flow/trustgraph/gateway/service.py`
|
||||
|
||||
שער ה-API מייבא ויוצר ישירות את לקוח ה-Pulsar:
|
||||
|
||||
**שורה 20:** `import pulsar`
|
||||
**שורות 54-61:** יצירה ישירה של `pulsar.Client()` עם `pulsar.AuthenticationToken()` אופציונלי
|
||||
**שורות 33-35:** תצורת מארח ברירת מחדל של Pulsar ממשתני סביבה
|
||||
**שורות 178-192:** ארגומנטים של שורת הפקודה עבור `--pulsar-host`, `--pulsar-api-key` ו-`--pulsar-listener`
|
||||
**שורות 78, 124:** מעביר `pulsar_client` ל-`ConfigReceiver` ו-`DispatcherManager`
|
||||
|
||||
זה המיקום היחיד שבו נוצר ישירות לקוח Pulsar מחוץ לשכבת ההפשטה.
|
||||
|
||||
### 2. מסגרת מעבד בסיסית
|
||||
|
||||
**מיקום:** `trustgraph-base/trustgraph/base/async_processor.py`
|
||||
|
||||
המחלקה הבסיסית לכל המעבדים מספקת קישוריות ל-Pulsar:
|
||||
|
||||
**שורה 9:** `import _pulsar` (לטיפול בחריגים)
|
||||
**שורה 18:** `from . pubsub import PulsarClient`
|
||||
**שורה 38:** יוצר `pulsar_client_object = PulsarClient(**params)`
|
||||
**שורות 104-108:** מאפיינים החושפים `pulsar_host` ו-`pulsar_client`
|
||||
**שורה 250:** שיטה סטטית `add_args()` קוראת ל-`PulsarClient.add_args(parser)` עבור ארגומנטים של שורת הפקודה
|
||||
**שורות 223-225:** טיפול בחריגים עבור `_pulsar.Interrupted`
|
||||
|
||||
כל המעבדים יורשים מ-`AsyncProcessor`, מה שהופך זאת לנקודת האינטגרציה המרכזית.
|
||||
|
||||
### 3. הפשטת צרכן
|
||||
|
||||
**מיקום:** `trustgraph-base/trustgraph/base/consumer.py`
|
||||
|
||||
צורך הודעות מתורים ומפעיל פונקציות מטפלות:
|
||||
|
||||
**ייבוא של Pulsar:**
|
||||
**שורה 12:** `from pulsar.schema import JsonSchema`
|
||||
**שורה 13:** `import pulsar`
|
||||
**שורה 14:** `import _pulsar`
|
||||
|
||||
**שימוש ספציפי ל-Pulsar:**
|
||||
**שורות 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest`
|
||||
**שורה 108:** עטיפה של `JsonSchema(self.schema)`
|
||||
**שורה 110:** `pulsar.ConsumerType.Shared`
|
||||
**שורות 104-111:** `self.client.subscribe()` עם פרמטרים ספציפיים ל-Pulsar
|
||||
**שורות 143, 150, 65:** שיטות `consumer.unsubscribe()` ו-`consumer.close()`
|
||||
**שורה 162:** חריגה של `_pulsar.Timeout`
|
||||
**שורות 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()`
|
||||
|
||||
**קובץ מפרט:** `trustgraph-base/trustgraph/base/consumer_spec.py`
|
||||
**שורה 22:** מפנה ל-`processor.pulsar_client`
|
||||
|
||||
### 4. הפשטת מפרסם
|
||||
|
||||
**מיקום:** `trustgraph-base/trustgraph/base/producer.py`
|
||||
|
||||
שולח הודעות לתורים:
|
||||
|
||||
**ייבוא של Pulsar:**
|
||||
**שורה 2:** `from pulsar.schema import JsonSchema`
|
||||
|
||||
**שימוש ספציפי ל-Pulsar:**
|
||||
**שורה 49:** עטיפה של `JsonSchema(self.schema)`
|
||||
**שורות 47-51:** `self.client.create_producer()` עם פרמטרים ספציפיים ל-Pulsar (נושא, סכימה, הפעלה של חלוקה לחלקים)
|
||||
**שורות 31, 76:** שיטה `producer.close()`
|
||||
**שורות 64-65:** `producer.send()` עם הודעה ומאפיינים
|
||||
|
||||
**קובץ מפרט:** `trustgraph-base/trustgraph/base/producer_spec.py`
|
||||
**שורה 18:** מפנה ל-`processor.pulsar_client`
|
||||
|
||||
### 5. הפשטת מפרסם
|
||||
|
||||
**מיקום:** `trustgraph-base/trustgraph/base/publisher.py`
|
||||
|
||||
פרסום הודעות אסינכרוני עם חיץ תורים:
|
||||
|
||||
**ייבוא של Pulsar:**
|
||||
**שורה 2:** `from pulsar.schema import JsonSchema`
|
||||
**שורה 6:** `import pulsar`
|
||||
|
||||
**שימוש ספציפי ל-Pulsar:**
|
||||
**שורה 52:** עטיפה של `JsonSchema(self.schema)`
|
||||
**שורות 50-54:** `self.client.create_producer()` עם פרמטרים ספציפיים ל-Pulsar
|
||||
**שורות 101, 103:** `producer.send()` עם הודעה ומאפיינים אופציונליים
|
||||
**שורות 106-107:** שיטות `producer.flush()` ו-`producer.close()`
|
||||
|
||||
### 6. הפשטת מנוי
|
||||
|
||||
**מיקום:** `trustgraph-base/trustgraph/base/subscriber.py`
|
||||
|
||||
מספק הפצת הודעות למספר נמענים ממחזורים:
|
||||
|
||||
**ייבוא מ-Pulsar:**
|
||||
**שורה 6:** `from pulsar.schema import JsonSchema`
|
||||
**שורה 8:** `import _pulsar`
|
||||
|
||||
**שימוש ספציפי ל-Pulsar:**
|
||||
**שורה 55:** `JsonSchema(self.schema)` wrapper
|
||||
**שורה 57:** `self.client.subscribe(**subscribe_args)`
|
||||
**שורות 101, 136, 160, 167-172:** חריגות של Pulsar: `_pulsar.Timeout`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed`
|
||||
**שורות 159, 166, 170:** שיטות צרכן: `negative_acknowledge()`, `unsubscribe()`, `close()`
|
||||
**שורות 247, 251:** אישור הודעות: `acknowledge()`, `negative_acknowledge()`
|
||||
|
||||
**קובץ מפרט:** `trustgraph-base/trustgraph/base/subscriber_spec.py`
|
||||
**שורה 19:** מפנה ל-`processor.pulsar_client`
|
||||
|
||||
### 7. מערכת סכימות (Heart of Darkness)
|
||||
|
||||
**מיקום:** `trustgraph-base/trustgraph/schema/`
|
||||
|
||||
כל סכימת הודעה במערכת מוגדרת באמצעות מסגרת הסכימות של Pulsar.
|
||||
|
||||
**אלמנטים בסיסיים:** `schema/core/primitives.py`
|
||||
**שורה 2:** `from pulsar.schema import Record, String, Boolean, Array, Integer`
|
||||
כל הסכימות יורשות מהמחלקה הבסיסית של Pulsar `Record`
|
||||
כל סוגי השדות הם סוגי Pulsar: `String()`, `Integer()`, `Boolean()`, `Array()`, `Map()`, `Double()`
|
||||
|
||||
**דוגמאות לסכימות:**
|
||||
`schema/services/llm.py` (שורה 2): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean`
|
||||
`schema/services/config.py` (שורה 2): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer`
|
||||
|
||||
**שמות נושאים:** `schema/core/topic.py`
|
||||
**שורות 2-3:** פורמט נושא: `{kind}://{tenant}/{namespace}/{topic}`
|
||||
מבנה ה-URI הזה ספציפי ל-Pulsar (לדוגמה, `persistent://tg/flow/config`)
|
||||
|
||||
**השפעה:**
|
||||
כל הגדרות הודעות בקשות/תגובות בכל בסיס הקוד משתמשות בסכימות של Pulsar
|
||||
זה כולל שירותים עבור: config, flow, llm, prompt, query, storage, agent, collection, diagnosis, library, lookup, nlp_query, objects_query, retrieval, structured_query
|
||||
הגדרות סכימות מיובאות ומשמשות באופן נרחב בכל המעבדים והשירותים
|
||||
|
||||
## סיכום
|
||||
|
||||
### תלויות של Pulsar לפי קטגוריה
|
||||
|
||||
1. **יצירת מופע לקוח:**
|
||||
ישיר: `gateway/service.py`
|
||||
מופשט: `async_processor.py` → `pubsub.py` (PulsarClient)
|
||||
|
||||
2. **העברת הודעות:**
|
||||
צרכן: `consumer.py`, `consumer_spec.py`
|
||||
מפיק: `producer.py`, `producer_spec.py`
|
||||
מפרסם: `publisher.py`
|
||||
מנוי: `subscriber.py`, `subscriber_spec.py`
|
||||
|
||||
3. **מערכת סכימות:**
|
||||
סוגים בסיסיים: `schema/core/primitives.py`
|
||||
כל סכימות השירות: `schema/services/*.py`
|
||||
שמות נושאים: `schema/core/topic.py`
|
||||
|
||||
4. **מושגים ספציפיים ל-Pulsar הנדרשים:**
|
||||
העברת הודעות מבוססת נושאים
|
||||
מערכת סכימות (Record, סוגי שדות)
|
||||
מנויים משותפים
|
||||
אישור הודעות (חיובי/שלילי)
|
||||
מיקום צרכן (מוקדם/מאוחר)
|
||||
מאפייני הודעות
|
||||
מיקומים התחלתיים וסוגי צרכנים
|
||||
תמיכה בפיצול
|
||||
נושאים קבועים לעומת לא קבועים
|
||||
|
||||
### אתגרי שינוי מבנה
|
||||
|
||||
החדשות הטובות: שכבת ההפשטה (צרכן, מפיק, מפרסם, מנוי) מספקת אריזה נקייה של רוב האינטראקציות של Pulsar.
|
||||
|
||||
האתגרים:
|
||||
1. **הנחת סכימות נרחבת:** כל הגדרת הודעה משתמשת ב-`pulsar.schema.Record` ובסוגי Pulsar
|
||||
2. **אנונימים ספציפיים ל-Pulsar:** `InitialPosition`, `ConsumerType`
|
||||
3. **חריגות של Pulsar:** `_pulsar.Timeout`, `_pulsar.Interrupted`, `_pulsar.InvalidConfiguration`, `_pulsar.AlreadyClosed`
|
||||
4. **חתימות שיטות:** `acknowledge()`, `negative_acknowledge()`, `subscribe()`, `create_producer()`, וכו'.
|
||||
5. **פורמט URI של נושא:** מבנה `kind://tenant/namespace/topic` של Pulsar
|
||||
|
||||
### שלבים הבאים
|
||||
|
||||
כדי להפוך את התשתית של pub/sub לכזו שניתן להגדיר, עלינו:
|
||||
|
||||
1. ליצור ממשק הפשטה עבור מערכת הלקוח/סכימות
|
||||
2. להפשיט אנונימים ספציפיים ל-Pulsar וחריגות
|
||||
3. ליצור עטיפות סכימות או הגדרות סכימות חלופיות
|
||||
4. ליישם את הממשק הן עבור Pulsar והן עבור מערכות חלופיות (Kafka, RabbitMQ, Redis Streams, וכו')
|
||||
5. לעדכן את `pubsub.py` כך שניתן יהיה להגדיר אותו ולתמוך במספר מערכות אחוריות
|
||||
6. לספק נתיב מעבר לפריסות קיימות
|
||||
|
||||
## טיוטת גישה 1: תבנית מתאם עם שכבת תרגום סכימות
|
||||
|
||||
### הערה
|
||||
|
||||
|
||||
### אסטרטגיה: הפרעה מינימלית באמצעות מתאמים
|
||||
|
||||
**1. שמירה על סכימות Pulsar כייצוג הפנימי**
|
||||
אין לשכתב את כל הגדרות הסכימות.
|
||||
הסכימות נשארות `pulsar.schema.Record` באופן פנימי.
|
||||
השתמשו במתאמים כדי לתרגם בגבול בין הקוד שלנו לבין ה-backend של ה-pub/sub.
|
||||
|
||||
**2. יצירת שכבת הפשטה עבור pub/sub:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Existing Code (unchanged) │
|
||||
│ - Uses Pulsar schemas internally │
|
||||
│ - Consumer/Producer/Publisher │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────────────┐
|
||||
│ PubSubFactory (configurable) │
|
||||
│ - Creates backend-specific client │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ │
|
||||
┌───────▼─────┐ ┌────▼─────────┐
|
||||
│ PulsarAdapter│ │ KafkaAdapter │ etc...
|
||||
│ (passthrough)│ │ (translates) │
|
||||
└──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
**3. הגדרת ממשקים מופשטים:**
|
||||
`PubSubClient` - חיבור לקוח
|
||||
`PubSubProducer` - שליחת הודעות
|
||||
`PubSubConsumer` - קבלת הודעות
|
||||
`SchemaAdapter` - המרת סכימות Pulsar ל-JSON או פורמטים ספציפיים ל-backend
|
||||
|
||||
**4. פרטי יישום:**
|
||||
|
||||
עבור **מתאם Pulsar**: כמעט העברה ישירה, המרה מינימלית
|
||||
|
||||
עבור **backends אחרים** (Kafka, RabbitMQ, וכו'):
|
||||
סריאליזציה של אובייקטי Pulsar Record ל-JSON/bytes
|
||||
מיפוי מושגים כמו:
|
||||
`InitialPosition.Earliest/Latest` → auto.offset.reset של Kafka
|
||||
`acknowledge()` → commit של Kafka
|
||||
`negative_acknowledge()` → תבנית Re-queue או DLQ
|
||||
URIs של נושאים → שמות נושאים ספציפיים ל-backend
|
||||
|
||||
### ניתוח
|
||||
|
||||
**יתרונות:**
|
||||
✅ שינויים מינימליים בקוד של שירותים קיימים
|
||||
✅ הסכימות נשארות כפי שהן (ללא כתיבה מחדש מסיבית)
|
||||
✅ מסלול מעבר הדרגתי
|
||||
✅ משתמשי Pulsar לא רואים הבדל
|
||||
✅ backends חדשים מתווספים באמצעות מתאמים
|
||||
|
||||
**חסרונות:**
|
||||
⚠️ עדיין כולל תלות ב-Pulsar (לצרכי הגדרות סכימה)
|
||||
⚠️ חוסר התאמה מסוים בהמרת מושגים
|
||||
|
||||
### שיקול חלופי
|
||||
|
||||
ליצור **מערכת סכימות TrustGraph** שאינה תלויה ב-pub/sub ספציפי (תוך שימוש ב-dataclasses או Pydantic), ולאחר מכן ליצור סכימות Pulsar/Kafka/וכו מתוך זה. זה דורש כתיבה מחדש של כל קובץ סכימה ועלול לגרום לשינויים משמעותיים.
|
||||
|
||||
### המלצה עבור טיוטה 1
|
||||
|
||||
להתחיל עם **גישת המתאם** מכיוון ש:
|
||||
1. זה פרגמטי - עובד עם קוד קיים
|
||||
2. מוכיח את הקונספט עם סיכון מינימלי
|
||||
3. ניתן להתפתח למערכת סכימה מקומית יותר בעתיד אם יש צורך
|
||||
4. מונחה תצורה: משתנה סביבה אחד משנה את ה-backends
|
||||
|
||||
## גישה טיוטה 2: מערכת סכימות עצמאית מ-backend באמצעות Dataclasses
|
||||
|
||||
### מושג מרכזי
|
||||
|
||||
להשתמש ב-**dataclasses** של Python כפורמט הגדרת סכימה ניטרלי. כל backend של pub/sub מספק את הסריאליזציה/דה-סריאליזציה שלו עבור dataclasses, מה שמבטל את הצורך לשמור על סכימות Pulsar בקוד הבסיס.
|
||||
|
||||
### פולימורפיזם של סכימה ברמת המפעל
|
||||
|
||||
במקום להמיר סכימות Pulsar, **כל backend מספק את הטיפול שלו בסכימות** שעובד עם dataclasses סטנדרטיים של Python.
|
||||
|
||||
### זרימת פרסום
|
||||
|
||||
```python
|
||||
# 1. Get the configured backend from factory
|
||||
pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc.
|
||||
|
||||
# 2. Get schema class from the backend
|
||||
# (Can be imported directly - backend-agnostic)
|
||||
from trustgraph.schema.services.llm import TextCompletionRequest
|
||||
|
||||
# 3. Create a producer/publisher for a specific topic
|
||||
producer = pubsub.create_producer(
|
||||
topic="text-completion-requests",
|
||||
schema=TextCompletionRequest # Tells backend what schema to use
|
||||
)
|
||||
|
||||
# 4. Create message instances (same API regardless of backend)
|
||||
request = TextCompletionRequest(
|
||||
system="You are helpful",
|
||||
prompt="Hello world",
|
||||
streaming=False
|
||||
)
|
||||
|
||||
# 5. Send the message
|
||||
producer.send(request) # Backend serializes appropriately
|
||||
```
|
||||
|
||||
### זרימת לקוח
|
||||
|
||||
```python
|
||||
# 1. Get the configured backend
|
||||
pubsub = get_pubsub()
|
||||
|
||||
# 2. Create a consumer
|
||||
consumer = pubsub.subscribe(
|
||||
topic="text-completion-requests",
|
||||
schema=TextCompletionRequest # Tells backend how to deserialize
|
||||
)
|
||||
|
||||
# 3. Receive and deserialize
|
||||
msg = consumer.receive()
|
||||
request = msg.value() # Returns TextCompletionRequest dataclass instance
|
||||
|
||||
# 4. Use the data (type-safe access)
|
||||
print(request.system) # "You are helpful"
|
||||
print(request.prompt) # "Hello world"
|
||||
print(request.streaming) # False
|
||||
```
|
||||
|
||||
### מה קורה מאחורי הקלעים
|
||||
|
||||
**עבור ה-backend של Pulsar:**
|
||||
`create_producer()` → יוצר יצרן Pulsar עם סכימה JSON או רשומה שנוצרה באופן דינמי
|
||||
`send(request)` → ממיר את מחלקת הנתונים לפורמט JSON/Pulsar, שולח ל-Pulsar
|
||||
`receive()` → מקבל הודעת Pulsar, ממיר חזרה למחלקת נתונים
|
||||
|
||||
**עבור ה-backend של MQTT:**
|
||||
`create_producer()` → מתחבר ל-MQTT broker, אין צורך ברישום סכימה
|
||||
`send(request)` → ממיר מחלקת נתונים ל-JSON, מפרסם לנושא MQTT
|
||||
`receive()` → נרשם לנושא MQTT, ממיר JSON למחלקת נתונים
|
||||
|
||||
**עבור ה-backend של Kafka:**
|
||||
`create_producer()` → יוצר יצרן Kafka, רושם סכימת Avro במידת הצורך
|
||||
`send(request)` → ממיר מחלקת נתונים לפורמט Avro, שולח ל-Kafka
|
||||
`receive()` → מקבל הודעת Kafka, ממיר Avro חזרה למחלקת נתונים
|
||||
|
||||
### נקודות עיצוב מרכזיות
|
||||
|
||||
1. **יצירת אובייקט סכימה**: מופע מחלקת הנתונים (`TextCompletionRequest(...)`) זהה ללא קשר ל-backend
|
||||
2. **ה-backend מטפל בקידוד**: כל backend יודע כיצד לתרגם את מחלקת הנתונים לפורמט הנתונים
|
||||
3. **הגדרת סכימה ביצירה**: בעת יצירת יצרן/צרכן, מציינים את סוג הסכימה
|
||||
4. **שמירה על בטיחות טיפוסים**: מקבלים בחזרה אובייקט `TextCompletionRequest` תקין, ולא מילון
|
||||
5. **ללא חשיפה ל-backend**: קוד האפליקציה לעולם לא מייבא ספריות ספציפיות ל-backend
|
||||
|
||||
### דוגמה לטרנספורמציה
|
||||
|
||||
**נוכחי (ספציפי ל-Pulsar):**
|
||||
```python
|
||||
# schema/services/llm.py
|
||||
from pulsar.schema import Record, String, Boolean, Integer
|
||||
|
||||
class TextCompletionRequest(Record):
|
||||
system = String()
|
||||
prompt = String()
|
||||
streaming = Boolean()
|
||||
```
|
||||
|
||||
**חדש (בלתי תלוי בטכנולוגיית השרת):**
|
||||
```python
|
||||
# schema/services/llm.py
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class TextCompletionRequest:
|
||||
system: str
|
||||
prompt: str
|
||||
streaming: bool = False
|
||||
```
|
||||
|
||||
### אינטגרציה עם השרת האחורי
|
||||
|
||||
כל שרת אחורי מטפל בסריאליזציה/דה-סריאליזציה של מחלקות נתונים:
|
||||
|
||||
**שרת אחורי של Pulsar:**
|
||||
יצירת מחלקות `pulsar.schema.Record` באופן דינמי ממחלקות נתונים
|
||||
או סריאליזציה של מחלקות נתונים ל-JSON ושימוש בסכימה של JSON של Pulsar
|
||||
שומר על תאימות לפריסות Pulsar קיימות
|
||||
|
||||
**שרת אחורי של MQTT/Redis:**
|
||||
סריאליזציה ישירה של מופעים של מחלקות נתונים ל-JSON
|
||||
שימוש ב-`dataclasses.asdict()` / `from_dict()`
|
||||
קל משקל, לא נדרש רישום סכימות
|
||||
|
||||
**שרת אחורי של Kafka:**
|
||||
יצירת סכימות Avro מהגדרות של מחלקות נתונים
|
||||
שימוש ברישום סכימות של Confluent
|
||||
סריאליזציה בטוחה עם תמיכה באבולוציה של סכימות
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Application Code │
|
||||
│ - Uses dataclass schemas │
|
||||
│ - Backend-agnostic │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────────────┐
|
||||
│ PubSubFactory (configurable) │
|
||||
│ - get_pubsub() returns backend │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ │
|
||||
┌───────▼─────────┐ ┌────▼──────────────┐
|
||||
│ PulsarBackend │ │ MQTTBackend │
|
||||
│ - JSON schema │ │ - JSON serialize │
|
||||
│ - or dynamic │ │ - Simple queues │
|
||||
│ Record gen │ │ │
|
||||
└─────────────────┘ └───────────────────┘
|
||||
```
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
**1. הגדרות סכימה:** מחלקות נתונים פשוטות עם רמזי סוג
|
||||
`str`, `int`, `bool`, `float` עבור ערכים בסיסיים
|
||||
`list[T]` עבור מערכים
|
||||
`dict[str, T]` עבור מפות
|
||||
מחלקות נתונים מקוננות עבור סוגים מורכבים
|
||||
|
||||
**2. כל ממשק מספק:**
|
||||
ממיר: `dataclass → bytes/wire format`
|
||||
ממיר הפוך: `bytes/wire format → dataclass`
|
||||
רישום סכימה (אם נדרש, כמו Pulsar/Kafka)
|
||||
|
||||
**3. הפשטה של צרכן/משדר:**
|
||||
כבר קיים (consumer.py, producer.py)
|
||||
עדכון לשימוש בשימוש בשידור של הממשק
|
||||
הסרת יבוא ישיר של Pulsar
|
||||
|
||||
**4. התאמות סוג:**
|
||||
Pulsar `String()` → Python `str`
|
||||
Pulsar `Integer()` → Python `int`
|
||||
Pulsar `Boolean()` → Python `bool`
|
||||
Pulsar `Array(T)` → Python `list[T]`
|
||||
Pulsar `Map(K, V)` → Python `dict[K, V]`
|
||||
Pulsar `Double()` → Python `float`
|
||||
Pulsar `Bytes()` → Python `bytes`
|
||||
|
||||
### נתיב מעבר
|
||||
|
||||
1. **צור גרסאות של מחלקות נתונים** עבור כל הסכימות ב-`trustgraph/schema/`
|
||||
2. **עדכן מחלקות ממשק** (צרכן, משדר, מפרסם, מנוי) לשימוש בשידור שמסופק על ידי הממשק
|
||||
3. **יישם PulsarBackend** עם סכימה ב-JSON או יצירת רשומות דינמית
|
||||
4. **בדוק עם Pulsar** כדי להבטיח תאימות לאחור עם פריסות קיימות
|
||||
5. **הוסף ממשקים חדשים** (MQTT, Kafka, Redis, וכו') לפי הצורך
|
||||
6. **הסר יבוא של Pulsar** מקבצי סכימה
|
||||
|
||||
### יתרונות
|
||||
|
||||
✅ **ללא תלות ב-pub/sub** בהגדרות סכימה
|
||||
✅ **Python סטנדרטי** - קל להבנה, בדיקת סוגים, תיעוד
|
||||
✅ **כלים מודרניים** - עובד עם mypy, השלמה אוטומטית של IDE, כלי ניתוח
|
||||
✅ **מותאם לממשק** - כל ממשק משתמש בשידור מקומי
|
||||
✅ **ללא תקורה של תרגום** - שידור ישיר, ללא מתאמים
|
||||
✅ **בטיחות סוג** - אובייקטים אמיתיים עם סוגים מתאימים
|
||||
✅ **אימות קל** - ניתן להשתמש ב-Pydantic אם נדרש
|
||||
|
||||
### אתגרים ופתרונות
|
||||
|
||||
**אתגר:** ל-Pulsar יש `Record` עם אימות שדה בזמן ריצה
|
||||
**פתרון:** השתמש במחלקות נתונים של Pydantic לאימות אם נדרש, או בתכונות של מחלקת נתונים של Python 3.10+ עם `__post_init__`
|
||||
|
||||
**אתגר:** תכונות ספציפיות של Pulsar (כמו סוג `Bytes`)
|
||||
**פתרון:** התאם לסוג `bytes` במחלקת נתונים, הממשק מטפל בקידוד המתאים
|
||||
|
||||
**אתגר:** שמות נושא (`persistent://tenant/namespace/topic`)
|
||||
**פתרון:** הפשט שמות נושא בהגדרות סכימה, הממשק ממיר לפורמט המתאים
|
||||
|
||||
**אתגר:** אבולוציה וגרסאות של סכימה
|
||||
**פתרון:** כל ממשק מטפל בכך בהתאם ליכולות שלו (גרסאות סכימה של Pulsar, רישום סכימה של Kafka, וכו')
|
||||
|
||||
**אתגר:** סוגים מורכבים מקוננים
|
||||
**פתרון:** השתמש במחלקות נתונים מקוננות, הממשקים מבצעים שידור/פענוח רקורסיבי
|
||||
|
||||
### החלטות עיצוב
|
||||
|
||||
1. **מחלקות נתונים פשוטות או Pydantic?**
|
||||
✅ **החלטה: השתמש במחלקות נתונים של Python פשוטות**
|
||||
פשוט יותר, ללא תלויות נוספות
|
||||
אימות אינו נדרש בפועל
|
||||
קל יותר להבנה ולתחזוקה
|
||||
|
||||
2. **אבולוציה של סכימה:**
|
||||
✅ **החלטה: לא נדרש מנגנון גרסאות**
|
||||
הסכימות יציבות וקיימות לאורך זמן
|
||||
עדכונים בדרך כלל מוסיפים שדות חדשים (תואמים לאחור)
|
||||
ממשקים מטפלים באבולוציה של סכימה בהתאם ליכולות שלהם
|
||||
|
||||
3. **תאימות לאחור:**
|
||||
✅ **החלטה: שינוי גרסה עיקרית, תאימות לאחור אינה נדרשת**
|
||||
יהיה שינוי משמעותי עם הוראות מעבר
|
||||
ניתוק נקי מאפשר עיצוב טוב יותר
|
||||
מדריך מעבר יסופק עבור פריסות קיימות
|
||||
|
||||
4. **סוגים מקוננים ומבנים מורכבים:**
|
||||
✅ **החלטה: השתמש במחלקות נתונים מקוננות באופן טבעי**
|
||||
מחלקות נתונים של Python מטפלות בקינון בצורה מושלמת
|
||||
`list[T]` עבור מערכים, `dict[K, V]` עבור מפות
|
||||
ממשקים מבצעים שידור/פענוח רקורסיבי
|
||||
דוגמה:
|
||||
```python
|
||||
@dataclass
|
||||
class Value:
|
||||
value: str
|
||||
is_uri: bool
|
||||
|
||||
@dataclass
|
||||
class Triple:
|
||||
s: Value # Nested dataclass
|
||||
p: Value
|
||||
o: Value
|
||||
|
||||
@dataclass
|
||||
class GraphQuery:
|
||||
triples: list[Triple] # Array of nested dataclasses
|
||||
metadata: dict[str, str]
|
||||
```
|
||||
|
||||
5. **ערכים ברירת מחדל ושדות אופציונליים:**
|
||||
✅ **החלטה: שילוב של שדות חובה, ערכי ברירת מחדל ושדות אופציונליים**
|
||||
שדות חובה: ללא ערך ברירת מחדל
|
||||
שדות עם ערכי ברירת מחדל: תמיד נוכחים, בעלי ערך ברירת מחדל הגיוני
|
||||
שדות אופציונליים לחלוטין: `T | None = None`, מושמטים מסריאליזציה כאשר `None`
|
||||
דוגמה:
|
||||
```python
|
||||
@dataclass
|
||||
class TextCompletionRequest:
|
||||
system: str # Required, no default
|
||||
prompt: str # Required, no default
|
||||
streaming: bool = False # Optional with default value
|
||||
metadata: dict | None = None # Truly optional, can be absent
|
||||
```
|
||||
|
||||
**סמנטיקה חשובה של סריאליזציה:**
|
||||
|
||||
כאשר `metadata = None`:
|
||||
```json
|
||||
{
|
||||
"system": "...",
|
||||
"prompt": "...",
|
||||
"streaming": false
|
||||
// metadata field NOT PRESENT
|
||||
}
|
||||
```
|
||||
|
||||
כאשר `metadata = {}` (ריק במפורש):
|
||||
```json
|
||||
{
|
||||
"system": "...",
|
||||
"prompt": "...",
|
||||
"streaming": false,
|
||||
"metadata": {} // Field PRESENT but empty
|
||||
}
|
||||
```
|
||||
|
||||
**ההבחנה העיקרית:**
|
||||
`None` → שדה שאינו קיים ב-JSON (לא מיוצא)
|
||||
ערך ריק (`{}`, `[]`, `""`) → שדה קיים עם ערך ריק
|
||||
זה חשוב מבחינה סמנטית: "לא סופק" לעומת "ריק באופן מפורש"
|
||||
מערכות הקידוד חייבות לדלג על שדות `None`, ולא לקודד אותם כ-`null`
|
||||
|
||||
## טיוטה 3 של הגישה: פרטי יישום
|
||||
|
||||
### פורמט שם תור גנרי
|
||||
|
||||
החליפו שמות תורים ספציפיים לכל מערכת קידוד בפורמט גנרי שמערכות הקידוד יכולות למפות בהתאם.
|
||||
|
||||
**פורמט:** `{qos}/{tenant}/{namespace}/{queue-name}`
|
||||
|
||||
כאשר:
|
||||
`qos`: רמת שירות (Quality of Service)
|
||||
`q0` = מאמץ מינימלי (שליחה ללא אישור)
|
||||
`q1` = לפחות פעם אחת (דורש אישור)
|
||||
`q2` = בדיוק פעם אחת (אישור בשני שלבים)
|
||||
`tenant`: קיבוץ לוגי עבור ריבוי דיירים
|
||||
`namespace`: תת-קיבוץ בתוך דייר
|
||||
`queue-name`: שם התור/נושא בפועל
|
||||
|
||||
**דוגמאות:**
|
||||
```
|
||||
q1/tg/flow/text-completion-requests
|
||||
q2/tg/config/config-push
|
||||
q0/tg/metrics/stats
|
||||
```
|
||||
|
||||
### מיפוי נושאים בצד השרת
|
||||
|
||||
כל צד שרת ממפה את הפורמט הכללי לפורמט הייחודי שלו:
|
||||
|
||||
**צד שרת Pulsar:**
|
||||
```python
|
||||
def map_topic(self, generic_topic: str) -> str:
|
||||
# Parse: q1/tg/flow/text-completion-requests
|
||||
qos, tenant, namespace, queue = generic_topic.split('/', 3)
|
||||
|
||||
# Map QoS to persistence
|
||||
persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent'
|
||||
|
||||
# Return Pulsar URI: persistent://tg/flow/text-completion-requests
|
||||
return f"{persistence}://{tenant}/{namespace}/{queue}"
|
||||
```
|
||||
|
||||
**שרת MQTT:**
|
||||
```python
|
||||
def map_topic(self, generic_topic: str) -> tuple[str, int]:
|
||||
# Parse: q1/tg/flow/text-completion-requests
|
||||
qos, tenant, namespace, queue = generic_topic.split('/', 3)
|
||||
|
||||
# Map QoS level
|
||||
qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos]
|
||||
|
||||
# Build MQTT topic including tenant/namespace for proper namespacing
|
||||
mqtt_topic = f"{tenant}/{namespace}/{queue}"
|
||||
|
||||
return mqtt_topic, qos_level
|
||||
```
|
||||
|
||||
### פונקציית עזר מעודכנת לנושא
|
||||
|
||||
```python
|
||||
# schema/core/topic.py
|
||||
def topic(queue_name, qos='q1', tenant='tg', namespace='flow'):
|
||||
"""
|
||||
Create a generic topic identifier that can be mapped by backends.
|
||||
|
||||
Args:
|
||||
queue_name: The queue/topic name
|
||||
qos: Quality of service
|
||||
- 'q0' = best-effort (no ack)
|
||||
- 'q1' = at-least-once (ack required)
|
||||
- 'q2' = exactly-once (two-phase ack)
|
||||
tenant: Tenant identifier for multi-tenancy
|
||||
namespace: Namespace within tenant
|
||||
|
||||
Returns:
|
||||
Generic topic string: qos/tenant/namespace/queue_name
|
||||
|
||||
Examples:
|
||||
topic('my-queue') # q1/tg/flow/my-queue
|
||||
topic('config', qos='q2', namespace='config') # q2/tg/config/config
|
||||
"""
|
||||
return f"{qos}/{tenant}/{namespace}/{queue_name}"
|
||||
```
|
||||
|
||||
### הגדרות ואתחול
|
||||
|
||||
**ארגומנטים של שורת הפקודה + משתני סביבה:**
|
||||
|
||||
```python
|
||||
# In base/async_processor.py - add_args() method
|
||||
@staticmethod
|
||||
def add_args(parser):
|
||||
# Pub/sub backend selection
|
||||
parser.add_argument(
|
||||
'--pubsub-backend',
|
||||
default=os.getenv('PUBSUB_BACKEND', 'pulsar'),
|
||||
choices=['pulsar', 'mqtt'],
|
||||
help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)'
|
||||
)
|
||||
|
||||
# Pulsar-specific configuration
|
||||
parser.add_argument(
|
||||
'--pulsar-host',
|
||||
default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'),
|
||||
help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--pulsar-api-key',
|
||||
default=os.getenv('PULSAR_API_KEY', None),
|
||||
help='Pulsar API key (env: PULSAR_API_KEY)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--pulsar-listener',
|
||||
default=os.getenv('PULSAR_LISTENER', None),
|
||||
help='Pulsar listener name (env: PULSAR_LISTENER)'
|
||||
)
|
||||
|
||||
# MQTT-specific configuration
|
||||
parser.add_argument(
|
||||
'--mqtt-host',
|
||||
default=os.getenv('MQTT_HOST', 'localhost'),
|
||||
help='MQTT broker host (default: localhost, env: MQTT_HOST)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--mqtt-port',
|
||||
type=int,
|
||||
default=int(os.getenv('MQTT_PORT', '1883')),
|
||||
help='MQTT broker port (default: 1883, env: MQTT_PORT)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--mqtt-username',
|
||||
default=os.getenv('MQTT_USERNAME', None),
|
||||
help='MQTT username (env: MQTT_USERNAME)'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--mqtt-password',
|
||||
default=os.getenv('MQTT_PASSWORD', None),
|
||||
help='MQTT password (env: MQTT_PASSWORD)'
|
||||
)
|
||||
```
|
||||
|
||||
**פונקציית יצירה:**
|
||||
|
||||
```python
|
||||
# In base/pubsub.py or base/pubsub_factory.py
|
||||
def get_pubsub(**config) -> PubSubBackend:
|
||||
"""
|
||||
Create and return a pub/sub backend based on configuration.
|
||||
|
||||
Args:
|
||||
config: Configuration dict from command-line args
|
||||
Must include 'pubsub_backend' key
|
||||
|
||||
Returns:
|
||||
Backend instance (PulsarBackend, MQTTBackend, etc.)
|
||||
"""
|
||||
backend_type = config.get('pubsub_backend', 'pulsar')
|
||||
|
||||
if backend_type == 'pulsar':
|
||||
return PulsarBackend(
|
||||
host=config.get('pulsar_host'),
|
||||
api_key=config.get('pulsar_api_key'),
|
||||
listener=config.get('pulsar_listener'),
|
||||
)
|
||||
elif backend_type == 'mqtt':
|
||||
return MQTTBackend(
|
||||
host=config.get('mqtt_host'),
|
||||
port=config.get('mqtt_port'),
|
||||
username=config.get('mqtt_username'),
|
||||
password=config.get('mqtt_password'),
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unknown pub/sub backend: {backend_type}")
|
||||
```
|
||||
|
||||
**שימוש ב-AsyncProcessor:**
|
||||
|
||||
```python
|
||||
# In async_processor.py
|
||||
class AsyncProcessor:
|
||||
def __init__(self, **params):
|
||||
self.id = params.get("id")
|
||||
|
||||
# Create backend from config (replaces PulsarClient)
|
||||
self.pubsub = get_pubsub(**params)
|
||||
|
||||
# Rest of initialization...
|
||||
```
|
||||
|
||||
### ממשק צד שרת
|
||||
|
||||
```python
|
||||
class PubSubBackend(Protocol):
|
||||
"""Protocol defining the interface all pub/sub backends must implement."""
|
||||
|
||||
def create_producer(self, topic: str, schema: type, **options) -> BackendProducer:
|
||||
"""
|
||||
Create a producer for a topic.
|
||||
|
||||
Args:
|
||||
topic: Generic topic format (qos/tenant/namespace/queue)
|
||||
schema: Dataclass type for messages
|
||||
options: Backend-specific options (e.g., chunking_enabled)
|
||||
|
||||
Returns:
|
||||
Backend-specific producer instance
|
||||
"""
|
||||
...
|
||||
|
||||
def create_consumer(
|
||||
self,
|
||||
topic: str,
|
||||
subscription: str,
|
||||
schema: type,
|
||||
initial_position: str = 'latest',
|
||||
consumer_type: str = 'shared',
|
||||
**options
|
||||
) -> BackendConsumer:
|
||||
"""
|
||||
Create a consumer for a topic.
|
||||
|
||||
Args:
|
||||
topic: Generic topic format (qos/tenant/namespace/queue)
|
||||
subscription: Subscription/consumer group name
|
||||
schema: Dataclass type for messages
|
||||
initial_position: 'earliest' or 'latest' (MQTT may ignore)
|
||||
consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore)
|
||||
options: Backend-specific options
|
||||
|
||||
Returns:
|
||||
Backend-specific consumer instance
|
||||
"""
|
||||
...
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the backend connection."""
|
||||
...
|
||||
```
|
||||
|
||||
```python
|
||||
class BackendProducer(Protocol):
|
||||
"""Protocol for backend-specific producer."""
|
||||
|
||||
def send(self, message: Any, properties: dict = {}) -> None:
|
||||
"""Send a message (dataclass instance) with optional properties."""
|
||||
...
|
||||
|
||||
def flush(self) -> None:
|
||||
"""Flush any buffered messages."""
|
||||
...
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the producer."""
|
||||
...
|
||||
```
|
||||
|
||||
```python
|
||||
class BackendConsumer(Protocol):
|
||||
"""Protocol for backend-specific consumer."""
|
||||
|
||||
def receive(self, timeout_millis: int = 2000) -> Message:
|
||||
"""
|
||||
Receive a message from the topic.
|
||||
|
||||
Raises:
|
||||
TimeoutError: If no message received within timeout
|
||||
"""
|
||||
...
|
||||
|
||||
def acknowledge(self, message: Message) -> None:
|
||||
"""Acknowledge successful processing of a message."""
|
||||
...
|
||||
|
||||
def negative_acknowledge(self, message: Message) -> None:
|
||||
"""Negative acknowledge - triggers redelivery."""
|
||||
...
|
||||
|
||||
def unsubscribe(self) -> None:
|
||||
"""Unsubscribe from the topic."""
|
||||
...
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the consumer."""
|
||||
...
|
||||
```
|
||||
|
||||
```python
|
||||
class Message(Protocol):
|
||||
"""Protocol for a received message."""
|
||||
|
||||
def value(self) -> Any:
|
||||
"""Get the deserialized message (dataclass instance)."""
|
||||
...
|
||||
|
||||
def properties(self) -> dict:
|
||||
"""Get message properties/metadata."""
|
||||
...
|
||||
```
|
||||
|
||||
### שינוי מבנה מחלקות קיימות
|
||||
|
||||
המחלקות הקיימות `Consumer`, `Producer`, `Publisher`, `Subscriber` נשארות ברובן ללא שינוי:
|
||||
|
||||
**אחריות נוכחית (לשמור):**
|
||||
מודל תהליכים אסינכרוניים וקבוצות משימות
|
||||
לוגיקת חיבור מחדש וטיפול בכישלונות
|
||||
איסוף מדדים
|
||||
הגבלת קצב
|
||||
ניהול תחרות
|
||||
|
||||
**שינויים נדרשים:**
|
||||
הסרת יבוא ישיר של Pulsar (`pulsar.schema`, `pulsar.InitialPosition`, וכו')
|
||||
קבלת `BackendProducer`/`BackendConsumer` במקום לקוח Pulsar
|
||||
העברת פעולות פרסום/מנוי בפועל לאינסטנסים אחוריים
|
||||
התאמת מושגים כלליים לפעולות אחוריות
|
||||
|
||||
**דוגמה לשינוי מבנה:**
|
||||
|
||||
```python
|
||||
# OLD - consumer.py
|
||||
class Consumer:
|
||||
def __init__(self, client, topic, subscriber, schema, ...):
|
||||
self.client = client # Direct Pulsar client
|
||||
# ...
|
||||
|
||||
async def consumer_run(self):
|
||||
# Uses pulsar.InitialPosition, pulsar.ConsumerType
|
||||
self.consumer = self.client.subscribe(
|
||||
topic=self.topic,
|
||||
schema=JsonSchema(self.schema),
|
||||
initial_position=pulsar.InitialPosition.Earliest,
|
||||
consumer_type=pulsar.ConsumerType.Shared,
|
||||
)
|
||||
|
||||
# NEW - consumer.py
|
||||
class Consumer:
|
||||
def __init__(self, backend_consumer, schema, ...):
|
||||
self.backend_consumer = backend_consumer # Backend-specific consumer
|
||||
self.schema = schema
|
||||
# ...
|
||||
|
||||
async def consumer_run(self):
|
||||
# Backend consumer already created with right settings
|
||||
# Just use it directly
|
||||
while self.running:
|
||||
msg = await asyncio.to_thread(
|
||||
self.backend_consumer.receive,
|
||||
timeout_millis=2000
|
||||
)
|
||||
await self.handle_message(msg)
|
||||
```
|
||||
|
||||
### התנהגויות ספציפיות לצד האחורי (Backend)
|
||||
|
||||
**צד אחורי Pulsar:**
|
||||
ממפה `q0` → `non-persistent://`, `q1`/`q2` → `persistent://`
|
||||
תומך בכל סוגי הצרכנים (משותף, בלעדי, גיבוי)
|
||||
תומך בעמדה התחלתית (הכי מוקדם/הכי מאוחר)
|
||||
אישור הודעות מקורי
|
||||
תמיכה ברישום סכימות
|
||||
|
||||
**צד אחורי MQTT:**
|
||||
ממפה `q0`/`q1`/`q2` → רמות QoS של MQTT 0/1/2
|
||||
כולל שוכר/מרחב שם בנתיב הנושא לצורך הפרדה
|
||||
מייצר באופן אוטומטי מזהי לקוח משמות מנויים
|
||||
מתעלם מעמדה התחלתית (אין היסטוריית הודעות ב-MQTT בסיסי)
|
||||
מתעלם מסוג צרכן (MQTT משתמש במזהי לקוח, לא בקבוצות צרכנים)
|
||||
מודל פרסום/מנוי פשוט
|
||||
|
||||
### סיכום החלטות עיצוב
|
||||
|
||||
1. ✅ **שמות תורים גנריים**: פורמט `qos/tenant/namespace/queue-name`
|
||||
2. ✅ **רמת QoS במזהה תור**: נקבעת על ידי הגדרת התור, ולא על ידי תצורה
|
||||
3. ✅ **חיבור מחדש**: מטופל על ידי מחלקות צרכן/מפיק, ולא על ידי הצד האחורי
|
||||
4. ✅ **נושאים של MQTT**: כוללים שוכר/מרחב שם לצורך הפרדה תקינה
|
||||
5. ✅ **היסטוריית הודעות**: MQTT מתעלם מהפרמטר `initial_position` (שיפור עתידי)
|
||||
6. ✅ **מזהי לקוח**: צד אחורי MQTT מייצר באופן אוטומטי משם מנוי
|
||||
|
||||
### שיפורים עתידיים
|
||||
|
||||
**היסטוריית הודעות של MQTT:**
|
||||
ניתן להוסיף שכבת שמירה אופציונלית (לדוגמה, הודעות שמורות, אחסון חיצוני)
|
||||
יאפשר תמיכה ב-`initial_position='earliest'`
|
||||
לא נדרש ליישום ראשוני
|
||||
1516
docs/tech-specs/he/python-api-refactor.he.md
Normal file
1516
docs/tech-specs/he/python-api-refactor.he.md
Normal file
File diff suppressed because it is too large
Load diff
187
docs/tech-specs/he/query-time-explainability.he.md
Normal file
187
docs/tech-specs/he/query-time-explainability.he.md
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
---
|
||||
layout: default
|
||||
title: "Query Time Explainability.He"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## הסבר על יכולת הסבר בזמן שאילתה
|
||||
|
||||
## סטטוס
|
||||
|
||||
יישום
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר כיצד GraphRAG מתעד ומעביר נתוני הסבר במהלך ביצוע שאילתה. המטרה היא מעקב מלא: מהתשובה הסופית בחזרה דרך הקצוות שנבחרו לתיקי המסמכים המקוריים.
|
||||
|
||||
הסבר בזמן שאילתה לוכד מה שהצינור של GraphRAG עשה במהלך ההיגיון. הוא מתחבר להקשר של ביצוע שאילתה, אשר מתעד היכן העובדות בגרף הידע מקורות.
|
||||
|
||||
## מונחים
|
||||
|
||||
| מונח | הגדרה |
|
||||
|---|---|
|
||||
| **הסבר** | תיעוד של איך התוצאה הושגה |
|
||||
| **סשן** | ביצוע שאילתה בודד של GraphRAG |
|
||||
| **בחירת קצה** | בחירה מבוססת LLM של קצוות רלוונטיים עם היגיון |
|
||||
| **שרשרת הקשר** | נתיב מ-קצה → חתיכה → עמוד → מסמך |
|
||||
|
||||
## ארכיטקטורה
|
||||
|
||||
### זרימת הסבר
|
||||
|
||||
```
|
||||
שאילת GraphRAG
|
||||
│
|
||||
├─► פעילות סשן
|
||||
│ └─► טקסט שאילתה, חותם זמן
|
||||
│
|
||||
├─► ישות אחזור
|
||||
│ └─► כל הקצוות שנשלפו מהסובגרף
|
||||
│
|
||||
├─► ישות בחירה
|
||||
│ └─► קצוות שנבחרו עם היגיון LLM
|
||||
│ └─► כל קצה מקושר להקשר של הסרת מידע
|
||||
│
|
||||
└─► ישות תשובה
|
||||
└─► הפניה לתשובה שנוצרה (בספריית הניהול)
|
||||
```
|
||||
|
||||
### צינור GraphRAG בשני שלבים
|
||||
|
||||
1. **בחירת קצה:** LLM בוחר קצוות רלוונטיים מהסובגרף, ומספק הסבר לכל אחד
|
||||
2. **סינתזה:** LLM מייצר תשובה מקצוות שנבחרו בלבד
|
||||
|
||||
ההפרדה מאפשרת הסבר - אנחנו יודעים בדיוק אילו קצוות תרמו.
|
||||
|
||||
### אחסון
|
||||
|
||||
- טריפלי הסבר מאוחסנים בספרייה שניתן להגדיר (ברירת מחדל: `explainability`)
|
||||
- משתמש ב-אונטולוגיה של PROV-O ליחסי הקשר
|
||||
- ייצוג RDF-star עבור הפניות לקצוות
|
||||
- תוכן התשובה מאוחסן בשירות הספרייה (לא באופן ישיר - גדול מדי)
|
||||
|
||||
### סטרימינג בזמן אמת
|
||||
|
||||
אירועי הסבר זורמים ללקוח בזמן ביצוע השאילתה:
|
||||
|
||||
1. סשן נוצר → הודעה נשלחת
|
||||
2. קצוות נשלפים → הודעה נשלחת
|
||||
3. קצוות נבחרו עם הסבר → הודעה נשלחת
|
||||
4. תשובה נוצרה → הודעה נשלחת
|
||||
|
||||
הלקוח מקבל `explain_id` ו-`explain_collection` כדי לשלוף פרטים מלאים.
|
||||
|
||||
## מבנה URI
|
||||
|
||||
כל ה-URIs משתמשים בשם מרחב שמות `urn:trustgraph:`, עם UUIDs:
|
||||
|
||||
| ישות | תבנית URI |
|
||||
|---|---|
|
||||
| סשן | `urn:trustgraph:session:{uuid}` |
|
||||
| אחזור | `urn:trustgraph:prov:retrieval:{uuid}` |
|
||||
| בחירה | `urn:trustgraph:prov:selection:{uuid}` |
|
||||
| תשובה | `urn:trustgraph:prov:answer:{uuid}` |
|
||||
| בחירת קצה | `urn:trustgraph:prov:edge:{uuid}:{index}` |
|
||||
|
||||
## מודל RDF (PROV-O)
|
||||
|
||||
### פעילות סשן
|
||||
|
||||
```turtle
|
||||
<session-uri> a prov:Activity ;
|
||||
rdfs:label "שאילת GraphRAG" ;
|
||||
prov:startedAtTime "2024-01-15T10:30:00Z" ;
|
||||
tg:query "מה היה מלחמת הטרור?" .
|
||||
```
|
||||
|
||||
### ישות אחזור
|
||||
|
||||
```turtle
|
||||
<retrieval-uri> a prov:Entity ;
|
||||
rdfs:label "קצוות שאובים" ;
|
||||
prov:wasGeneratedBy <session-uri> ;
|
||||
tg:edgeCount 50 .
|
||||
```
|
||||
|
||||
### ישות בחירה
|
||||
|
||||
```turtle
|
||||
<selection-uri> a prov:Entity ;
|
||||
rdfs:label "קצוות שנבחרו" ;
|
||||
prov:wasDerivedFrom <retrieval-uri> ;
|
||||
tg:selectedEdge <edge-sel-0> ;
|
||||
tg:selectedEdge <edge-sel-1> .
|
||||
|
||||
<edge-sel-0> tg:edge << <s> <p> <o> >> ;
|
||||
tg:reasoning "קצה זה מייצג את הקשר המרכזי..." .
|
||||
```
|
||||
|
||||
### ישות תשובה
|
||||
|
||||
```turtle
|
||||
<answer-uri> a prov:Entity ;
|
||||
rdfs:label "תשובת GraphRAG" ;
|
||||
prov:wasDerivedFrom <selection-uri> ;
|
||||
tg:document <urn:trustgraph:answer:{uuid}> .
|
||||
```
|
||||
|
||||
הפניה `tg:document` מתייחסת לתשובה המאוחסנת בשירות הספרייה.
|
||||
|
||||
## קבועי מרחב שמות
|
||||
|
||||
מוגדרים ב-`trustgraph-base/trustgraph/provenance/namespaces.py`:
|
||||
|
||||
| קבוע | URI |
|
||||
|---|---|
|
||||
| `TG_QUERY` | `https://trustgraph.ai/ns/query` |
|
||||
| `TG_EDGE_COUNT` | `https://trustgraph.ai/ns/edgeCount` |
|
||||
| `TG_SELECTED_EDGE` | `https://trustgraph.ai/ns/selectedEdge` |
|
||||
| `TG_EDGE` | `https://trustgraph.ai/ns/edge` |
|
||||
| `TG_REASONING` | `https://trustgraph.ai/ns/reasoning` |
|
||||
| `TG_CONTENT` | `https://trustgraph.ai/ns/content` |
|
||||
| `TG_DOCUMENT` | `https://trustgraph.ai/ns/document` |
|
||||
|
||||
## תרשים GraphRagResponse
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class GraphRagResponse:
|
||||
error: Error | None = None
|
||||
response: str = ""
|
||||
end_of_stream: bool = False
|
||||
explain_id: str | None = None
|
||||
explain_collection: str | None = None
|
||||
message_type: str = "" # "chunk" or "explain"
|
||||
end_of_session: bool = False
|
||||
```
|
||||
|
||||
### סוגי הודעות
|
||||
|
||||
| message_type | מטרת |
|
||||
|---|---|
|
||||
| `chunk` | טקסט תגובה (זרם או סופי) |
|
||||
| `explain` | אירוע הסבר עם הפניה IRI |
|
||||
|
||||
### מחזור חיים של סשן
|
||||
|
||||
1. מספר הודעות `explain` (סשן, אחזור, בחירה, תשובה)
|
||||
2. מספר הודעות `chunk` (טקסט זרם)
|
||||
3. הודעת `chunk` סופית עם `end_of_session=True`
|
||||
|
||||
## פורמט בחירת קצה
|
||||
|
||||
LLM מחזיר JSONL עם הקצוות שנבחרו:
|
||||
|
||||
```jsonl
|
||||
{"id": "edge-hash-1", "reasoning": "קצה זה מראה את הקשר המרכזי..."}
|
||||
{"id": "edge-hash-2", "reasoning": "מספק ראיות תומכות..."}
|
||||
```
|
||||
|
||||
ה-`id` הוא פאש של `(labeled_s, labeled_p, labeled_o)`
|
||||
ה-`reasoning` הוא הסבר של ה-LLM.
|
||||
|
||||
## יישומים
|
||||
|
||||
- `docs/tech-specs/extraction-time-provenance.md`
|
||||
176
docs/tech-specs/he/rag-streaming-support.he.md
Normal file
176
docs/tech-specs/he/rag-streaming-support.he.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
---
|
||||
layout: default
|
||||
title: "תמיכה בסטרימינג של RAG - ספציפיציה טכנית"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# תמיכה בסטרימינג של RAG - ספציפיציה טכנית
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מתאר את הוספת תמיכה בסטרימינג לשירותי GraphRAG ו-DocumentRAG, המאפשרות תגובות בזמן אמת, שוט אחר שוט, עבור שאילתות שליפה של גרפי ידע ומסמכים. זה מרחיב את הארכיטקטורה הסטנדרטית לסטרימינג, אשר כבר מיושמת עבור שירותי LLM להשלמת טקסט, בקשות וסוכנים.
|
||||
|
||||
## מטרות
|
||||
|
||||
- **חוויית משתמש סטנדרטית בסטרימינג**: לספק חוויית סטרימינג אחידה בכל שירותי TrustGraph.
|
||||
- **שינויים מינימליים בממשק API**: להוסיף תמיכה בסטרימינג באמצעות דגל `streaming` יחיד, תוך עמידה בדפוסי העבודה הקיימים.
|
||||
- **תאימות לאחור**: לשמור על התנהגות לא סטנדרטית קיימת כברירת מחדל.
|
||||
- **ניצול תשתית קיימת**: להשתמש בסטרימינג הקיים, אשר כבר מיושם עבור ה-PromptClient.
|
||||
- **תמיכה בדגלים**: לאפשר סטרימינג באמצעות דגל websocket עבור יישומי לקוח.
|
||||
|
||||
## רקע
|
||||
|
||||
שירותי סטרימינג קיימים:
|
||||
- **שירות השלמת טקסט של LLM**: שלב 1 - סטרימינג מספקי LLM
|
||||
- **שירות בקשות**: שלב 2 - סטרימינג באמצעות תבניות בקשות
|
||||
- **שירות סוכן**: שלבים 3-4 - סטרימינג של תגובות ReAct עם חלקים של מחשבה/תצפית/תשובה
|
||||
|
||||
מגבלות נוכחיות לשירותי RAG:
|
||||
- GraphRAG ו-DocumentRAG תומכים רק בתגובות בלתי סטנדרטיות.
|
||||
- משתמשים צריכים לחכות לתגובה שלמה של LLM לפני קבלת כל תוצאה.
|
||||
- חוויית משתמש גרועה עבור תגובות ארוכות לשאילתות של גרפי ידע או מסמכים.
|
||||
- חוויה לא עקבית בהשוואה לשירותי TrustGraph אחרים.
|
||||
|
||||
מסמך זה מטפל בבעיות אלו על ידי הוספת תמיכה בסטרימינג ל-GraphRAG ו-DocumentRAG. על ידי אפשרות תגובות שוט אחר שוט, TrustGraph יכול:
|
||||
- לספק חוויית משתמש סטנדרטית בסטרימינג עבור כל סוגי השאילתות.
|
||||
- להפחית את הפיגור הרגשי עבור שאילתות RAG.
|
||||
- לאפשר משוב מתקדם עבור שאילתות ארוכות.
|
||||
- לתמוך בהצגה בזמן אמת ביישומים של לקוח.
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
היישום הסטנדרטי של RAG של מנצל את התשתית הקיימת:
|
||||
|
||||
1. **סטרימינג של PromptClient** (כבר מיושם)
|
||||
- הפרמטרים `kg_prompt()` ו-`document_prompt()` כבר מקבלים את הפרמטרים `streaming` ו-`chunk_callback`.
|
||||
- הפרמטרים אלו קוראים לפונקציה `prompt()` עם תמיכה בסטרימינג.
|
||||
- אין צורך לשנות את ה-PromptClient.
|
||||
- מודול: `trustgraph-base/trustgraph/base/prompt_client.py`
|
||||
|
||||
2. **שירות GraphRAG** (דורש העברת פרמטר סטרימינג)
|
||||
- להוסיף את הפרמטר `streaming` למתודה `query()`.
|
||||
- להעביר את הדגל הסטרימינג ואת ה-callbacks ל-`prompt_client.kg_prompt()`.
|
||||
- סכימת ה-GraphRagRequest צריכה לכלול את השדה `streaming`.
|
||||
- מודולים:
|
||||
- `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py`
|
||||
- `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (Processor)
|
||||
- `trustgraph-base/trustgraph/schema/graph_rag.py` (סכימת בקשה)
|
||||
- `trustgraph-flow/trustgraph/gateway/dispatch/graph_rag.py` (Gateway)
|
||||
|
||||
3. **שירות DocumentRAG** (דורש העברת פרמטר סטרימינג)
|
||||
- להוסיף את הפרמטר `streaming` למתודה `query()`.
|
||||
- להעביר את הדגל הסטרימינג ואת ה-callbacks ל-`prompt_client.document_prompt()`.
|
||||
- סכימת ה-DocumentRagRequest צריכה לכלול את השדה `streaming`.
|
||||
- מודולים:
|
||||
- `trustgraph-flow/trustgraph/retrieval/document_rag/document_rag.py`
|
||||
- `trustgraph-flow/trustgraph/retrieval/document_rag/rag.py` (Processor)
|
||||
- `trustgraph-base/trustgraph/schema/document_rag.py` (סכימת בקשה)
|
||||
- `trustgraph-flow/trustgraph/gateway/dispatch/document_rag.py` (Gateway)
|
||||
|
||||
### זרימת נתונים
|
||||
|
||||
**לא סטנדרטי (נוכחי)**:
|
||||
```
|
||||
לקוח → דגל → שירות RAG → PromptClient.kg_prompt(streaming=False)
|
||||
↓
|
||||
שירות בקשות → LLM
|
||||
↓
|
||||
תגובה שלמה
|
||||
↓
|
||||
לקוח ← דגל ← שירות RAG ← תגובה
|
||||
```
|
||||
|
||||
**סטנדרטי (מוצע)**:
|
||||
```
|
||||
לקוח → דגל → שירות RAG → PromptClient.kg_prompt(streaming=True, chunk_callback=cb)
|
||||
↓
|
||||
שירות בקשות → LLM (סטרימינג)
|
||||
↓
|
||||
חלק → Callback → תגובת RAG (חלק)
|
||||
↓ ↓
|
||||
לקוח ← דגל ← ────────────────────────────────── זרם תגובה
|
||||
```
|
||||
|
||||
### ממשקי API
|
||||
|
||||
**שינויים ב-GraphRAG**:
|
||||
|
||||
1. **GraphRag.query()** - הוספת פרמטרים סטרימינג
|
||||
```python
|
||||
async def query(
|
||||
self, query, user, collection,
|
||||
streaming=False, chunk_callback=None
|
||||
):
|
||||
# ...
|
||||
```
|
||||
2. **שינויים ב-DocumentRAG**:
|
||||
- כפי שמתואר עבור GraphRAG.
|
||||
|
||||
### בדיקות
|
||||
|
||||
**בדיקות יחידות**:
|
||||
- בדיקת GraphRag.query() עם `streaming=True/False`.
|
||||
- בדיקת DocumentRAG.query() עם `streaming=True/False`.
|
||||
- שימוש ב-Mock עבור PromptClient כדי לבדוק את קריאות ה-callbacks.
|
||||
|
||||
**בדיקות אינטגרציה**:
|
||||
- בדיקת זרימת הסטרימינג המלאה של GraphRAG (בדיקות דומות לבדיקות סטרימינג של סוכן קיימות).
|
||||
- בדיקת זרימת הסטרימינג המלאה של DocumentRAG.
|
||||
- בדיקת העברת דגל ה-סטרימינג.
|
||||
- בדיקת הפלט של ה-CLI עם סטרימינג.
|
||||
|
||||
**בדיקות ידניות**:
|
||||
- `tg-invoke-graph-rag -q "מהו למידת מכונה?"` (סטרימינג כברירת מחדל).
|
||||
- `tg-invoke-document-rag -q "סכם את המסמכים על AI"` (סטרימינג כברירת מחדל).
|
||||
- `tg-invoke-graph-rag --no-streaming -q "..."` (בדיקת מצב לא סטנדרטי).
|
||||
- בדיקה שהחלקים מופיעים בסטרימינג.
|
||||
|
||||
## תכנון בדיקות
|
||||
|
||||
**בדיקות יחידות**:
|
||||
- בדיקת GraphRag.query() עם `streaming=True/False`.
|
||||
- בדיקת DocumentRAG.query() עם `streaming=True/False`.
|
||||
- שימוש ב-Mock עבור PromptClient כדי לבדוק את קריאות ה-callbacks.
|
||||
|
||||
**בדיקות אינטגרציה**:
|
||||
- בדיקת זרימת הסטרימינג המלאה של GraphRAG (בדיקות דומות לבדיקות סטרימינג של סוכן קיימות).
|
||||
- בדיקת זרימת הסטרימינג המלאה של DocumentRAG.
|
||||
- בדיקת העברת דגל ה-סטרימינג.
|
||||
- בדיקת הפלט של ה-CLI עם סטרימינג.
|
||||
|
||||
**בדיקות ידניות**:
|
||||
- `tg-invoke-graph-rag -q "מהו למידת מכונה?"` (סטרימינג כברירת מחדל).
|
||||
- `tg-invoke-document-rag -q "סכם את המסמכים על AI"` (סטרימינג כברירת מחדל).
|
||||
- `tg-invoke-graph-rag --no-streaming -q "..."` (בדיקת מצב לא סטנדרטי).
|
||||
- בדיקה שהחלקים מופיעים בסטרימינג.
|
||||
|
||||
## תכנון המיגרציה
|
||||
|
||||
אין צורך במיגרציה:
|
||||
- הסטרימינג הוא "אופציונלי" באמצעות הפרמטר `streaming` (ברירת מחדל היא False).
|
||||
- לקוחות קיימים ממשיכים לעבוד ללא שינוי.
|
||||
- לקוחות חדשים יכולים לבחור בסטרימינג.
|
||||
|
||||
## לוח זמנים
|
||||
|
||||
הערכת זמן ליישום: 4-6 שעות
|
||||
- שלב 1 (2 שעות): תמיכה בסטרימינג של GraphRAG.
|
||||
- שלב 2 (2 שעות): תמיכה בסטרימינג של DocumentRAG.
|
||||
- שלב 3 (1-2 שעות): עדכוני דגל ו-CLI.
|
||||
- בדיקות: בונה לתוך כל שלב.
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
- האם עלינו להוסיף תמיכה בסטרימינג לשירות ה-NLP Query גם כן?
|
||||
- האם עלינו להזרים גם את השלבים הביניים (לדוגמה, "שליפת ישויות...", "שאילתה על הגרף...") או רק את הפלט של ה-LLM?
|
||||
- האם עלינו לכלול מידע על החלקים בתגובות של RAG (לדוגמה, מספר החלק, מספר כולל צפוי)?
|
||||
|
||||
## מקורות
|
||||
|
||||
- יישום קיימת: `docs/tech-specs/streaming-llm-responses.md`
|
||||
- סטרימינג של PromptClient: `trustgraph-base/trustgraph/base/prompt_client.py`
|
||||
- סטרימינג של סוכן: `trustgraph-flow/trustgraph/agent/react/agent_manager.py`
|
||||
99
docs/tech-specs/he/schema-refactoring-proposal.he.md
Normal file
99
docs/tech-specs/he/schema-refactoring-proposal.he.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
layout: default
|
||||
title: "הצעה לשחזור תיקיית הסכימה"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# הצעה לשחזור תיקיית הסכימה
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## בעיות נוכחיות
|
||||
|
||||
1. **מבנה שטוח** - כל הסכימות במקום אחד מקשות על הבנת הקשרים
|
||||
2. **שילוב דאגות** - סוגי ליבה, אובייקטים של תחום, וחוזים של API משולבים יחד
|
||||
3. **שמות לא ברורים** - קבצים כמו "object.py", "types.py", "topic.py" לא מציינים בבירור את מטרתם
|
||||
4. **ללא שכבות ברורות** - קשה לראות מה תלוי במה
|
||||
|
||||
## מבנה מוצע
|
||||
|
||||
```
|
||||
trustgraph-base/trustgraph/schema/
|
||||
├── __init__.py
|
||||
├── core/ # סוגי ליבה בסיסיים המשמשים בכל מקום
|
||||
│ ├── __init__.py
|
||||
│ ├── primitives.py # שגיאה, ערך, טריפל, שדה, סכימת שורה
|
||||
│ ├── metadata.py # רשומת מטא-דאטה
|
||||
│ └── topic.py # כלי לטיפול בנושאים
|
||||
│
|
||||
├── knowledge/ # מודלים של תחום ידע ואיסוף
|
||||
│ ├── __init__.py
|
||||
│ ├── graph.py # EntityContext, EntityEmbeddings, Triples
|
||||
│ ├── document.py # מסמך, TextDocument, חתיכה
|
||||
│ ├── knowledge.py # סוגי איסוף ידע
|
||||
│ ├── embeddings.py # כל סוגי הסתמכות הקשורים (הועברו מקבצים רבים)
|
||||
│ └── nlp.py # סוגי הגדרה, נושא, קשר, עובדה
|
||||
│
|
||||
└── services/ # חוזים של בקשות/תגובות שירות
|
||||
├── __init__.py
|
||||
├── llm.py # TextCompletion, Embeddings, בקשות/תגובות של כלי
|
||||
├── retrieval.py # שאילתות/תגובות של GraphRAG, DocumentRAG
|
||||
├── query.py # בקשות/תגובות של GraphEmbeddings, DocumentEmbeddings
|
||||
├── agent.py # בקשות/תגובות של סוכן
|
||||
├── flow.py # בקשות/תגובות של זרימה
|
||||
├── prompt.py # בקשות/תגובות של שירות בקשות
|
||||
├── config.py # שירות תצורה
|
||||
├── library.py # שירות ספרייה
|
||||
└── lookup.py # שירות חיפוש
|
||||
```
|
||||
|
||||
## שינויים מרכזיים
|
||||
|
||||
1. **ארגון היררכי** - הפרדה ברורה בין סוגים ליבה, מודלים של ידע, וחוזים של שירות
|
||||
2. **שמות טובים יותר**:
|
||||
- `types.py` → `core/primitives.py` (מטרה ברורה יותר)
|
||||
- `object.py` → פירוק בין קבצים מתאימים בהתאם לתוכן
|
||||
- `documents.py` → `knowledge/document.py` (יחיד, עקבי)
|
||||
- `models.py` → `services/llm.py` (סוגי מודלים ברורים יותר)
|
||||
- `prompt.py` → פירוק: חלקי שירות ל- `services/prompt.py`, סוגי נתונים ל- `knowledge/nlp.py`
|
||||
|
||||
3. **קבוצות לוגיות**:
|
||||
- כל סוגי ההסתמכות הועברו ל- `knowledge/embeddings.py`
|
||||
- כל חוזי השירות הקשורים ל-LLM ב- `services/llm.py`
|
||||
- הפרדה ברורה של זוגות בקשות/תגובות בספריית השירותים
|
||||
- סוגי איסוף ידע מקובצים עם מודלים אחרים של תחום ידע
|
||||
|
||||
4. **בהירות תלות**:
|
||||
- סוגים ליבה אין תלות
|
||||
- מודלים של ידע תלויים רק בסוגים ליבה
|
||||
- חוזי שירות יכולים להיות תלויים בשני סוגים ליבה ומודלים של ידע
|
||||
|
||||
## יתרונות המעבר
|
||||
|
||||
1. **ניווט קל יותר** - מפתחים יכולים למצוא במהירות את מה שהם צריכים
|
||||
2. **מודולריות טובה יותר** - גבולות ברורים בין דאגות שונות
|
||||
3. **ייבוא פשוט יותר** - מסלולי ייבוא אינטואיטיביים יותר
|
||||
4. **עתידי** - קל להוסיף סוגי ידע חדשים או שירותים ללא בלבול
|
||||
|
||||
## שינויים דוגמה לייבוא
|
||||
|
||||
```python
|
||||
# לפני
|
||||
from trustgraph.schema import Error, Triple, GraphEmbeddings, TextCompletionRequest
|
||||
|
||||
# אחרי
|
||||
from trustgraph.schema.core import Error, Triple
|
||||
from trustgraph.schema.knowledge import GraphEmbeddings
|
||||
from trustgraph.schema.services import TextCompletionRequest
|
||||
```
|
||||
|
||||
## הערות ליישום
|
||||
|
||||
1. שמירה על תאימות אחורה על ידי שמירה על ייבוא ב- `__init__.py`
|
||||
2. העברת קבצים בהדרגה, תוך עדכון ייבוא לפי הצורך
|
||||
3. שקול להוסיף קובץ `legacy.py` שיבוא הכל עבור תקופת המעבר
|
||||
4. עדכון תיעוד כדי לשקף את המבנה החדש
|
||||
|
||||
<function_calls>
|
||||
<invoke name="TodoWrite">
|
||||
<parameter name="todos">[{"id": "1", "content": "להעריך את מבנה תיקיית הסכימה הנוכחי", "status": "completed", "priority": "high"}, {"id": "2", "content": "לנתח את הקבצים של הסכימה ולמטרות שלהם", "status": "completed", "priority": "high"}, {"id": "3", "content": "להציע מבנה ושמות טובים יותר", "status": "completed", "priority": "high"}]
|
||||
578
docs/tech-specs/he/streaming-llm-responses.he.md
Normal file
578
docs/tech-specs/he/streaming-llm-responses.he.md
Normal file
|
|
@ -0,0 +1,578 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לתגובות LLM בסטרימינג"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לתגובות LLM בסטרימינג
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר את יישום התמיכה בסטרימינג עבור תגובות LLM
|
||||
ב-TrustGraph. סטרימינג מאפשר העברה בזמן אמת של טוקנים שנוצרו
|
||||
ככל שהם מיוצרים על ידי ה-LLM, במקום לחכות להשלמת יצירת
|
||||
התגובה.
|
||||
|
||||
יישום זה תומך בתרחישי שימוש הבאים:
|
||||
|
||||
1. **ממשקי משתמש בזמן אמת**: העברת טוקנים לממשק המשתמש בזמן יצירתם,
|
||||
תוך מתן משוב ויזואלי מיידי.
|
||||
2. **זמן עד לטוקן הראשון מופחת**: המשתמש רואה את הפלט מיד
|
||||
ולא מחכה ליצירה מלאה.
|
||||
3. **טיפול בתגובות ארוכות**: טיפול בפלטים ארוכים מאוד שעלולים
|
||||
אחרת לגרום לחריגה מהזמן או לחרוג ממגבלות הזיכרון.
|
||||
4. **יישומים אינטראקטיביים**: אפשור ממשקי צ'אט וסוכנים מגיבים.
|
||||
|
||||
## מטרות
|
||||
|
||||
**תאימות לאחור**: לקוחות קיימים שאינם משתמשים בסטרימינג ממשיכים
|
||||
לעבוד ללא שינוי.
|
||||
**עיצוב API עקבי**: סטרימינג ולא סטרימינג משתמשים באותם דפוסי
|
||||
סכימה עם סטייה מינימלית.
|
||||
**גמישות ספק**: תמיכה בסטרימינג כאשר הוא זמין, מעבר חלק
|
||||
כאשר הוא אינו זמין.
|
||||
**פריסה מדורגת**: יישום הדרגתי להפחתת סיכונים.
|
||||
**תמיכה מקצה לקצה**: סטרימינג מספק ה-LLM דרך ליישומי לקוח
|
||||
באמצעות Pulsar, Gateway API ו-Python API.
|
||||
|
||||
## רקע
|
||||
|
||||
### ארכיטקטורה נוכחית
|
||||
|
||||
זרימת השלמת הטקסט הנוכחית של ה-LLM פועלת באופן הבא:
|
||||
|
||||
1. לקוח שולח `TextCompletionRequest` עם שדות `system` ו-`prompt`.
|
||||
2. שירות ה-LLM מעבד את הבקשה וממתין להשלמת היצירה.
|
||||
3. `TextCompletionResponse` יחיד מוחזר עם מחרוזת `response` מלאה.
|
||||
|
||||
סכימה נוכחית (`trustgraph-base/trustgraph/schema/services/llm.py`):
|
||||
|
||||
```python
|
||||
class TextCompletionRequest(Record):
|
||||
system = String()
|
||||
prompt = String()
|
||||
|
||||
class TextCompletionResponse(Record):
|
||||
error = Error()
|
||||
response = String()
|
||||
in_token = Integer()
|
||||
out_token = Integer()
|
||||
model = String()
|
||||
```
|
||||
|
||||
### מגבלות נוכחיות
|
||||
|
||||
**השהייה (Latency)**: משתמשים חייבים לחכות לסיום יצירת התוכן לפני שהם רואים פלט כלשהו.
|
||||
**סיכון לחריגת זמן (Timeout)**: יצירת תוכן ארוכה עלולה לחרוג מספי זמן המוגדר בלקוח.
|
||||
**חוויית משתמש ירודה (Poor UX)**: היעדר משוב במהלך היצירה יוצר תחושה של איטיות.
|
||||
**שימוש במשאבים**: תגובות מלאות חייבות להיות מאוחסנות בזיכרון.
|
||||
|
||||
מפרט זה מתייחס למגבלות אלה על ידי אפשור העברת תגובה הדרגתית תוך שמירה על תאימות מלאה לאחור.
|
||||
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### שלב 1: תשתית
|
||||
|
||||
שלב 1 מקיים את הבסיס להעברה באמצעות שינוי סכימות, ממשקי API וכלי שורת פקודה.
|
||||
|
||||
|
||||
#### שינויים בסכימה
|
||||
|
||||
##### סכימת LLM (`trustgraph-base/trustgraph/schema/services/llm.py`)
|
||||
|
||||
**שינויים בבקשה:**
|
||||
|
||||
```python
|
||||
class TextCompletionRequest(Record):
|
||||
system = String()
|
||||
prompt = String()
|
||||
streaming = Boolean() # NEW: Default false for backward compatibility
|
||||
```
|
||||
|
||||
`streaming`: כאשר `true`, מבקשים משלוח תגובה בסטרימינג.
|
||||
ברירת מחדל: `false` (ההתנהגות הקיימת נשמרת).
|
||||
|
||||
**שינויים בתגובה:**
|
||||
|
||||
```python
|
||||
class TextCompletionResponse(Record):
|
||||
error = Error()
|
||||
response = String()
|
||||
in_token = Integer()
|
||||
out_token = Integer()
|
||||
model = String()
|
||||
end_of_stream = Boolean() # NEW: Indicates final message
|
||||
```
|
||||
|
||||
`end_of_stream`: כאשר `true`, מציין שזו התגובה הסופית (או היחידה).
|
||||
עבור בקשות שאינן סטרימינג: תגובה יחידה עם `end_of_stream=true`.
|
||||
עבור בקשות סטרימינג: מספר תגובות, כולן עם `end_of_stream=false`.
|
||||
מלבד התגובה האחרונה.
|
||||
|
||||
##### סכימת הפרומפט (`trustgraph-base/trustgraph/schema/services/prompt.py`)
|
||||
|
||||
שירות הפרומפט עוטף השלמת טקסט, ולכן הוא משקף את אותו דפוס:
|
||||
|
||||
**שינויים בבקשה:**
|
||||
|
||||
```python
|
||||
class PromptRequest(Record):
|
||||
id = String()
|
||||
terms = Map(String())
|
||||
streaming = Boolean() # NEW: Default false
|
||||
```
|
||||
|
||||
**שינויים בתגובה:**
|
||||
|
||||
```python
|
||||
class PromptResponse(Record):
|
||||
error = Error()
|
||||
text = String()
|
||||
object = String()
|
||||
end_of_stream = Boolean() # NEW: Indicates final message
|
||||
```
|
||||
|
||||
#### שינויים בממשק ה-Gateway API
|
||||
|
||||
ממשק ה-Gateway API חייב לחשוף יכולות סטרימינג ללקוחות HTTP/WebSocket.
|
||||
|
||||
**עדכונים לממשק ה-REST API:**
|
||||
|
||||
`POST /api/v1/text-completion`: קבלת פרמטר `streaming` בגוף הבקשה
|
||||
התנהגות התגובה תלויה בדגל הסטרימינג:
|
||||
`streaming=false`: תגובת JSON בודדת (ההתנהגות הנוכחית)
|
||||
`streaming=true`: זרם Server-Sent Events (SSE) או הודעות WebSocket
|
||||
|
||||
**פורמט תגובה (סטרימינג):**
|
||||
|
||||
כל חלק בזרם עוקב אחר מבנה הסכימה זהה:
|
||||
```json
|
||||
{
|
||||
"response": "partial text...",
|
||||
"end_of_stream": false,
|
||||
"model": "model-name"
|
||||
}
|
||||
```
|
||||
|
||||
חלק אחרון:
|
||||
```json
|
||||
{
|
||||
"response": "final text chunk",
|
||||
"end_of_stream": true,
|
||||
"in_token": 150,
|
||||
"out_token": 500,
|
||||
"model": "model-name"
|
||||
}
|
||||
```
|
||||
|
||||
#### שינויים בממשק ה-API של Python
|
||||
|
||||
ממשק ה-API של הלקוח ב-Python חייב לתמוך הן במצב סטרימינג והן במצב לא-סטרימינג
|
||||
תוך שמירה על תאימות לאחור.
|
||||
|
||||
**עדכונים ל-LlmClient** (`trustgraph-base/trustgraph/clients/llm_client.py`):
|
||||
|
||||
```python
|
||||
class LlmClient(BaseClient):
|
||||
def request(self, system, prompt, timeout=300, streaming=False):
|
||||
"""
|
||||
Non-streaming request (backward compatible).
|
||||
Returns complete response string.
|
||||
"""
|
||||
# Existing behavior when streaming=False
|
||||
|
||||
async def request_stream(self, system, prompt, timeout=300):
|
||||
"""
|
||||
Streaming request.
|
||||
Yields response chunks as they arrive.
|
||||
"""
|
||||
# New async generator method
|
||||
```
|
||||
|
||||
**עדכונים עבור PromptClient** (`trustgraph-base/trustgraph/base/prompt_client.py`):
|
||||
|
||||
דפוס דומה עם הפרמטר `streaming` וגרסה אסינכרונית של מחולל.
|
||||
|
||||
#### שינויים בכלי שורת הפקודה
|
||||
|
||||
**tg-invoke-llm** (`trustgraph-cli/trustgraph/cli/invoke_llm.py`):
|
||||
|
||||
```
|
||||
tg-invoke-llm [system] [prompt] [--no-streaming] [-u URL] [-f flow-id]
|
||||
```
|
||||
|
||||
הפעלת סטרימינג כברירת מחדל לשיפור חוויית משתמש אינטראקטיבית.
|
||||
הדגל `--no-streaming` משבית את הסטרימינג.
|
||||
כאשר הסטרימינג מופעל: פלט טוקנים לפלט סטנדרטי כשהם מגיעים.
|
||||
כאשר הסטרימינג אינו מופעל: ממתינים לתגובה מלאה, ולאחר מכן מבצעים פלט.
|
||||
|
||||
**tg-invoke-prompt** (`trustgraph-cli/trustgraph/cli/invoke_prompt.py`):
|
||||
|
||||
```
|
||||
tg-invoke-prompt [template-id] [var=value...] [--no-streaming] [-u URL] [-f flow-id]
|
||||
```
|
||||
|
||||
אותו דפוס כמו `tg-invoke-llm`.
|
||||
|
||||
#### שינויים במחלקת הבסיס של שירות מודל שפה גדול (LLM).
|
||||
|
||||
**LlmService** (`trustgraph-base/trustgraph/base/llm_service.py`):
|
||||
|
||||
```python
|
||||
class LlmService(FlowProcessor):
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
request = msg.value()
|
||||
streaming = getattr(request, 'streaming', False)
|
||||
|
||||
if streaming and self.supports_streaming():
|
||||
async for chunk in self.generate_content_stream(...):
|
||||
await self.send_response(chunk, end_of_stream=False)
|
||||
await self.send_response(final_chunk, end_of_stream=True)
|
||||
else:
|
||||
response = await self.generate_content(...)
|
||||
await self.send_response(response, end_of_stream=True)
|
||||
|
||||
def supports_streaming(self):
|
||||
"""Override in subclass to indicate streaming support."""
|
||||
return False
|
||||
|
||||
async def generate_content_stream(self, system, prompt, model, temperature):
|
||||
"""Override in subclass to implement streaming."""
|
||||
raise NotImplementedError()
|
||||
```
|
||||
|
||||
--
|
||||
|
||||
### שלב 2: הוכחת היתכנות של VertexAI
|
||||
|
||||
שלב 2 מיישם סטרימינג בספק יחיד (VertexAI) כדי לאמת את
|
||||
התשתית ולאפשר בדיקות מקצה לקצה.
|
||||
|
||||
#### יישום VertexAI
|
||||
|
||||
**מודול:** `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py`
|
||||
|
||||
**שינויים:**
|
||||
|
||||
1. החלפה של `supports_streaming()` כדי להחזיר `True`
|
||||
2. יישום מחולל אסינכרוני `generate_content_stream()`
|
||||
3. טיפול גם במודלים של Gemini וגם של Claude (דרך ממשק ה-API של VertexAI Anthropic)
|
||||
|
||||
**סטרימינג של Gemini:**
|
||||
|
||||
```python
|
||||
async def generate_content_stream(self, system, prompt, model, temperature):
|
||||
model_instance = self.get_model(model, temperature)
|
||||
response = model_instance.generate_content(
|
||||
[system, prompt],
|
||||
stream=True # Enable streaming
|
||||
)
|
||||
for chunk in response:
|
||||
yield LlmChunk(
|
||||
text=chunk.text,
|
||||
in_token=None, # Available only in final chunk
|
||||
out_token=None,
|
||||
)
|
||||
# Final chunk includes token counts from response.usage_metadata
|
||||
```
|
||||
|
||||
**קלוד (דרך VertexAI של חברת Anthropic) - סטרימינג:**
|
||||
|
||||
```python
|
||||
async def generate_content_stream(self, system, prompt, model, temperature):
|
||||
with self.anthropic_client.messages.stream(...) as stream:
|
||||
for text in stream.text_stream:
|
||||
yield LlmChunk(text=text)
|
||||
# Token counts from stream.get_final_message()
|
||||
```
|
||||
|
||||
#### בדיקות
|
||||
|
||||
בדיקות יחידה עבור הרכבת תגובות סטרימינג
|
||||
בדיקות אינטגרציה עם VertexAI (Gemini ו-Claude)
|
||||
בדיקות מקצה לקצה: CLI -> Gateway -> Pulsar -> VertexAI -> חזרה
|
||||
בדיקות תאימות לאחור: בקשות שאינן סטרימינג עדיין עובדות
|
||||
|
||||
--
|
||||
|
||||
### שלב 3: כל ספקי מודלי שפה גדולים (LLM)
|
||||
|
||||
שלב 3 מרחיב את תמיכת הסטרימינג לכל ספקי מודלי השפה הגדולים במערכת.
|
||||
|
||||
#### סטטוס יישום ספק
|
||||
|
||||
כל ספק חייב לבצע אחת מהפעולות הבאות:
|
||||
1. **תמיכה מלאה בסטרימינג**: ליישם `generate_content_stream()`
|
||||
2. **מצב תאימות**: לטפל בדגל `end_of_stream` בצורה נכונה
|
||||
(להחזיר תגובה בודדת עם `end_of_stream=true`)
|
||||
|
||||
| ספק | חבילה | תמיכה בסטרימינג |
|
||||
|----------|---------|-------------------|
|
||||
| OpenAI | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| Claude/Anthropic | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| Ollama | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| Cohere | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| Mistral | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| Azure OpenAI | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| Google AI Studio | trustgraph-flow | מלא (ממשק סטרימינג מקורי) |
|
||||
| VertexAI | trustgraph-vertexai | מלא (שלב 2) |
|
||||
| Bedrock | trustgraph-bedrock | מלא (ממשק סטרימינג מקורי) |
|
||||
| LM Studio | trustgraph-flow | מלא (תואם ל-OpenAI) |
|
||||
| LlamaFile | trustgraph-flow | מלא (תואם ל-OpenAI) |
|
||||
| vLLM | trustgraph-flow | מלא (תואם ל-OpenAI) |
|
||||
| TGI | trustgraph-flow | מצומצם |
|
||||
| Azure | trustgraph-flow | מצומצם |
|
||||
|
||||
#### תבנית יישום
|
||||
|
||||
עבור ספקים התואמים ל-OpenAI (OpenAI, LM Studio, LlamaFile, vLLM):
|
||||
|
||||
```python
|
||||
async def generate_content_stream(self, system, prompt, model, temperature):
|
||||
response = await self.client.chat.completions.create(
|
||||
model=model,
|
||||
messages=[
|
||||
{"role": "system", "content": system},
|
||||
{"role": "user", "content": prompt}
|
||||
],
|
||||
temperature=temperature,
|
||||
stream=True
|
||||
)
|
||||
async for chunk in response:
|
||||
if chunk.choices[0].delta.content:
|
||||
yield LlmChunk(text=chunk.choices[0].delta.content)
|
||||
```
|
||||
|
||||
--
|
||||
|
||||
### שלב 4: ממשק API של הסוכן
|
||||
|
||||
שלב 4 מרחיב את הסטרימינג לממשק ה-API של הסוכן. זה מורכב יותר מכיוון שה-
|
||||
ממשק ה-API של הסוכן הוא כבר מטבעו רב-הודעות (מחשבה → פעולה → תצפית
|
||||
→ חזור → תשובה סופית).
|
||||
|
||||
#### הסכימה הנוכחית של הסוכן
|
||||
|
||||
```python
|
||||
class AgentStep(Record):
|
||||
thought = String()
|
||||
action = String()
|
||||
arguments = Map(String())
|
||||
observation = String()
|
||||
user = String()
|
||||
|
||||
class AgentRequest(Record):
|
||||
question = String()
|
||||
state = String()
|
||||
group = Array(String())
|
||||
history = Array(AgentStep())
|
||||
user = String()
|
||||
|
||||
class AgentResponse(Record):
|
||||
answer = String()
|
||||
error = Error()
|
||||
thought = String()
|
||||
observation = String()
|
||||
```
|
||||
|
||||
#### שינויים מוצעים בסכימת הסוכן
|
||||
|
||||
**בקשות לשינויים:**
|
||||
|
||||
```python
|
||||
class AgentRequest(Record):
|
||||
question = String()
|
||||
state = String()
|
||||
group = Array(String())
|
||||
history = Array(AgentStep())
|
||||
user = String()
|
||||
streaming = Boolean() # NEW: Default false
|
||||
```
|
||||
|
||||
**שינויים בתגובה:**
|
||||
|
||||
הסוכן מייצר סוגים שונים של פלט במהלך מחזור החשיבה שלו:
|
||||
מחשבות (היגיון)
|
||||
פעולות (קריאות לכלי)
|
||||
תצפיות (תוצאות של כלי)
|
||||
תשובה (תגובה סופית)
|
||||
שגיאות
|
||||
|
||||
מכיוון ש-`chunk_type` מציין איזה סוג תוכן נשלח, השדות הנפרדים
|
||||
`answer`, `error`, `thought` ו-`observation` יכולים להיות מקובצים לשדה
|
||||
`content` יחיד:
|
||||
|
||||
```python
|
||||
class AgentResponse(Record):
|
||||
chunk_type = String() # "thought", "action", "observation", "answer", "error"
|
||||
content = String() # The actual content (interpretation depends on chunk_type)
|
||||
end_of_message = Boolean() # Current thought/action/observation/answer is complete
|
||||
end_of_dialog = Boolean() # Entire agent dialog is complete
|
||||
```
|
||||
|
||||
**סמנטיקה של שדות:**
|
||||
|
||||
`chunk_type`: מציין איזה סוג תוכן נמצא בשדה `content`
|
||||
`"thought"`: חשיבה/היגיון של הסוכן
|
||||
`"action"`: כלי/פעולה המופעלת
|
||||
`"observation"`: תוצאה מהפעלת הכלי
|
||||
`"answer"`: תשובה סופית לשאלה של המשתמש
|
||||
`"error"`: הודעת שגיאה
|
||||
|
||||
`content`: התוכן המועבר בפועל, המפורש בהתאם ל-`chunk_type`
|
||||
|
||||
`end_of_message`: כאשר `true`, סוג החלק הנוכחי הושלם
|
||||
דוגמה: כל הטוקנים עבור המחשבה הנוכחית נשלחו
|
||||
מאפשר ללקוחות לדעת מתי לעבור לשלב הבא
|
||||
|
||||
`end_of_dialog`: כאשר `true`, האינטראקציה כולה של הסוכן הושלמה
|
||||
זו ההודעה האחרונה בזרם
|
||||
|
||||
#### התנהגות סטרימינג של הסוכן
|
||||
|
||||
כאשר `streaming=true`:
|
||||
|
||||
1. **סטרימינג של מחשבות:**
|
||||
מספר חלקים עם `chunk_type="thought"`, `end_of_message=false`
|
||||
החלק האחרון של המחשבה מכיל `end_of_message=true`
|
||||
2. **הודעת פעולה:**
|
||||
חלק יחיד עם `chunk_type="action"`, `end_of_message=true`
|
||||
3. **תצפית:**
|
||||
חלק/ים עם `chunk_type="observation"`, האחרון מכיל `end_of_message=true`
|
||||
4. **חזור** על שלבים 1-3 כאשר הסוכן מסיק מסקנות
|
||||
5. **תשובה סופית:**
|
||||
`chunk_type="answer"` עם התגובה הסופית ב-`content`
|
||||
החלק האחרון מכיל `end_of_message=true`, `end_of_dialog=true`
|
||||
|
||||
**רצף סטרימינג לדוגמה:**
|
||||
|
||||
```
|
||||
{chunk_type: "thought", content: "I need to", end_of_message: false, end_of_dialog: false}
|
||||
{chunk_type: "thought", content: " search for...", end_of_message: true, end_of_dialog: false}
|
||||
{chunk_type: "action", content: "search", end_of_message: true, end_of_dialog: false}
|
||||
{chunk_type: "observation", content: "Found: ...", end_of_message: true, end_of_dialog: false}
|
||||
{chunk_type: "thought", content: "Based on this", end_of_message: false, end_of_dialog: false}
|
||||
{chunk_type: "thought", content: " I can answer...", end_of_message: true, end_of_dialog: false}
|
||||
{chunk_type: "answer", content: "The answer is...", end_of_message: true, end_of_dialog: true}
|
||||
```
|
||||
|
||||
כאשר `streaming=false`:
|
||||
התנהגות נוכחית נשמרת
|
||||
תגובה אחת עם תשובה מלאה
|
||||
`end_of_message=true`, `end_of_dialog=true`
|
||||
|
||||
#### שער (Gateway) ו-API בפייתון
|
||||
|
||||
שער: נקודת קצה חדשה של SSE/WebSocket עבור סטרימינג של סוכן
|
||||
API בפייתון: שיטת גנרטור אסינכרונית חדשה `agent_stream()`
|
||||
|
||||
--
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
**ללא נקודות תורפה חדשות**: סטרימינג משתמש באותה אימות/הרשאה
|
||||
**הגבלת קצב**: יש להחיל מגבלות קצב פר-טוקן או פר-חלק במידת הצורך
|
||||
**טיפול בחיבורים**: יש לסיים חיבורים בצורה תקינה בעת ניתוק הלקוח
|
||||
**ניהול תזמון**: בקשות סטרימינג דורשות טיפול מתאים בתזמון
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
**זיכרון**: סטרימינג מפחית את השימוש בזיכרון המקסימלי (ללא אחסון מלא של התגובה)
|
||||
**השהיה**: זמן עד לקבלת הטוקן הראשון קטן משמעותית
|
||||
**תקורה של חיבורים**: לחיבורי SSE/WebSocket יש תקורה של שמירה על חיבור פעיל
|
||||
**תפוקת Pulsar**: מספר הודעות קטנות לעומת הודעה גדולה אחת
|
||||
פשרה
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
### בדיקות יחידה
|
||||
סריאליזציה/דה-סריאליזציה של סכימה עם שדות חדשים
|
||||
תאימות לאחור (שדות חסרים משתמשים בערכי ברירת מחדל)
|
||||
לוגיקת הרכבת חלקים
|
||||
|
||||
### בדיקות אינטגרציה
|
||||
יישום הסטרימינג של כל ספק מודלי שפה גדולים (LLM)
|
||||
נקודות קצה של סטרימינג של API בשער
|
||||
שיטות סטרימינג של לקוח בפייתון
|
||||
|
||||
### בדיקות מקצה לקצה
|
||||
פלט סטרימינג של כלי שורת הפקודה (CLI)
|
||||
זרימה מלאה: לקוח → שער → Pulsar → LLM → חזרה
|
||||
עומסי עבודה מעורבים של סטרימינג/לא סטרימינג
|
||||
|
||||
### בדיקות תאימות לאחור
|
||||
לקוחות קיימים עובדים ללא שינוי
|
||||
בקשות לא סטרימינג מתנהגות באופן זהה
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
### שלב 1: תשתית
|
||||
פריסת שינויי סכימה (תואמת לאחור)
|
||||
פריסת עדכוני API בשער
|
||||
פריסת עדכוני API בפייתון
|
||||
שחרור עדכוני כלי שורת הפקודה
|
||||
|
||||
### שלב 2: VertexAI
|
||||
הטמעת יישום סטרימינג של VertexAI
|
||||
אימות באמצעות עומסי עבודה לבדיקה
|
||||
|
||||
### שלב 3: כל הספקים
|
||||
הטמעת עדכוני ספק באופן הדרגתי
|
||||
ניטור לאיתור בעיות
|
||||
|
||||
### שלב 4: ממשק API של סוכן
|
||||
הטמעת שינויים בסכימת הסוכן
|
||||
הטמעת יישום סטרימינג של סוכן
|
||||
עדכון התיעוד
|
||||
|
||||
## ציר זמן
|
||||
|
||||
| שלב | תיאור | תלויות |
|
||||
|-------|-------------|--------------|
|
||||
| שלב 1 | תשתית | אין |
|
||||
| שלב 2 | הוכחת היתכנות של VertexAI | שלב 1 |
|
||||
| שלב 3 | כל הספקים | שלב 2 |
|
||||
| שלב 4 | ממשק API של סוכן | שלב 3 |
|
||||
|
||||
## החלטות עיצוב
|
||||
|
||||
השאלות הבאות נפתרו במהלך המפרט:
|
||||
|
||||
1. **ספירת טוקנים בסטרימינג**: ספירת הטוקנים היא הפרשים, ולא סכומים מצטברים.
|
||||
צרכנים יכולים לחבר אותם אם יש צורך. זה תואם לאופן שבו רוב הספקים מדווחים
|
||||
על שימוש ומפשט את היישום.
|
||||
|
||||
2. **טיפול בשגיאות בזרמים**: אם מתרחשת שגיאה, השדה `error` מאוכלס ושאר השדות אינם נחוצים. שגיאה היא תמיד ההודעה האחרונה - אסור לשלוח או לצפות להודעות נוספות לאחר מכן.
|
||||
|
||||
|
||||
שגיאה. עבור זרמי מודלים שפתיים (LLM) / הנחיות, `end_of_stream=true`. עבור זרמי סוכנים,
|
||||
`chunk_type="error"` עם `end_of_dialog=true`.
|
||||
|
||||
3. **התאוששות מתגובה חלקית**: פרוטוקול העברת ההודעות (Pulsar) עמיד,
|
||||
ולכן אין צורך בניסיונות חוזרים ברמת ההודעה. אם לקוח מאבד את המעקב אחר הזרם
|
||||
או מתנתק, עליו לנסות שוב את כל הבקשה מההתחלה.
|
||||
|
||||
4. **שירות מהיר עם סטרימינג**: סטרימינג נתמך רק עבור טקסט (`text`)
|
||||
תשובות, ולא עבור תשובות מובנות (`object`). שירות הפרומפט יודע מראש
|
||||
האם הפלט יהיה JSON או טקסט, בהתבסס על תבנית הפרומפט. אם מתבצעת
|
||||
בקשת סטרימינג עבור פרומפט שפלטו הוא JSON, אז...
|
||||
השירות צריך או:
|
||||
להחזיר את קובץ ה-JSON השלם בתגובה אחת עם `end_of_stream=true`, או
|
||||
לדחות את בקשת הסטרימינג עם שגיאה
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
אין כרגע.
|
||||
|
||||
## הפניות
|
||||
|
||||
סכימת מודל שפה גדול (LLM) נוכחית: `trustgraph-base/trustgraph/schema/services/llm.py`
|
||||
סכימת הנחיה נוכחית: `trustgraph-base/trustgraph/schema/services/prompt.py`
|
||||
סכימת סוכן נוכחית: `trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
שירות LLM בסיסי: `trustgraph-base/trustgraph/base/llm_service.py`
|
||||
ספק VertexAI: `trustgraph-vertexai/trustgraph/model/text_completion/vertexai/llm.py`
|
||||
ממשק API של שער: `trustgraph-base/trustgraph/api/`
|
||||
כלי שורת פקודה: `trustgraph-cli/trustgraph/cli/`
|
||||
621
docs/tech-specs/he/structured-data-2.he.md
Normal file
621
docs/tech-specs/he/structured-data-2.he.md
Normal file
|
|
@ -0,0 +1,621 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של נתונים מובנים (חלק 2)"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של נתונים מובנים (חלק 2)
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה עוסק בנושאים ופערים שזוהו במהלך יישום ראשוני של שילוב נתונים מובנים של TrustGraph, כפי שמתואר ב-`structured-data.md`.
|
||||
|
||||
## הצגת בעיות
|
||||
|
||||
### 1. חוסר עקביות בשמות: "אובייקט" לעומת "שורה"
|
||||
|
||||
יישום נוכחי משתמש בטרמינולוגיה של "אובייקט" בכל מקום (לדוגמה, `ExtractedObject`, חילוץ אובייקטים, הטמעות אובייקטים). שם זה כללי מדי וגורם לבלבול:
|
||||
|
||||
"אובייקט" הוא מונח מוגדר מראש בתוכנה (אובייקטים בפייתון, אובייקטים ב-JSON, וכו')
|
||||
הנתונים המטופלים הם למעשה טבלאיים - שורות בטבלאות עם סכימות מוגדרות
|
||||
"שורה" מתארת במדויק יותר את מודל הנתונים ומתאימה לטרמינולוגיה של מסדי נתונים
|
||||
|
||||
חוסר עקביות זה מופיע בשמות מודולים, שמות מחלקות, סוגי הודעות ובתעוד.
|
||||
|
||||
### 2. מגבלות שאילתות של אחסון שורות
|
||||
|
||||
ליישום הנוכחי של אחסון שורות יש מגבלות שאילתות משמעותיות:
|
||||
|
||||
**אי התאמה לשפה טבעית**: שאילתות מתקשות עם וריאציות של נתונים מהעולם האמיתי. לדוגמה:
|
||||
קשה למצוא מסד נתונים של רחובות המכיל `"CHESTNUT ST"` כאשר שואלים על `"Chestnut Street"`
|
||||
קיצורים, הבדלי רישיות ווריאציות בפורמט שוברים שאילתות התאמה מדויקת
|
||||
משתמשים מצפים להבנה סמנטית, אך המאגר מספק התאמה מילולית
|
||||
|
||||
**בעיות בהתפתחות סכימה**: שינוי סכימות גורם לבעיות:
|
||||
נתונים קיימים עשויים שלא להתאים לסכימות מעודכנות
|
||||
שינויים במבנה הטבלה עלולים לשבור שאילתות ושלמות נתונים
|
||||
אין מסלול מעבר ברור לעדכוני סכימה
|
||||
|
||||
### 3. הטמעות שורות נדרשות
|
||||
|
||||
בהקשר לבעיה 2, המערכת זקוקה להטמעות וקטוריות עבור נתוני שורה כדי לאפשר:
|
||||
|
||||
חיפוש סמנטי בנתונים מובנים (מציאת "Chestnut Street" כאשר הנתונים מכילים "CHESTNUT ST")
|
||||
התאמת דמיון לשאילתות מעורפלות
|
||||
חיפוש היברידי המשלב מסננים מובנים עם דמיון סמנטי
|
||||
תמיכה טובה יותר בשפה טבעית
|
||||
|
||||
שירות ההטמעה הוגדר אך לא יושם.
|
||||
|
||||
### 4. הטמעה של נתוני שורה לא שלמה
|
||||
|
||||
צינור ההטמעה של נתונים מובנים אינו פעיל במלואו:
|
||||
|
||||
קיימות הנחיות אבחון כדי לסווג פורמטים של קלט (CSV, JSON, וכו')
|
||||
שירות ההטמעה המשתמש בהנחיות אלה אינו מחובר למערכת
|
||||
אין מסלול מקצה לקצה לטעינת נתונים מובנים לאחסון השורות
|
||||
|
||||
## מטרות
|
||||
|
||||
**גמישות סכימה**: לאפשר התפתחות סכימה מבלי לשבור נתונים קיימים או לדרוש מעברים
|
||||
**שמות עקביים**: לתקנן על "שורה" בכל בסיס הקוד
|
||||
**יכולת שאילתא סמנטית**: לתמוך בהתאמה מעורפלת/סמנטית באמצעות הטמעות שורות
|
||||
**צינור הטמעה שלם**: לספק מסלול מקצה לקצה לטעינת נתונים מובנים
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### סכימת אחסון שורות מאוחדת
|
||||
|
||||
יישום קודם יצר טבלת Cassandra נפרדת עבור כל סכימה. זה גרם לבעיות כאשר הסכימות התפתחו, מכיוון ששינויים במבנה הטבלה דרשו מעברים.
|
||||
|
||||
העיצוב החדש משתמש בטבלה מאוחדת אחת עבור כל נתוני שורה:
|
||||
|
||||
```sql
|
||||
CREATE TABLE rows (
|
||||
collection text,
|
||||
schema_name text,
|
||||
index_name text,
|
||||
index_value frozen<list<text>>,
|
||||
data map<text, text>,
|
||||
source text,
|
||||
PRIMARY KEY ((collection, schema_name, index_name), index_value)
|
||||
)
|
||||
```
|
||||
|
||||
#### הגדרות עמודות
|
||||
|
||||
| עמודה | סוג | תיאור |
|
||||
|--------|------|-------------|
|
||||
| `collection` | `text` | מזהה איסוף/ייבוא נתונים (ממטא-נתונים) |
|
||||
| `schema_name` | `text` | שם הסכימה אליה השורה הזו מתאימה |
|
||||
| `index_name` | `text` | שם השדה/ים המאומדד, מחובר באמצעות פסיק עבור אינדקסים מורכבים |
|
||||
| `index_value` | `frozen<list<text>>` | ערכי האינדקס כרשימה |
|
||||
| `data` | `map<text, text>` | נתוני השורה כזוגות מפתח-ערך |
|
||||
| `source` | `text` | URI אופציונלי המקשר למידע על מקור בגרף הידע. מחרוזת ריקה או NULL מציינים שאין מקור. |
|
||||
|
||||
#### טיפול באינדקסים
|
||||
|
||||
כל שורה מאוחסנת מספר פעמים - פעם אחת עבור כל שדה מאומדד המוגדר בסכימה. שדות המפתח הראשוניים מטופלים כאינדקס ללא סימון מיוחד, מה שמספק גמישות עתידית.
|
||||
|
||||
**דוגמה לאינדקס של שדה בודד:**
|
||||
הסכימה מגדירה את `email` כמאומדד
|
||||
`index_name = "email"`
|
||||
`index_value = ['foo@bar.com']`
|
||||
|
||||
**דוגמה לאינדקס מורכב:**
|
||||
הסכימה מגדירה אינדקס מורכב על `region` ו-`status`
|
||||
`index_name = "region,status"` (שמות השדות ממוינים ומחוברים באמצעות פסיק)
|
||||
`index_value = ['US', 'active']` (הערכים באותו סדר כמו שמות השדות)
|
||||
|
||||
**דוגמה למפתח ראשי:**
|
||||
הסכימה מגדירה את `customer_id` כמפתח ראשי
|
||||
`index_name = "customer_id"`
|
||||
`index_value = ['CUST001']`
|
||||
|
||||
#### תבניות שאילתה
|
||||
|
||||
כל השאילתות עוקבות אחר אותו תבנית, ללא קשר לאיזה אינדקס משתמשים:
|
||||
|
||||
```sql
|
||||
SELECT * FROM rows
|
||||
WHERE collection = 'import_2024'
|
||||
AND schema_name = 'customers'
|
||||
AND index_name = 'email'
|
||||
AND index_value = ['foo@bar.com']
|
||||
```
|
||||
|
||||
#### פשרות עיצוביות
|
||||
|
||||
**יתרונות:**
|
||||
שינויים בסכימה אינם מחייבים שינויים במבנה הטבלה
|
||||
נתוני השורה אינם גלויים ל-Cassandra - הוספות/הסרות שדות הן שקופות
|
||||
דפוס שאילתות עקבי לכל שיטות הגישה
|
||||
אין אינדקסים משניים של Cassandra (שיכולים להיות איטיים בקנה מידה גדול)
|
||||
סוגי Cassandra מקוריים בכל מקום (`map`, `frozen<list>`)
|
||||
|
||||
**פשרות:**
|
||||
הגברה בכתיבה: כל הוספת שורה = N הוספות (אחת לכל שדה מועדן)
|
||||
תקורה של אחסון עקב שכפול נתוני שורה
|
||||
מידע על סוגים מאוחסן בתצורת הסכימה, המרה בשכבת האפליקציה
|
||||
|
||||
#### מודל עקביות
|
||||
|
||||
העיצוב מקבל מספר פישוטים:
|
||||
|
||||
1. **אין עדכוני שורות**: המערכת היא רק להוספה. זה מבטל חששות לגבי עקביות בעדכון עותקים מרובים של אותה שורה.
|
||||
|
||||
2. **סובלנות לשינויי סכימה**: כאשר הסכימות משתנות (לדוגמה, הוספת/הסרת אינדקסים), שורות קיימות שומרות על האינדוקס המקורי שלהן. שורות ישנות לא יהיו ניתנות לגילוי באמצעות אינדקסים חדשים. משתמשים יכולים למחוק וליצור מחדש סכימה כדי להבטיח עקביות במידת הצורך.
|
||||
|
||||
### מעקב ומחיקת מחיצות
|
||||
|
||||
#### הבעיה
|
||||
|
||||
עם מפתח המחיצה `(collection, schema_name, index_name)`, מחיקה יעילה דורשת ידיעת כל מפתחות המחיצה למחיקה. מחיקה רק לפי `collection` או `collection + schema_name` דורשת ידיעת כל ערכי `index_name` שיש להם נתונים.
|
||||
|
||||
#### טבלת מעקב מחיצות
|
||||
|
||||
טבלת חיפוש משנית עוקבת אחר אילו מחיצות קיימות:
|
||||
|
||||
```sql
|
||||
CREATE TABLE row_partitions (
|
||||
collection text,
|
||||
schema_name text,
|
||||
index_name text,
|
||||
PRIMARY KEY ((collection), schema_name, index_name)
|
||||
)
|
||||
```
|
||||
|
||||
זה מאפשר גילוי יעיל של מחיצות עבור פעולות מחיקה.
|
||||
|
||||
#### התנהגות של כותב שורות
|
||||
|
||||
כותב השורות שומר מטמון בזיכרון של זוגות `(collection, schema_name)` רשומים. בעת עיבוד שורה:
|
||||
|
||||
1. בדוק אם `(collection, schema_name)` נמצא במטמון
|
||||
2. אם לא שמור במטמון (השורה הראשונה עבור זוג זה):
|
||||
חפש את תצורת הסכימה כדי לקבל את כל שמות האינדקסים
|
||||
הכנס ערכים ל-`row_partitions` עבור כל `(collection, schema_name, index_name)`
|
||||
הוסף את הזוג למטמון
|
||||
3. המשך בכתיבת נתוני השורה
|
||||
|
||||
כותב השורות גם עוקב אחר אירועי שינוי בתצורת הסכימה. כאשר סכימה משתנה, רשומות מטמון רלוונטיות נמחקים כך שהשורה הבאה תגרום לרישום מחדש עם שמות האינדקסים המעודכנים.
|
||||
|
||||
גישה זו מבטיחה:
|
||||
כתיבות לטבלת חיפוש מתרחשות פעם אחת לכל זוג `(collection, schema_name)`, ולא לכל שורה
|
||||
טבלת החיפוש משקפת את האינדקסים שהיו פעילים בעת כתיבת הנתונים
|
||||
שינויי סכימה במהלך הייבוא מזוהים כראוי
|
||||
|
||||
#### פעולות מחיקה
|
||||
|
||||
**מחיקת אוסף:**
|
||||
```sql
|
||||
-- 1. Discover all partitions
|
||||
SELECT schema_name, index_name FROM row_partitions WHERE collection = 'X';
|
||||
|
||||
-- 2. Delete each partition from rows table
|
||||
DELETE FROM rows WHERE collection = 'X' AND schema_name = '...' AND index_name = '...';
|
||||
-- (repeat for each discovered partition)
|
||||
|
||||
-- 3. Clean up the lookup table
|
||||
DELETE FROM row_partitions WHERE collection = 'X';
|
||||
```
|
||||
|
||||
**מחיקת אוסף וסכימה:**
|
||||
```sql
|
||||
-- 1. Discover partitions for this schema
|
||||
SELECT index_name FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y';
|
||||
|
||||
-- 2. Delete each partition from rows table
|
||||
DELETE FROM rows WHERE collection = 'X' AND schema_name = 'Y' AND index_name = '...';
|
||||
-- (repeat for each discovered partition)
|
||||
|
||||
-- 3. Clean up the lookup table entries
|
||||
DELETE FROM row_partitions WHERE collection = 'X' AND schema_name = 'Y';
|
||||
```
|
||||
|
||||
### הטמעות שורות
|
||||
|
||||
הטמעות שורות מאפשרות התאמה סמנטית/עמומה על ערכים מוענקים, תוך פתרון בעיית אי ההתאמה בשפה טבעית (לדוגמה, מציאת "CHESTNUT ST" בעת חיפוש עבור "Chestnut Street").
|
||||
|
||||
#### סקירה כללית של העיצוב
|
||||
|
||||
כל ערך מוענק מוטמע ונשמר במאגר וקטורים (Qdrant). בזמן שאילתה, השאילתה מוטמעת, וקטורים דומים נמצאים, ומטא-הנתונים המשויכים משמשים לאחזור השורות בפועל ב-Cassandra.
|
||||
|
||||
#### מבנה אוסף Qdrant
|
||||
|
||||
אוסף Qdrant אחד לכל טופל `(user, collection, schema_name, dimension)`:
|
||||
|
||||
**שם האוסף:** `rows_{user}_{collection}_{schema_name}_{dimension}`
|
||||
השמות עוברים סינון (תווים שאינם אלפא-נומריים מוחלפים ב-`_`, אותיות קטנות, קידומות מספריות מקבלות קידומת `r_`)
|
||||
**ההצדקה:** מאפשר מחיקה נקייה של מופע `(user, collection, schema_name)` על ידי מחיקת אוספי Qdrant תואמים; הסיומת של הממד מאפשרת למודלי הטמעה שונים להתקיים יחד.
|
||||
|
||||
#### מה מוטמע
|
||||
|
||||
הייצוג הטקסטואלי של ערכי אינדקס:
|
||||
|
||||
| סוג אינדקס | דוגמה `index_value` | טקסט להטמעה |
|
||||
|------------|----------------------|---------------|
|
||||
| שדה בודד | `['foo@bar.com']` | `"foo@bar.com"` |
|
||||
| מורכב | `['US', 'active']` | `"US active"` (מחוברים באמצעות רווח) |
|
||||
|
||||
#### מבנה נקודה
|
||||
|
||||
כל נקודה ב-Qdrant מכילה:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "<uuid>",
|
||||
"vector": [0.1, 0.2, ...],
|
||||
"payload": {
|
||||
"index_name": "street_name",
|
||||
"index_value": ["CHESTNUT ST"],
|
||||
"text": "CHESTNUT ST"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| שדה מטען | תיאור |
|
||||
|---------------|-------------|
|
||||
| `index_name` | השדות המאופיינים בהטמעה זו |
|
||||
| `index_value` | הרשימה המקורית של הערכים (לחיפוש בקסנדרה) |
|
||||
| `text` | הטקסט שהוטמע (לצרכי ניפוי באגים/הצגה) |
|
||||
|
||||
הערה: `user`, `collection` ו-`schema_name` משתמעים משם האוסף של Qdrant.
|
||||
|
||||
#### זרימת שאילתה
|
||||
|
||||
1. משתמש מבקש מידע על "Chestnut Street" בתוך משתמש U, אוסף X, סכימה Y.
|
||||
2. הטמע את טקסט השאילתה.
|
||||
3. קבע את שם/שמות האוסף של Qdrant התואמים לפריט `rows_U_X_Y_`.
|
||||
4. חפש באוספי Qdrant התואמים את הווקטורים הקרובים ביותר.
|
||||
5. קבל נקודות תואמות עם מטענים המכילים `index_name` ו-`index_value`.
|
||||
6. שאילתת קסנדרה:
|
||||
```sql
|
||||
SELECT * FROM rows
|
||||
WHERE collection = 'X'
|
||||
AND schema_name = 'Y'
|
||||
AND index_name = '<from payload>'
|
||||
AND index_value = <from payload>
|
||||
```
|
||||
7. החזרת שורות תואמות
|
||||
|
||||
#### אופציונלי: סינון לפי שם אינדקס
|
||||
|
||||
שאילתות יכולות, באופן אופציונלי, לסנן לפי `index_name` ב-Qdrant כדי לחפש רק שדות ספציפיים:
|
||||
|
||||
**"מצא כל שדה התואם ל-'Chestnut'"** → חיפוש בכל הווקטורים באוסף
|
||||
**"מצא את street_name התואם ל-'Chestnut'"** → סינון כאשר `payload.index_name = 'street_name'`
|
||||
|
||||
#### ארכיטקטורה
|
||||
|
||||
הטמעות שורות עוקבות את ה**תבנית בשני שלבים** המשמשת את GraphRAG (graph-embeddings, document-embeddings):
|
||||
|
||||
**שלב 1: חישוב הטמעה** (`trustgraph-flow/trustgraph/embeddings/row_embeddings/`) - צורך `ExtractedObject`, מחשב הטמעות באמצעות שירות ההטמעות, מוציא `RowEmbeddings`
|
||||
**שלב 2: אחסון הטמעה** (`trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/`) - צורך `RowEmbeddings`, כותב וקטורים ל-Qdrant
|
||||
|
||||
כותב השורות של Cassandra הוא צרכן מקבילי נפרד:
|
||||
|
||||
**כותב שורות Cassandra** (`trustgraph-flow/trustgraph/storage/rows/cassandra`) - צורך `ExtractedObject`, כותב שורות ל-Cassandra
|
||||
|
||||
שלושת השירותים צורכים מאותו זרימה, תוך שמירה על הפרדה ביניהם. זה מאפשר:
|
||||
התאמה עצמאית של כתיבת Cassandra לעומת יצירת הטמעות לעומת אחסון וקטורים
|
||||
ניתן להשבית שירותי הטמעות אם אינם נחוצים
|
||||
כשל בשירות אחד לא משפיע על השירותים האחרים
|
||||
ארכיטקטורה עקבית עם צינורות GraphRAG
|
||||
|
||||
#### נתיב כתיבה
|
||||
|
||||
**שלב 1 (מעבד הטמעות שורות):** בעת קבלת `ExtractedObject`:
|
||||
|
||||
1. חפש את הסכימה כדי למצוא שדות מודדים
|
||||
2. עבור כל שדה מודד:
|
||||
בנה את הייצוג הטקסטואלי של ערך האינדקס
|
||||
חשב הטמעה באמצעות שירות ההטמעות
|
||||
3. הפק פלט הודעה `RowEmbeddings` המכילה את כל הווקטורים שחושבו
|
||||
|
||||
**שלב 2 (כתיבת הטמעות שורות ל-Qdrant):** בעת קבלת `RowEmbeddings`:
|
||||
|
||||
1. עבור כל הטמעה בהודעה:
|
||||
קבע את האוסף של Qdrant מ-`(user, collection, schema_name, dimension)`
|
||||
צור אוסף אם יש צורך (יצירה עצלה בכתיבה הראשונה)
|
||||
הוסף נקודה עם וקטור ו-payload
|
||||
|
||||
#### סוגי הודעות
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class RowIndexEmbedding:
|
||||
index_name: str # The indexed field name(s)
|
||||
index_value: list[str] # The field value(s)
|
||||
text: str # Text that was embedded
|
||||
vectors: list[list[float]] # Computed embedding vectors
|
||||
|
||||
@dataclass
|
||||
class RowEmbeddings:
|
||||
metadata: Metadata
|
||||
schema_name: str
|
||||
embeddings: list[RowIndexEmbedding]
|
||||
```
|
||||
|
||||
#### אינטגרציה של מחיקה
|
||||
|
||||
אוספי Qdrant מתגלים באמצעות התאמה מקדימה של תבנית שם האוסף:
|
||||
|
||||
**מחיקת `(user, collection)`:**
|
||||
1. רשום את כל אוספי Qdrant התואמים לקידומת `rows_{user}_{collection}_`
|
||||
2. מחק כל אוסף תואם
|
||||
3. מחק מחיצות שורות Cassandra (כפי שמפורט לעיל)
|
||||
4. נקה רשומות `row_partitions`
|
||||
|
||||
**מחיקת `(user, collection, schema_name)`:**
|
||||
1. רשום את כל אוספי Qdrant התואמים לקידומת `rows_{user}_{collection}_{schema_name}_`
|
||||
2. מחק כל אוסף תואם (מטפל בממדים מרובים)
|
||||
3. מחק מחיצות שורות Cassandra
|
||||
4. נקה `row_partitions`
|
||||
|
||||
#### מיקומי מודולים
|
||||
|
||||
| שלב | מודול | נקודת כניסה |
|
||||
|-------|--------|-------------|
|
||||
| שלב 1 | `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | `row-embeddings` |
|
||||
| שלב 2 | `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | `row-embeddings-write-qdrant` |
|
||||
|
||||
### API לשאילתות הטמעות שורות
|
||||
|
||||
שאילתת הטמעות השורות היא **API נפרד** משירות שאילתות השורות GraphQL:
|
||||
|
||||
| API | מטרה | בסיס נתונים |
|
||||
|-----|---------|---------|
|
||||
| שאילתת שורות (GraphQL) | התאמה מדויקת בשדות מועדנים | Cassandra |
|
||||
| שאילתת הטמעות שורות | התאמה מעורפלת/סמנטית | Qdrant |
|
||||
|
||||
הפרדה זו שומרת על הפרדת אחריות:
|
||||
שירות GraphQL מתמקד בשאילתות מדויקות ומובנות
|
||||
ממשק הטמעות מטפל בדמיון סמנטי
|
||||
זרימת עבודה של משתמש: חיפוש מעורפל באמצעות הטמעות כדי למצוא מועמדים, ולאחר מכן שאילתה מדויקת כדי לקבל את נתוני השורה המלאים
|
||||
|
||||
#### סכימת בקשה/תגובה
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class RowEmbeddingsRequest:
|
||||
vectors: list[list[float]] # Query vectors (pre-computed embeddings)
|
||||
user: str = ""
|
||||
collection: str = ""
|
||||
schema_name: str = ""
|
||||
index_name: str = "" # Optional: filter to specific index
|
||||
limit: int = 10 # Max results per vector
|
||||
|
||||
@dataclass
|
||||
class RowIndexMatch:
|
||||
index_name: str = "" # The matched index field(s)
|
||||
index_value: list[str] = [] # The matched value(s)
|
||||
text: str = "" # Original text that was embedded
|
||||
score: float = 0.0 # Similarity score
|
||||
|
||||
@dataclass
|
||||
class RowEmbeddingsResponse:
|
||||
error: Error | None = None
|
||||
matches: list[RowIndexMatch] = []
|
||||
```
|
||||
|
||||
#### מעבד שאילתות
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/query/row_embeddings/qdrant`
|
||||
|
||||
נקודת כניסה: `row-embeddings-query-qdrant`
|
||||
|
||||
המעבד:
|
||||
1. מקבל `RowEmbeddingsRequest` עם וקטורי שאילתה
|
||||
2. מוצא את אוסף Qdrant המתאים באמצעות התאמה מקדימה
|
||||
3. מחפש את הווקטורים הקרובים ביותר עם מסנן אופציונלי `index_name`
|
||||
4. מחזיר `RowEmbeddingsResponse` עם מידע אינדקס תואם
|
||||
|
||||
#### אינטגרציה עם שער API
|
||||
|
||||
השער חושף שאילתות הטבעה של שורות באמצעות תבנית בקשה/תגובה סטנדרטית:
|
||||
|
||||
| רכיב | מיקום |
|
||||
|-----------|----------|
|
||||
| מפזר | `trustgraph-flow/trustgraph/gateway/dispatch/row_embeddings_query.py` |
|
||||
| רישום | הוסף `"row-embeddings"` ל-`request_response_dispatchers` ב-`manager.py` |
|
||||
|
||||
שם ממשק זרימה: `row-embeddings`
|
||||
|
||||
הגדרת ממשק בתרשים זרימה:
|
||||
```json
|
||||
{
|
||||
"interfaces": {
|
||||
"row-embeddings": {
|
||||
"request": "non-persistent://tg/request/row-embeddings:{id}",
|
||||
"response": "non-persistent://tg/response/row-embeddings:{id}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### תמיכה ב-SDK של Python
|
||||
|
||||
ה-SDK מספק שיטות לשאילתות הטמעות שורות:
|
||||
|
||||
```python
|
||||
# Flow-scoped query (preferred)
|
||||
api = Api(url)
|
||||
flow = api.flow().id("default")
|
||||
|
||||
# Query with text (SDK computes embeddings)
|
||||
matches = flow.row_embeddings_query(
|
||||
text="Chestnut Street",
|
||||
collection="my_collection",
|
||||
schema_name="addresses",
|
||||
index_name="street_name", # Optional filter
|
||||
limit=10
|
||||
)
|
||||
|
||||
# Query with pre-computed vectors
|
||||
matches = flow.row_embeddings_query(
|
||||
vectors=[[0.1, 0.2, ...]],
|
||||
collection="my_collection",
|
||||
schema_name="addresses"
|
||||
)
|
||||
|
||||
# Each match contains:
|
||||
for match in matches:
|
||||
print(match.index_name) # e.g., "street_name"
|
||||
print(match.index_value) # e.g., ["CHESTNUT ST"]
|
||||
print(match.text) # e.g., "CHESTNUT ST"
|
||||
print(match.score) # e.g., 0.95
|
||||
```
|
||||
|
||||
#### כלי שורת הפקודה
|
||||
|
||||
פקודה: `tg-invoke-row-embeddings`
|
||||
|
||||
```bash
|
||||
# Query by text (computes embedding automatically)
|
||||
tg-invoke-row-embeddings \
|
||||
--text "Chestnut Street" \
|
||||
--collection my_collection \
|
||||
--schema addresses \
|
||||
--index street_name \
|
||||
--limit 10
|
||||
|
||||
# Query by vector file
|
||||
tg-invoke-row-embeddings \
|
||||
--vectors vectors.json \
|
||||
--collection my_collection \
|
||||
--schema addresses
|
||||
|
||||
# Output formats
|
||||
tg-invoke-row-embeddings --text "..." --format json
|
||||
tg-invoke-row-embeddings --text "..." --format table
|
||||
```
|
||||
|
||||
#### דוגמה טיפוסית לשימוש
|
||||
|
||||
שאילתת הטמעות השורות משמשת בדרך כלל כחלק מזרימת חיפוש "מעורפל" לחיפוש מדויק:
|
||||
|
||||
```python
|
||||
# Step 1: Fuzzy search via embeddings
|
||||
matches = flow.row_embeddings_query(
|
||||
text="chestnut street",
|
||||
collection="geo",
|
||||
schema_name="streets"
|
||||
)
|
||||
|
||||
# Step 2: Exact lookup via GraphQL for full row data
|
||||
for match in matches:
|
||||
query = f'''
|
||||
query {{
|
||||
streets(where: {{ {match.index_name}: {{ eq: "{match.index_value[0]}" }} }}) {{
|
||||
street_name
|
||||
city
|
||||
zip_code
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
rows = flow.rows_query(query, collection="geo")
|
||||
```
|
||||
|
||||
דפוס בן שני שלבים זה מאפשר:
|
||||
מציאת "CHESTNUT ST" כאשר המשתמש מחפש "Chestnut Street"
|
||||
שליפת נתוני שורה שלמים עם כל השדות
|
||||
שילוב של דמיון סמנטי עם גישה לנתונים מובנים
|
||||
|
||||
### קליטת נתוני שורה
|
||||
|
||||
נדחה לשלב מאוחר יותר. יתוכנן יחד עם שינויי קליטה אחרים.
|
||||
|
||||
## השפעה על יישום
|
||||
|
||||
### ניתוח מצב נוכחי
|
||||
|
||||
ליישום הקיים יש שני מרכיבים עיקריים:
|
||||
|
||||
| רכיב | מיקום | שורות | תיאור |
|
||||
|-----------|----------|-------|-------------|
|
||||
| שירות שאילתות | `trustgraph-flow/trustgraph/query/objects/cassandra/service.py` | ~740 | מונוליטי: יצירת סכימת GraphQL, ניתוח פילטרים, שאילתות Cassandra, טיפול בבקשות |
|
||||
| כותב | `trustgraph-flow/trustgraph/storage/objects/cassandra/write.py` | ~540 | יצירת טבלאות לפי סכימה, אינדקסים משניים, הוספה/מחיקה |
|
||||
|
||||
**דפוס שאילתות נוכחי:**
|
||||
```sql
|
||||
SELECT * FROM {keyspace}.o_{schema_name}
|
||||
WHERE collection = 'X' AND email = 'foo@bar.com'
|
||||
ALLOW FILTERING
|
||||
```
|
||||
|
||||
**תבנית שאילתה חדשה:**
|
||||
```sql
|
||||
SELECT * FROM {keyspace}.rows
|
||||
WHERE collection = 'X' AND schema_name = 'customers'
|
||||
AND index_name = 'email' AND index_value = ['foo@bar.com']
|
||||
```
|
||||
|
||||
### שינויים מרכזיים
|
||||
|
||||
1. **הפשטת סמנטיקת שאילתות**: הסכימה החדשה תומכת רק בהתאמות מדויקות עבור `index_value`. מסנני ה-GraphQL הנוכחיים (`gt`, `lt`, `contains`, וכו') או:
|
||||
הופכים לסינון לאחר קבלת הנתונים (אם עדיין נדרש)
|
||||
מוסרים לטובת שימוש ב-API של הטמעות (embeddings) לביצוע התאמות משוערות
|
||||
|
||||
2. **קוד GraphQL משולב הדוק**: ה-`service.py` הנוכחי כולל יצירת טיפוסים של Strawberry, ניתוח מסננים ושאילתות ספציפיות ל-Cassandra. הוספת בסיס נתונים טבלאי נוסף תכפיל כ-400 שורות של קוד GraphQL.
|
||||
|
||||
### שינוי מבנה מוצע
|
||||
|
||||
השינוי המבני כולל שני חלקים:
|
||||
|
||||
#### 1. הפרדת קוד GraphQL
|
||||
|
||||
חילוץ רכיבי GraphQL שניתן לעשות בהם שימוש חוזר למודול משותף:
|
||||
|
||||
```
|
||||
trustgraph-flow/trustgraph/query/graphql/
|
||||
├── __init__.py
|
||||
├── types.py # Filter types (IntFilter, StringFilter, FloatFilter)
|
||||
├── schema.py # Dynamic schema generation from RowSchema
|
||||
└── filters.py # Filter parsing utilities
|
||||
```
|
||||
|
||||
זה מאפשר:
|
||||
שימוש חוזר בין בסיסי נתונים שונים
|
||||
הפרדה נקייה יותר של תחומים
|
||||
בדיקה קלה יותר של לוגיקת GraphQL באופן עצמאי
|
||||
|
||||
#### 2. יישום סכימת טבלה חדשה
|
||||
|
||||
שינוי הקוד הספציפי ל-Cassandra לשימוש בטבלה המאוחדת:
|
||||
|
||||
**כותב** (`trustgraph-flow/trustgraph/storage/rows/cassandra/`):
|
||||
טבלה אחת של `rows` במקום טבלאות לכל סכימה
|
||||
כתיבת N עותקים לשורה (אחד לכל אינדקס)
|
||||
רישום לטבלה `row_partitions`
|
||||
יצירת טבלה פשוטה יותר (הגדרה חד-פעמית)
|
||||
|
||||
**שירות שאילתות** (`trustgraph-flow/trustgraph/query/rows/cassandra/`):
|
||||
שאילתא של הטבלה המאוחדת `rows`
|
||||
שימוש במודול GraphQL חלץ ליצירת סכימה
|
||||
טיפול פשוט יותר בסינון (התאמה מדויקת בלבד ברמת מסד הנתונים)
|
||||
|
||||
### שינוי שמות מודולים
|
||||
|
||||
כחלק מניקוי השמות מ-"object" ל-"row":
|
||||
|
||||
| נוכחי | חדש |
|
||||
|---------|-----|
|
||||
| `storage/objects/cassandra/` | `storage/rows/cassandra/` |
|
||||
| `query/objects/cassandra/` | `query/rows/cassandra/` |
|
||||
| `embeddings/object_embeddings/` | `embeddings/row_embeddings/` |
|
||||
|
||||
### מודולים חדשים
|
||||
|
||||
| מודול | מטרה |
|
||||
|--------|---------|
|
||||
| `trustgraph-flow/trustgraph/query/graphql/` | כלי GraphQL משותפים |
|
||||
| `trustgraph-flow/trustgraph/query/row_embeddings/qdrant/` | ממשק API לשאילתות הטמעות שורות |
|
||||
| `trustgraph-flow/trustgraph/embeddings/row_embeddings/` | חישוב הטמעות שורות (שלב 1) |
|
||||
| `trustgraph-flow/trustgraph/storage/row_embeddings/qdrant/` | אחסון הטמעות שורות (שלב 2) |
|
||||
|
||||
## הפניות
|
||||
|
||||
[מפרט טכני של נתונים מובנים](structured-data.md)
|
||||
567
docs/tech-specs/he/structured-data-descriptor.he.md
Normal file
567
docs/tech-specs/he/structured-data-descriptor.he.md
Normal file
|
|
@ -0,0 +1,567 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט עבור תיאור נתונים מובנים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט עבור תיאור נתונים מובנים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
תיאור הנתונים המובנים הוא שפת תצורה מבוססת JSON המתארת כיצד לנתח, להמיר ולייבא נתונים מובנים ל-TrustGraph. הוא מספק גישה הצהרתית לייבוא נתונים, תוך תמיכה בפורמטים מרובים של קלט וצינורות המרה מורכבים מבלי לדרוש קוד מותאם אישית.
|
||||
|
||||
## מושגים מרכזיים
|
||||
|
||||
### 1. הגדרת פורמט
|
||||
מתאר את סוג הקובץ הנכנס ואפשרויות הניתוח. קובע איזה מנתח להשתמש וכיצד לפרש את הנתונים המקור.
|
||||
|
||||
### 2. מיפוי שדות
|
||||
ממפה נתיבים מקור לשדות יעד עם המרות. מגדיר כיצד הנתונים זורמים ממקורות קלט לשדות סכימה בפלט.
|
||||
|
||||
### 3. צינור המרה
|
||||
שרשרת של המרות נתונים שניתן להחיל על ערכי שדות, כולל:
|
||||
ניקוי נתונים (חיתוך, נרמול)
|
||||
המרת פורמט (ניתוח תאריכים, המרת טיפוסים)
|
||||
חישובים (חשבון, מניפולציה של מחרוזות)
|
||||
חיפושים (טבלאות הפניה, החלפות)
|
||||
|
||||
### 4. כללי אימות
|
||||
בדיקות איכות נתונים המיושמות כדי להבטיח את שלמות הנתונים:
|
||||
אימות טיפוס
|
||||
בדיקות טווח
|
||||
התאמת תבניות (ביטויים רגולריים)
|
||||
אימות שדות חובה
|
||||
לוגיקה מותאמת אישית לאימות
|
||||
|
||||
### 5. הגדרות גלובליות
|
||||
תצורה החלה על כל תהליך הייבוא:
|
||||
טבלאות חיפוש להעשרת נתונים
|
||||
משתנים וקבועים גלובליים
|
||||
מפרטי פורמט פלט
|
||||
מדיניות טיפול בשגיאות
|
||||
|
||||
## אסטרטגיית יישום
|
||||
|
||||
יישום המייבא עוקב אחר הצינור הבא:
|
||||
|
||||
1. **ניתוח תצורה** - טעינה ואימות של תיאור JSON
|
||||
2. **אתחול מנתח** - טעינת מנתח מתאים (CSV, XML, JSON, וכו') בהתבסס על `format.type`
|
||||
3. **החלת עיבוד מקדים** - ביצוע פילטרים והמרות גלובליים
|
||||
4. **עיבוד רשומות** - עבור כל רשומה נכנסת:
|
||||
חילוץ נתונים באמצעות נתיבי מקור (JSONPath, XPath, שמות עמודות)
|
||||
החלת המרות ברמת השדה בסדר
|
||||
אימות תוצאות בהתאם לכללים מוגדרים
|
||||
החלת ערכי ברירת מחדל עבור נתונים חסרים
|
||||
5. **החלת עיבוד לאחר** - ביצוע הסרה כפילות, אגרגציה, וכו'.
|
||||
6. **יצירת פלט** - יצירת נתונים בפורמט יעד מוגדר
|
||||
|
||||
## תמיכה בביטוי נתיב
|
||||
|
||||
פורמטים שונים של קלט משתמשים בשפות ביטוי נתיב מתאימות:
|
||||
|
||||
**CSV**: שמות עמודות או אינדקסים (`"column_name"` או `"[2]"`)
|
||||
**JSON**: תחביר JSONPath (`"$.user.profile.email"`)
|
||||
**XML**: ביטויי XPath (`"//product[@id='123']/price"`)
|
||||
**רוחב קבוע**: שמות שדות מהגדרות שדות
|
||||
|
||||
## יתרונות
|
||||
|
||||
**בסיס קוד יחיד** - מייבא אחד מטפל בפורמטים מרובים של קלט
|
||||
**ידידותי למשתמש** - משתמשים לא טכניים יכולים ליצור תצורות
|
||||
**ניתן לשימוש חוזר** - ניתן לשתף תצורות ולגרסן
|
||||
**גמיש** - המרות מורכבות ללא קידוד מותאם אישית
|
||||
**יציב** - אימות מובנה וטיפול מקיף בשגיאות
|
||||
**ניתן לתחזוקה** - גישה הצהרתית מפחיתה את מורכבות היישום
|
||||
|
||||
## מפרט שפה
|
||||
|
||||
תיאור הנתונים המובנים משתמש בפורמט תצורה JSON עם המבנה הבסיסי הבא ברמה העליונה:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"metadata": {
|
||||
"name": "Configuration Name",
|
||||
"description": "Description of what this config does",
|
||||
"author": "Author Name",
|
||||
"created": "2024-01-01T00:00:00Z"
|
||||
},
|
||||
"format": { ... },
|
||||
"globals": { ... },
|
||||
"preprocessing": [ ... ],
|
||||
"mappings": [ ... ],
|
||||
"postprocessing": [ ... ],
|
||||
"output": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### הגדרת פורמט
|
||||
|
||||
מתאר את פורמט הנתונים הקלט ואפשרויות הניתוח:
|
||||
|
||||
```json
|
||||
{
|
||||
"format": {
|
||||
"type": "csv|json|xml|fixed-width|excel|parquet",
|
||||
"encoding": "utf-8",
|
||||
"options": {
|
||||
// Format-specific options
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### אפשרויות פורמט CSV
|
||||
```json
|
||||
{
|
||||
"format": {
|
||||
"type": "csv",
|
||||
"options": {
|
||||
"delimiter": ",",
|
||||
"quote_char": "\"",
|
||||
"escape_char": "\\",
|
||||
"skip_rows": 1,
|
||||
"has_header": true,
|
||||
"null_values": ["", "NULL", "null", "N/A"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### אפשרויות פורמט JSON
|
||||
```json
|
||||
{
|
||||
"format": {
|
||||
"type": "json",
|
||||
"options": {
|
||||
"root_path": "$.data",
|
||||
"array_mode": "records|single",
|
||||
"flatten": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### אפשרויות פורמט XML
|
||||
```json
|
||||
{
|
||||
"format": {
|
||||
"type": "xml",
|
||||
"options": {
|
||||
"root_element": "//records/record",
|
||||
"namespaces": {
|
||||
"ns": "http://example.com/namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### הגדרות גלובליות
|
||||
|
||||
הגדירו טבלאות חיפוש, משתנים ותצורות גלובליות:
|
||||
|
||||
```json
|
||||
{
|
||||
"globals": {
|
||||
"variables": {
|
||||
"current_date": "2024-01-01",
|
||||
"batch_id": "BATCH_001",
|
||||
"default_confidence": 0.8
|
||||
},
|
||||
"lookup_tables": {
|
||||
"country_codes": {
|
||||
"US": "United States",
|
||||
"UK": "United Kingdom",
|
||||
"CA": "Canada"
|
||||
},
|
||||
"status_mapping": {
|
||||
"1": "active",
|
||||
"0": "inactive"
|
||||
}
|
||||
},
|
||||
"constants": {
|
||||
"source_system": "legacy_crm",
|
||||
"import_type": "full"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### מיפוי שדות
|
||||
|
||||
הגדירו כיצד נתוני המקור ממופים לשדות היעד עם טרנספורמציות:
|
||||
|
||||
```json
|
||||
{
|
||||
"mappings": [
|
||||
{
|
||||
"target_field": "person_name",
|
||||
"source": "$.name",
|
||||
"transforms": [
|
||||
{"type": "trim"},
|
||||
{"type": "title_case"},
|
||||
{"type": "required"}
|
||||
],
|
||||
"validation": [
|
||||
{"type": "min_length", "value": 2},
|
||||
{"type": "max_length", "value": 100},
|
||||
{"type": "pattern", "value": "^[A-Za-z\\s]+$"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"target_field": "age",
|
||||
"source": "$.age",
|
||||
"transforms": [
|
||||
{"type": "to_int"},
|
||||
{"type": "default", "value": 0}
|
||||
],
|
||||
"validation": [
|
||||
{"type": "range", "min": 0, "max": 150}
|
||||
]
|
||||
},
|
||||
{
|
||||
"target_field": "country",
|
||||
"source": "$.country_code",
|
||||
"transforms": [
|
||||
{"type": "lookup", "table": "country_codes"},
|
||||
{"type": "default", "value": "Unknown"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### סוגי טרנספורמציה
|
||||
|
||||
פונקציות טרנספורמציה זמינות:
|
||||
|
||||
#### טרנספורמציות מחרוזות
|
||||
```json
|
||||
{"type": "trim"},
|
||||
{"type": "upper"},
|
||||
{"type": "lower"},
|
||||
{"type": "title_case"},
|
||||
{"type": "replace", "pattern": "old", "replacement": "new"},
|
||||
{"type": "regex_replace", "pattern": "\\d+", "replacement": "XXX"},
|
||||
{"type": "substring", "start": 0, "end": 10},
|
||||
{"type": "pad_left", "length": 10, "char": "0"}
|
||||
```
|
||||
|
||||
#### המרות טיפוסים
|
||||
```json
|
||||
{"type": "to_string"},
|
||||
{"type": "to_int"},
|
||||
{"type": "to_float"},
|
||||
{"type": "to_bool"},
|
||||
{"type": "to_date", "format": "YYYY-MM-DD"},
|
||||
{"type": "parse_json"}
|
||||
```
|
||||
|
||||
#### פעולות נתונים
|
||||
```json
|
||||
{"type": "default", "value": "default_value"},
|
||||
{"type": "lookup", "table": "table_name"},
|
||||
{"type": "concat", "values": ["field1", " - ", "field2"]},
|
||||
{"type": "calculate", "expression": "${field1} + ${field2}"},
|
||||
{"type": "conditional", "condition": "${age} > 18", "true_value": "adult", "false_value": "minor"}
|
||||
```
|
||||
|
||||
### כללי אימות
|
||||
|
||||
בדיקות איכות נתונים עם טיפול בשגיאות הניתן להגדרה:
|
||||
|
||||
#### אימותים בסיסיים
|
||||
```json
|
||||
{"type": "required"},
|
||||
{"type": "not_null"},
|
||||
{"type": "min_length", "value": 5},
|
||||
{"type": "max_length", "value": 100},
|
||||
{"type": "range", "min": 0, "max": 1000},
|
||||
{"type": "pattern", "value": "^[A-Z]{2,3}$"},
|
||||
{"type": "in_list", "values": ["active", "inactive", "pending"]}
|
||||
```
|
||||
|
||||
#### אימותים מותאמים אישית
|
||||
```json
|
||||
{
|
||||
"type": "custom",
|
||||
"expression": "${age} >= 18 && ${country} == 'US'",
|
||||
"message": "Must be 18+ and in US"
|
||||
},
|
||||
{
|
||||
"type": "cross_field",
|
||||
"fields": ["start_date", "end_date"],
|
||||
"expression": "${start_date} < ${end_date}",
|
||||
"message": "Start date must be before end date"
|
||||
}
|
||||
```
|
||||
|
||||
### עיבוד מקדים ועיבוד סופי
|
||||
|
||||
פעולות גלובליות המיושמות לפני/אחרי מיפוי שדות:
|
||||
|
||||
```json
|
||||
{
|
||||
"preprocessing": [
|
||||
{
|
||||
"type": "filter",
|
||||
"condition": "${status} != 'deleted'"
|
||||
},
|
||||
{
|
||||
"type": "sort",
|
||||
"field": "created_date",
|
||||
"order": "asc"
|
||||
}
|
||||
],
|
||||
"postprocessing": [
|
||||
{
|
||||
"type": "deduplicate",
|
||||
"key_fields": ["email", "phone"]
|
||||
},
|
||||
{
|
||||
"type": "aggregate",
|
||||
"group_by": ["country"],
|
||||
"functions": {
|
||||
"total_count": {"type": "count"},
|
||||
"avg_age": {"type": "avg", "field": "age"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### הגדרות פלט
|
||||
|
||||
הגדירו כיצד יש להוציא את הנתונים שעברו עיבוד:
|
||||
|
||||
```json
|
||||
{
|
||||
"output": {
|
||||
"format": "trustgraph-objects",
|
||||
"schema_name": "person",
|
||||
"options": {
|
||||
"batch_size": 1000,
|
||||
"confidence": 0.9,
|
||||
"source_span_field": "raw_text",
|
||||
"metadata": {
|
||||
"source": "crm_import",
|
||||
"version": "1.0"
|
||||
}
|
||||
},
|
||||
"error_handling": {
|
||||
"on_validation_error": "skip|fail|log",
|
||||
"on_transform_error": "skip|fail|default",
|
||||
"max_errors": 100,
|
||||
"error_output": "errors.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## דוגמה מלאה
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0",
|
||||
"metadata": {
|
||||
"name": "Customer Import from CRM CSV",
|
||||
"description": "Imports customer data from legacy CRM system",
|
||||
"author": "Data Team",
|
||||
"created": "2024-01-01T00:00:00Z"
|
||||
},
|
||||
"format": {
|
||||
"type": "csv",
|
||||
"encoding": "utf-8",
|
||||
"options": {
|
||||
"delimiter": ",",
|
||||
"has_header": true,
|
||||
"skip_rows": 1
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"variables": {
|
||||
"import_date": "2024-01-01",
|
||||
"default_confidence": 0.85
|
||||
},
|
||||
"lookup_tables": {
|
||||
"country_codes": {
|
||||
"US": "United States",
|
||||
"CA": "Canada",
|
||||
"UK": "United Kingdom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"preprocessing": [
|
||||
{
|
||||
"type": "filter",
|
||||
"condition": "${status} == 'active'"
|
||||
}
|
||||
],
|
||||
"mappings": [
|
||||
{
|
||||
"target_field": "full_name",
|
||||
"source": "customer_name",
|
||||
"transforms": [
|
||||
{"type": "trim"},
|
||||
{"type": "title_case"}
|
||||
],
|
||||
"validation": [
|
||||
{"type": "required"},
|
||||
{"type": "min_length", "value": 2}
|
||||
]
|
||||
},
|
||||
{
|
||||
"target_field": "email",
|
||||
"source": "email_address",
|
||||
"transforms": [
|
||||
{"type": "trim"},
|
||||
{"type": "lower"}
|
||||
],
|
||||
"validation": [
|
||||
{"type": "pattern", "value": "^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"target_field": "age",
|
||||
"source": "age",
|
||||
"transforms": [
|
||||
{"type": "to_int"},
|
||||
{"type": "default", "value": 0}
|
||||
],
|
||||
"validation": [
|
||||
{"type": "range", "min": 0, "max": 120}
|
||||
]
|
||||
},
|
||||
{
|
||||
"target_field": "country",
|
||||
"source": "country_code",
|
||||
"transforms": [
|
||||
{"type": "lookup", "table": "country_codes"},
|
||||
{"type": "default", "value": "Unknown"}
|
||||
]
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"format": "trustgraph-objects",
|
||||
"schema_name": "customer",
|
||||
"options": {
|
||||
"confidence": "${default_confidence}",
|
||||
"batch_size": 500
|
||||
},
|
||||
"error_handling": {
|
||||
"on_validation_error": "log",
|
||||
"max_errors": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## הנחיה עבור מודל שפה גדול (LLM) ליצירת תיאור
|
||||
|
||||
ניתן להשתמש בהנחיה הבאה כדי לגרום למודל שפה גדול לנתח נתוני דוגמה וליצור תצורת תיאור:
|
||||
|
||||
```
|
||||
I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format.
|
||||
|
||||
The descriptor should follow this specification:
|
||||
- version: "1.0"
|
||||
- metadata: Configuration name, description, author, and creation date
|
||||
- format: Input format type and parsing options
|
||||
- globals: Variables, lookup tables, and constants
|
||||
- preprocessing: Filters and transformations applied before mapping
|
||||
- mappings: Field-by-field mapping from source to target with transformations and validations
|
||||
- postprocessing: Operations like deduplication or aggregation
|
||||
- output: Target format and error handling configuration
|
||||
|
||||
ANALYZE THE DATA:
|
||||
1. Identify the format (CSV, JSON, XML, etc.)
|
||||
2. Detect delimiters, encodings, and structure
|
||||
3. Find data types for each field
|
||||
4. Identify patterns and constraints
|
||||
5. Look for fields that need cleaning or transformation
|
||||
6. Find relationships between fields
|
||||
7. Identify lookup opportunities (codes that map to values)
|
||||
8. Detect required vs optional fields
|
||||
|
||||
CREATE THE DESCRIPTOR:
|
||||
For each field in the sample data:
|
||||
- Map it to an appropriate target field name
|
||||
- Add necessary transformations (trim, case conversion, type casting)
|
||||
- Include appropriate validations (required, patterns, ranges)
|
||||
- Set defaults for missing values
|
||||
|
||||
Include preprocessing if needed:
|
||||
- Filters to exclude invalid records
|
||||
- Sorting requirements
|
||||
|
||||
Include postprocessing if beneficial:
|
||||
- Deduplication on key fields
|
||||
- Aggregation for summary data
|
||||
|
||||
Configure output for TrustGraph:
|
||||
- format: "trustgraph-objects"
|
||||
- schema_name: Based on the data entity type
|
||||
- Appropriate error handling
|
||||
|
||||
DATA SAMPLE:
|
||||
[Insert data sample here]
|
||||
|
||||
ADDITIONAL CONTEXT (optional):
|
||||
- Target schema name: [if known]
|
||||
- Business rules: [any specific requirements]
|
||||
- Data quality issues to address: [known problems]
|
||||
|
||||
Generate a complete, valid Structured Data Descriptor configuration that will properly import this data into TrustGraph. Include comments explaining key decisions.
|
||||
```
|
||||
|
||||
### הנחיה לדוגמה לשימוש
|
||||
|
||||
```
|
||||
I need you to analyze the provided data sample and create a Structured Data Descriptor configuration in JSON format.
|
||||
|
||||
[Standard instructions from above...]
|
||||
|
||||
DATA SAMPLE:
|
||||
```csv
|
||||
CustomerID,שם לקוח,כתובת דוא"ל,גיל,מדינה,סטטוס,תאריך הצטרפות,סך רכישות
|
||||
1001,"Smith, John",john.smith@email.com,35,US,1,2023-01-15,5420.50
|
||||
1002,"doe, jane",JANE.DOE@GMAIL.COM,28,CA,1,2023-03-22,3200.00
|
||||
1003,"Bob Johnson",bob@,62,UK,0,2022-11-01,0
|
||||
1004,"Alice Chen","alice.chen@company.org",41,US,1,2023-06-10,8900.25
|
||||
1005,,invalid-email,25,XX,1,2024-01-01,100
|
||||
```
|
||||
|
||||
ADDITIONAL CONTEXT:
|
||||
- Target schema name: customer
|
||||
- Business rules: Email should be valid and lowercase, names should be title case
|
||||
- Data quality issues: Some emails are invalid, some names are missing, country codes need mapping
|
||||
```
|
||||
|
||||
### הנחיה לניתוח נתונים קיימים ללא דוגמה
|
||||
|
||||
```
|
||||
I need you to help me create a Structured Data Descriptor configuration for importing [data type] data.
|
||||
|
||||
The source data has these characteristics:
|
||||
- Format: [CSV/JSON/XML/etc]
|
||||
- Fields: [list the fields]
|
||||
- Data quality issues: [describe any known issues]
|
||||
- Volume: [approximate number of records]
|
||||
|
||||
Requirements:
|
||||
- [List any specific transformation needs]
|
||||
- [List any validation requirements]
|
||||
- [List any business rules]
|
||||
|
||||
Please generate a Structured Data Descriptor configuration that will:
|
||||
1. Parse the input format correctly
|
||||
2. Clean and standardize the data
|
||||
3. Validate according to the requirements
|
||||
4. Handle errors gracefully
|
||||
5. Output in TrustGraph ExtractedObject format
|
||||
|
||||
Focus on making the configuration robust and reusable.
|
||||
```
|
||||
147
docs/tech-specs/he/structured-data-schemas.he.md
Normal file
147
docs/tech-specs/he/structured-data-schemas.he.md
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
---
|
||||
layout: default
|
||||
title: "שינויים בסכימת נתונים מובנית עבור פולסר"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# שינויים בסכימת נתונים מובנית עבור פולסר
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
בהתבסס על מפרט ה-STRUCTURED_DATA.md, המסמך מציע את התוספות והשינויים הנדרשים בסכימת פולסר כדי לתמוך ביכולות נתונים מובנות ב-TrustGraph.
|
||||
|
||||
## שינויים בסכימה נדרשים
|
||||
|
||||
### 1. שיפורים בסכימה הליבה
|
||||
|
||||
#### הגדרת שדה משופרת
|
||||
המחלקה `Field` הקיימת בקובץ `core/primitives.py` זקוקה לתכונות נוספות:
|
||||
|
||||
```python
|
||||
class Field(Record):
|
||||
name = String()
|
||||
type = String() # int, string, long, bool, float, double, timestamp
|
||||
size = Integer()
|
||||
primary = Boolean()
|
||||
description = String()
|
||||
# שדות חדשים:
|
||||
required = Boolean() # האם השדה נדרש
|
||||
enum_values = Array(String()) # עבור סוגי שדות enum
|
||||
indexed = Boolean() # האם השדה צריך להיות מצביע
|
||||
```
|
||||
|
||||
### 2. סכימות ידע חדשות
|
||||
|
||||
#### 2.1 שליחת נתונים מובנים
|
||||
קובץ חדש: `knowledge/structured.py`
|
||||
|
||||
```python
|
||||
from pulsar.schema import Record, String, Bytes, Map
|
||||
from ..core.metadata import Metadata
|
||||
|
||||
class StructuredDataSubmission(Record):
|
||||
metadata = Metadata()
|
||||
format = String() # "json", "csv", "xml"
|
||||
schema_name = String() # הפניה לסכימה בקונפיגורציה
|
||||
data = Bytes() # נתונים גולמיים לשליחה
|
||||
options = Map(String()) # אפשרויות ספציפיות לפורמט
|
||||
```
|
||||
|
||||
#### 3. סכימות שירות חדשות
|
||||
|
||||
#### 3.1 שירות שאילתות NLP לנתונים מובנים
|
||||
קובץ חדש: `services/nlp_query.py`
|
||||
|
||||
```python
|
||||
from pulsar.schema import Record, String, Array, Map, Integer, Double
|
||||
from ..core.primitives import Error
|
||||
|
||||
class NLPToStructuredQueryRequest(Record):
|
||||
natural_language_query = String()
|
||||
max_results = Integer()
|
||||
context_hints = Map(String()) # הקשר אופציונלי לשליפת שאילתה
|
||||
|
||||
class NLPToStructuredQueryResponse(Record):
|
||||
error = Error()
|
||||
graphql_query = String() # שאילתת GraphQL שנוצרה
|
||||
variables = Map(String()) # משתני GraphQL אם יש
|
||||
detected_schemas = Array(String()) # אילו סכימות השאילתה מכוונות
|
||||
confidence = Double()
|
||||
```
|
||||
|
||||
#### 3.2 שירות שאילתות מובנות
|
||||
קובץ חדש: `services/structured_query.py`
|
||||
|
||||
```python
|
||||
from pulsar.schema import Record, String, Map, Array
|
||||
from ..core.primitives import Error
|
||||
|
||||
class StructuredQueryRequest(Record):
|
||||
query = String() # שאילתת GraphQL
|
||||
variables = Map(String()) # משתני GraphQL
|
||||
operation_name = String() # שם פעולה אופציונלי למסמכים מרובי פעולות
|
||||
|
||||
class StructuredQueryResponse(Record):
|
||||
error = Error()
|
||||
data = String() # נתוני התגובה של GraphQL מקודדים ב-JSON
|
||||
errors = Array(String()) # שגיאות GraphQL אם יש
|
||||
```
|
||||
|
||||
#### 2.2 פלט חילוץ אובייקטים
|
||||
קובץ חדש: `knowledge/object.py`
|
||||
|
||||
```python
|
||||
from pulsar.schema import Record, String, Map, Double
|
||||
from ..core.metadata import Metadata
|
||||
|
||||
class ExtractedObject(Record):
|
||||
metadata = Metadata()
|
||||
schema_name = String() # לאיזו סכימה השם הזה שייך
|
||||
values = Map(String()) # שם שדה -> ערך
|
||||
confidence = Double()
|
||||
source_span = String() # טקסט השדה בו נמצא האובייקט
|
||||
```
|
||||
|
||||
### 4. סכימות ידע משופרות
|
||||
|
||||
#### 4.1 שיפור אמצעי הטבע
|
||||
עדכן את `knowledge/embeddings.py` כדי לתמוך טוב יותר באמצעי הטבע מובנים:
|
||||
|
||||
```python
|
||||
class StructuredObjectEmbedding(Record):
|
||||
metadata = Metadata()
|
||||
vectors = Array(Array(Double()))
|
||||
schema_name = String()
|
||||
object_id = String() # ערך מפתח ראשי
|
||||
field_embeddings = Map(Array(Double())) # אמצעי הטבע לכל שדה
|
||||
```
|
||||
|
||||
## נקודות אינטגרציה
|
||||
|
||||
### אינטגרציה של זרימה
|
||||
|
||||
הסכימות ישמשו על ידי מודולי זרימה חדשים:
|
||||
- `trustgraph-flow/trustgraph/decoding/structured` - משתמש ב-StructuredDataSubmission
|
||||
- `trustgraph-flow/trustgraph/query/nlp_query/cassandra` - משתמש בסכימות שאילתות NLP
|
||||
- `trustgraph-flow/trustgraph/query/objects/cassandra` - משתמש בסכימות שאילתות מובנות
|
||||
- `trustgraph-flow/trustgraph/extract/object/row/` - צורך Chunk, מייצר ExtractedObject
|
||||
- `trustgraph-flow/trustgraph/storage/objects/cassandra` - משתמש בסכימה Rows
|
||||
- `trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant` - משתמש בסכימות אמצעי הטבע
|
||||
|
||||
## הערות על יישום
|
||||
|
||||
1. **גרסת סכימה**: כדאי להוסיף שדה `version` ל-RowSchema לתמיכה בעדכונים עתידיים.
|
||||
2. **מערכת סוגים**: ה-`Field.type` צריך לתמוך בכל סוגי הנתונים המקוריים של Cassandra.
|
||||
3. **פעולות אצווה**: רוב השירותים צריכים לתמוך הן בפעולות בודדות והן בפעולות אצווה.
|
||||
4. **טיפול בשגיאות**: דיווח אחיד על שגיאות בכל השירותים החדשים.
|
||||
5. **תאימות לאחור**: הסכימות הקיימות נשארות ללא שינוי, מלבד שיפורים קטנים בשדות.
|
||||
|
||||
## שלבים הבאים
|
||||
|
||||
1. יישום קבצי הסכימה במבנה החדש.
|
||||
2. עדכון שירותים קיימים כדי לזהות סוגי סכימה חדשים.
|
||||
3. יישום מודולי זרימה המשתמשים בסכימות אלה.
|
||||
4. הוספת סיומות גשר/rev-גשר לשירותים החדשים.
|
||||
5. יצירת בדיקות יחידה עבור אימות סכימה.
|
||||
260
docs/tech-specs/he/structured-data.he.md
Normal file
260
docs/tech-specs/he/structured-data.he.md
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני של נתונים מובנים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני של נתונים מובנים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר את השילוב של TrustGraph עם זרימות נתונים מובנים, המאפשר למערכת לעבוד עם נתונים שניתן לייצג אותם כשורות בטבלאות או כאובייקטים במאגרי אובייקטים. השילוב תומך בארבעה תרחישי שימוש עיקריים:
|
||||
|
||||
1. **חילוץ מנתונים לא מובנים לנתונים מובנים**: קריאת מקורות נתונים לא מובנים, זיהוי וחילוץ מבני אובייקטים, ואחסונם בפורמט טבלאי.
|
||||
2. **טעינת נתונים מובנים**: טעינת נתונים שכבר נמצאים בפורמטים מובנים ישירות לחנות הנתונים המובנים, יחד עם נתונים מחולצים.
|
||||
3. **שאילתות בשפה טבעית**: המרת שאלות בשפה טבעית לשאילתות מובנות כדי לחלץ נתונים תואמים מהחנות.
|
||||
4. **שאילתות מובנות ישירות**: ביצוע שאילתות מובנות ישירות מול מאגר הנתונים לשליפת נתונים מדויקת.
|
||||
|
||||
## מטרות
|
||||
|
||||
**גישה מאוחדת לנתונים**: מתן ממשק יחיד לגישה הן לנתונים מובנים והן לנתונים לא מובנים בתוך TrustGraph.
|
||||
**שילוב חלק**: אפשור תאימות הדוקה בין ייצוג הידע מבוסס הגרף של TrustGraph לבין פורמטים מובנים מסורתיים.
|
||||
**חילוץ גמיש**: תמיכה בחילוץ אוטומטי של נתונים מובנים ממקורות לא מובנים שונים (מסמכים, טקסט וכו').
|
||||
**גמישות שאילתא**: לאפשר למשתמשים לשאול נתונים באמצעות שפה טבעית ושפות שאילתא מובנות.
|
||||
**עקביות נתונים**: שמירה על שלמות ועקביות הנתונים בייצוגי נתונים שונים.
|
||||
**אופטימיזציה של ביצועים**: הבטחת אחסון ושליפה יעילים של נתונים מובנים בקנה מידה גדול.
|
||||
**גמישות סכימה**: תמיכה בגישות "סכימה בכתיבה" ו"סכימה בקריאה" כדי להתאים למקורות נתונים מגוונים.
|
||||
**תאימות לאחור**: שמירה על פונקציונליות קיימת של TrustGraph תוך הוספת יכולות נתונים מובנים.
|
||||
|
||||
## רקע
|
||||
|
||||
TrustGraph מצטיינת כיום בעיבוד נתונים לא מובנים ובבניית גרפי ידע ממקורות מגוונים. עם זאת, תרחישי שימוש רבים בארגונים כוללים נתונים המובנים מטבעם - רשומות לקוחות, יומני עסקאות, מסדי נתונים של מלאי וערכות נתונים טבלאיים אחרים. ערכות נתונים מובנות אלו לעתים קרובות צריכות להיות מנותחות יחד עם תוכן לא מובנה כדי לספק תובנות מקיפות.
|
||||
|
||||
מגבלות נוכחיות כוללות:
|
||||
חוסר תמיכה מובנית בטעינת פורמטים מובנים מראש (CSV, מערכי JSON, יצוא מסדי נתונים).
|
||||
חוסר יכולת לשמור על המבנה הטבעי בעת חילוץ נתונים טבלאיים ממסמכים.
|
||||
היעדר מנגנוני שאילתא יעילים עבור דפוסי נתונים מובנים.
|
||||
חוסר גשר בין שאילתות בסגנון SQL לשאילתות גרפיות של TrustGraph.
|
||||
|
||||
מפרט זה מתייחס לפערים אלה על ידי הצגת שכבת נתונים מובנים המשלימה את היכולות הקיימות של TrustGraph. על ידי תמיכה בנתונים מובנים באופן טבעי, TrustGraph יכולה:
|
||||
לשמש כפלטפורמה מאוחדת לניתוח נתונים מובנים ולא מובנים.
|
||||
לאפשר שאילתות היברידיות החוצות קשרי גרף ונתונים טבלאיים.
|
||||
לספק ממשקים מוכרים למשתמשים המורגלים לעבודה עם נתונים מובנים.
|
||||
לפתוח תרחישי שימוש חדשים בשילוב נתונים ובינה עסקית.
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
השילוב של נתונים מובנים דורש את הרכיבים הטכניים הבאים:
|
||||
|
||||
1. **שירות NLP ל-Structured-Query**
|
||||
ממיר שאלות בשפה טבעית לשאילתות מובנות.
|
||||
תומך במספר יעדי שפת שאילתא (בשלב הראשוני תחביר בסגנון SQL).
|
||||
משתלב עם יכולות NLP קיימות של TrustGraph.
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/query/nlp_query/cassandra
|
||||
|
||||
2. **תמיכה בסכימה לתצורה** ✅ **[הושלם]**
|
||||
מערכת תצורה מורחבת לאחסון סכימות נתונים מובנים.
|
||||
תמיכה בהגדרת מבני טבלאות, סוגי שדות ויחסים.
|
||||
יכולות גרסאות סכימה ומיגרציה.
|
||||
|
||||
3. **מודול חילוץ אובייקטים** ✅ **[הושלם]**
|
||||
שילוב משופר של זרימת חילוץ ידע.
|
||||
מזהה ומחלץ אובייקטים מובנים ממקורות לא מובנים.
|
||||
שומר על מוצא וציוני אמון.
|
||||
רושם מטפל תצורה (לדוגמה: trustgraph-flow/trustgraph/prompt/template/service.py) כדי לקבל נתוני תצורה ולפענח מידע סכימה.
|
||||
מקבל אובייקטים ומפענח אותם לאובייקטים של ExtractedObject לצורך העברה בתורת ההודעות Pulsar.
|
||||
הערה: קיים קוד ב-`trustgraph-flow/trustgraph/extract/object/row/`. זו הייתה ניסיון קודם וצריך לשכתב אותו באופן משמעותי מכיוון שהוא אינו תואם ל-APIs הנוכחיים. השתמש בו אם זה שימושי, התחל מאפס אם לא.
|
||||
דורש ממשק שורת פקודה: `kg-extract-objects`
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/extract/kg/objects/
|
||||
|
||||
4. **מודול כתיבת אחסון מובנה** ✅ **[הושלם]**
|
||||
מקבל אובייקטים בפורמט ExtractedObject מתורי Pulsar.
|
||||
יישום ראשוני המכוון ל-Apache Cassandra כאחסון נתונים מובנים.
|
||||
מטפל ביצירת טבלאות דינמית על סמך סכימות המתגלות.
|
||||
מנהל מיפוי סכימה לטבלאות Cassandra והמרת נתונים.
|
||||
מספק פעולות כתיבה באצווה ובסטרימינג לשיפור ביצועים.
|
||||
אין פלטים של Pulsar - זוהי שירות סופי בזרימת הנתונים.
|
||||
|
||||
**טיפול בסכימה**:
|
||||
מנטר הודעות ExtractedObject נכנסות עבור הפניות סכימה.
|
||||
כאשר מתגלה סכימה חדשה בפעם הראשונה, יוצרת טבלה באופן אוטומטי.
|
||||
תומך בגישות "סכימה בקריאה" ו"סכימה בכתיבה" כדי להתאים למקורות נתונים מגוונים.
|
||||
|
||||
פלט חוזה (יש לעקוב בדיוק אחר הפורמט הבא).
|
||||
**מיפוי טבלאות Cassandra**:
|
||||
מרחב הנתונים (Keyspace) נקרא על שם השדה `user` מתוך מטא-הנתונים של ExtractedObject.
|
||||
הטבלה נקראת על שם השדה `schema_name` מתוך ExtractedObject.
|
||||
אוסף מתוך מטא-הנתונים הופך לחלק ממפתח המחיצה (partition key) כדי להבטיח:
|
||||
התפלגות נתונים טבעית על פני צמתים של Cassandra.
|
||||
שאילתות יעילות בתוך אוסף ספציפי.
|
||||
בידוד לוגי בין יבוא נתונים/מקורות שונים.
|
||||
מבנה מפתח ראשי: `PRIMARY KEY ((collection, <schema_primary_key_fields>), <clustering_keys>)`.
|
||||
האוסף הוא תמיד הרכיב הראשון של מפתח המחיצה.
|
||||
שדות מפתח ראשי המוגדרים בסכימה מופיעים כחלק ממפתח המחיצה המורכב.
|
||||
זה דורש ששאילתות יציינו את האוסף, מה שמבטיח ביצועים צפויים.
|
||||
הגדרות שדות ממופות לעמודות של Cassandra עם המרות סוג:
|
||||
`string` → `text`.
|
||||
`integer` → `int` או `bigint` בהתאם לרמז לגודל.
|
||||
`float` → `float` או `double` בהתאם לדרישות דיוק.
|
||||
`boolean` → `boolean`.
|
||||
`timestamp` → `timestamp`.
|
||||
`enum` → `text` עם אימות ברמת היישום.
|
||||
שדות עם אינדקס יוצרים אינדקסים משניים של Cassandra (למעט שדות שכבר נמצאים במפתח הראשי).
|
||||
שדות חובה מיושמים ברמת היישום (Cassandra אינה תומכת ב-NOT NULL).
|
||||
|
||||
**אחסון אובייקטים**:
|
||||
מחלץ ערכים ממפת ExtractedObject.values.
|
||||
מבצע המרת סוג ואימות לפני הכנסה.
|
||||
מטפל בשדות אופציונליים חסרים בצורה חלקה.
|
||||
שומר על מטא-נתונים לגבי מקור האובייקט (מסמך מקור, ציוני אמון).
|
||||
תומך בכתיבות אידמפוטנטיות כדי לטפל בתרחישי שידור חוזר של הודעות.
|
||||
|
||||
**הערות יישום**:
|
||||
קוד קיים ב-`trustgraph-flow/trustgraph/storage/objects/cassandra/` מיושן ואינו תואם ל-APIs הנוכחיים.
|
||||
יש להתייחס ל-`trustgraph-flow/trustgraph/storage/triples/cassandra` כדוגמה למעבד אחסון תקין.
|
||||
יש להעריך את הקוד הקיים כדי לזהות רכיבים שניתן לעשות בהם שימוש חוזר לפני שמחליטים לבצע שינוי מבני או כתיבה מחדש.
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/storage/objects/cassandra
|
||||
|
||||
5. **שירות שאילתות מובנה** ✅ **[הושלם]**
|
||||
מקבל שאילתות מובנות בפורמטים מוגדרים.
|
||||
מבצע שאילתות על הנתונים המובנים.
|
||||
מחזיר אובייקטים התואמים לקריטריוני השאילתה.
|
||||
תומך בדפדוף וסינון תוצאות.
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/query/objects/cassandra
|
||||
|
||||
6. **אינטגרציה עם כלי סוכן**:
|
||||
מחלקת כלי חדשה עבור מסגרות סוכן.
|
||||
מאפשר לסוכנים לשאול נתונים מובנים.
|
||||
מספק ממשקי שפה טבעית ושאילתות מובנות.
|
||||
משתלב עם תהליכי קבלת החלטות קיימים של סוכנים.
|
||||
|
||||
7. **שירות הכנסת נתונים מובנים**:
|
||||
מקבל נתונים מובנים בפורמטים מרובים (JSON, CSV, XML).
|
||||
מנתח ומאמת נתונים נכנסים בהתאם לסכימות מוגדרות.
|
||||
ממיר נתונים לזרמי אובייקטים מנורמלים.
|
||||
פולט אובייקטים לתורי הודעות מתאימים לעיבוד.
|
||||
תומך בהעלאות אצווה ובהכנסה רציפה.
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/decoding/structured
|
||||
|
||||
8. **שירות הטמעת אובייקטים**:
|
||||
מייצר הטמעות וקטוריות עבור אובייקטים מובנים.
|
||||
מאפשר חיפוש סמנטי על פני נתונים מובנים.
|
||||
תומך בחיפוש היברידי המשלב שאילתות מובנות עם דמיון סמנטי.
|
||||
משתלב עם מאגרי וקטורים קיימים.
|
||||
|
||||
מודול: trustgraph-flow/trustgraph/embeddings/object_embeddings/qdrant
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### מנגנון אחסון סכימות
|
||||
|
||||
סכימות מאוחסנות במערכת התצורה של TrustGraph באמצעות המבנה הבא:
|
||||
|
||||
**סוג**: `schema` (ערך קבוע עבור כל סכימות הנתונים המובנים).
|
||||
**מפתח**: השם/מזהה הייחודי של הסכימה (לדוגמה, `customer_records`, `transaction_log`).
|
||||
**ערך**: הגדרת סכימת JSON המכילה את המבנה.
|
||||
|
||||
רשומה לדוגמה בתצורה:
|
||||
```
|
||||
Type: schema
|
||||
Key: customer_records
|
||||
Value: {
|
||||
"name": "customer_records",
|
||||
"description": "Customer information table",
|
||||
"fields": [
|
||||
{
|
||||
"name": "customer_id",
|
||||
"type": "string",
|
||||
"primary_key": true
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "registration_date",
|
||||
"type": "timestamp"
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"type": "string",
|
||||
"enum": ["active", "inactive", "suspended"]
|
||||
}
|
||||
],
|
||||
"indexes": ["email", "registration_date"]
|
||||
}
|
||||
```
|
||||
|
||||
גישה זו מאפשרת:
|
||||
הגדרה דינמית של סכימה ללא שינויים בקוד
|
||||
עדכונים וגרסאות קלים של הסכימה
|
||||
אינטגרציה עקבית עם ניהול התצורה הקיים של TrustGraph
|
||||
תמיכה במספר סכימות בתוך פריסה אחת
|
||||
|
||||
### ממשקי API
|
||||
|
||||
ממשקי API חדשים:
|
||||
סכימות Pulsar עבור הסוגים שלעיל
|
||||
ממשקי Pulsar בזרמים חדשים
|
||||
נדרש אמצעי לציין סוגי סכימה בזרמים כך שהזרמים ידעו אילו
|
||||
סוגי סכימה לטעון
|
||||
ממשקי API נוספו לשער ולשער ההיפוך
|
||||
|
||||
ממשקי API ששונו:
|
||||
נקודות קצה לחילוץ ידע - הוספת אפשרות פלט של אובייקט מובנה
|
||||
נקודות קצה של סוכנים - הוספת תמיכה בכלי נתונים מובנים
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
בהתאם לקונבנציות קיימות - אלו מודולים חדשים לעיבוד בלבד.
|
||||
הכל נמצא בחבילות trustgraph-flow למעט פריטי סכימה
|
||||
ב-trustgraph-base.
|
||||
|
||||
נדרשת עבודה כלשהי בממשק המשתמש ב-Workbench כדי שניתן יהיה להדגים / לבצע פיילוט
|
||||
ליכולת זו.
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
אין שיקולים נוספים.
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
ישנן שאלות בנוגע לשימוש בשאילתות ואינדקסים של Cassandra כך ששאלות
|
||||
לא יאטו את העבודה.
|
||||
|
||||
## אסטרטגיית בדיקה
|
||||
|
||||
יש להשתמש באסטרטגיית בדיקה קיימת, ייבנו בדיקות יחידה, חוזה ואינטגרציה.
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
אין.
|
||||
|
||||
## ציר זמן
|
||||
|
||||
לא צוין.
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
האם ניתן לגרום לזה לעבוד עם סוגי אחסון אחרים? אנו שואפים להשתמש
|
||||
בממשקים אשר הופכים מודולים שעובדים עם אחסון אחד ליישומיים
|
||||
לאחסון אחר.
|
||||
|
||||
## הפניות
|
||||
|
||||
n/a.
|
||||
281
docs/tech-specs/he/structured-diag-service.he.md
Normal file
281
docs/tech-specs/he/structured-diag-service.he.md
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפרט טכני לשירות אבחון נתונים מובנים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפרט טכני לשירות אבחון נתונים מובנים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מתאר שירות חדש הניתן לביצוע לאבחון וניתוח נתונים מובנים בתוך TrustGraph. השירות שואב פונקציונליות מכלי שורת הפקודה הקיים `tg-load-structured-data` ומציג אותו כשירות בקשה/תגובה, ומאפשר גישה תכנותית ליכולות זיהוי סוג נתונים ויצירת תיאורים.
|
||||
|
||||
השירות תומך בשלוש פעולות עיקריות:
|
||||
|
||||
1. **זיהוי סוג נתונים**: ניתוח דוגמת נתונים כדי לקבוע את הפורמט שלה (CSV, JSON או XML)
|
||||
2. **יצירת תיאור**: יצירת תיאור נתונים מובנים עבור דוגמת נתונים מסוימת וסוג
|
||||
3. **אבחון משולב**: ביצוע גם זיהוי סוג וגם יצירת תיאור ברצף
|
||||
|
||||
## מטרות
|
||||
|
||||
**מודולריזציה של ניתוח נתונים**: העברת לוגיקת אבחון נתונים משורת הפקודה לרכיבי שירות הניתנים לשימוש חוזר
|
||||
**אפשרות לגישה תכנותית**: מתן גישה מבוססת API ליכולות ניתוח נתונים
|
||||
**תמיכה במספר פורמטים של נתונים**: טיפול בפורמטי נתונים של CSV, JSON ו-XML באופן עקבי
|
||||
**יצירת תיאורים מדויקים**: יצירת תיאורי נתונים מובנים המתאימים בצורה מדויקת לנתוני המקור לתוך סכימות TrustGraph
|
||||
**שמירה על תאימות לאחור**: הבטחה שפונקציונליות קיימת של שורת הפקודה תמשיך לעבוד
|
||||
**אפשרות לחיבור שירותים**: לאפשר לשירותים אחרים לנצל יכולות אבחון נתונים
|
||||
**שיפור יכולת בדיקה**: הפרדת לוגיקה עסקית מממשק שורת הפקודה לצורך בדיקות טובות יותר
|
||||
**תמיכה בניתוח סטרימינג**: אפשרות לניתוח דוגמאות נתונים מבלי לטעון קבצים שלמים
|
||||
|
||||
## רקע
|
||||
|
||||
כיום, הפקודה `tg-load-structured-data` מספקת פונקציונליות מקיפה לניתוח נתונים מובנים ויצירת תיאורים. עם זאת, פונקציונליות זו קשורה הדוקות לממשק שורת הפקודה, מה שמגביל את יכולת השימוש החוזר בה.
|
||||
|
||||
מגבלות נוכחיות כוללות:
|
||||
לוגיקת אבחון נתונים מוטמעת בקוד שורת הפקודה
|
||||
אין גישה תכנותית לזיהוי סוג ויצירת תיאורים
|
||||
קשה לשלב יכולות אבחון בשירותים אחרים
|
||||
יכולת מוגבלת ליצור זרימות עבודה לניתוח נתונים
|
||||
|
||||
מפרט זה מתייחס לפערים אלה על ידי יצירת שירות ייעודי לאבחון נתונים מובנים. על ידי חשיפת יכולות אלה כשירות, TrustGraph יכולה:
|
||||
לאפשר לשירותים אחרים לנתח נתונים באופן תכנותי
|
||||
לתמוך בצינורות עיבוד נתונים מורכבים יותר
|
||||
להקל על שילוב עם מערכות חיצוניות
|
||||
לשפר את תחזוקת המערכת באמצעות הפרדת אחריות
|
||||
|
||||
## עיצוב טכני
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
שירות האבחון של נתונים מובנים דורש את הרכיבים הטכניים הבאים:
|
||||
|
||||
1. **מעבד שירות אבחון**
|
||||
מטפל בבקשות אבחון נכנסות
|
||||
מתאם זיהוי סוג ויצירת תיאורים
|
||||
מחזיר תגובות מובנות עם תוצאות אבחון
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/diagnosis/structured_data/service.py`
|
||||
|
||||
2. **מגַלֶּה סוג נתונים**
|
||||
משתמש בגילוי אלגוריתמי כדי לזהות פורמט נתונים (CSV, JSON, XML)
|
||||
מנתח מבנה נתונים, מפרידים ותבניות תחביר
|
||||
מחזיר פורמט מזוהה וציוני אמון
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/diagnosis/structured_data/type_detector.py`
|
||||
|
||||
3. **יוצר תיאורים**
|
||||
משתמש בשירות פרומפטים כדי ליצור תיאורים
|
||||
מפעיל פרומפטים ספציפיים לפורמט (diagnose-csv, diagnose-json, diagnose-xml)
|
||||
ממפה שדות נתונים לשדות סכימת TrustGraph באמצעות תגובות פרומפטים
|
||||
|
||||
מודול: `trustgraph-flow/trustgraph/diagnosis/structured_data/descriptor_generator.py`
|
||||
|
||||
### מודלים של נתונים
|
||||
|
||||
#### StructuredDataDiagnosisRequest
|
||||
|
||||
הודעת בקשה לפעולות אבחון נתונים מובנים:
|
||||
|
||||
```python
|
||||
class StructuredDataDiagnosisRequest:
|
||||
operation: str # "detect-type", "generate-descriptor", or "diagnose"
|
||||
sample: str # Data sample to analyze (text content)
|
||||
type: Optional[str] # Data type (csv, json, xml) - required for generate-descriptor
|
||||
schema_name: Optional[str] # Target schema name for descriptor generation
|
||||
options: Dict[str, Any] # Additional options (e.g., delimiter for CSV)
|
||||
```
|
||||
|
||||
#### תגובת אבחון נתונים מובנים
|
||||
|
||||
הודעת תגובה המכילה תוצאות אבחון:
|
||||
|
||||
```python
|
||||
class StructuredDataDiagnosisResponse:
|
||||
operation: str # The operation that was performed
|
||||
detected_type: Optional[str] # Detected data type (for detect-type/diagnose)
|
||||
confidence: Optional[float] # Confidence score for type detection
|
||||
descriptor: Optional[Dict] # Generated descriptor (for generate-descriptor/diagnose)
|
||||
error: Optional[str] # Error message if operation failed
|
||||
metadata: Dict[str, Any] # Additional metadata (e.g., field count, sample records)
|
||||
```
|
||||
|
||||
#### מבנה תיאור
|
||||
|
||||
התיאור שנוצר עוקב אחר פורמט התיאור המובנה הקיים:
|
||||
|
||||
```json
|
||||
{
|
||||
"format": {
|
||||
"type": "csv",
|
||||
"encoding": "utf-8",
|
||||
"options": {
|
||||
"delimiter": ",",
|
||||
"has_header": true
|
||||
}
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"source_field": "customer_id",
|
||||
"target_field": "id",
|
||||
"transforms": [
|
||||
{"type": "trim"}
|
||||
]
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"schema_name": "customer",
|
||||
"options": {
|
||||
"batch_size": 1000,
|
||||
"confidence": 0.9
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ממשק שירות
|
||||
|
||||
השירות יחשוף את הפעולות הבאות באמצעות תבנית בקשה/תגובה:
|
||||
|
||||
1. **פעולת זיהוי סוג**
|
||||
קלט: דוגמת נתונים
|
||||
עיבוד: ניתוח מבנה הנתונים באמצעות זיהוי אלגוריתמי
|
||||
פלט: סוג מזוהה עם ציון אמון
|
||||
|
||||
2. **פעולת יצירת תיאור**
|
||||
קלט: דוגמת נתונים, סוג, שם סכימה יעד
|
||||
עיבוד:
|
||||
הפעלת שירות הפרומפט עם מזהה הפרומפט הספציפי לפורמט (diagnose-csv, diagnose-json או diagnose-xml)
|
||||
העברת דוגמת הנתונים והסכימות הזמינות לפרומפט
|
||||
קבלת התיאור שנוצר מתגובת הפרומפט
|
||||
פלט: תיאור נתונים מובנים
|
||||
|
||||
3. **פעולת אבחון משולבת**
|
||||
קלט: דוגמת נתונים, שם סכימה אופציונלי
|
||||
עיבוד:
|
||||
שימוש בזיהוי אלגוריתמי לזיהוי הפורמט תחילה
|
||||
בחירת פרומפט ספציפי לפורמט בהתאם לסוג המזוהה
|
||||
הפעלת שירות הפרומפט ליצירת תיאור
|
||||
פלט: גם הסוג המזוהה וגם התיאור
|
||||
|
||||
### פרטי יישום
|
||||
|
||||
השירות יפעל בהתאם לקונבנציות של שירות TrustGraph:
|
||||
|
||||
1. **רישום שירות**
|
||||
רישום כסוג שירות `structured-diag`
|
||||
שימוש בנושאים סטנדרטיים של בקשה/תגובה
|
||||
יישום מחלקת FlowProcessor בסיסית
|
||||
רישום PromptClientSpec עבור אינטראקציה עם שירות הפרומפט
|
||||
|
||||
2. **ניהול תצורה**
|
||||
גישה לתצורות סכימה באמצעות שירות התצורה
|
||||
שמירת סכימות במטמון לביצועים
|
||||
טיפול בעדכוני תצורה באופן דינמי
|
||||
|
||||
3. **שילוב פרומפט**
|
||||
שימוש בתשתית קיימת של שירות הפרומפט
|
||||
הפעלת שירות הפרומפט עם מזהי פרומפט ספציפיים לפורמט:
|
||||
`diagnose-csv`: לניתוח נתוני CSV
|
||||
`diagnose-json`: לניתוח נתוני JSON
|
||||
`diagnose-xml`: לניתוח נתוני XML
|
||||
הפרומפטים מוגדרים בתצורת הפרומפט, ולא מקודדים קשות בשירות
|
||||
העברת סכימות ודוגמאות נתונים כמשתני פרומפט
|
||||
ניתוח תגובות פרומפט לחילוץ תיאורים
|
||||
|
||||
4. **טיפול בשגיאות**
|
||||
אימות דוגמאות נתונים
|
||||
מתן הודעות שגיאה תיאוריות
|
||||
טיפול מסודר בנתונים פגומים
|
||||
טיפול בכשלים בשירות הפרומפט
|
||||
|
||||
5. **דגימת נתונים**
|
||||
עיבוד גדלי דגימה הניתנים לתצורה
|
||||
טיפול מתאים ברשומות חסרות
|
||||
שמירה על עקביות דגימה
|
||||
|
||||
### שילוב API
|
||||
|
||||
השירות ישולב עם ממשקי TrustGraph קיימים:
|
||||
|
||||
רכיבים שעברו שינוי:
|
||||
`tg-load-structured-data` CLI - שופץ לשימוש בשירות החדש לפעולות אבחון
|
||||
Flow API - הורחב לתמיכה בבקשות אבחון נתונים מובנים
|
||||
|
||||
נקודות שירות חדשות:
|
||||
`/api/v1/flow/{flow}/diagnose/structured-data` - נקודת קצה WebSocket לבקשות אבחון
|
||||
`/api/v1/diagnose/structured-data` - נקודת קצה REST לאבחון סינכרוני
|
||||
|
||||
### זרימת הודעות
|
||||
|
||||
```
|
||||
Client → Gateway → Structured Diag Service → Config Service (for schemas)
|
||||
↓
|
||||
Type Detector (algorithmic)
|
||||
↓
|
||||
Prompt Service (diagnose-csv/json/xml)
|
||||
↓
|
||||
Descriptor Generator (parses prompt response)
|
||||
↓
|
||||
Client ← Gateway ← Structured Diag Service (response)
|
||||
```
|
||||
|
||||
## שיקולי אבטחה
|
||||
|
||||
אימות קלט למניעת התקפות הזרקה
|
||||
מגבלות גודל על דוגמאות נתונים למניעת התקפות מניעת שירות (DoS)
|
||||
ניקוי של מזהים שנוצרו
|
||||
בקרת גישה באמצעות אימות TrustGraph הקיים
|
||||
|
||||
## שיקולי ביצועים
|
||||
|
||||
שמירת הגדרות סכימה במטמון להפחתת קריאות לשירות התצורה
|
||||
הגבלת גודל הדוגמאות לשמירה על ביצועים מהירים
|
||||
שימוש בעיבוד סטרימינג עבור דוגמאות נתונים גדולות
|
||||
הטמעת מנגנוני זמן קצוב עבור ניתוחים ארוכים
|
||||
|
||||
## אסטרטגיית בדיקות
|
||||
|
||||
1. **בדיקות יחידה**
|
||||
זיהוי סוג עבור פורמטי נתונים שונים
|
||||
דיוק יצירת מזהים
|
||||
תרחישי טיפול בשגיאות
|
||||
|
||||
2. **בדיקות אינטגרציה**
|
||||
זרימת בקשות/תגובות של שירות
|
||||
שליפה ושמירה במטמון של סכימות
|
||||
אינטגרציה עם שורת הפקודה (CLI)
|
||||
|
||||
3. **בדיקות ביצועים**
|
||||
עיבוד של דוגמאות גדולות
|
||||
טיפול בבקשות מקבילות
|
||||
שימוש בזיכרון בתנאי עומס
|
||||
|
||||
## תוכנית מעבר
|
||||
|
||||
1. **שלב 1**: הטמעת שירות עם פונקציונליות בסיסית
|
||||
2. **שלב 2**: שינוי שורת הפקודה (CLI) לשימוש בשירות (שמירה על תאימות לאחור)
|
||||
3. **שלב 3**: הוספת נקודות קצה של ממשק API REST
|
||||
4. **שלב 4**: הפסקת השימוש בלוגיקה מוטמעת של שורת הפקודה (עם תקופת התראה)
|
||||
|
||||
## ציר זמן
|
||||
|
||||
שבוע 1-2: הטמעת שירות וזיהוי סוג בסיסי
|
||||
שבוע 3-4: הוספת יצירת מזהים ואינטגרציה
|
||||
שבוע 5: בדיקות ותיעוד
|
||||
שבוע 6: שינוי שורת הפקודה (CLI) ומעבר
|
||||
|
||||
## שאלות פתוחות
|
||||
|
||||
האם השירות צריך לתמוך בפורמטי נתונים נוספים (לדוגמה, Parquet, Avro)?
|
||||
מהו גודל הדוגמה המקסימלי לניתוח?
|
||||
האם תוצאות האבחון צריכות להיות שמורות במטמון עבור בקשות חוזרות?
|
||||
כיצד השירות צריך להתמודד עם תרחישים של סכימות מרובות?
|
||||
האם מזהי הבקשות צריכים להיות פרמטרים הניתנים להגדרה עבור השירות?
|
||||
|
||||
## הפניות
|
||||
|
||||
[מפרט מזהה נתונים מובנים](structured-data-descriptor.md)
|
||||
[תיעוד טעינת נתונים מובנים](structured-data.md)
|
||||
`tg-load-structured-data` יישום: `trustgraph-cli/trustgraph/cli/load_structured_data.py`
|
||||
499
docs/tech-specs/he/tool-group.he.md
Normal file
499
docs/tech-specs/he/tool-group.he.md
Normal file
|
|
@ -0,0 +1,499 @@
|
|||
---
|
||||
layout: default
|
||||
title: "קבוצת כלים עבור TrustGraph"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# קבוצת כלים עבור TrustGraph
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
## מפרט טכני גרסה 1.0
|
||||
|
||||
### תקציר מנהלים
|
||||
|
||||
מפרט זה מגדיר מערכת לקבוצות כלים עבור סוכני TrustGraph, המאפשרת שליטה מדויקת על אילו כלים זמינים עבור בקשות ספציפיות. המערכת מציגה סינון כלים מבוסס קבוצות באמצעות תצורה ומפרט ברמת הבקשה, ומאפשרת גבולות אבטחה טובים יותר, ניהול משאבים וחלוקת פונקציונליות של יכולות הסוכנים.
|
||||
|
||||
### 1. סקירה כללית
|
||||
|
||||
#### 1.1 הצגת הבעיה
|
||||
|
||||
כיום, לסוכני TrustGraph יש גישה לכל הכלים המוגדרים, ללא קשר להקשר הבקשה או לדרישות האבטחה. זה יוצר מספר אתגרים:
|
||||
|
||||
**סיכון אבטחה**: כלים רגישים (לדוגמה, שינוי נתונים) זמינים גם עבור שאילתות לקריאה בלבד.
|
||||
**בזבוז משאבים**: כלים מורכבים נטענים גם כאשר שאילתות פשוטות אינן דורשים אותם.
|
||||
**בלבול פונקציונלי**: סוכנים עשויים לבחור כלים לא מתאימים כאשר קיימות חלופות פשוטות יותר.
|
||||
**בידוד מרובה דיירים**: קבוצות משתמשים שונות צריכות גישה לקבוצות כלים שונות.
|
||||
|
||||
#### 1.2 סקירה כללית של הפתרון
|
||||
|
||||
מערכת קבוצות הכלים מציגה:
|
||||
|
||||
1. **סיווג קבוצות**: כלים מסומנים עם שייכות לקבוצות במהלך התצורה.
|
||||
2. **סינון ברמת הבקשה**: בקשת סוכן מציינת אילו קבוצות כלים מותרות.
|
||||
3. **אכיפה בזמן ריצה**: לסוכנים יש גישה רק לכלים התואמים לקבוצות המבוקשות.
|
||||
4. **קיבוץ גמיש**: כלים יכולים להיות שייכים למספר קבוצות עבור תרחישים מורכבים.
|
||||
|
||||
### 2. שינויים בסכימה
|
||||
|
||||
#### 2.1 שיפור סכימת תצורת הכלים
|
||||
|
||||
תצורת הכלים הקיימת משופרת עם שדה `group`:
|
||||
|
||||
**לפני:**
|
||||
```json
|
||||
{
|
||||
"name": "knowledge-query",
|
||||
"type": "knowledge-query",
|
||||
"description": "Query the knowledge graph"
|
||||
}
|
||||
```
|
||||
|
||||
**אחרי:**
|
||||
```json
|
||||
{
|
||||
"name": "knowledge-query",
|
||||
"type": "knowledge-query",
|
||||
"description": "Query the knowledge graph",
|
||||
"group": ["read-only", "knowledge", "basic"]
|
||||
}
|
||||
```
|
||||
|
||||
**מפרט שדה קבוצה:**
|
||||
`group`: Array(String) - רשימה של קבוצות שאליהן הכלי הזה שייך
|
||||
**אופציונלי**: כלים ללא שדה קבוצה שייכים לקבוצה "ברירת מחדל"
|
||||
**חברות מרובות**: כלים יכולים להיות שייכים למספר קבוצות
|
||||
**רגישות לאותיות**: שמות הקבוצות חייבים להיות התאמה מדויקת של מחרוזות
|
||||
|
||||
#### 2.1.2 שיפור מעבר מצבים של כלי
|
||||
|
||||
כלים יכולים לציין אופציונלית מעברי מצבים וזמינות מבוססת מצב:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "knowledge-query",
|
||||
"type": "knowledge-query",
|
||||
"description": "Query the knowledge graph",
|
||||
"group": ["read-only", "knowledge", "basic"],
|
||||
"state": "analysis",
|
||||
"available_in_states": ["undefined", "research"]
|
||||
}
|
||||
```
|
||||
|
||||
**מפרט שדה מצב:**
|
||||
`state`: מחרוזת - **אופציונלי** - המצב שאליו יש לעבור לאחר ביצוע מוצלח של הכלי
|
||||
`available_in_states`: מערך(מחרוזת) - **אופציונלי** - מצבים שבהם הכלי זמין
|
||||
**התנהגות ברירת מחדל**: כלים ללא `available_in_states` זמינים בכל המצבים
|
||||
**מעבר מצב**: מתרחש רק לאחר ביצוע מוצלח של הכלי
|
||||
|
||||
#### 2.2 שיפור סכימת AgentRequest
|
||||
|
||||
הסכימה `AgentRequest` ב-`trustgraph-base/trustgraph/schema/services/agent.py` משופרת:
|
||||
|
||||
**AgentRequest נוכחי:**
|
||||
`question`: מחרוזת - שאילתת משתמש
|
||||
`plan`: מחרוזת - תוכנית ביצוע (ניתן להסיר)
|
||||
`state`: מחרוזת - מצב סוכן
|
||||
`history`: מערך(AgentStep) - היסטוריית ביצוע
|
||||
|
||||
**AgentRequest משופר:**
|
||||
`question`: מחרוזת - שאילתת משתמש
|
||||
`state`: מחרוזת - מצב ביצוע סוכן (כעת בשימוש פעיל לסינון כלים)
|
||||
`history`: מערך(AgentStep) - היסטוריית ביצוע
|
||||
`group`: מערך(מחרוזת) - **חדש** - קבוצות כלים מותרות עבור בקשה זו
|
||||
|
||||
**שינויים בסכימה:**
|
||||
**הוסר**: השדה `plan` אינו נחוץ יותר וניתן להסירו (היה מיועד במקור למפרט כלים)
|
||||
**נוסף**: השדה `group` למפרט קבוצות כלים
|
||||
**שופר**: השדה `state` שולט כעת בזמינות הכלים במהלך הביצוע
|
||||
|
||||
**התנהגויות של שדות:**
|
||||
|
||||
**קבוצת שדות:**
|
||||
**אופציונלי**: אם לא צוין, ברירת המחדל היא ["default"]
|
||||
**חיתוך**: זמינים רק כלים התואמים לפחות לקבוצה אחת שצוינה
|
||||
**מערך ריק**: אין כלים זמינים (הסוכן יכול להשתמש רק בנימוקים פנימיים)
|
||||
**תו גלובלי**: קבוצה מיוחדת "*" מעניקה גישה לכל הכלים
|
||||
|
||||
**שדה מצב:**
|
||||
**אופציונלי**: אם לא צוין, ברירת המחדל היא "לא מוגדר"
|
||||
**סינון מבוסס מצב**: זכאים רק כלים הזמינים במצב הנוכחי
|
||||
**מצב ברירת מחדל**: מצב "לא מוגדר" מאפשר לכל הכלים (בהתאם לסינון קבוצות)
|
||||
**מעברי מצב**: כלים יכולים לשנות מצב לאחר ביצוע מוצלח
|
||||
|
||||
### 3. דוגמאות לקבוצות מותאמות אישית
|
||||
|
||||
ארגונים יכולים להגדיר קבוצות ספציפיות לתחום:
|
||||
|
||||
```json
|
||||
{
|
||||
"financial-tools": ["stock-query", "portfolio-analysis"],
|
||||
"medical-tools": ["diagnosis-assist", "drug-interaction"],
|
||||
"legal-tools": ["contract-analysis", "case-search"]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. פרטי יישום
|
||||
|
||||
#### 4.1 טעינת כלים וסינון
|
||||
|
||||
**שלב התצורה:**
|
||||
1. כל הכלים נטענים מקובץ התצורה עם ההקצאות שלהם לקבוצות.
|
||||
2. כלים שאין להם קבוצות מוגדרות מוקצים לקבוצה "ברירת מחדל".
|
||||
3. חברות בקבוצות מאומתות ונשמרות במאגר הכלים.
|
||||
|
||||
**שלב עיבוד בקשות:**
|
||||
1. בקשת סוכן מגיעה עם ציון קבוצה אופציונלי.
|
||||
2. הסוכן מסנן את הכלים הזמינים בהתבסס על חיתוך קבוצות.
|
||||
3. רק כלים תואמים מועברים להקשר הביצוע של הסוכן.
|
||||
4. הסוכן פועל עם סט הכלים המסונן לאורך כל מחזור החיים של הבקשה.
|
||||
|
||||
#### 4.2 לוגיקת סינון כלים
|
||||
|
||||
**סינון משולב של קבוצות ומצבים:**
|
||||
|
||||
```
|
||||
For each configured tool:
|
||||
tool_groups = tool.group || ["default"]
|
||||
tool_states = tool.available_in_states || ["*"] // Available in all states
|
||||
|
||||
For each request:
|
||||
requested_groups = request.group || ["default"]
|
||||
current_state = request.state || "undefined"
|
||||
|
||||
Tool is available if:
|
||||
// Group filtering
|
||||
(intersection(tool_groups, requested_groups) is not empty OR "*" in requested_groups)
|
||||
AND
|
||||
// State filtering
|
||||
(current_state in tool_states OR "*" in tool_states)
|
||||
```
|
||||
|
||||
**לוגיקת מעבר מצבים:**
|
||||
|
||||
```
|
||||
After successful tool execution:
|
||||
if tool.state is defined:
|
||||
next_request.state = tool.state
|
||||
else:
|
||||
next_request.state = current_request.state // No change
|
||||
```
|
||||
|
||||
#### 4.3 נקודות אינטגרציה של סוכן
|
||||
|
||||
**סוכן ReAct:**
|
||||
סינון כלים מתבצע ב-agent_manager.py במהלך יצירת רישום הכלים
|
||||
רשימת הכלים הזמינים מסוננת לפי קבוצה ומצב לפני יצירת תוכנית
|
||||
מעברי מצבים מעדכנים את השדה AgentRequest.state לאחר ביצוע מוצלח של כלי
|
||||
האיטרציה הבאה משתמשת במצב המעודכן לסינון כלים
|
||||
|
||||
**סוכן מבוסס ביטחון:**
|
||||
סינון כלים מתבצע ב-planner.py במהלך יצירת תוכנית
|
||||
אימות ExecutionStep מבטיח שרק כלים מתאימים לקבוצה ולמצב משמשים
|
||||
בקר הזרימה (Flow controller) מאכף את זמינות הכלים בזמן ריצה
|
||||
מעברי מצבים מנוהלים על ידי בקר הזרימה בין שלבים
|
||||
|
||||
### 5. דוגמאות תצורה
|
||||
|
||||
#### 5.1 תצורת כלים עם קבוצות ומצבים
|
||||
|
||||
```yaml
|
||||
tool:
|
||||
knowledge-query:
|
||||
type: knowledge-query
|
||||
name: "Knowledge Graph Query"
|
||||
description: "Query the knowledge graph for entities and relationships"
|
||||
group: ["read-only", "knowledge", "basic"]
|
||||
state: "analysis"
|
||||
available_in_states: ["undefined", "research"]
|
||||
|
||||
graph-update:
|
||||
type: graph-update
|
||||
name: "Graph Update"
|
||||
description: "Add or modify entities in the knowledge graph"
|
||||
group: ["write", "knowledge", "admin"]
|
||||
available_in_states: ["analysis", "modification"]
|
||||
|
||||
text-completion:
|
||||
type: text-completion
|
||||
name: "Text Completion"
|
||||
description: "Generate text using language models"
|
||||
group: ["read-only", "text", "basic"]
|
||||
state: "undefined"
|
||||
# No available_in_states = available in all states
|
||||
|
||||
complex-analysis:
|
||||
type: mcp-tool
|
||||
name: "Complex Analysis Tool"
|
||||
description: "Perform complex data analysis"
|
||||
group: ["advanced", "compute", "expensive"]
|
||||
state: "results"
|
||||
available_in_states: ["analysis"]
|
||||
mcp_tool_id: "analysis-server"
|
||||
|
||||
reset-workflow:
|
||||
type: mcp-tool
|
||||
name: "Reset Workflow"
|
||||
description: "Reset to initial state"
|
||||
group: ["admin"]
|
||||
state: "undefined"
|
||||
available_in_states: ["analysis", "results"]
|
||||
```
|
||||
|
||||
#### 5.2 דוגמאות לבקשות עם תהליכי עבודה מוגדרים מראש
|
||||
|
||||
**בקשה ראשונית למחקר:**
|
||||
```json
|
||||
{
|
||||
"question": "What entities are connected to Company X?",
|
||||
"group": ["read-only", "knowledge"],
|
||||
"state": "undefined"
|
||||
}
|
||||
```
|
||||
*כלים זמינים: שאילתת ידע, השלמת טקסט*
|
||||
*לאחר שאילתת ידע: מצב → "ניתוח"*
|
||||
|
||||
**שלב הניתוח:**
|
||||
```json
|
||||
{
|
||||
"question": "Continue analysis based on previous results",
|
||||
"group": ["advanced", "compute", "write"],
|
||||
"state": "analysis"
|
||||
}
|
||||
```
|
||||
*כלים זמינים: complex-analysis, graph-update, reset-workflow*
|
||||
*לאחר complex-analysis: מצב → "תוצאות"*
|
||||
|
||||
**שלב התוצאות:**
|
||||
```json
|
||||
{
|
||||
"question": "What should I do with these results?",
|
||||
"group": ["admin"],
|
||||
"state": "results"
|
||||
}
|
||||
```
|
||||
*כלים זמינים: reset-workflow בלבד*
|
||||
*לאחר הפעלת reset-workflow: מצב → "לא מוגדר"*
|
||||
|
||||
**דוגמה לזרימת עבודה - זרימה מלאה:**
|
||||
1. **התחלה (לא מוגדר):** השתמש ב-knowledge-query → מעבר למצב "ניתוח"
|
||||
2. **מצב ניתוח:** השתמש ב-complex-analysis → מעבר למצב "תוצאות"
|
||||
3. **מצב תוצאות:** השתמש ב-reset-workflow → חזרה למצב "לא מוגדר"
|
||||
4. **חזרה להתחלה:** כל הכלים הזמינים זמינים שוב
|
||||
|
||||
### 6. שיקולי אבטחה
|
||||
|
||||
#### 6.1 שילוב בקרת גישה
|
||||
|
||||
**סינון ברמת השער (Gateway):**
|
||||
השער יכול לאכוף הגבלות קבוצתיות בהתבסס על הרשאות משתמש
|
||||
מניעת העלאת הרשאות באמצעות מניפולציה של בקשות
|
||||
רישום ביקורת כולל קבוצות כלים מבוקשות ומוענקות
|
||||
|
||||
**לוגיקה לדוגמה של השער:**
|
||||
```
|
||||
user_permissions = get_user_permissions(request.user_id)
|
||||
allowed_groups = user_permissions.tool_groups
|
||||
requested_groups = request.group
|
||||
|
||||
# Validate request doesn't exceed permissions
|
||||
if not is_subset(requested_groups, allowed_groups):
|
||||
reject_request("Insufficient permissions for requested tool groups")
|
||||
```
|
||||
|
||||
#### 6.2 ביקורת וניטור
|
||||
|
||||
**רשומות ביקורת משופרות:**
|
||||
רישום קבוצות כלים מבוקשות ומצב התחלתי עבור כל בקשה
|
||||
מעקב אחר מעברי מצבים ושימוש בכלים לפי חברות בקבוצה
|
||||
ניטור ניסיונות גישה לא מורשים לקבוצות ושינויי מצב לא חוקיים
|
||||
התראה על דפוסי שימוש חריגים בקבוצות או זרימות עבודה חשודות במצב
|
||||
|
||||
### 7. אסטרטגיית מעבר
|
||||
|
||||
#### 7.1 תאימות לאחור
|
||||
|
||||
**שלב 1: שינויים מצטברים**
|
||||
הוספת שדה אופציונלי `group` לתצורות כלים
|
||||
הוספת שדה אופציונלי `group` לתבנית AgentRequest
|
||||
התנהגות ברירת מחדל: כל הכלים הקיימים שייכים לקבוצה "ברירת מחדל"
|
||||
בקשות קיימות ללא שדה קבוצה משתמשות בקבוצה "ברירת מחדל"
|
||||
|
||||
**התנהגות קיימת נשמרת:**
|
||||
כלים ללא תצורת קבוצה ממשיכים לעבוד (קבוצת ברירת מחדל)
|
||||
כלים ללא תצורת מצב זמינים בכל המצבים
|
||||
בקשות ללא ציון קבוצה ניגשות לכל הכלים (קבוצת ברירת מחדל)
|
||||
בקשות ללא ציון מצב משתמשות במצב "לא מוגדר" (כל הכלים זמינים)
|
||||
אין שינויים משמעותיים לפריסות קיימות
|
||||
|
||||
### 8. ניטור וניתוח
|
||||
|
||||
#### 8.1 מדדים חדשים
|
||||
|
||||
**שימוש בקבוצות כלים:**
|
||||
`agent_tool_group_requests_total` - מונה של בקשות לפי קבוצה
|
||||
`agent_tool_group_availability` - מדד של כלים זמינים לכל קבוצה
|
||||
`agent_filtered_tools_count` - היסטוגרמה של מספר כלים לאחר סינון לפי קבוצה + מצב
|
||||
|
||||
**מדדי זרימת עבודה של מצבים:**
|
||||
`agent_state_transitions_total` - מונה של מעברי מצבים לפי כלי
|
||||
`agent_workflow_duration_seconds` - היסטוגרמה של זמן שהייה בכל מצב
|
||||
`agent_state_availability` - מדד של כלים זמינים לכל מצב
|
||||
|
||||
**מדדי אבטחה:**
|
||||
`agent_group_access_denied_total` - מונה של גישה לא מורשית לקבוצה
|
||||
`agent_invalid_state_transition_total` - מונה של מעברי מצב לא חוקיים
|
||||
`agent_privilege_escalation_attempts_total` - מונה של בקשות חשודות
|
||||
|
||||
#### 8.2 שיפורים ברישום
|
||||
|
||||
**רישום בקשות:**
|
||||
```json
|
||||
{
|
||||
"request_id": "req-123",
|
||||
"requested_groups": ["read-only", "knowledge"],
|
||||
"initial_state": "undefined",
|
||||
"state_transitions": [
|
||||
{"tool": "knowledge-query", "from": "undefined", "to": "analysis", "timestamp": "2024-01-01T10:00:01Z"}
|
||||
],
|
||||
"available_tools": ["knowledge-query", "text-completion"],
|
||||
"filtered_by_group": ["graph-update", "admin-tool"],
|
||||
"filtered_by_state": [],
|
||||
"execution_time": "1.2s"
|
||||
}
|
||||
```
|
||||
|
||||
### 9. אסטרטגיית בדיקות
|
||||
|
||||
#### 9.1 בדיקות יחידה
|
||||
|
||||
**לוגיקת סינון כלים:**
|
||||
חישובים של חיתוך קבוצות בדיקה
|
||||
לוגיקת סינון מבוססת מצבים
|
||||
אימות הקצאה ברירת מחדל של קבוצות ומצבים
|
||||
בדיקת התנהגות של קבוצות עם תווים מיוחדים (wildcard)
|
||||
אימות טיפול בקבוצות ריקות
|
||||
בדיקת תרחישים משולבים של סינון קבוצות + מצבים
|
||||
|
||||
**אימות תצורה:**
|
||||
בדיקת טעינת כלים עם תצורות שונות של קבוצות ומצבים
|
||||
אימות של תקינות הסכימה עבור מפרטי קבוצות ומצבים לא חוקיים
|
||||
בדיקת תאימות לאחור עם תצורות קיימות
|
||||
אימות של הגדרות מעברים בין מצבים ומחזורים
|
||||
|
||||
#### 9.2 בדיקות אינטגרציה
|
||||
|
||||
**התנהגות של סוכן (Agent):**
|
||||
אימות שהסוכן רואה רק כלים שעברו סינון לפי קבוצה + מצב
|
||||
בדיקת ביצוע בקשות עם שילובים שונים של קבוצות
|
||||
בדיקת מעברים בין מצבים במהלך ביצוע הסוכן
|
||||
אימות של טיפול בשגיאות כאשר אין כלים זמינים
|
||||
בדיקת התקדמות של זרימת עבודה דרך מצבים שונים
|
||||
|
||||
**בדיקות אבטחה:**
|
||||
בדיקת מניעת העלאת הרשאות
|
||||
אימות של דיוק רישום ביקורת (audit trail)
|
||||
בדיקת שילוב של שער (gateway) עם הרשאות משתמש
|
||||
|
||||
#### 9.3 תרחישים מקצה לקצה
|
||||
|
||||
**שימוש מרובה דיירים (Multi-tenant) עם זרימות עבודה מבוססות מצבים:**
|
||||
```
|
||||
Scenario: Different users with different tool access and workflow states
|
||||
Given: User A has "read-only" permissions, state "undefined"
|
||||
And: User B has "write" permissions, state "analysis"
|
||||
When: Both request knowledge operations
|
||||
Then: User A gets read-only tools available in "undefined" state
|
||||
And: User B gets write tools available in "analysis" state
|
||||
And: State transitions are tracked per user session
|
||||
And: All usage and transitions are properly audited
|
||||
```
|
||||
|
||||
**התקדמות מצב העבודה:**
|
||||
```
|
||||
Scenario: Complete workflow execution
|
||||
Given: Request with groups ["knowledge", "compute"] and state "undefined"
|
||||
When: Agent executes knowledge-query tool (transitions to "analysis")
|
||||
And: Agent executes complex-analysis tool (transitions to "results")
|
||||
And: Agent executes reset-workflow tool (transitions to "undefined")
|
||||
Then: Each step has correctly filtered available tools
|
||||
And: State transitions are logged with timestamps
|
||||
And: Final state allows initial workflow to repeat
|
||||
```
|
||||
|
||||
### 10. שיקולי ביצועים
|
||||
|
||||
#### 10.1 השפעת טעינת כלים
|
||||
|
||||
**טעינת תצורה:**
|
||||
מטא-נתונים של קבוצה ומצב נטענים פעם אחת בעת ההפעלה
|
||||
תקורה מינימלית של זיכרון לכל כלי (שדות נוספים)
|
||||
אין השפעה על זמן אתחול הכלי
|
||||
|
||||
**עיבוד בקשות:**
|
||||
סינון משולב של קבוצה+מצב מתבצע פעם אחת לכל בקשה
|
||||
מורכבות O(n) כאשר n = מספר הכלים המוגדרים
|
||||
מעברים של מצבים מוסיפים תקורה מינימלית (הקצאת מחרוזות)
|
||||
השפעה זניחה עבור מספר טיפוסי של כלים (< 100)
|
||||
|
||||
#### 10.2 אסטרטגיות אופטימיזציה
|
||||
|
||||
**סטים של כלים מחושבים מראש:**
|
||||
שמירת סטים של כלים לפי שילוב של קבוצה+מצב
|
||||
הימנעות מסינון חוזר עבור דפוסי קבוצה/מצב נפוצים
|
||||
פשרה בין זיכרון לחישוב עבור שילובים בשימוש תכוף
|
||||
|
||||
**טעינה עצלה:**
|
||||
טעינת יישומי כלים רק כאשר נדרש
|
||||
הפחתת זמן אתחול עבור פריסות עם מספר רב של כלים
|
||||
רישום דינמי של כלים בהתאם לדרישות הקבוצה
|
||||
|
||||
### 11. שיפורים עתידיים
|
||||
|
||||
#### 11.1 הקצאת קבוצות דינמית
|
||||
|
||||
**קיבוץ מודע להקשר:**
|
||||
הקצאת כלים לקבוצות בהתבסס על הקשר הבקשה
|
||||
זמינות קבוצה מבוססת זמן (שעות עסקים בלבד)
|
||||
הגבלות קבוצה מבוססות עומס (כלים יקרים בזמן שימוש נמוך)
|
||||
|
||||
#### 11.2 היררכיות קבוצות
|
||||
|
||||
**מבנה קבוצות מקונן:**
|
||||
```json
|
||||
{
|
||||
"knowledge": {
|
||||
"read": ["knowledge-query", "entity-search"],
|
||||
"write": ["graph-update", "entity-create"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 11.3 המלצות כלים
|
||||
|
||||
**הצעות מבוססות קבוצות:**
|
||||
הצעת קבוצות כלים אופטימליות עבור סוגי בקשות
|
||||
למידה מדפוסי שימוש לשיפור ההמלצות
|
||||
מתן קבוצות חלופיות כאשר הכלים המועדפים אינם זמינים
|
||||
|
||||
### 12. שאלות פתוחות
|
||||
|
||||
1. **אימות קבוצות**: האם שמות קבוצות לא חוקיים בבקשות צריכים לגרום לכישלונות קשים או אזהרות?
|
||||
|
||||
2. **גילוי קבוצות**: האם המערכת צריכה לספק API לרשימת קבוצות זמינות והכלים שלהן?
|
||||
|
||||
3. **קבוצות דינמיות**: האם הקבוצות צריכות להיות ניתנות להגדרה בזמן ריצה או רק בזמן ההתחלה?
|
||||
|
||||
4. **ירושה של קבוצות**: האם כלים צריכים לרשת קבוצות מהקטגוריות או המימושים הראשיים שלהם?
|
||||
|
||||
5. **ניטור ביצועים**: אילו מדדים נוספים נחוצים למעקב יעיל אחר שימוש בכלים מבוססי קבוצות?
|
||||
|
||||
### 13. סיכום
|
||||
|
||||
מערכת קבוצות הכלים מספקת:
|
||||
|
||||
**אבטחה**: בקרת גישה מפורטת על יכולות הסוכן
|
||||
**ביצועים**: הפחתת עומס טעינה ובחירת כלים
|
||||
**גמישות**: סיווג רב-ממדי של כלים
|
||||
**תאימות**: שילוב חלק עם ארכיטקטורות סוכן קיימות
|
||||
|
||||
מערכת זו מאפשרת לפריסות TrustGraph לנהל טוב יותר את גישת הכלים, לשפר את גבולות האבטחה ולייעל את השימוש במשאבים תוך שמירה על תאימות מלאה לאחור עם תצורות ובקשות קיימות.
|
||||
479
docs/tech-specs/he/tool-services.he.md
Normal file
479
docs/tech-specs/he/tool-services.he.md
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
---
|
||||
layout: default
|
||||
title: "שירותי כלים: כלים דינמיים הניתנים לחיבור"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# שירותי כלים: כלים דינמיים הניתנים לחיבור
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סטטוס
|
||||
|
||||
מיושם
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מפרט זה מגדיר מנגנון לכלים דינמיים הניתנים לחיבור הנקראים "שירותי כלים". בניגוד לסוגי הכלים המובנים הקיימים (`KnowledgeQueryImpl`, `McpToolImpl`, וכו'), שירותי כלים מאפשרים להציג כלים חדשים על ידי:
|
||||
|
||||
1. פריסת שירות חדש המבוסס על Pulsar
|
||||
2. הוספת תיאור תצורה המציין לסוכן כיצד להפעיל אותו
|
||||
|
||||
זה מאפשר הרחבה מבלי לשנות את מסגרת התגובה הבסיסית של הסוכן.
|
||||
|
||||
## מונחים
|
||||
|
||||
| מונח | הגדרה |
|
||||
|------|------------|
|
||||
| **כלי מובנה** | סוגי כלים קיימים עם יישומים מוגדרים מראש ב-`tools.py` |
|
||||
| **שירות כלי** | שירות Pulsar שניתן להפעיל ככלי סוכן, המוגדר על ידי תיאור שירות |
|
||||
| **כלי** | מופע מוגדר המתייחס לשירות כלי, החשוף לסוכן/LLM |
|
||||
|
||||
זהו מודל דו-שכבתי, אנלוגי לכלי MCP:
|
||||
MCP: שרת MCP מגדיר את ממשק הכלי → תצורת הכלי מתייחסת אליו
|
||||
שירותי כלים: שירות הכלי מגדיר את ממשק Pulsar → תצורת הכלי מתייחסת אליו
|
||||
|
||||
## רקע: כלים קיימים
|
||||
|
||||
### יישום כלי מובנה
|
||||
|
||||
כלי מוגדרים כיום ב-`trustgraph-flow/trustgraph/agent/react/tools.py` עם יישומים מטיפוסים:
|
||||
|
||||
```python
|
||||
class KnowledgeQueryImpl:
|
||||
async def invoke(self, question):
|
||||
client = self.context("graph-rag-request")
|
||||
return await client.rag(question, self.collection)
|
||||
```
|
||||
|
||||
כל סוג כלי:
|
||||
כולל שירות Pulsar מובנה שהוא קורא אליו (לדוגמה: `graph-rag-request`)
|
||||
יודע בדיוק את השיטה לקריאה בלקוח (לדוגמה: `client.rag()`)
|
||||
מכיל ארגומנטים מוגדרים בסביבת היישום
|
||||
|
||||
### רישום כלים (service.py:105-214)
|
||||
|
||||
כלים נטענים מקובץ תצורה עם שדה `type` שממפה ליישום:
|
||||
|
||||
```python
|
||||
if impl_id == "knowledge-query":
|
||||
impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection"))
|
||||
elif impl_id == "text-completion":
|
||||
impl = TextCompletionImpl
|
||||
# ... etc
|
||||
```
|
||||
|
||||
## ארכיטקטורה
|
||||
|
||||
### מודל דו-שכבתי
|
||||
|
||||
#### שכבה 1: תיאור שירות כלי
|
||||
|
||||
שירות כלי מגדיר ממשק שירות של פולסר. הוא מכריז על:
|
||||
תורי הפולסר עבור בקשות/תגובות
|
||||
פרמטרי תצורה שהוא דורש מכלי המשתמשים בו
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "custom-rag",
|
||||
"request-queue": "non-persistent://tg/request/custom-rag",
|
||||
"response-queue": "non-persistent://tg/response/custom-rag",
|
||||
"config-params": [
|
||||
{"name": "collection", "required": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
שירות כלי שאינו דורש פרמטרים של תצורה:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "calculator",
|
||||
"request-queue": "non-persistent://tg/request/calc",
|
||||
"response-queue": "non-persistent://tg/response/calc",
|
||||
"config-params": []
|
||||
}
|
||||
```
|
||||
|
||||
#### שכבה 2: תיאור כלי
|
||||
|
||||
כלי מפנה לשירות כלי ומספק:
|
||||
ערכי פרמטרים של תצורה (העונים על דרישות השירות)
|
||||
מטא-נתונים של הכלי עבור הסוכן (שם, תיאור)
|
||||
הגדרות ארגומנטים עבור מודל השפה הגדול (LLM)
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-customers",
|
||||
"description": "Query the customer knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "customers",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about customers"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
מספר כלים יכולים להתייחס לאותה שירות עם תצורות שונות:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-products",
|
||||
"description": "Query the product knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "products",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about products"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### פורמט בקשה
|
||||
|
||||
כאשר כלי מופעל, הבקשה לשירות הכלי כוללת:
|
||||
`user`: מהבקשה של הסוכן (ריבוי דיירים)
|
||||
`config`: ערכי תצורה מקודדים ב-JSON מהתיאור של הכלי
|
||||
`arguments`: ארגומנטים מקודדים ב-JSON מהמודל הלשוני הגדול (LLM)
|
||||
|
||||
```json
|
||||
{
|
||||
"user": "alice",
|
||||
"config": "{\"collection\": \"customers\"}",
|
||||
"arguments": "{\"question\": \"What are the top customer complaints?\"}"
|
||||
}
|
||||
```
|
||||
|
||||
השירות של הכלי מקבל זאת כ-dicts שעברו ניתוח בשיטה `invoke`.
|
||||
|
||||
### יישום כללי של שירות הכלי
|
||||
|
||||
מחלקה `ToolServiceImpl` מפעילה שירותי כלי בהתבסס על תצורה:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
self.request_queue = request_queue
|
||||
self.response_queue = response_queue
|
||||
self.config_values = config_values # e.g., {"collection": "customers"}
|
||||
# ...
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, self.config_values, arguments)
|
||||
if isinstance(response, str):
|
||||
return response
|
||||
else:
|
||||
return json.dumps(response)
|
||||
```
|
||||
|
||||
## החלטות עיצוב
|
||||
|
||||
### מודל תצורה דו-שכבתי
|
||||
|
||||
שירותי כלים פועלים לפי מודל דו-שכבתי הדומה לכלי MCP:
|
||||
|
||||
1. **שירות כלי**: מגדיר את ממשק השירות של Pulsar (נושא, פרמטרי תצורה נדרשים)
|
||||
2. **כלי**: מפנה לשירות כלי, מספק ערכי תצורה, מגדיר ארגומנטים של LLM
|
||||
|
||||
הפרדה זו מאפשרת:
|
||||
שירות כלי אחד יכול לשמש מספר כלים עם תצורות שונות
|
||||
הבחנה ברורה בין ממשק השירות לתצורת הכלי
|
||||
שימוש חוזר בהגדרות שירות
|
||||
|
||||
### מיפוי בקשות: העברה עם מעטפה
|
||||
|
||||
הבקשה לשירות כלי היא מעטפה מובנית המכילה:
|
||||
`user`: מועבר מבקשת הסוכן עבור ריבוי דיירים
|
||||
ערכי תצורה: מתיאור הכלי (לדוגמה, `collection`)
|
||||
`arguments`: ארגומנטים המסופקים על ידי LLM, מועברים כמילון
|
||||
|
||||
מנהל הסוכן מנתח את התגובה של ה-LLM ל-`act.arguments` כמילון (`agent_manager.py:117-154`). מילון זה כלול במעטפת הבקשה.
|
||||
|
||||
### טיפול בסכימה: לא מסווג
|
||||
|
||||
בקשות ותגובות משתמשות במילונים לא מסווגים. אין אימות סכימה ברמת הסוכן - שירות הכלי אחראי לאימות הקלט שלו. זה מספק גמישות מרבית בהגדרת שירותים חדשים.
|
||||
|
||||
### ממשק לקוח: נושאים ישירים של Pulsar
|
||||
|
||||
שירותי כלים משתמשים בנושאים ישירים של Pulsar מבלי לדרוש תצורת זרימה. תיאור שירות הכלי מציין את שמות התורים המלאים:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [...]
|
||||
}
|
||||
```
|
||||
|
||||
זה מאפשר לארח שירותים בכל מרחב שם.
|
||||
|
||||
### טיפול בשגיאות: מוסכמות שגיאות סטנדרטיות
|
||||
|
||||
תגובות של שירותי כלים עוקבות אחר מוסכמות הסכימה הקיימות עם שדה `error`:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Error:
|
||||
type: str = ""
|
||||
message: str = ""
|
||||
```
|
||||
|
||||
מבנה תגובה:
|
||||
הצלחה: `error` הוא `None`, התגובה מכילה תוצאה
|
||||
שגיאה: `error` מאוכלס עם `type` ו- `message`
|
||||
|
||||
זה תואם לדפוס המשמש בכל סכימות השירות הקיימות (לדוגמה, `PromptResponse`, `QueryResponse`, `AgentResponse`).
|
||||
|
||||
### התאמה בין בקשה לתגובה
|
||||
|
||||
בקשות ותגובות משויכות באמצעות `id` במאפייני הודעות Pulsar:
|
||||
|
||||
בקשה כוללת `id` במאפיינים: `properties={"id": id}`
|
||||
התגובות כוללות את אותו `id`: `properties={"id": id}`
|
||||
|
||||
זה עוקב אחר הדפוס הקיים המשמש בכל בסיס הקוד (לדוגמה, `agent_service.py`, `llm_service.py`).
|
||||
|
||||
### תמיכה בסטרימינג
|
||||
|
||||
שירותי כלים יכולים להחזיר תגובות בסטרימינג:
|
||||
|
||||
הודעות תגובה מרובות עם אותו `id` במאפיינים
|
||||
כל תגובה כוללת את השדה `end_of_stream: bool`
|
||||
התגובה הסופית כוללת את `end_of_stream: True`
|
||||
|
||||
זה תואם לדפוס המשמש ב- `AgentResponse` ובשירותי סטרימינג אחרים.
|
||||
|
||||
### טיפול בתגובה: החזרת מחרוזת
|
||||
|
||||
כל הכלים הקיימים עוקבים אחר אותו דפוס: **קבלת ארגומנטים כמילון, החזרת התצפית כמחרוזת**.
|
||||
|
||||
| כלי | טיפול בתגובה |
|
||||
|------|------------------|
|
||||
| `KnowledgeQueryImpl` | מחזיר את `client.rag()` ישירות (מחרוזת) |
|
||||
| `TextCompletionImpl` | מחזיר את `client.question()` ישירות (מחרוזת) |
|
||||
| `McpToolImpl` | מחזיר מחרוזת, או `json.dumps(output)` אם אינה מחרוזת |
|
||||
| `StructuredQueryImpl` | מעצב את התוצאה למחרוזת |
|
||||
| `PromptImpl` | מחזיר את `client.prompt()` ישירות (מחרוזת) |
|
||||
|
||||
שירותי כלים עוקבים אחר אותו חוזה:
|
||||
השירות מחזיר תגובת מחרוזת (התצפית)
|
||||
אם התגובה אינה מחרוזת, היא מומרת באמצעות `json.dumps()`
|
||||
אין צורך בתצורת חילוץ במגדיר
|
||||
|
||||
זה שומר על המגדיר פשוט ומעביר את האחריות לשירות להחזיר תגובת טקסט מתאימה עבור הסוכן.
|
||||
|
||||
## מדריך תצורה
|
||||
|
||||
כדי להוסיף שירות כלי חדש, נדרשים שני פריטי תצורה:
|
||||
|
||||
### 1. תצורת שירות כלי
|
||||
|
||||
מאוחסן תחת מפתח התצורה `tool-service`. מגדיר את תורי Pulsar ואת פרמטרי התצורה הזמינים.
|
||||
|
||||
| שדה | נדרש | תיאור |
|
||||
|-------|----------|-------------|
|
||||
| `id` | כן | מזהה ייחודי עבור שירות הכלי |
|
||||
| `request-queue` | כן | נושא Pulsar מלא עבור בקשות (לדוגמה, `non-persistent://tg/request/joke`) |
|
||||
| `response-queue` | כן | נושא Pulsar מלא עבור תגובות (לדוגמה, `non-persistent://tg/response/joke`) |
|
||||
| `config-params` | לא | מערך של פרמטרי תצורה שהשירות מקבל |
|
||||
|
||||
ניתן לציין כל פרמטר תצורה:
|
||||
`name`: שם הפרמטר (נדרש)
|
||||
`required`: האם הפרמטר חייב להיות מסופק על ידי כלים (ברירת מחדל: false)
|
||||
|
||||
דוגמה:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [
|
||||
{"name": "style", "required": false}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. תצורת כלי
|
||||
|
||||
שמור תחת מפתח התצורה `tool`. מגדיר כלי שהסוכן יכול להשתמש בו.
|
||||
|
||||
| שדה | נדרש | תיאור |
|
||||
|-------|----------|-------------|
|
||||
| `type` | כן | חייב להיות `"tool-service"` |
|
||||
| `name` | כן | שם הכלי החשוף ל-LLM |
|
||||
| `description` | כן | תיאור של מה הכלי עושה (מוצג ל-LLM) |
|
||||
| `service` | כן | מזהה של שירות הכלי לביצוע |
|
||||
| `arguments` | לא | מערך של הגדרות ארגומנטים עבור ה-LLM |
|
||||
| *(פרמטרי תצורה)* | משתנה | כל פרמטרי תצורה המוגדרים על ידי השירות |
|
||||
|
||||
כל ארגומנט יכול לציין:
|
||||
`name`: שם הארגומנט (נדרש)
|
||||
`type`: סוג נתונים, לדוגמה, `"string"` (נדרש)
|
||||
`description`: תיאור המוצג ל-LLM (נדרש)
|
||||
|
||||
דוגמה:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "topic",
|
||||
"type": "string",
|
||||
"description": "The topic for the joke (e.g., programming, animals, food)"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### טעינת הגדרות
|
||||
|
||||
השתמשו ב-`tg-put-config-item` כדי לטעון הגדרות:
|
||||
|
||||
```bash
|
||||
# Load tool-service config
|
||||
tg-put-config-item tool-service/joke-service < joke-service.json
|
||||
|
||||
# Load tool config
|
||||
tg-put-config-item tool/tell-joke < tell-joke.json
|
||||
```
|
||||
|
||||
יש להפעיל מחדש את מנהל הסוכן כדי לקלוט הגדרות חדשות.
|
||||
|
||||
## פרטי יישום
|
||||
|
||||
### סכימה
|
||||
|
||||
סוגי בקשות ותגובות ב-`trustgraph-base/trustgraph/schema/services/tool_service.py`:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ToolServiceRequest:
|
||||
user: str = "" # User context for multi-tenancy
|
||||
config: str = "" # JSON-encoded config values from tool descriptor
|
||||
arguments: str = "" # JSON-encoded arguments from LLM
|
||||
|
||||
@dataclass
|
||||
class ToolServiceResponse:
|
||||
error: Error | None = None
|
||||
response: str = "" # String response (the observation)
|
||||
end_of_stream: bool = False
|
||||
```
|
||||
|
||||
### צד שרת: DynamicToolService
|
||||
|
||||
מחלקה בסיסית ב-`trustgraph-base/trustgraph/base/dynamic_tool_service.py`:
|
||||
|
||||
```python
|
||||
class DynamicToolService(AsyncProcessor):
|
||||
"""Base class for implementing tool services."""
|
||||
|
||||
def __init__(self, **params):
|
||||
topic = params.get("topic", default_topic)
|
||||
# Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic}
|
||||
# Sets up Consumer and Producer
|
||||
|
||||
async def invoke(self, user, config, arguments):
|
||||
"""Override this method to implement the tool's logic."""
|
||||
raise NotImplementedError()
|
||||
```
|
||||
|
||||
### צד לקוח: ToolServiceImpl
|
||||
|
||||
יישום ב-`trustgraph-flow/trustgraph/agent/react/tools.py`:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
# Uses the provided queue paths directly
|
||||
# Creates ToolServiceClient on first use
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, config_values, arguments)
|
||||
return response if isinstance(response, str) else json.dumps(response)
|
||||
```
|
||||
|
||||
### קבצים
|
||||
|
||||
| קובץ | מטרה |
|
||||
|------|---------|
|
||||
| `trustgraph-base/trustgraph/schema/services/tool_service.py` | סכימות בקשה/תגובה |
|
||||
| `trustgraph-base/trustgraph/base/tool_service_client.py` | לקוח להפעלת שירותים |
|
||||
| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | מחלקה בסיסית ליישום שירות |
|
||||
| `trustgraph-flow/trustgraph/agent/react/tools.py` | מחלקה `ToolServiceImpl` |
|
||||
| `trustgraph-flow/trustgraph/agent/react/service.py` | טעינת תצורה |
|
||||
|
||||
### דוגמה: שירות בדיחות
|
||||
|
||||
דוגמה לשירות ב-`trustgraph-flow/trustgraph/tool_service/joke/`:
|
||||
|
||||
```python
|
||||
class Processor(DynamicToolService):
|
||||
async def invoke(self, user, config, arguments):
|
||||
style = config.get("style", "pun")
|
||||
topic = arguments.get("topic", "")
|
||||
joke = pick_joke(topic, style)
|
||||
return f"Hey {user}! Here's a {style} for you:\n\n{joke}"
|
||||
```
|
||||
|
||||
תצורת שירות הכלי:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [{"name": "style", "required": false}]
|
||||
}
|
||||
```
|
||||
|
||||
הגדרות כלי:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{"name": "topic", "type": "string", "description": "The topic for the joke"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### תאימות לאחור
|
||||
|
||||
סוגי כלים מובנים קיימים ממשיכים לעבוד ללא שינוי.
|
||||
`tool-service` הוא סוג כלי חדש לצד סוגים קיימים (`knowledge-query`, `mcp-tool`, וכו').
|
||||
|
||||
## שיקולים עתידיים
|
||||
|
||||
### שירותים המצהירים על עצמם
|
||||
|
||||
שיפור עתידי יכול לאפשר לשירותים לפרסם את התיאורים שלהם:
|
||||
|
||||
שירותים מפרסמים לנושא `tool-descriptors` ידוע בעת ההפעלה.
|
||||
הסוכן נרשם ורושם כלים באופן דינמי.
|
||||
מאפשר חיבור והפעלה אמיתיים ללא שינויי תצורה.
|
||||
|
||||
זה מחוץ לתחום של המימוש הראשוני.
|
||||
|
||||
## הפניות
|
||||
|
||||
יישום כלי נוכחי: `trustgraph-flow/trustgraph/agent/react/tools.py`
|
||||
רישום כלים: `trustgraph-flow/trustgraph/agent/react/service.py:105-214`
|
||||
סכימות סוכן: `trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
404
docs/tech-specs/he/universal-decoder.he.md
Normal file
404
docs/tech-specs/he/universal-decoder.he.md
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
---
|
||||
layout: default
|
||||
title: "מפענח מסמכים אוניברסלי"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# מפענח מסמכים אוניברסלי
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## כותרת
|
||||
|
||||
מפענח מסמכים אוניברסלי המופעל על ידי `unstructured` - קליטת כל פורמט מסמך נפוץ
|
||||
דרך שירות יחיד עם תיעוד מלא ושילוב עם ספרייה, תוך רישום מיקומי המקור כמטא-נתונים של גרף ידע
|
||||
למעקב מקצה לקצה.
|
||||
|
||||
## בעיה
|
||||
|
||||
|
||||
כיום, ל-TrustGraph יש מפענח ספציפי ל-PDF. תמיכה בפורמטים נוספים (DOCX, XLSX, HTML, Markdown, טקסט רגיל, PPTX וכו') דורשת
|
||||
או כתיבת מפענח חדש לכל פורמט או אימוץ ספריית חילוץ אוניברסלית. לכל פורמט יש מבנה שונה - חלקם מבוססי דפים, וחלקם לא -
|
||||
ושרשרת התיעוד חייבת לתעד מאיפה בכל מסמך המקורי הגיע כל פיסת טקסט שחולצה.
|
||||
|
||||
## גישה
|
||||
לתעד כל פיסת טקסט שחולצה ולציין את מקורה.
|
||||
|
||||
## גישה
|
||||
|
||||
### ספריה: `unstructured`
|
||||
|
||||
השתמשו ב-`unstructured.partition.auto.partition()` שמזהה אוטומטית את הפורמט
|
||||
מחלק סוג MIME או סיומת קובץ ומחלץ אלמנטים מובנים
|
||||
(כותרת, טקסט, טבלה, פריט רשימה, וכו'). כל אלמנט נושא
|
||||
מטא-דאטה, כולל:
|
||||
|
||||
`page_number` (עבור פורמטים מבוססי דפים כמו PDF, PPTX)
|
||||
`element_id` (ייחודי לכל אלמנט)
|
||||
`coordinates` (מלבן תוחם עבור קבצי PDF)
|
||||
`text` (תוכן הטקסט שנחלץ)
|
||||
`category` (סוג האלמנט: כותרת, טקסט, טבלה, וכו')
|
||||
|
||||
### סוגי אלמנטים
|
||||
|
||||
`unstructured` מחלץ אלמנטים מסוגים שונים ממסמכים. לכל אלמנט יש
|
||||
קטגוריה ומטא-דאטה נלווים:
|
||||
|
||||
**אלמנטים טקסטואליים:**
|
||||
`Title` — כותרות סעיפים
|
||||
`NarrativeText` — פסקאות גוף הטקסט
|
||||
`ListItem` — פריטי רשימות (ממוספרות או עם נקודות)
|
||||
`Header`, `Footer` — כותרות/שוליים של עמודים
|
||||
`FigureCaption` — כיתובים עבור תמונות/איורים
|
||||
`Formula` — ביטויים מתמטיים
|
||||
`Address`, `EmailAddress` — פרטי יצירת קשר
|
||||
`CodeSnippet` — בלוקי קוד (מתוך markdown)
|
||||
|
||||
**טבלאות:**
|
||||
`Table` - נתונים טבלאיים מובנים. `unstructured` מספק גם
|
||||
`element.text` (טקסט רגיל) וגם `element.metadata.text_as_html`
|
||||
(HTML מלא `<table>` עם שורות, עמודות וכותרות שמורות).
|
||||
עבור פורמטים עם מבנה טבלה מפורש (DOCX, XLSX, HTML), החילוץ אמין מאוד. עבור קבצי PDF, זיהוי טבלאות תלוי ב
|
||||
⟦CODE_0⟧. For PDFs, table detection depends on ⟦CODE_0⟧.
|
||||
האסטרטגיה של `hi_res` עם ניתוח פריסה.
|
||||
|
||||
**תמונות:**
|
||||
`Image` — זיהוי תמונות מוטמעות באמצעות ניתוח פריסה (דורש
|
||||
`hi_res` אסטרטגיה). עם `extract_image_block_to_payload=True`,
|
||||
מחזיר את נתוני התמונה כ-base64 ב-`element.metadata.image_base64`.
|
||||
טקסט OCR מהתמונה זמין ב-`element.text`.
|
||||
|
||||
### טיפול בטבלאות
|
||||
|
||||
טבלאות הן פלט ברמה ראשונה. כאשר המפענח נתקל באלמנט `Table`,
|
||||
הוא שומר על מבנה ה-HTML במקום לשטח לטקסט
|
||||
רגיל. זה מספק למחלץ ה-LLM במורד קלט טוב בהרבה
|
||||
לשליפת ידע מובנה מנתונים טבלאיים.
|
||||
|
||||
הטקסט של העמוד/הקטע מורכב באופן הבא:
|
||||
אלמנטי טקסט: טקסט רגיל, המחוברים בשורות חדשות
|
||||
אלמנטי טבלה: תגי HTML של טבלה מ-`text_as_html`, עטופים ב-
|
||||
`<table>` סימון כך שה-LLM יכול להבחין בין טבלאות לבין טקסט
|
||||
|
||||
לדוגמה, עמוד עם כותרת, פסקה וטבלה מייצר:
|
||||
|
||||
```
|
||||
Financial Overview
|
||||
|
||||
Revenue grew 15% year-over-year driven by enterprise adoption.
|
||||
|
||||
<table>
|
||||
<tr><th>Quarter</th><th>Revenue</th><th>Growth</th></tr>
|
||||
<tr><td>Q1</td><td>$12M</td><td>12%</td></tr>
|
||||
<tr><td>Q2</td><td>$14M</td><td>17%</td></tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
זה שומר על מבנה הטבלאות באמצעות חלוקה לחלקים וליחידת העיבוד
|
||||
(pipeline), כאשר מודל השפה הגדול (LLM) יכול לחלץ קשרים ישירות מתוך
|
||||
תאים מובנים, ולא לנחש את יישור העמודות על סמך
|
||||
רווחים.
|
||||
|
||||
### טיפול בתמונות
|
||||
|
||||
תמונות מחולצות ונשמרות בספרייה כמסמכים משניים
|
||||
עם `document_type="image"` ו-`urn:image:{uuid}` מזהה. הן מקבלות
|
||||
טריפלים של מקור (provenance) מסוג `tg:Image`, המקושרים לעמוד/קטע
|
||||
הראשי שלהן דרך `prov:wasDerivedFrom`. מטא-נתונים של תמונה (קואורדינטות,
|
||||
מידות, element_id) נרשמים במקור.
|
||||
|
||||
**חשוב מאוד: תמונות אינן משודרות כפלט של מסמך טקסט (TextDocument).** הן
|
||||
נשמרות בלבד - אינן נשלחות כלפי מטה ליחידת החלוקה (chunker) או לכל
|
||||
תהליך עיבוד טקסט. זה נעשה בכוונה:
|
||||
|
||||
1. אין עדיין תהליך עיבוד תמונות (שילוב מודל ראייה הוא עבודה
|
||||
עתידית)
|
||||
2. העברת נתוני תמונה בפורמט base64 או פיסות OCR ליחידת החילוץ
|
||||
של טקסט תייצר טריפלים של גרף ידע (KG) לא מועילים.
|
||||
|
||||
תמונות גם אינן נכללות בטקסט המורכב של העמוד - כל `Image`
|
||||
אלמנטים מתעלמים כאשר מחברים טקסט של אלמנטים עבור
|
||||
עמוד/קטע. שרשרת המקור (provenance) רושמת שתמונות קיימות ואיפה
|
||||
הן הופיעו במסמך, כך שניתן יהיה לאסוף אותן על ידי תהליך
|
||||
עיבוד תמונות עתידי מבלי להכניס מחדש את המסמך.
|
||||
|
||||
#### עבודה עתידית
|
||||
|
||||
להעביר `tg:Image` ישויות למודל ראייה לצורך תיאור,
|
||||
פרשנות דיאגרמות או חילוץ נתוני טבלה.
|
||||
לשמור תיאורי תמונה כמסמכי טקסט משניים שמוזנים
|
||||
לתוך תהליך החלוקה/חילוץ הסטנדרטי.
|
||||
לקשר ידע מחולץ בחזרה לתמונות המקוריות דרך מקור.
|
||||
|
||||
### אסטרטגיות סעיפים
|
||||
|
||||
עבור פורמטים מבוססי עמודים (PDF, PPTX, XLSX), אלמנטים תמיד מקובצים
|
||||
לפי עמוד/שקופית/גיליון. עבור פורמטים שאינם מבוססי עמודים (DOCX, HTML, Markdown,
|
||||
וכו'), למפענח יש אסטרטגיה לחלוקת המסמך לקטעים.
|
||||
זה מוגדר בזמן ריצה באמצעות `--section-strategy`.
|
||||
|
||||
כל אסטרטגיה היא פונקציית קיבוץ על רשימת `unstructured`
|
||||
אלמנטים. הפלט הוא רשימה של קבוצות אלמנטים; שאר
|
||||
התהליך (הרכבת טקסט, אחסון בספרייה, מקור, פלט של מסמך טקסט
|
||||
(TextDocument)) זהים ללא קשר לאסטרטגיה.
|
||||
|
||||
#### `whole-document` (ברירת מחדל)
|
||||
|
||||
להוציא את כל המסמך כקטע יחיד. לאפשר ליחידת החלוקה
|
||||
(chunker) לטפל בכל החלוקה.
|
||||
|
||||
גישה פשוטה, קו בסיס טוב
|
||||
עלול לייצר מסמך טקסט גדול מאוד עבור קבצים גדולים, אך יחידת החלוקה
|
||||
מטפלת בכך
|
||||
הטוב ביותר כאשר רוצים הקשר מקסימלי לכל קטע
|
||||
|
||||
#### `heading`
|
||||
|
||||
לחלק בנקודות כותרת (`Title`). כל קטע הוא כותרת וכל
|
||||
התוכן עד הכותרת הבאה באותו רמה או ברמה גבוהה יותר.
|
||||
כותרות מקוננות יוצרות קטעים מקוננים.
|
||||
|
||||
מייצר יחידות בעלות קוהרנטיות נושאית
|
||||
עובד היטב עבור מסמכים מובנים (דוחות, מדריכים, מפרטים)
|
||||
מספק למודל השפה הגדול (LLM) שמבצע חילוץ הקשר של כותרת יחד עם תוכן
|
||||
חוזר ל-`whole-document` אם לא נמצאות כותרות
|
||||
|
||||
#### `element-type`
|
||||
|
||||
לחלק כאשר סוג האלמנט משתנה באופן משמעותי - ספציפית,
|
||||
להתחיל קטע חדש במעברים בין טקסט נרטיבי לטבלאות.
|
||||
אלמנטים עוקבים מאותה קטגוריה רחבה (טקסט, טקסט, טקסט או
|
||||
טבלה, טבלה) נשארים מקובצים.
|
||||
|
||||
שומר על טבלאות כקטעים עצמאיים
|
||||
טוב עבור מסמכים עם תוכן מעורב (דוחות עם טבלאות נתונים)
|
||||
לטבלאות ניתנת תשומת לב ייעודית לחילוץ
|
||||
|
||||
#### `count`
|
||||
|
||||
לקבץ מספר קבוע של אלמנטים לכל קטע. ניתן להגדרה באמצעות
|
||||
`--section-element-count` (ברירת מחדל: 20).
|
||||
|
||||
פשוט וצפוי
|
||||
אינו מכבד את מבנה המסמך
|
||||
שימושי כברירת מחדל או לניסויים
|
||||
|
||||
#### `size`
|
||||
|
||||
צבירה של אלמנטים עד להגעה למגבלת תווים, ולאחר מכן התחלה של
|
||||
סעיף חדש. מכבד גבולות של אלמנטים - לעולם לא מפצל באמצע אלמנט.
|
||||
ניתן להגדיר באמצעות `--section-max-size` (ברירת מחדל: 4000 תווים).
|
||||
|
||||
מייצר גדלי חלקים אחידים בערך.
|
||||
מכבד גבולות של אלמנטים (בניגוד למחלק החלקים הבא).
|
||||
פשרה טובה בין מבנה לשליטה בגודל.
|
||||
אם אלמנט בודד חורג מהמגבלה, הוא הופך לחלק בפני עצמו.
|
||||
|
||||
#### פורמט מבוסס עמודים - אינטראקציה
|
||||
|
||||
עבור פורמטים מבוססי עמודים, קיבוץ העמודים תמיד מקבל עדיפות.
|
||||
ניתן ליישם אסטרטגיות סעיפים באופן אופציונלי *בתוך* עמוד אם הוא גדול מאוד
|
||||
(לדוגמה, עמוד PDF עם טבלה עצומה), תוך שליטה באמצעות
|
||||
`--section-within-pages` (ברירת מחדל: false). כאשר הערך הוא false, כל עמוד הוא
|
||||
תמיד סעיף אחד ללא קשר לגודלו.
|
||||
|
||||
### זיהוי פורמט
|
||||
|
||||
ה-דקודר צריך לדעת את סוג ה-mime של המסמך כדי להעביר ל-
|
||||
`unstructured`'s `partition()`. שני מסלולים:
|
||||
|
||||
**נתיב הספרן** (הגדרת `document_id`): אחזור מטא-דאטה של המסמך
|
||||
מהספרן תחילה - זה נותן לנו את ה-`kind` (סוג ה-mime)
|
||||
שנרשם בזמן ההעלאה. לאחר מכן, אחזור תוכן המסמך.
|
||||
שני שימושים בספרן, אך אחזור המטא-דאטה קל משקל.
|
||||
**נתיב מקוון** (תאימות לאחור, הגדרת `data`): אין מטא-דאטה
|
||||
זמין בהודעה. השתמש ב-`python-magic` כדי לזהות את הפורמט
|
||||
מתוך בייטי התוכן כפתרון חלופי.
|
||||
|
||||
אין צורך בשינויים בסכימה של `Document` - הספרן כבר מאחסן את סוג ה-mime.
|
||||
|
||||
|
||||
### ארכיטקטורה
|
||||
|
||||
שירות `universal-decoder` יחיד שמבצע:
|
||||
|
||||
1. מקבל הודעה `Document` (בשורת הטקסט או דרך הפניה לספרייה).
|
||||
2. אם הנתיב הוא דרך הספרייה: שולף מטא-דאטה של המסמך (מקבל את סוג ה-mime), ואז
|
||||
שולף את התוכן. אם הנתיב הוא בתוך הטקסט: מזהה את הפורמט מהבייטים של התוכן.
|
||||
3. קורא לפונקציה `partition()` כדי לחלץ אלמנטים.
|
||||
4. קיבוץ אלמנטים: לפי עמוד עבור פורמטים מבוססי עמוד, לפי אסטרטגיית סעיפים מוגדרת עבור פורמטים שאינם מבוססי עמוד.
|
||||
סעיף.
|
||||
5. עבור כל עמוד/קטע:
|
||||
מייצר מזהה `urn:page:{uuid}` או `urn:section:{uuid}`
|
||||
מרכיב את תוכן העמוד: טקסט נרטיבי כטקסט רגיל, טבלאות כ-HTML,
|
||||
תמונות מדלגות
|
||||
מחשב את ההיסטים של כל תו בתוך הטקסט של העמוד.
|
||||
שומר ל-librarian כמסמך משני.
|
||||
משדר משולשי מוצא עם מטא-נתונים מיקומיים.
|
||||
שולח `TextDocument` במורד הזרם לצורך חלוקה.
|
||||
6. עבור כל אלמנט תמונה:
|
||||
מייצר מזהה `urn:image:{uuid}`.
|
||||
שומר את נתוני התמונה ל-librarian כמסמך משני.
|
||||
משדר משולשי מוצא (נשמרים בלבד, לא נשלחים במורד הזרם).
|
||||
|
||||
### טיפול בפורמטים
|
||||
|
||||
| פורמט | סוג MIME | מבוסס דפים | הערות |
|
||||
|----------|------------------------------------|------------|--------------------------------|
|
||||
| PDF | application/pdf | כן | קיבוץ לפי דף |
|
||||
| DOCX | application/vnd.openxmlformats... | לא | משתמש באסטרטגיית סעיפים |
|
||||
| PPTX | application/vnd.openxmlformats... | כן | קיבוץ לפי שקופית |
|
||||
| XLSX/XLS | application/vnd.openxmlformats... | כן | קיבוץ לפי גיליון |
|
||||
| HTML | text/html | לא | משתמש באסטרטגיית סעיפים |
|
||||
| Markdown | text/markdown | לא | משתמש באסטרטגיית סעיפים |
|
||||
| Plain | text/plain | לא | משתמש באסטרטגיית סעיפים |
|
||||
| CSV | text/csv | לא | משתמש באסטרטגיית סעיפים |
|
||||
| RST | text/x-rst | לא | משתמש באסטרטגיית סעיפים |
|
||||
| RTF | application/rtf | לא | משתמש באסטרטגיית סעיפים |
|
||||
| ODT | application/vnd.oasis... | לא | משתמש באסטרטגיית סעיפים |
|
||||
| TSV | text/tab-separated-values | לא | משתמש באסטרטגיית סעיפים |
|
||||
|
||||
### מטא-דאטה של מקור
|
||||
|
||||
כל ישות דף/סעיף מתעדת מטא-דאטה מיקום כמשולשים של מקור
|
||||
ב-`GRAPH_SOURCE`, המאפשר מעקב מלא ממשולשים של גרף ידע
|
||||
חזרה למיקומי המסמך המקורי.
|
||||
|
||||
#### שדות קיימים (כבר ב-`derived_entity_triples`)
|
||||
|
||||
`page_number` — מספר דף/גיליון/שקופית (מתחיל מ-1, רק עבור פורמטים מבוססי דפים)
|
||||
`char_offset` — ההיסט של התווים של דף/סעיף זה בתוך
|
||||
הטקסט המלא של המסמך
|
||||
`char_length` — אורך התווים של הטקסט של דף/סעיף זה
|
||||
|
||||
#### שדות חדשים (הרחבה של `derived_entity_triples`)
|
||||
|
||||
`mime_type` — פורמט המסמך המקורי (לדוגמה, `application/pdf`)
|
||||
`element_types` — רשימה מופרדת בפסיקים של קטגוריות `unstructured`
|
||||
שנמצאו בדף/סעיף זה (לדוגמה, "כותרת,טקסט נרטיבי,טבלה")
|
||||
`table_count` — מספר הטבלאות בדף/סעיף זה
|
||||
`image_count` — מספר התמונות בדף/סעיף זה
|
||||
|
||||
אלה דורשים טווח שמות של טריגרים חדשים:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
TG_IMAGE_TYPE = "https://trustgraph.ai/ns/Image"
|
||||
TG_ELEMENT_TYPES = "https://trustgraph.ai/ns/elementTypes"
|
||||
TG_TABLE_COUNT = "https://trustgraph.ai/ns/tableCount"
|
||||
TG_IMAGE_COUNT = "https://trustgraph.ai/ns/imageCount"
|
||||
```
|
||||
|
||||
סכימת URN לתמונות: `urn:image:{uuid}`
|
||||
|
||||
(`TG_MIME_TYPE` כבר קיים.)
|
||||
|
||||
#### סוג ישות חדש
|
||||
|
||||
עבור פורמטים שאינם דפי אינטרנט (DOCX, HTML, Markdown, וכו') שבהם
|
||||
ה-דקודר משדר את כל המסמך כיחידה אחת ולא מחלק אותו לדפים,
|
||||
הישות מקבלת סוג חדש:
|
||||
|
||||
```
|
||||
TG_SECTION_TYPE = "https://trustgraph.ai/ns/Section"
|
||||
```
|
||||
|
||||
זה מבחין בין חלקים לדפים בעת שאילתת מקור:
|
||||
|
||||
| ישות | סוג | מתי משמש |
|
||||
|----------|-----------------------------|----------------------------------------|
|
||||
| מסמך | `tg:Document` | קובץ שהועלה במקור |
|
||||
| דף | `tg:Page` | פורמטים מבוססי דפים (PDF, PPTX, XLSX) |
|
||||
| חלק | `tg:Section` | פורמטים שאינם מבוססי דפים (DOCX, HTML, MD, וכו') |
|
||||
| תמונה | `tg:Image` | תמונות מוטמעות (מאוחסנות, לא מעובדות) |
|
||||
| מקטע | `tg:Chunk` | פלט של מפריד מקטעים |
|
||||
| תת-גרף | `tg:Subgraph` | פלט של חילוץ גרף ידע |
|
||||
|
||||
הסוג נקבע על ידי ה-decoder בהתאם לשאלה האם הוא מקבץ לפי עמוד
|
||||
או פולט חלק שלם מהמסמך. `derived_entity_triples` מקבל
|
||||
פרמטר בוליאני אופציונלי `section` — כאשר הוא מוגדר כ-true, היישות היא
|
||||
הוקלד כ-`tg:Section` במקום `tg:Page`.
|
||||
|
||||
#### שרשרת מקור מלאה
|
||||
|
||||
```
|
||||
KG triple
|
||||
→ subgraph (extraction provenance)
|
||||
→ chunk (char_offset, char_length within page)
|
||||
→ page/section (page_number, char_offset, char_length within doc, mime_type, element_types)
|
||||
→ document (original file in librarian)
|
||||
```
|
||||
|
||||
כל קישור הוא קבוצה של שלשות בגרף המכונה `GRAPH_SOURCE`.
|
||||
|
||||
### תצורת שירות
|
||||
|
||||
ארגומנטים של שורת הפקודה:
|
||||
|
||||
```
|
||||
--strategy Partitioning strategy: auto, hi_res, fast (default: auto)
|
||||
--languages Comma-separated OCR language codes (default: eng)
|
||||
--section-strategy Section grouping: whole-document, heading, element-type,
|
||||
count, size (default: whole-document)
|
||||
--section-element-count Elements per section for 'count' strategy (default: 20)
|
||||
--section-max-size Max chars per section for 'size' strategy (default: 4000)
|
||||
--section-within-pages Apply section strategy within pages too (default: false)
|
||||
```
|
||||
|
||||
בנוסף ל-`FlowProcessor` הסטנדרטי ולטיעוני תור המאפשרים גישה לספרייה.
|
||||
|
||||
### אינטגרציה של זרימת העבודה
|
||||
|
||||
ה-דקודר האוניברסלי תופס את אותו מיקום בזרימת העיבוד
|
||||
כמו ה-דקודר של PDF הנוכחי:
|
||||
|
||||
```
|
||||
Document → [universal-decoder] → TextDocument → [chunker] → Chunk → ...
|
||||
```
|
||||
|
||||
זה רושם:
|
||||
`input` צרכן (סכימת מסמכים)
|
||||
`output` מפיק (סכימת TextDocument)
|
||||
`triples` מפיק (סכימת Triples)
|
||||
בקשה/תגובה של ספרן (לשליפה ואחסון של מסמכים משניים)
|
||||
|
||||
### פריסה
|
||||
|
||||
קונטיינר חדש: `trustgraph-flow-universal-decoder`
|
||||
תלות: `unstructured[all-docs]` (כולל PDF, DOCX, PPTX, וכו')
|
||||
ניתן להפעיל לצד או להחליף את מפענח ה-PDF הקיים, בהתאם
|
||||
לתצורת זרימת העבודה
|
||||
מפענח ה-PDF הקיים נשאר זמין עבור סביבות שבהן
|
||||
התלויות של `unstructured` כבדות מדי
|
||||
|
||||
### מה משתנה
|
||||
|
||||
| רכיב | שינוי |
|
||||
|------------------------------|-------------------------------------------------|
|
||||
| `provenance/namespaces.py` | הוספת `TG_SECTION_TYPE`, `TG_IMAGE_TYPE`, `TG_ELEMENT_TYPES`, `TG_TABLE_COUNT`, `TG_IMAGE_COUNT` |
|
||||
| `provenance/triples.py` | הוספת ארגומנטים `mime_type`, `element_types`, `table_count`, `image_count` (kwargs) |
|
||||
| `provenance/__init__.py` | ייצוא קבועים חדשים |
|
||||
| חדש: `decoding/universal/` | מודול שירות פענוח חדש |
|
||||
| `setup.cfg` / `pyproject` | הוספת תלות `unstructured[all-docs]` |
|
||||
| Docker | תמונת קונטיינר חדשה |
|
||||
| הגדרות זרימה | חיבור universal-decoder כקלט מסמך |
|
||||
|
||||
### מה שלא משתנה
|
||||
|
||||
Chunker (מקבל TextDocument, פועל כרגיל)
|
||||
מודולים לחילוץ מידע (מקבלים Chunk, ללא שינוי)
|
||||
Librarian (מאחסן מסמכים משניים, ללא שינוי)
|
||||
Schema (Document, TextDocument, Chunk ללא שינוי)
|
||||
מקור מידע בזמן שאילתה (ללא שינוי)
|
||||
|
||||
## סיכונים
|
||||
|
||||
ל-`unstructured[all-docs]` יש תלות רבה (poppler, tesseract,
|
||||
libreoffice עבור פורמטים מסוימים). תמונת המכולה תהיה גדולה יותר.
|
||||
פתרון אפשרי: להציע גרסה של `[light]` ללא תלות ב-OCR/office.
|
||||
פורמטים מסוימים עשויים לייצר חילוץ טקסט באיכות ירודה (קבצי PDF מסרוקים ללא
|
||||
OCR, פריסות מורכבות של קבצי XLSX). אמצעי מניעה: פרמטר הניתן להגדרה `strategy`.
|
||||
ומפענח ה-OCR של Mistral הקיים זמין
|
||||
עבור OCR באיכות גבוהה של קבצי PDF.
|
||||
עדכוני גרסה של `unstructured` עשויים לשנות מטא-נתונים של אלמנטים.
|
||||
אמצעי מניעה: קביעת גרסה, בדיקת איכות החילוץ עבור כל פורמט.
|
||||
307
docs/tech-specs/he/vector-store-lifecycle.he.md
Normal file
307
docs/tech-specs/he/vector-store-lifecycle.he.md
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
---
|
||||
layout: default
|
||||
title: "ניהול מחזור החיים של מאגר וקטורים"
|
||||
parent: "Hebrew (Beta)"
|
||||
---
|
||||
|
||||
# ניהול מחזור החיים של מאגר וקטורים
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## סקירה כללית
|
||||
|
||||
מסמך זה מתאר כיצד TrustGraph מנהלת אוספי מאגרי וקטורים על פני יישומים שונים (Qdrant, Pinecone, Milvus). העיצוב מתמודד עם האתגר של תמיכה בהטבעות עם ממדים שונים מבלי לקודד ערכי ממדים באופן קשיח.
|
||||
|
||||
## הצהרת בעיה
|
||||
|
||||
מאגרי וקטורים דורשים ציון הממד של ההטבעה בעת יצירת אוספים/אינדקסים. עם זאת:
|
||||
מודלים שונים של הטבעה מייצרים ממדים שונים (לדוגמה, 384, 768, 1536)
|
||||
הממד אינו ידוע עד ליצירת ההטבעה הראשונה
|
||||
אוסף TrustGraph יחיד עשוי לקבל הטבעות ממודלים מרובים
|
||||
קידוד קשיח של ממד (לדוגמה, 384) גורם לכשלים עם גדלי הטבעה אחרים
|
||||
|
||||
## עקרונות עיצוב
|
||||
|
||||
1. **יצירה עצלה**: אוספים נוצרים לפי דרישה במהלך הכתיבה הראשונה, ולא במהלך פעולות ניהול אוספים.
|
||||
2. **שמות המבוססים על ממד**: שמות האוספים כוללים את הממד כסיומת.
|
||||
3. **התדרדרות חלקה**: שאילתות לאוספים שאינם קיימים מחזירות תוצאות ריקות, ולא שגיאות.
|
||||
4. **תמיכה במספר ממדים**: אוסף לוגי יחיד יכול לכלול מספר אוספים פיזיים (אחד לכל ממד).
|
||||
|
||||
## ארכיטקטורה
|
||||
|
||||
### מוסכמות מתן שמות לאוספים
|
||||
|
||||
אוספי מאגרי וקטורים משתמשים בסיומות ממד כדי לתמוך במספר גדלי הטבעה:
|
||||
|
||||
**הטבעות מסמכים:**
|
||||
Qdrant: `d_{user}_{collection}_{dimension}`
|
||||
Pinecone: `d-{user}-{collection}-{dimension}`
|
||||
Milvus: `doc_{user}_{collection}_{dimension}`
|
||||
|
||||
**הטבעות גרף:**
|
||||
Qdrant: `t_{user}_{collection}_{dimension}`
|
||||
Pinecone: `t-{user}-{collection}-{dimension}`
|
||||
Milvus: `entity_{user}_{collection}_{dimension}`
|
||||
|
||||
דוגמאות:
|
||||
`d_alice_papers_384` - אוסף המאמרים של אליס עם הטבעות ממדיות של 384.
|
||||
`d_alice_papers_768` - אותו אוסף לוגי עם הטבעות ממדיות של 768.
|
||||
`t_bob_knowledge_1536` - גרף הידע של בוב עם הטבעות ממדיות של 1536.
|
||||
|
||||
### שלבי מחזור חיים
|
||||
|
||||
#### 1. בקשת יצירת אוסף
|
||||
|
||||
**זרימת בקשה:**
|
||||
```
|
||||
User/System → Librarian → Storage Management Topic → Vector Stores
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
הספרן משדר בקשות `create-collection` לכל אחסוני הנתונים.
|
||||
מעבדי אחסון וקטורים מאשרים את הבקשה, אך **אינם יוצרים אוספים פיזיים**.
|
||||
התגובה מוחזרת מיד עם הצלחה.
|
||||
יצירת האוסף בפועל נדחית עד לכתיבה הראשונה.
|
||||
|
||||
**ההצדקה:**
|
||||
המימד אינו ידוע בזמן היצירה.
|
||||
מונע יצירת אוספים עם מימדים שגויים.
|
||||
מפשט את לוגיקת ניהול האוספים.
|
||||
|
||||
#### 2. פעולות כתיבה (יצירה עצלה)
|
||||
|
||||
**זרימת הכתיבה:**
|
||||
```
|
||||
Data → Storage Processor → Check Collection → Create if Needed → Insert
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
1. חילוץ ממד ההטבעה מהווקטור: `dim = len(vector)`
|
||||
2. יצירת שם אוסף עם סיומת הממד
|
||||
3. בדיקה האם קיים אוסף עם אותו ממד ספציפי
|
||||
4. אם לא קיים:
|
||||
יצירת אוסף עם הממד הנכון
|
||||
רישום: `"Lazily creating collection {name} with dimension {dim}"`
|
||||
5. הכנסת ההטבעה לאוסף הספציפי לממד
|
||||
|
||||
**תרחיש לדוגמה:**
|
||||
```
|
||||
1. User creates collection "papers"
|
||||
→ No physical collections created yet
|
||||
|
||||
2. First document with 384-dim embedding arrives
|
||||
→ Creates d_user_papers_384
|
||||
→ Inserts data
|
||||
|
||||
3. Second document with 768-dim embedding arrives
|
||||
→ Creates d_user_papers_768
|
||||
→ Inserts data
|
||||
|
||||
Result: Two physical collections for one logical collection
|
||||
```
|
||||
|
||||
#### 3. פעולות שאילתה
|
||||
|
||||
**זרימת השאילתה:**
|
||||
```
|
||||
Query Vector → Determine Dimension → Check Collection → Search or Return Empty
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
1. חילוץ מימד מהווקטור של השאילתה: `dim = len(vector)`
|
||||
2. יצירת שם אוסף עם סיומת המציינת את המימד
|
||||
3. בדיקה האם האוסף קיים
|
||||
4. אם קיים:
|
||||
ביצוע חיפוש דמיון
|
||||
החזרת תוצאות
|
||||
5. אם לא קיים:
|
||||
רישום: `"Collection {name} does not exist, returning empty results"`
|
||||
החזרת רשימה ריקה (ללא העלאת שגיאה)
|
||||
|
||||
**מימדים מרובים באותה שאילתה:**
|
||||
אם השאילתה מכילה וקטורים של מימדים שונים
|
||||
כל מימד מבצע שאילתה על האוסף המתאים לו
|
||||
התוצאות מאוחדות
|
||||
אוספים חסרים מדלגים (לא מטופלים כשגיאות)
|
||||
|
||||
**ההצדקה:**
|
||||
שאילתה על אוסף ריק היא מקרה שימוש חוקי
|
||||
החזרת תוצאות ריקות היא נכונה מבחינה סמנטית
|
||||
מונע שגיאות במהלך אתחול המערכת או לפני טעינת נתונים
|
||||
|
||||
#### 4. מחיקת אוסף
|
||||
|
||||
**תהליך מחיקה:**
|
||||
```
|
||||
Delete Request → List All Collections → Filter by Prefix → Delete All Matches
|
||||
```
|
||||
|
||||
**התנהגות:**
|
||||
1. בניית תבנית קידומת: `d_{user}_{collection}_` (שימו לב לקו התחתון בסוף)
|
||||
2. רשימת כל האוספים במאגר הווקטורים
|
||||
3. סינון אוספים התואמים לקידומת
|
||||
4. מחיקת כל האוספים התואמים
|
||||
5. רישום כל מחיקה: `"Deleted collection {name}"`
|
||||
6. רישום סיכום: `"Deleted {count} collection(s) for {user}/{collection}"`
|
||||
|
||||
**דוגמה:**
|
||||
```
|
||||
Collections in store:
|
||||
- d_alice_papers_384
|
||||
- d_alice_papers_768
|
||||
- d_alice_reports_384
|
||||
- d_bob_papers_384
|
||||
|
||||
Delete "papers" for alice:
|
||||
→ Deletes: d_alice_papers_384, d_alice_papers_768
|
||||
→ Keeps: d_alice_reports_384, d_bob_papers_384
|
||||
```
|
||||
|
||||
**הסבר:**
|
||||
מבטיח ניקוי מלא של כל וריאציות המימדים.
|
||||
התאמת תבניות מונעת מחיקה בשוגע של אוספים לא קשורים.
|
||||
פעולה אטומית מנקודת מבטו של המשתמש (כל המימדים נמחקים יחד).
|
||||
|
||||
## מאפיינים התנהגותיים
|
||||
|
||||
### פעולות רגילות
|
||||
|
||||
**יצירת אוסף:**
|
||||
✓ מחזיר הצלחה באופן מיידי.
|
||||
✓ לא מוקצה אחסון פיזי.
|
||||
✓ פעולה מהירה (ללא קלט/פלט של מערכת הפעלה).
|
||||
|
||||
**כתיבה ראשונה:**
|
||||
✓ יוצר אוסף עם מימד נכון.
|
||||
✓ מעט איטי יותר עקב תקורה של יצירת האוסף.
|
||||
✓ כתיבות עוקבות לאותו מימד מהירות.
|
||||
|
||||
**שאילתות לפני כל כתיבה:**
|
||||
✓ מחזיר תוצאות ריקות.
|
||||
✓ אין שגיאות או חריגות.
|
||||
✓ המערכת נשארת יציבה.
|
||||
|
||||
**כתיבות של מימדים שונים:**
|
||||
✓ יוצר באופן אוטומטי אוספים נפרדים לכל מימד.
|
||||
✓ כל מימד מבודד באוסף משלו.
|
||||
✓ אין התנגשויות מימדים או שגיאות סכימה.
|
||||
|
||||
**מחיקת אוסף:**
|
||||
✓ מסיר את כל וריאציות המימדים.
|
||||
✓ ניקוי מלא.
|
||||
✓ אין אוספים יתומים.
|
||||
|
||||
### מקרים קצה
|
||||
|
||||
**מודלים משובצים מרובים:**
|
||||
```
|
||||
Scenario: User switches from model A (384-dim) to model B (768-dim)
|
||||
Behavior:
|
||||
- Both dimensions coexist in separate collections
|
||||
- Old data (384-dim) remains queryable with 384-dim vectors
|
||||
- New data (768-dim) queryable with 768-dim vectors
|
||||
- Cross-dimension queries return results only for matching dimension
|
||||
```
|
||||
|
||||
**כתיבות ראשוניות מקבילות:**
|
||||
```
|
||||
Scenario: Multiple processes write to same collection simultaneously
|
||||
Behavior:
|
||||
- Each process checks for existence before creating
|
||||
- Most vector stores handle concurrent creation gracefully
|
||||
- If race condition occurs, second create is typically idempotent
|
||||
- Final state: Collection exists and both writes succeed
|
||||
```
|
||||
|
||||
**הגירה של ממדים:**
|
||||
```
|
||||
Scenario: User wants to migrate from 384-dim to 768-dim embeddings
|
||||
Behavior:
|
||||
- No automatic migration
|
||||
- Old collection (384-dim) persists
|
||||
- New collection (768-dim) created on first new write
|
||||
- Both dimensions remain accessible
|
||||
- Manual deletion of old dimension collections possible
|
||||
```
|
||||
|
||||
**שאילתות לאוספים ריקים:**
|
||||
```
|
||||
Scenario: Query a collection that has never received data
|
||||
Behavior:
|
||||
- Collection doesn't exist (never created)
|
||||
- Query returns empty list
|
||||
- No error state
|
||||
- System logs: "Collection does not exist, returning empty results"
|
||||
```
|
||||
|
||||
## הערות יישום
|
||||
|
||||
### פרטים ספציפיים לגבי אחסון
|
||||
|
||||
**Qdrant:**
|
||||
משתמש ב-`collection_exists()` לבדיקות קיום
|
||||
משתמש ב-`get_collections()` לרשימה במהלך מחיקה
|
||||
יצירת אוסף דורשת `VectorParams(size=dim, distance=Distance.COSINE)`
|
||||
|
||||
**Pinecone:**
|
||||
משתמש ב-`has_index()` לבדיקות קיום
|
||||
משתמש ב-`list_indexes()` לרשימה במהלך מחיקה
|
||||
יצירת אינדקס דורשת המתנה למצב "מוכן"
|
||||
מפרט שרת חסר מוגדר עם ענן/אזור
|
||||
|
||||
**Milvus:**
|
||||
מחלקות ישירות (`DocVectors`, `EntityVectors`) מנהלות את מחזור החיים
|
||||
מטמון פנימי `self.collections[(dim, user, collection)]` לביצועים
|
||||
שמות אוספים עוברים סינון (רק תווים אלפאנומריים וקו תחתון)
|
||||
תומך בסכימה עם מזהים עם הגדלה אוטומטית
|
||||
|
||||
### שיקולי ביצועים
|
||||
|
||||
**זמן השהייה לכתיבה ראשונה:**
|
||||
תקורה נוספת עקב יצירת אוסף
|
||||
Qdrant: ~100-500ms
|
||||
Pinecone: ~10-30 שניות (הקצאת שרת חסר)
|
||||
Milvus: ~500-2000ms (כולל אינדקס)
|
||||
|
||||
**ביצועי שאילתות:**
|
||||
בדיקת קיום מוסיפה תקורה מינימלית (~1-10ms)
|
||||
אין השפעה על הביצועים לאחר יצירת האוסף
|
||||
כל אוסף ממד מותאם באופן עצמאי
|
||||
|
||||
**תקורה של אחסון:**
|
||||
מטא-דאטה מינימלי לכל אוסף
|
||||
התקורה העיקרית היא אחסון לכל ממד
|
||||
פשרה: שטח אחסון לעומת גמישות ממדים
|
||||
|
||||
## שיקולים עתידיים
|
||||
|
||||
**איחוד ממדים אוטומטי:**
|
||||
ניתן להוסיף תהליך רקע לזיהוי ומיזוג גרסאות ממדים לא בשימוש
|
||||
זה ידרוש הטמעה מחדש או צמצום ממדים
|
||||
|
||||
**גילוי ממדים:**
|
||||
ניתן לחשוף API לרשימת כל הממדים בשימוש עבור אוסף
|
||||
שימושי לניהול וניטור
|
||||
|
||||
**העדפה ברירת מחדל לממד:**
|
||||
ניתן לעקוב אחר "ממד ראשי" לכל אוסף
|
||||
להשתמש עבור שאילתות כאשר הקשר הממד אינו זמין
|
||||
|
||||
**מכסות אחסון:**
|
||||
ייתכן שיהיה צורך במגבלות ממדים לכל אוסף
|
||||
למנוע התרבות של גרסאות ממדים
|
||||
|
||||
## הערות העברה
|
||||
|
||||
**ממערכת קודמת עם סיומת ממד:**
|
||||
אוספים ישנים: `d_{user}_{collection}` (ללא סיומת ממד)
|
||||
אוספים חדשים: `d_{user}_{collection}_{dim}` (עם סיומת ממד)
|
||||
אין העברה אוטומטית - אוספים ישנים נשארים נגישים
|
||||
שקול סקריפט העברה ידני אם יש צורך
|
||||
ניתן להפעיל שני סכימות שמות בו זמנית
|
||||
|
||||
## הפניות
|
||||
|
||||
ניהול אוספים: `docs/tech-specs/collection-management.md`
|
||||
סכימת אחסון: `trustgraph-base/trustgraph/schema/services/storage.py`
|
||||
שירות ספרית: `trustgraph-flow/trustgraph/librarian/service.py`
|
||||
Loading…
Add table
Add a link
Reference in a new issue