mindnet/docs/mindnet_technical_architecture.md
Lars 9ee39277ae
All checks were successful
Deploy mindnet to llm-node / deploy (push) Successful in 3s
docs/mindnet_technical_architecture.md aktualisiert
2025-12-08 09:08:12 +01:00

252 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mindnet v2.2 Technische Architektur
**Datei:** `docs/mindnet_technical_architecture_v2.2.md`
**Stand:** 2025-12-08
**Status:** **FINAL** (Integrierter Stand WP01WP04c)
**Quellen:** `mindnet_technical_architecture.md`, `chunking_strategy.md`, `Handbuch.md`, `wp04_retriever_scoring.md`.
> **Ziel dieses Dokuments:**
> Vollständige, konsolidierte Beschreibung der aktuellen technischen Architektur von **Mindnet v2.2**. Es definiert die Datenstrukturen in Qdrant, die Verarbeitungspipelines (Importer, Chunker, Edges) und die Retrieval-Logik. Es bildet den **aktuellen Implementierungsstand** ab.
---
## 1. Systemüberblick
### 1.1 Architektur-Zielbild
Mindnet ist ein **persönliches Wissensnetz**. Technisch bedeutet das:
1. **Source:** Markdown-Notizen in einem Vault (Obsidian-kompatibel).
2. **Pipeline:** Ein Python-Importer transformiert diese in **Notes**, **Chunks** und **Edges**.
3. **Storage:**
* **Qdrant:** Vektor-Datenbank für Graph und Semantik (Collections: notes, chunks, edges).
* **Local Files (JSONL):** Append-Only Logs für Feedback und Search-History (Data Flywheel).
4. **Service:** Eine FastAPI-Anwendung stellt Endpunkte für **Semantische** und **Hybride Suche** sowie **Feedback** bereit.
Das System arbeitet **deterministisch** (stabile IDs) und ist **konfigurationsgetrieben** (`types.yaml`, `retriever.yaml`).
### 1.2 Verzeichnisstruktur & Komponenten
Die Codebasis ist modular aufgebaut.
/mindnet/
├── app/
│ ├── main.py # FastAPI Einstiegspunkt
│ ├── core/
│ │ ├── qdrant.py # Client-Factory & Connection
│ │ ├── qdrant_points.py # Low-Level Point Operations (Upsert/Delete)
│ │ ├── note_payload.py # Bau der Note-Objekte
│ │ ├── chunk_payload.py # Bau der Chunk-Objekte
│ │ ├── chunker.py # Text-Zerlegung (Profiling)
│ │ ├── edges.py # Edge-Datenstrukturen
│ │ ├── derive_edges.py # Logik der Kantenableitung (WP03)
│ │ ├── graph_adapter.py # Subgraph & Reverse-Lookup (WP04b)
│ │ └── retriever.py # Scoring, Expansion & Explanation (WP04a/b)
│ ├── models/ # Pydantic DTOs (QueryHit, Explanation, FeedbackRequest)
│ ├── routers/
│ │ ├── query.py # Such-Endpunkt
│ │ ├── feedback.py # Feedback-Endpunkt (WP04c)
│ │ └── ...
│ ├── services/
│ │ ├── feedback_service.py # Logging-Logik (WP04c)
│ │ └── embeddings_client.py
├── config/
│ ├── types.yaml # Typ-Definitionen (Import-Zeit)
│ └── retriever.yaml # Scoring-Gewichte (Laufzeit)
├── data/
│ └── logs/ # Lokale JSONL-Logs (WP04c)
├── scripts/
│ ├── import_markdown.py # Haupt-Importer CLI
│ ├── payload_dryrun.py # Diagnose: JSON-Generierung ohne DB
│ └── edges_full_check.py # Diagnose: Graph-Integrität
└── tests/ # Pytest Suite
---
## 2. Datenmodell & Collections (Qdrant)
Das Datenmodell verteilt sich auf drei Collections, definiert durch `COLLECTION_PREFIX` (Standard: `mindnet`).
### 2.1 Notes Collection (`<prefix>_notes`)
Repräsentiert die Metadaten einer Datei.
* **Zweck:** Filterung, Metadaten-Haltung, Vererbung von Eigenschaften an Chunks.
* **Schema (Payload):**
| Feld | Datentyp | Beschreibung | Herkunft |
| :--- | :--- | :--- | :--- |
| `note_id` | Keyword | Stabile ID (UUIDv5 oder Slug). | Frontmatter |
| `title` | Text | Titel der Notiz. | Frontmatter |
| `type` | Keyword | Logischer Typ (z.B. `concept`). | `types.yaml` Resolver |
| `retriever_weight` | Float | Wichtigkeit im Retrieval. | `types.yaml` |
| `chunk_profile` | Keyword | Genutztes Chunking-Profil. | `types.yaml` |
| `edge_defaults` | List[Str] | Aktive Default-Relationen. | `types.yaml` |
| `tags` | List[Kw] | Tags zur Filterung. | Frontmatter |
| `updated` | Integer | Zeitstempel (z.B. YYYYMMDD...). | File Stats |
| `fulltext` | Text | Gesamter Inhalt (für Export/Rekonstruktion). | Body |
### 2.2 Chunks Collection (`<prefix>_chunks`)
Die atomaren Sucheinheiten.
* **Zweck:** Vektorsuche (Embeddings), Granulares Ergebnis.
* **Schema (Payload):**
| Feld | Datentyp | Beschreibung |
| :--- | :--- | :--- |
| `chunk_id` | Keyword | Deterministisch: `{note_id}#c{index:02d}`. |
| `note_id` | Keyword | Referenz zur Note. |
| `text` | Text | **Reiner Inhalt** (ohne Overlap). Anzeige-Text. |
| `window` | Text | **Kontext-Fenster** (mit Overlap). Embedding-Basis. |
| `ord` | Integer | Sortierreihenfolge (1..N). |
| `retriever_weight` | Float | Vererbt von Note. |
| `chunk_profile` | Keyword | Vererbt von Note. |
| `neighbors_prev` | List[Str] | ID des Vorgänger-Chunks. |
| `neighbors_next` | List[Str] | ID des Nachfolger-Chunks. |
### 2.3 Edges Collection (`<prefix>_edges`)
Gerichtete Kanten. Massiv erweitert in WP03 für Provenienz-Tracking.
* **Zweck:** Graph-Traversal, Kontext-Anreicherung.
* **Schema (Payload):**
| Feld | Datentyp | Beschreibung | Wertebereich (Bsp.) |
| :--- | :--- | :--- | :--- |
| `edge_id` | Keyword | Hash aus (src, dst, kind). | |
| `source_id` | Keyword | ID des Start-Chunks. | |
| `target_id` | Keyword | ID des Ziel-Chunks (oder Note-Titel). | |
| `note_id` | Keyword | Note, die diese Kante definiert. | |
| `kind` | Keyword | Art der Beziehung. | `references`, `depends_on`, `next` |
| `scope` | Keyword | Geltungsbereich. | Immer `"chunk"` (v2.2). |
| `rule_id` | Keyword | Herkunftsregel. | `explicit:wikilink`, `inline:rel` |
| `confidence` | Float | Vertrauenswürdigkeit (0.0-1.0). | 1.0, 0.95, 0.7 |
---
## 3. Konfiguration
Die Logik ist ausgelagert in YAML-Dateien.
### 3.1 Typ-Registry (`config/types.yaml`)
Steuert den Import-Prozess.
* **Priorität:** Frontmatter > Pfad > Default.
* **Inhalt:**
```yaml
types:
concept:
chunk_profile: medium
edge_defaults: ["references", "related_to"]
retriever_weight: 0.60
```
### 3.2 Retriever-Config (`config/retriever.yaml`)
Steuert das Scoring zur Laufzeit (WP04a).
* **Inhalt:**
```yaml
scoring:
semantic_weight: 1.0
edge_weight: 0.7
centrality_weight: 0.5
```
---
## 4. Import-Pipeline (Markdown → Qdrant)
Das Skript `scripts/import_markdown.py` orchestriert den Prozess.
### 4.1 Verarbeitungsschritte
1. **Discovery & Parsing:**
* Einlesen der `.md` Dateien. Hash-Vergleich (Body/Frontmatter) zur Erkennung von Änderungen.
2. **Typauflösung:**
* Laden der `types.yaml`. Bestimmen des effektiven Typs und der `edge_defaults`.
3. **Chunking:**
* Zerlegung via `chunker.py` basierend auf `chunk_profile` (z.B. `by_heading`, `short`, `long`).
* Trennung von `text` (Kern) und `window` (Embedding-Kontext).
4. **Kantenableitung (Edge Derivation):**
Die `derive_edges.py` erzeugt Kanten in strikter Reihenfolge:
1. **Inline-Edges:** `[[rel:depends_on X]]``kind=depends_on`, `rule_id=inline:rel`, `conf=0.95`.
2. **Callout-Edges:** `> [!edge] related_to: [[X]]``kind=related_to`, `rule_id=callout:edge`, `conf=0.90`.
3. **Explizite Referenzen:** `[[X]]``kind=references`, `rule_id=explicit:wikilink`, `conf=1.0`.
4. **Typ-Defaults:** Für jede Referenz werden Zusatzkanten gemäß `edge_defaults` erzeugt (z.B. `project` -> `depends_on`). `rule_id=edge_defaults:...`, `conf=0.7`.
5. **Struktur:** `belongs_to`, `next`, `prev` (automatisch).
5. **Upsert:**
* Schreiben in Qdrant. Nutzung von `--purge-before-upsert` für saubere Updates.
---
## 5. Retriever-Architektur & Scoring
Der Retriever (`app/core/retriever.py`) realisiert die Logik hinter `/query`.
### 5.1 Betriebsmodi
* **Semantic:** Reine Vektorsuche. Schnell.
* **Hybrid:** Vektorsuche + Graph-Expansion (Tiefe N) + Re-Ranking.
### 5.2 Scoring-Formel (WP04a)
Die Relevanzberechnung ist nun eine gewichtete Summe:
$$
TotalScore = (W_{sem} \cdot S_{sem} \cdot \max(W_{type}, 0)) + (W_{edge} \cdot B_{edge}) + (W_{cent} \cdot B_{cent})
$$
* **Komponenten:**
* $S_{sem}$: Semantic Score (Cosine Similarity).
* $W_{type}$: `retriever_weight` (aus Note/Chunk Payload).
* $B_{edge}$: Edge-Bonus (Summe der Konfidenzen eingehender relevanter Kanten).
* $B_{cent}$: Centrality-Bonus (im lokalen Subgraphen).
* **Gewichte ($W$):** Stammen aus `retriever.yaml`.
### 5.3 Explanation Layer (WP04b)
Der Retriever kann Ergebnisse erklären (`explain=True`).
* **Logik:**
* Berechnung des `ScoreBreakdown` (Anteile von Semantik, Graph, Typ).
* Analyse des lokalen Subgraphen mittels `graph_adapter.py`.
* **Incoming Edges (Authority):** Wer zeigt auf diesen Treffer? (z.B. "Referenziert von...")
* **Outgoing Edges (Hub):** Worauf zeigt dieser Treffer? (z.B. "Verweist auf...")
* **Output:** `QueryHit` enthält ein `explanation` Objekt mit menschenlesbaren `reasons` und `related_edges`.
### 5.4 Graph-Expansion
Der Hybrid-Modus lädt dynamisch die Nachbarschaft der Top-K Vektor-Treffer ("Seeds") über `graph_adapter.expand`. Dies baut einen temporären `NetworkX`-artigen Graphen im Speicher (Klasse `Subgraph`), auf dem Boni berechnet werden.
---
## 6. Feedback & Logging Architektur (WP04c)
Mindnet implementiert ein "Data Flywheel" zur späteren Optimierung (Self-Tuning).
### 6.1 Komponenten
* **Feedback Service (`app/services/feedback_service.py`):** Kapselt die Schreibzugriffe.
* **Storage:** Lokales Dateisystem (`data/logs/`), Format JSONL (Line-delimited JSON).
### 6.2 Log-Dateien
1. **`search_history.jsonl`**:
* Speichert jede Anfrage an `/query`.
* Enthält: `query_id`, `query_text`, `timestamp`, `hits` (inkl. `score_breakdown` Snapshots).
* Zweck: Trainingsdaten ("Was hat das System gesehen?").
2. **`feedback.jsonl`**:
* Speichert User-Reaktionen an `/feedback`.
* Enthält: `query_id`, `node_id`, `score` (1-5), `comment`.
* Zweck: Labels ("War es gut?").
### 6.3 Traceability
Die `query_id` (UUIDv4) wird im `/query` Response generiert und muss vom Client beim `/feedback` Aufruf mitgesendet werden. Dies ermöglicht den Join zwischen Snapshot und Bewertung.
---
## 7. Indizes & Performance
Damit Qdrant performant bleibt, sind Payload-Indizes essenziell.
**Erforderliche Indizes:**
* **Notes:** `note_id`, `type`, `tags`.
* **Chunks:** `note_id`, `chunk_id`.
* **Edges:** `source_id`, `target_id`, `kind`, `scope`, `note_id`.
Validierung erfolgt über `tests/ensure_indexes_and_show.py`.
---
## 8. Offene Punkte / Known Limitations
1. **Multi-Target Inline-Relations:**
* `rel: similar_to [[A]] [[B]]` wird aktuell parser-seitig nicht unterstützt.
* Workaround: Zwei separate Inline-Links `[[rel:similar_to A]] [[rel:similar_to B]]`.
2. **Unresolved Targets:**
* Kanten zu Notizen, die noch nicht existieren, werden mit `target_id="Titel"` angelegt.
* Heilung durch `scripts/resolve_unresolved_references.py` möglich.
3. **Vektor-Konfiguration für Edges:**
* `mindnet_edges` hat aktuell keine Vektoren (`vectors = null`). Eine semantische Suche *auf Kanten* ist noch nicht möglich.