20 KiB
Mindnet v2.4 – Technische Architektur
Datei: docs/mindnet_technical_architecture_v2.4.md
Stand: 2025-12-10
Status: FINAL (Integrierter Stand WP01–WP10 + WP07)
Quellen: Programmplan_V2.2.md, Handbuch.md, chunking_strategy.md, wp04_retriever_scoring.md.
Ziel dieses Dokuments: Vollständige Beschreibung der technischen Architektur inkl. Graph-Datenbank, Retrieval-Logik, der RAG-Komponenten (Decision Engine & Hybrid Router), des Interview-Modus und dem Frontend (Streamlit).
📖 Inhaltsverzeichnis (Klicken zum Öffnen)
- Mindnet v2.4 – Technische Architektur
- 1. Systemüberblick
- 2. Datenmodell & Collections (Qdrant)
- 3. Konfiguration
- 4. Import-Pipeline (Markdown → Qdrant)
- 5. Retriever-Architektur & Scoring
- 6. RAG & Chat Architektur (WP06 Hybrid Router + WP07 Interview)
- 7. Frontend Architektur (WP10)
- 8. Feedback & Logging Architektur (WP04c)
- 9. Indizes & Performance
- 10. Offene Punkte / Known Limitations
1. Systemüberblick
1.1 Architektur-Zielbild
Mindnet ist ein lokales RAG-System (Retrieval Augmented Generation) mit Web-Interface.
- Source: Markdown-Notizen in einem Vault (Obsidian-kompatibel).
- Pipeline: Ein Python-Importer transformiert diese in Notes, Chunks und Edges.
- 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).
- Backend: Eine FastAPI-Anwendung stellt Endpunkte für Semantische und Hybride Suche sowie Feedback bereit.
- Frontend: Streamlit-App (
ui.py) für Interaktion und Visualisierung inkl. Draft Editor. - Inference: Lokales LLM (Ollama: Phi-3 Mini) für RAG-Chat und Antwortgenerierung.
Das System arbeitet deterministisch (stabile IDs) und ist konfigurationsgetrieben (types.yaml, retriever.yaml, decision_engine.yaml, prompts.yaml).
1.2 Verzeichnisstruktur & Komponenten (Post-WP10)
/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
│ ├── routers/
│ │ ├── query.py # Such-Endpunkt
│ │ ├── chat.py # Hybrid Router & Interview Logic (WP06/07)
│ │ ├── feedback.py # Feedback-Endpunkt (WP04c)
│ │ └── ...
│ ├── services/
│ │ ├── llm_service.py # Ollama Client mit Timeout & Raw-Mode
│ │ ├── feedback_service.py # JSONL Logging (WP04c)
│ │ └── embeddings_client.py
│ ├── frontend/ # NEU (WP10)
│ └── ui.py # Streamlit Application inkl. Sanitizer
├── config/
│ ├── types.yaml # Typ-Definitionen (Import-Zeit)
│ ├── retriever.yaml # Scoring-Gewichte (Laufzeit)
│ ├── decision_engine.yaml # Strategien & Schemas (WP06/WP07)
│ └── prompts.yaml # LLM System-Prompts & Templates (WP06)
├── 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_idKeyword Stabile ID (UUIDv5 oder Slug). Frontmatter titleText Titel der Notiz. Frontmatter typeKeyword Logischer Typ (z.B. concept).types.yamlResolverretriever_weightFloat Wichtigkeit im Retrieval. types.yamlchunk_profileKeyword Genutztes Chunking-Profil. types.yamledge_defaultsList[Str] Aktive Default-Relationen. types.yamltagsList[Kw] Tags zur Filterung. Frontmatter updatedInteger Zeitstempel (z.B. YYYYMMDD...). File Stats fulltextText 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_idKeyword Deterministisch: {note_id}#c{index:02d}.note_idKeyword Referenz zur Note. typeKeyword Kopie des Note-Typs (Denormalisiert für Filter). textText Reiner Inhalt (ohne Overlap). Anzeige-Text. windowText Kontext-Fenster (mit Overlap). Embedding-Basis. ordInteger Sortierreihenfolge (1..N). retriever_weightFloat Vererbt von Note. chunk_profileKeyword Vererbt von Note. neighbors_prevList[Str] ID des Vorgänger-Chunks. neighbors_nextList[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_idKeyword Hash aus (src, dst, kind). source_idKeyword ID des Start-Chunks. target_idKeyword ID des Ziel-Chunks (oder Note-Titel). note_idKeyword Note, die diese Kante definiert. kindKeyword Art der Beziehung. references,depends_on,nextscopeKeyword Geltungsbereich. Immer "chunk"(v2.2).rule_idKeyword Herkunftsregel. explicit:wikilink,inline:relconfidenceFloat 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 (Beispiel):
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 (Beispiel):
scoring: semantic_weight: 1.0 edge_weight: 0.7 centrality_weight: 0.5
3.3 Decision Engine (config/decision_engine.yaml)
Neu in WP06/07: Steuert den Intent-Router und die Interview-Schemas.
- Definiert Strategien (
DECISION,INTERVIEW, etc.). - Definiert
schemasfür den Interview-Modus (Pflichtfelder pro Typ). - Definiert LLM-Router-Settings (
llm_fallback_enabled).
3.4 Prompts (config/prompts.yaml)
Steuert die LLM-Persönlichkeit und Templates.
- Enthält Templates für alle Strategien inkl.
interview_templatemit One-Shot Logik.
3.5 Environment (.env)
Erweiterung für LLM-Steuerung:
MINDNET_LLM_MODEL=phi3:mini
MINDNET_OLLAMA_URL=http://127.0.0.1:11434
MINDNET_LLM_TIMEOUT=300.0 # Neu: Erhöht für CPU-Inference Cold-Starts
MINDNET_DECISION_CONFIG="config/decision_engine.yaml"
4. Import-Pipeline (Markdown → Qdrant)
Das Skript scripts/import_markdown.py orchestriert den Prozess.
4.1 Verarbeitungsschritte
- Discovery & Parsing:
- Einlesen der
.mdDateien. Hash-Vergleich (Body/Frontmatter) zur Erkennung von Änderungen.
- Einlesen der
- Typauflösung:
- Laden der
types.yaml. Bestimmen des effektiven Typs und deredge_defaults.
- Laden der
- Chunking:
- Zerlegung via
chunker.pybasierend aufchunk_profile(z.B.by_heading,short,long). - Trennung von
text(Kern) undwindow(Embedding-Kontext).
- Zerlegung via
- Kantenableitung (Edge Derivation):
Die
derive_edges.pyerzeugt Kanten in strikter Reihenfolge:- Inline-Edges:
[[rel:depends_on X]]→kind=depends_on,rule_id=inline:rel,conf=0.95. - Callout-Edges:
> [!edge] related_to: [[X]]→kind=related_to,rule_id=callout:edge,conf=0.90. - Explizite Referenzen:
[[X]]→kind=references,rule_id=explicit:wikilink,conf=1.0. - Typ-Defaults: Für jede Referenz werden Zusatzkanten gemäß
edge_defaultserzeugt (z.B.project->depends_on).rule_id=edge_defaults:...,conf=0.7. - Struktur:
belongs_to,next,prev(automatisch).
- Inline-Edges:
- Upsert:
- Schreiben in Qdrant. Nutzung von
--purge-before-upsertfür saubere Updates.
- Schreiben in Qdrant. Nutzung von
5. Retriever-Architektur & Scoring
Der Retriever (app/core/retriever.py) unterstützt zwei Modi. Für den Chat wird zwingend der Hybrid-Modus genutzt.
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...")
- Berechnung des
- Output:
QueryHitenthält einexplanationObjekt mit menschenlesbarenreasonsundrelated_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. RAG & Chat Architektur (WP06 Hybrid Router + WP07 Interview)
Der Flow für eine Chat-Anfrage (/chat) wurde in WP06 auf eine Configuration-Driven Architecture umgestellt. Der ChatRouter (app/routers/chat.py) fungiert als zentraler Dispatcher.
6.1 Architektur-Pattern: Intent Router
Die Behandlung einer Anfrage ist nicht mehr hartkodiert, sondern wird dynamisch zur Laufzeit entschieden.
- Input: User Message.
- Config:
config/decision_engine.yaml(Strategien & Keywords). - Komponenten:
- Fast Path: Keyword Matching (CPU-schonend).
- Slow Path: LLM-basierter Semantic Router (für subtile Intents).
6.2 Schritt 1: Intent Detection (Hybrid)
Der Router ermittelt die Absicht (Intent) des Nutzers.
- Keyword Scan (Fast Path):
- Iteration über alle Strategien in
decision_engine.yaml. - Prüfung auf
trigger_keywords. - Best Match: Bei mehreren Treffern gewinnt das längste/spezifischste Keyword (Robustheit gegen Shadowing).
- Iteration über alle Strategien in
- LLM Fallback (Slow Path):
- Nur aktiv, wenn
llm_fallback_enabled: true. - Greift, wenn keine Keywords gefunden wurden.
- Sendet die Query an das LLM mit einem Klassifizierungs-Prompt (
llm_router_prompt). - Ergebnis:
EMPATHY,DECISION,INTERVIEW,CODINGoderFACT.
- Nur aktiv, wenn
6.3 Schritt 2: Strategy Resolution (Late Binding)
Basierend auf dem Intent lädt der Router die Parameter:
- Bei RAG (FACT/DECISION):
inject_typesfür Strategic Retrieval. - Bei INTERVIEW (WP07):
schemas(Pflichtfelder) basierend auf der erkannten Ziel-Entität (_detect_target_type).
6.4 Schritt 3: Retrieval vs. Extraction
Der Router verzweigt hier:
A) RAG Modus (FACT, DECISION, EMPATHY):
- Primary Retrieval: Hybride Suche nach der User-Query.
- Strategic Retrieval (Conditional): Wenn
inject_typesdefiniert sind, erfolgt eine zweite Suche, die explizit auf diese Typen filtert. - Merge: Ergebnisse werden dedupliziert zusammengeführt.
B) Interview Modus (INTERVIEW):
- Kein Retrieval: Der Kontext ist der Chat-Verlauf (oder initial die Query).
- Schema Injection: Das Schema für den erkannten Typ (z.B. "Project") wird geladen.
- Prompt Assembly: Der
interview_templatePrompt wird mit der Schema-Definition ("Ziel", "Status") gefüllt.
6.5 Schritt 4: Generation & Response
- Templating: Das LLM erhält den Prompt basierend auf dem gewählten Template.
- Execution: Der
LLMServiceführt den Call aus. Ein konfigurierbarer Timeout (MINDNET_LLM_TIMEOUT) fängt Cold-Start-Verzögerungen auf CPU-Hardware ab. - Response: Rückgabe enthält Antworttext (im Interview-Modus: Markdown Codeblock), Quellenliste und den erkannten
intent.
7. Frontend Architektur (WP10)
Das Frontend ist eine Streamlit-Anwendung (app/frontend/ui.py), die als separater Prozess läuft und via HTTP mit dem Backend kommuniziert.
7.1 Kommunikation
- Backend-URL: Konfiguriert via
MINDNET_API_URL(Default:http://localhost:8002). - Endpoints: Nutzt
/chatfür Interaktion und/feedbackfür Bewertungen. - Resilienz: Das Frontend implementiert eigene Timeouts (
MINDNET_API_TIMEOUT, Default 300s).
7.2 Features & UI-Logik
- State Management: Session-State speichert Chat-Verlauf und
query_id. - Visualisierung:
- Intent Badges: Zeigt Router-Entscheidung (
DECISION,INTERVIEW, etc.). - Source Expanders: Zeigt verwendete Chunks inkl. Score und "Why"-Explanation.
- Sidebar: Zeigt Suchhistorie (Log-basiert) und Konfiguration.
- Intent Badges: Zeigt Router-Entscheidung (
7.3 Draft-Editor & Sanitizer (Neu in WP10a)
Wenn der Intent INTERVIEW ist, rendert die UI statt einer Textblase den Draft-Editor.
- Parsing: Die Funktion
parse_markdown_draftextrahiert den Codeblock aus der LLM-Antwort. - Sanitization (
normalize_meta_and_body):- Prüft den YAML-Frontmatter auf unerlaubte Felder (Halluzinationen des LLMs).
- Verschiebt ungültige Felder (z.B. "Situation") in den Body der Notiz.
- Stellt sicher, dass das Markdown valide bleibt.
- Editor Widget:
st.text_areaerlaubt das Bearbeiten des Inhalts vor dem Speichern. - Action: Buttons zum Download oder Kopieren des fertigen Markdowns.
7.4 Deployment Ports
Zur sauberen Trennung von Prod und Dev laufen Frontend und Backend auf dedizierten Ports:
| Umgebung | Backend (FastAPI) | Frontend (Streamlit) |
|---|---|---|
| Production | 8001 | 8501 |
| Development | 8002 | 8502 |
8. Feedback & Logging Architektur (WP04c)
Mindnet implementiert ein "Data Flywheel" zur späteren Optimierung (Self-Tuning).
8.1 Komponenten
- Feedback Service (
app/services/feedback_service.py): Kapselt die Schreibzugriffe. - Storage: Lokales Dateisystem (
data/logs/), Format JSONL (Line-delimited JSON).
8.2 Log-Dateien
search_history.jsonl:- Speichert jede Anfrage an
/queryund/chat. - Enthält:
query_id,query_text,timestamp,hits(inkl.score_breakdownSnapshots). - Zweck: Trainingsdaten ("Was hat das System gesehen?").
- Speichert jede Anfrage an
feedback.jsonl:- Speichert User-Reaktionen an
/feedback. - Enthält:
query_id,node_id,score(1-5),comment. - Granularität: Kann sich auf
generated_answer(Global) oder eine spezifischenode_id(Quelle) beziehen. - Zweck: Labels ("War es gut?").
- Speichert User-Reaktionen an
8.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.
9. Indizes & Performance
Damit Qdrant performant bleibt, sind Payload-Indizes essenziell.
Erforderliche Indizes:
- Notes:
note_id,type,tags. - Chunks:
note_id,chunk_id,type. - Edges:
source_id,target_id,kind,scope,note_id.
Validierung erfolgt über tests/ensure_indexes_and_show.py.
10. Offene Punkte / Known Limitations
- 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]].
- Unresolved Targets:
- Kanten zu Notizen, die noch nicht existieren, werden mit
target_id="Titel"angelegt. - Heilung durch
scripts/resolve_unresolved_references.pymöglich.
- Kanten zu Notizen, die noch nicht existieren, werden mit
- Vektor-Konfiguration für Edges:
mindnet_edgeshat aktuell keine Vektoren (vectors = null). Eine semantische Suche auf Kanten ist noch nicht möglich.