23 KiB
Mindnet v2.6 – Technische Architektur
Datei: docs/mindnet_technical_architecture_v2.6.md
Stand: 2025-12-12
Status: FINAL (Integrierter Stand WP01–WP15: Smart Edges & Traffic Control)
Quellen: Programmplan_V2.6.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 Traffic Control Systems und dem Frontend (Streamlit).
📖 Inhaltsverzeichnis (Klicken zum Öffnen)
- Mindnet v2.6 – 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.
- Neu in v2.6: Intelligente Kanten-Zuweisung durch lokale LLMs (Smart Edge Allocation).
- 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.
- Update v2.6: Der Core arbeitet nun vollständig asynchron (AsyncIO) mit Traffic Control (Semaphore zur Lastverteilung).
- Frontend: Streamlit-App (
ui.py) für Interaktion und Visualisierung inkl. Draft Editor, Active Intelligence und Healing Parser. - Inference: Lokales LLM (Ollama: Phi-3 Mini) für RAG-Chat und Antwortgenerierung. Embedding via
nomic-embed-text.
Das System arbeitet deterministisch (stabile IDs) und ist konfigurationsgetrieben (types.yaml, retriever.yaml, decision_engine.yaml, prompts.yaml).
1.2 Verzeichnisstruktur & Komponenten (Post-WP15)
/mindnet/
├── app/
│ ├── main.py # FastAPI Einstiegspunkt
│ ├── core/
│ │ ├── ingestion.py # NEU: Async Ingestion mit Change Detection
│ │ ├── 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 # Smart Chunker Orchestrator (WP15)
│ │ ├── 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
│ │ └── dto.py # Zentrale DTO-Definition
│ ├── routers/
│ │ ├── query.py # Such-Endpunkt
│ │ ├── ingest.py # NEU: API für Save & Analyze (WP11)
│ │ ├── chat.py # Hybrid Router v5 & Interview Logic (WP06/07)
│ │ ├── feedback.py # Feedback-Endpunkt (WP04c)
│ │ └── ...
│ ├── services/
│ │ ├── llm_service.py # Ollama Chat Client mit Traffic Control (v2.8.0)
│ │ ├── semantic_analyzer.py# NEU: LLM-Filter für Edges (WP15)
│ │ ├── embeddings_client.py# NEU: Async Embeddings (HTTPX)
│ │ ├── feedback_service.py # Logging (JSONL Writer)
│ │ └── discovery.py # NEU: Intelligence Logic (WP11)
│ ├── frontend/ # NEU (WP10)
│ │ └── ui.py # Streamlit Application inkl. Healing Parser
│ └── main.py # Entrypoint der API
├── config/ # YAML-Konfigurationen (Single Source of Truth)
│ ├── types.yaml # Import-Regeln & Smart-Edge Config
│ ├── prompts.yaml # LLM Prompts & Interview Templates (WP06/07)
│ ├── decision_engine.yaml # Router-Strategien (Actions only)
│ └── retriever.yaml # Scoring-Regeln & Kantengewichte
├── data/
│ └── logs/ # Lokale Logs (search_history.jsonl, feedback.jsonl)
├── scripts/ # CLI-Tools (Import, Diagnose, Reset)
│ ├── import_markdown.py # Haupt-Importer CLI (Async)
│ ├── payload_dryrun.py # Diagnose: JSON-Generierung ohne DB
│ └── edges_full_check.py # Diagnose: Graph-Integrität
├── tests/ # Pytest Suite & Smoke Scripts
└── vault/ # Dein lokaler Markdown-Content (Git-ignored)
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.
- Update v2.4: Vektor-Dimension ist jetzt 768 (für
nomic-embed-text). - 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 provenanceKeyword Quelle der Kante (Neu in v2.6). explicit,rule,smart
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.
-
Neu in v2.6:
enable_smart_edge_allocation: (Bool) Aktiviert den LLM-Filter für diesen Typ.detection_keywords: (List) Keywords für den Hybrid Router ("Objekterkennung").
-
Inhalt (Beispiel):
types: concept: chunk_profile: sliding_standard edge_defaults: ["references", "related_to"] retriever_weight: 0.60 experience: chunk_profile: sliding_smart_edges enable_smart_edge_allocation: true detection_keywords: ["erfahrung", "erlebt"]
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.
- Definiert Strategien (
DECISION,INTERVIEW, etc.). - Update v2.6: Enthält nur noch Handlungs-Keywords (Verben wie "neu", "erstellen"). Objektnamen ("Projekt") werden nun über
types.yamlaufgelöst. - 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_templateund neurouter_prompt.
3.5 Environment (.env)
Erweiterung für LLM-Steuerung und Embedding-Modell:
MINDNET_LLM_MODEL=phi3:mini
MINDNET_EMBEDDING_MODEL=nomic-embed-text # NEU in v2.3.10
MINDNET_OLLAMA_URL=http://127.0.0.1:11434
MINDNET_LLM_TIMEOUT=300.0 # Neu: Erhöht für CPU-Inference Cold-Starts
MINDNET_API_TIMEOUT=300.0 # Neu: Timeout für Frontend-API (Smart Edges brauchen Zeit)
MINDNET_DECISION_CONFIG="config/decision_engine.yaml"
MINDNET_VAULT_ROOT="./vault" # Neu: Pfad für Write-Back
MINDNET_LLM_BACKGROUND_LIMIT=2 # Neu: Limit für parallele Hintergrund-Jobs (Traffic Control)
4. Import-Pipeline (Markdown → Qdrant)
Das Skript scripts/import_markdown.py orchestriert den Prozess.
Neu in v2.6: Der Import nutzt asyncio und Traffic Control, um Ollama nicht zu überlasten.
4.1 Verarbeitungsschritte (Async + Smart)
- Discovery & Parsing: Hash-Vergleich zur Erkennung von Änderungen.
- Typauflösung: Bestimmung des
typeviatypes.yaml. - Config Check: Laden des
chunk_profileundenable_smart_edge_allocation. - Chunking & Smart Edges (WP15):
- Zerlegung des Textes via
chunker.py. - Wenn Smart Edges aktiv: Der
SemanticAnalyzersendet Chunks an das LLM. - Traffic Control: Der Request nutzt
priority="background". Die Semaphore (Limit: 2) drosselt die Parallelität.
- Zerlegung des Textes via
- Kantenableitung (Edge Derivation):
derive_edges.pyerzeugt Inline-, Callout- und Default-Edges.
- Embedding (Async):
- Der
EmbeddingsClient(app/services/embeddings_client.py) sendet Text-Chunks asynchron an Ollama. - Modell:
nomic-embed-text(768d).
- Der
- Upsert:
- Schreiben in Qdrant. Nutzung von
--purge-before-upsert. - Strict Mode: Der Prozess bricht ab, wenn Embeddings leer sind oder Dimension
0haben.
- 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 (768d).
- 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 ist keine Blackbox mehr. Er liefert auf Wunsch (explain=True) eine strukturierte Begründung (Explanation-Objekt).
Die "Warum"-Logik:
- Semantik: Prüfung der Cosine-Similarity ("Sehr hohe textuelle Übereinstimmung").
- Typ: Prüfung des
retriever_weight("Bevorzugt, da Entscheidung"). - Graph (Kontext):
- Hub (Outgoing): Worauf verweist dieser Treffer? ("Verweist auf Qdrant").
- Authority (Incoming): Wer verweist auf diesen Treffer? ("Wird referenziert von Projekt Alpha").
Die API gibt diese Analysen als menschenlesbare Sätze (reasons) und als Datenstruktur (score_breakdown) zurück.
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 und in WP15 (v2.6) verfeinert.
6.1 Architektur-Pattern: Intent Router v5
Die Behandlung einer Anfrage ist nicht mehr hartkodiert, sondern wird dynamisch zur Laufzeit entschieden.
- Input: User Message.
- Config:
decision_engine.yaml(Strategien) +types.yaml(Objekte). - Komponenten:
- Traffic Control:
LLMServicepriorisiert Chat-Anfragen. - Question Detection: Unterscheidung Frage vs. Befehl.
- Traffic Control:
6.2 Traffic Control (Priorisierung)
Der LLMService implementiert zwei Spuren basierend auf app/services/llm_service.py (v2.8.0):
- Realtime (Chat):
priority="realtime". Umgeht die Semaphore. Antwortet sofort. - Background (Import/Analyse):
priority="background". Wartet in der Semaphore (asyncio.Semaphore), die lazy mitMINDNET_LLM_BACKGROUND_LIMITinitialisiert wird.
6.3 Schritt 1: Intent Detection (Question vs. Action)
Der Router ermittelt die Absicht (Intent) des Nutzers.
- Frage-Check: Wenn der Input ein
?enthält oder mit W-Wörtern beginnt, wird der RAG-Modus erzwungen (oder LLM-Entscheidung). Interviews werden hier unterdrückt. - Keyword Scan (Fast Path):
- Prüfung auf
trigger_keywords(Handlung) indecision_engine.yaml. - Prüfung auf
detection_keywords(Objekt) intypes.yaml. - Treffer -> INTERVIEW Modus (Erfassen).
- Prüfung auf
- LLM Fallback (Slow Path):
- Greift, wenn keine Keywords passen. Sendet Query an LLM Router.
6.4 Schritt 2: Strategy Resolution
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.5 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.6 Schritt 4: Generation & Response
- Templating: Das LLM erhält den Prompt basierend auf dem gewählten Template.
- Execution: Der
LLMServiceführt den Call mitpriority="realtime"aus. - 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:
/chat(Interaktion)/feedback(Bewertungen)/ingest/analyze(Active Intelligence / Link-Vorschläge)/ingest/save(Persistence / Speichern im Vault)
- Resilienz: Das Frontend nutzt
MINDNET_API_TIMEOUT(300s), um auf langsame Backend-Prozesse (Smart Edges) zu warten.
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 & Healing Parser (Neu in WP10a/v2.5)
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.- Healing: Erkennt und repariert defekte YAML-Frontmatter (z.B. fehlendes schließendes
---), falls das LLM unter Last Fehler macht.
- Healing: Erkennt und repariert defekte YAML-Frontmatter (z.B. fehlendes schließendes
- 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.
- Editor Widget:
st.text_areaerlaubt das Bearbeiten des Inhalts vor dem Speichern. - Save Action: Speichert über
/ingest/saveatomar in Vault und DB. Erzeugt intelligente Dateinamen viaslugify.
7.4 State Management (Resurrection Pattern)
Um Datenverlust bei Tab-Wechseln (Chat <-> Editor) zu verhindern, nutzt ui.py ein Persistenz-Muster:
- Daten liegen in
st.session_state[data_key]. - Widgets liegen in
st.session_state[widget_key]. - Callbacks (
on_change) synchronisieren Widget -> Data. - Beim Neu-Rendern wird Widget-State aus Data-State wiederhergestellt.
7.5 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
- Hardware-Last bei Smart Import:
- Der "Smart Edge" Import ist rechenintensiv. Trotz Traffic Control kann die Antwortzeit im Chat leicht steigen, wenn die GPU am VRAM-Limit arbeitet.