mindnet/docs/02_concepts/02_concept_architecture_patterns.md
Lars 5225090490
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
Dokumentationsaupdate
2025-12-28 10:56:34 +01:00

457 lines
12 KiB
Markdown

---
doc_type: concept
audience: architect, developer
scope: architecture, design_patterns, modularization
status: active
version: 2.9.1
context: "Architektur-Patterns, Design-Entscheidungen und modulare Struktur von Mindnet. Basis für Verständnis und Erweiterungen."
---
# Architektur-Patterns & Design-Entscheidungen
Dieses Dokument beschreibt die zentralen Architektur-Patterns und Design-Entscheidungen, die Mindnet prägen. Es dient als Referenz für Entwickler und Architekten, um das System zu verstehen und konsistent zu erweitern.
## 1. Kern-Paradigmen
### 1.1 Filesystem First (Source of Truth)
**Prinzip:** Markdown-Dateien im Vault sind die einzige Quelle der Wahrheit. Die Datenbank (Qdrant) ist ein abgeleiteter Index.
**Implikationen:**
- Dateien werden immer direkt von der Festplatte gelesen (z.B. im Editor)
- Datenbank-Inhalte können aus Markdown rekonstruiert werden
- Änderungen erfolgen primär im Vault, nicht in der DB
- Die Datenbank ist ein Cache, kein primärer Speicher
**Code-Beispiele:**
- `ui_callbacks.py`: Liest Dateien direkt von Disk
- `ingestion_processor.py`: Schreibt zuerst auf Disk, dann in DB
### 1.2 Late Binding (Späte Semantik)
**Prinzip:** Struktur und Interpretation werden in Konfigurationen definiert, nicht im Code.
**Implikationen:**
- Neue Note-Typen werden in `types.yaml` definiert, nicht im Code
- Prompt-Templates sind in `prompts.yaml` konfigurierbar
- Edge-Typen werden in `edge_vocabulary.md` verwaltet
- Die "Persönlichkeit" ist Config, kein Code
**Vorteile:**
- Erweiterbarkeit ohne Code-Änderungen
- A/B-Testing von Prompt-Strategien
- Anpassung an verschiedene Use-Cases
### 1.3 Virtual Schema Layer
**Prinzip:** Markdown-Dateien benötigen nur minimale Frontmatter-Angaben. Komplexität wird zur Laufzeit injiziert.
**Beispiel:**
```yaml
# Minimal im Frontmatter
---
id: 20250101-test
title: Test
type: project
---
# Im Code wird zur Laufzeit ergänzt:
# - chunking_profile aus types.yaml
# - retriever_weight aus types.yaml
# - edge_defaults aus types.yaml
```
**Vorteile:**
- Robuste Markdown-Dateien (weniger Breaking Changes)
- Zentrale Verwaltung von Logik
- Einfache Migration zwischen Versionen
---
## 2. Modulare Architektur (WP-14)
### 2.1 Paket-Struktur
Seit WP-14 ist die Core-Logik in spezialisierte Pakete unterteilt:
```
app/core/
├── chunking/ # Text-Segmentierung
│ ├── chunking_strategies.py # Sliding/Heading-Strategien
│ ├── chunking_processor.py # Orchestrierung
│ └── chunking_propagation.py # Edge-Vererbung
├── database/ # Qdrant-Infrastruktur
│ ├── qdrant.py # Client & Config
│ └── qdrant_points.py # Point-Mapping
├── graph/ # Graph-Logik
│ ├── graph_subgraph.py # Expansion
│ └── graph_weights.py # Scoring
├── ingestion/ # Import-Pipeline
│ ├── ingestion_processor.py # Two-Pass Workflow
│ └── ingestion_validation.py # Mistral-safe Parsing
├── parser/ # Markdown-Parsing
│ ├── parsing_markdown.py # Frontmatter/Body
│ └── parsing_scanner.py # File-Scan
└── retrieval/ # Suche & Scoring
├── retriever.py # Orchestrator
└── retriever_scoring.py # Mathematik
```
### 2.2 Design-Pattern: Proxy-Adapter (Abwärtskompatibilität)
**Problem:** Nach WP-14 Modularisierung müssen alte Import-Pfade weiter funktionieren.
**Lösung:** Proxy-Module leiten Anfragen an neue Pakete weiter.
**Beispiel:**
```python
# app/core/retriever.py (Proxy)
from .retrieval.retriever import (
Retriever, hybrid_retrieve, semantic_retrieve
)
__all__ = ["Retriever", "hybrid_retrieve", "semantic_retrieve"]
```
**Vorteile:**
- Keine Breaking Changes für bestehenden Code
- Graduelle Migration möglich
- Alte Scripts funktionieren weiter
### 2.3 Design-Pattern: Singleton (Edge Registry)
**Problem:** Edge Registry muss konsistent über alle Services sein.
**Lösung:** Singleton-Pattern mit Lazy Loading.
**Code:**
```python
# app/services/edge_registry.py
class EdgeRegistry:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
```
**Vorteile:**
- Einheitliche Validierung
- Keine Duplikation von Vokabular-Daten
- Thread-safe Initialisierung
---
## 3. Asynchrone Verarbeitung
### 3.1 Background Tasks Pattern
**Problem:** Ingestion kann lange dauern (LLM-Calls, Embeddings). Blockiert API nicht.
**Lösung:** FastAPI Background Tasks für non-blocking Verarbeitung.
**Flow:**
1. API empfängt Request (`/ingest/save`)
2. Datei wird sofort auf Disk geschrieben
3. API antwortet mit `status: "queued"`
4. Background Task startet Ingestion asynchron
5. User kann weiterarbeiten
**Code:**
```python
@router.post("/save")
async def save_note(req: SaveRequest, background_tasks: BackgroundTasks):
# Sofortige Persistenz
write_to_disk(req.markdown_content)
# Async Processing
background_tasks.add_task(run_ingestion_task, ...)
return SaveResponse(status="queued", ...)
```
**Vorteile:**
- Keine Timeouts bei großen Dateien
- Bessere User Experience
- System bleibt responsiv
### 3.2 Traffic Control (Semaphore Pattern)
**Problem:** Parallele LLM-Calls können System überlasten.
**Lösung:** Semaphore begrenzt parallele Hintergrund-Tasks.
**Code:**
```python
# app/services/llm_service.py
background_semaphore = asyncio.Semaphore(
settings.BACKGROUND_LIMIT # Default: 2
)
async def generate(...):
if priority == "background":
async with background_semaphore:
return await _call_llm(...)
else: # realtime
return await _call_llm(...) # Keine Limitierung
```
**Vorteile:**
- Schutz vor API-Quoten-Überschreitung
- Stabiler Betrieb bei hoher Last
- Priorisierung von Echtzeit-Anfragen
---
## 4. Resilienz-Patterns
### 4.1 Provider-Kaskade (Fallback-Kette)
**Problem:** Cloud-Provider können ausfallen oder Quoten überschreiten.
**Lösung:** Dreistufige Kaskade mit intelligentem Fallback.
**Stufen:**
1. **Cloud (OpenRouter/Gemini):** Schnell, aber abhängig von Provider
2. **Rate-Limit-Handling:** Automatische Retries bei HTTP 429
3. **Lokaler Fallback (Ollama):** Langsam, aber immer verfügbar
**Code:**
```python
# app/services/llm_service.py
async def generate(...):
try:
return await _call_cloud(...)
except RateLimitError:
await asyncio.sleep(LLM_RATE_LIMIT_WAIT)
return await _call_cloud(...) # Retry
except Exception:
return await _call_ollama(...) # Fallback
```
**Vorteile:**
- Hohe Verfügbarkeit
- Kostenoptimierung (Cloud für Speed, Lokal für Fallback)
- Resilienz gegen Provider-Ausfälle
### 4.2 Deep Fallback (Kognitiver Fallback)
**Problem:** Cloud liefert technisch erfolgreiche, aber inhaltlich leere Antworten (Silent Refusal).
**Lösung:** Validierung der Antwort-Qualität, nicht nur HTTP-Status.
**Code:**
```python
response = await _call_cloud(...)
if is_valid_json(response):
return response
else:
# Deep Fallback: Cloud hat blockiert, lokaler Fallback
return await _call_ollama(...)
```
**Vorteile:**
- Erkennung von Policy-Violations
- Datenintegrität trotz Cloud-Filter
- Lokale Souveränität
---
## 5. Datenfluss-Patterns
### 5.1 Two-Pass Workflow (WP-15b)
**Problem:** Smart Edge Validation benötigt globalen Kontext (alle Notizen).
**Lösung:** Zwei-Phasen-Import mit Pre-Scan.
**Pass 1: Pre-Scan**
- Schnelles Scannen aller Dateien
- Aufbau von `LocalBatchCache` (IDs, Titel, Summaries)
- Keine LLM-Calls
**Pass 2: Semantic Processing**
- Nur für geänderte Dateien
- Binäre Validierung gegen Cache
- Effiziente Nutzung von LLM-Quoten
**Vorteile:**
- Reduktion von LLM-Calls (nur Validierung, keine Extraktion)
- Konsistente Validierung (globaler Kontext)
- Schnellerer Import
### 5.2 Idempotenz-Pattern
**Prinzip:** Mehrfache Imports derselben Datei führen zum gleichen Ergebnis.
**Mechanismen:**
- **Deterministische IDs:** UUIDv5 basierend auf Datei-Inhalt
- **Hash-basierte Change Detection:** Multi-Hash für `body` und `full`
- **Deduplizierung:** Kanten werden anhand Identität erkannt
**Code:**
```python
# Deterministische ID
note_id = uuid.uuid5(NAMESPACE_URL, f"{file_path}#{content_hash}")
# Change Detection
if current_hash == stored_hash:
skip_processing() # Idempotent
```
**Vorteile:**
- Sicherheit bei Re-Imports
- Keine Duplikate
- Konsistente Datenbank
---
## 6. Frontend-Patterns
### 6.1 Active Inspector Pattern
**Problem:** Graph-Re-Renders bei Knoten-Selektion führen zu Flackern.
**Lösung:** CSS-Klassen statt State-Änderungen für Selektion.
**Code:**
```python
# ui_graph_cytoscape.py
stylesheet = [
{
"selector": ".inspected",
"style": {"border-width": 6, "border-color": "#FFC300"}
}
]
# Selektion ändert nur CSS-Klasse, nicht React-Key
```
**Vorteile:**
- Stabiles UI (kein Re-Render)
- Bessere Performance
- Smooth User Experience
### 6.2 Resurrection Pattern
**Problem:** Streamlit vergisst Eingaben bei Re-Runs.
**Lösung:** Aggressive Synchronisation in `session_state`.
**Code:**
```python
# ui_editor.py
if widget_key not in st.session_state:
st.session_state[widget_key] = restore_from_data_key()
```
**Vorteile:**
- Texteingaben überleben Tab-Wechsel
- Keine Datenverluste
- Bessere UX
---
## 7. Erweiterbarkeit: "Teach-the-AI" Paradigma
Mindnet lernt durch **Konfiguration**, nicht durch Training.
### 7.1 Drei-Ebenen-Erweiterung
**1. Daten-Ebene (`types.yaml`):**
```yaml
risk:
retriever_weight: 0.90
edge_defaults: ["blocks"]
```
**2. Strategie-Ebene (`decision_engine.yaml`):**
```yaml
DECISION:
inject_types: ["value", "risk"]
```
**3. Kognitive Ebene (`prompts.yaml`):**
```yaml
risk_definition:
ollama: "Ein Risiko ist eine potenzielle Gefahr..."
```
**Vorteile:**
- Keine Code-Änderungen nötig
- Schnelle Iteration
- A/B-Testing möglich
---
## 8. Design-Entscheidungen & Trade-offs
### 8.1 Qdrant als Vektor-DB
**Entscheidung:** Qdrant statt Pinecone/Weaviate
**Gründe:**
- Self-hosted (Privacy First)
- Open Source
- Gute Performance bei lokaler Installation
**Trade-off:** Mehr Wartungsaufwand als Managed Service
### 8.2 Hybrid Retrieval (Semantik + Graph)
**Entscheidung:** Kombination von Vektor-Suche und Graph-Expansion
**Gründe:**
- Semantik findet ähnliche Inhalte
- Graph findet strukturelle Verbindungen
- Kombination liefert bessere Relevanz
**Trade-off:** Höhere Komplexität, mehr Berechnungsaufwand
### 8.3 Background Tasks statt Queue-System
**Entscheidung:** FastAPI Background Tasks statt Redis/RabbitMQ
**Gründe:**
- Einfacher Setup (keine zusätzliche Infrastruktur)
- Ausreichend für Single-User-Szenario
- Weniger Moving Parts
**Trade-off:** Keine Persistenz bei Server-Neustart (Tasks gehen verloren)
---
## 9. Konsistenz-Garantien
### 9.1 Deterministische IDs
**Prinzip:** UUIDv5 basierend auf Datei-Inhalt
**Vorteile:**
- Reproduzierbare IDs
- Keine Duplikate bei Re-Import
- Graph ist aus Markdown rekonstruierbar
### 9.2 Provenance-Hierarchie
**Prinzip:** Kanten haben Qualitätsstufen (explicit > smart > rule)
**Vorteile:**
- Menschliche Intention hat Vorrang
- System-Heuristiken können überschrieben werden
- Transparente Gewichtung
---
## 10. Weitere Informationen
- **Vision & Strategie:** Siehe [Vision & Strategie](../00_General/00_vision_and_strategy.md)
- **Graph-Logik:** Siehe [Graph-Logik](02_concept_graph_logic.md)
- **KI-Persönlichkeit:** Siehe [KI-Persönlichkeit](02_concept_ai_personality.md)
- **Developer Guide:** Siehe [Developer Guide](../05_Development/05_developer_guide.md)
---
**Letzte Aktualisierung:** 2025-01-XX
**Version:** 2.9.1