2025-12-07 11:59:05 +01:00
# Mindnet v2.2 – Technische Architektur
**Datei:** `docs/mindnet_technical_architecture_v2.2.md`
**Stand:** 2025-12-07
**Status:** **FINAL** (Integrierter Stand WP01– WP04a)
**Quellen:** `mindnet_technical_architecture.md` , `chunking_strategy.md` , `Handbuch.md` , `wp04_retriever_scoring.md` , `Überarbeitungshinweise_WP03.md` , `Überarbeitungshinweise_WP04.md` .
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
> **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.
2025-11-09 21:16:56 +01:00
---
2025-11-18 10:38:03 +01:00
## 1. Systemüberblick
2025-11-09 21:16:56 +01:00
2025-12-07 11:59:05 +01:00
### 1.1 Architektur-Zielbild
2025-11-18 10:38:03 +01:00
Mindnet ist ein **persönliches Wissensnetz** . Technisch bedeutet das:
2025-12-07 11:59:05 +01:00
1. **Source:** Markdown-Notizen in einem Vault (Obsidian-kompatibel).
2. **Pipeline:** Ein Python-Importer transformiert diese in **Notes** , **Chunks** und **Edges** .
3. **Storage:** Speicherung in **Qdrant** (Vektor-Datenbank) in drei getrennten Collections.
4. **Service:** Eine FastAPI-Anwendung stellt Endpunkte für **Semantische** und **Hybride Suche** 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)
│ │ └── retriever.py # Scoring & Graph-Expansion (WP04)
│ ├── models/ # Pydantic DTOs (QueryRequest, etc.)
│ └── routers/ # API Routen
├── config/
│ ├── types.yaml # Typ-Definitionen (Import-Zeit)
│ └── retriever.yaml # Scoring-Gewichte (Laufzeit)
├── 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:**
2025-11-18 10:38:03 +01:00
```yaml
types:
concept:
chunk_profile: medium
edge_defaults: ["references", "related_to"]
2025-12-07 11:59:05 +01:00
retriever_weight: 0.60
2025-11-18 10:38:03 +01:00
```
2025-11-09 21:16:56 +01:00
2025-12-07 11:59:05 +01:00
### 3.2 Retriever-Config (`config/retriever.yaml`)
Steuert das Scoring zur Laufzeit (WP04a).
* **Inhalt:**
2025-11-18 10:38:03 +01:00
```yaml
2025-12-07 11:59:05 +01:00
scoring:
semantic_weight: 1.0
edge_weight: 0.7
centrality_weight: 0.5
2025-11-18 10:38:03 +01:00
```
2025-11-09 21:16:56 +01:00
---
2025-12-07 11:59:05 +01:00
## 4. Import-Pipeline (Markdown → Qdrant)
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
Das Skript `scripts/import_markdown.py` orchestriert den Prozess.
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
### 4.1 Verarbeitungsschritte
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
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.
2025-11-09 21:16:56 +01:00
---
2025-12-07 11:59:05 +01:00
## 5. Retriever-Architektur & Scoring
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
Der Retriever (`app/core/retriever.py`) realisiert die Logik hinter `/query` .
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
### 5.1 Betriebsmodi
* **Semantic:** Reine Vektorsuche. Schnell.
* **Hybrid:** Vektorsuche + Graph-Expansion (Tiefe N) + Re-Ranking.
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
### 5.2 Scoring-Formel (WP04a)
Die Relevanzberechnung ist nun eine gewichtete Summe:
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
$$
TotalScore = (W_{sem} \cdot S_{sem} \cdot \max(W_{type}, 0)) + (W_{edge} \cdot B_{edge}) + (W_{cent} \cdot B_{cent})
$$
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
* **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` .
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
### 5.3 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` -Graphen im Speicher, auf dem Boni berechnet werden.
2025-11-09 21:16:56 +01:00
---
2025-12-07 11:59:05 +01:00
## 6. Indizes & Performance
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
Damit Qdrant performant bleibt, sind Payload-Indizes essenziell.
2025-11-09 21:16:56 +01:00
2025-12-07 11:59:05 +01:00
**Erforderliche Indizes:**
* **Notes:** `note_id` , `type` , `tags` .
* **Chunks:** `note_id` , `chunk_id` .
* **Edges:** `source_id` , `target_id` , `kind` , `scope` , `note_id` .
2025-11-09 21:16:56 +01:00
2025-12-07 11:59:05 +01:00
Validierung erfolgt über `tests/ensure_indexes_and_show.py` .
2025-11-09 21:16:56 +01:00
---
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
## 7. Offene Punkte / Known Limitations
2025-11-18 10:38:03 +01:00
2025-12-07 11:59:05 +01:00
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.