315 lines
5.4 KiB
Markdown
315 lines
5.4 KiB
Markdown
# mitho AI Agent – Developer README
|
||
Enterprise Hybrid RAG System (Symfony + NDJSON + FAISS)
|
||
|
||
Stand: Februar 2026
|
||
Status: Produktiv stabil – Job-basierte Ingest-Architektur vollständig integriert
|
||
|
||
---
|
||
|
||
# 1. Systemüberblick
|
||
|
||
Dieses System implementiert eine deterministische, governance-stabile
|
||
Hybrid-RAG-Architektur mit:
|
||
|
||
- Symfony (PHP Backend)
|
||
- NDJSON als Single Source of Truth
|
||
- FAISS als Vektorindex (immer Full Rebuild)
|
||
- Hybrid Retrieval (Keyword + Vektor)
|
||
- Versioniertes Dokumentmodell
|
||
- Job-basierte Ingest-Pipeline
|
||
- Lock-geschützte Reindex-Operationen
|
||
- SSE-Streaming im Frontend
|
||
|
||
Grundprinzip:
|
||
Keine inkrementellen Vektor-Updates.
|
||
FAISS wird immer vollständig aus index.ndjson neu gebaut.
|
||
|
||
---
|
||
|
||
# 2. Architekturprinzipien
|
||
|
||
Determinismus:
|
||
- Gleiche Dokumente + gleiche Konfiguration → identisches index.ndjson
|
||
- Gleiches index.ndjson → identisches FAISS
|
||
- Gleiche Query → identisches Retrieval-Ergebnis
|
||
|
||
Governance:
|
||
- Eine aktive Version pro Dokument
|
||
- Keine impliziten Index-Änderungen
|
||
- Strukturänderungen erzwingen Global Reindex
|
||
- Keine Selbstmodifikation durch KI
|
||
|
||
Skalierbarkeit:
|
||
- NDJSON (streamingfähig)
|
||
- Keine RAM-basierte JSON-Arrays
|
||
- Zielgröße > 200k Chunks
|
||
|
||
---
|
||
|
||
# 3. Wissensspeicher
|
||
|
||
## 3.1 index.ndjson
|
||
|
||
Single Source of Truth.
|
||
|
||
- 1 JSON-Objekt pro Zeile
|
||
- Streaming-Append
|
||
- Deterministische Compaction by document_id
|
||
|
||
Beispielstruktur:
|
||
|
||
{
|
||
"chunk_id": "uuid",
|
||
"document_id": "uuid",
|
||
"document_version_id": "uuid",
|
||
"text": "...",
|
||
"meta": {...}
|
||
}
|
||
|
||
Keine JSON-Array-Datei.
|
||
Keine Mutation einzelner Chunks.
|
||
Nur Append + deterministische Entfernung per document_id.
|
||
|
||
---
|
||
|
||
## 3.2 index_meta.json
|
||
|
||
Enthält Strukturparameter:
|
||
|
||
- index_version
|
||
- embedding_model
|
||
- embedding_dimension
|
||
- chunk_size
|
||
- chunk_overlap
|
||
- scoring_version
|
||
- index_format
|
||
- vector_backend
|
||
|
||
Wenn einer dieser Werte sich ändert:
|
||
→ Global Reindex zwingend erforderlich.
|
||
|
||
---
|
||
|
||
## 3.3 FAISS
|
||
|
||
Dateien:
|
||
|
||
- vector.index
|
||
- vector_meta.json (Chunk-ID Mapping)
|
||
|
||
FAISS wird IMMER vollständig aus index.ndjson gebaut.
|
||
Keine Partial Updates.
|
||
|
||
---
|
||
|
||
# 4. Dokument- & Versionsmodell
|
||
|
||
Document
|
||
→ enthält mehrere DocumentVersion
|
||
→ genau eine Version ist aktiv
|
||
|
||
Regel:
|
||
Es darf immer nur eine aktive Version pro Dokument existieren.
|
||
|
||
Beim Aktivieren einer Version:
|
||
- Alle anderen Versionen werden inaktiv
|
||
- IngestStatus → PENDING
|
||
- Re-Ingest via Job
|
||
|
||
---
|
||
|
||
# 5. Ingest-Architektur (vollständig Job-basiert)
|
||
|
||
Ingest läuft NIEMALS synchron im HTTP-Request.
|
||
|
||
Jede Mutation am Index läuft über:
|
||
|
||
IngestJob → CLI Runner → IngestOrchestrator → IngestFlow
|
||
|
||
---
|
||
|
||
## 5.1 Job-Typen
|
||
|
||
DOCUMENT_VERSION_ACTIVATE
|
||
- Wird genutzt für:
|
||
- Version aktivieren
|
||
- Neue Datei hochladen (Auto-Ingest)
|
||
|
||
DOCUMENT
|
||
- Manuelles Ingest einer Version
|
||
|
||
GLOBAL_REINDEX
|
||
- Strukturänderungen
|
||
|
||
---
|
||
|
||
## 5.2 Job-Status
|
||
|
||
- QUEUED
|
||
- RUNNING
|
||
- COMPLETED
|
||
- FAILED
|
||
- ABORTED
|
||
|
||
Jobs werden über CLI ausgeführt:
|
||
|
||
php bin/console mto:agent:ingest:run <jobId>
|
||
|
||
Start erfolgt asynchron per exec() aus dem Controller.
|
||
|
||
---
|
||
|
||
# 6. Admin-Flows (aktueller Stand)
|
||
|
||
## 6.1 Neue Datei hochladen (NEU: Auto-Ingest)
|
||
|
||
Beim Upload:
|
||
|
||
1. Datei speichern
|
||
2. Document + Version 1 erzeugen
|
||
3. Version 1 aktiv setzen
|
||
4. IngestJob vom Typ DOCUMENT_VERSION_ACTIVATE anlegen
|
||
5. Job asynchron starten
|
||
6. Redirect auf Job-Detailseite
|
||
|
||
Ergebnis:
|
||
Neue Dokumente werden automatisch indexiert.
|
||
|
||
---
|
||
|
||
## 6.2 Version aktivieren
|
||
|
||
1. DB-Status anpassen
|
||
2. IngestStatus → PENDING
|
||
3. DOCUMENT_VERSION_ACTIVATE Job erzeugen
|
||
4. Async Runner starten
|
||
5. Redirect zur Job-Seite
|
||
|
||
---
|
||
|
||
## 6.3 Manuelles Ingest
|
||
|
||
1. DOCUMENT Job erzeugen
|
||
2. Async Runner starten
|
||
3. Redirect zur Job-Seite
|
||
|
||
---
|
||
|
||
## 6.4 Reset
|
||
|
||
Reset löscht:
|
||
|
||
- index.ndjson
|
||
- vector.index
|
||
- vector_meta.json
|
||
- Upload-Verzeichnis
|
||
- Tabellen:
|
||
- document
|
||
- document_version
|
||
- ingest_job
|
||
|
||
Nur möglich, wenn exec() aktiv ist.
|
||
|
||
---
|
||
|
||
# 7. Ingest-Flow Details
|
||
|
||
Local Ingest (ein Dokument):
|
||
|
||
1. Extract
|
||
2. Normalize
|
||
3. Chunk deterministisch
|
||
4. Entferne alte Chunks per document_id
|
||
5. Append neue Chunks
|
||
6. Full FAISS Rebuild
|
||
|
||
Global Reindex:
|
||
|
||
1. Alle aktiven Versionen neu verarbeiten
|
||
2. Komplettes index.ndjson neu schreiben
|
||
3. FAISS neu bauen
|
||
4. index_version++
|
||
|
||
---
|
||
|
||
# 8. Hybrid Retrieval
|
||
|
||
Ablauf:
|
||
|
||
User Query
|
||
→ Keyword Retrieval
|
||
→ FAISS Vector Retrieval
|
||
→ Score Fusion
|
||
→ NDJSON Chunk Lookup
|
||
→ Context Builder
|
||
→ LLM
|
||
→ SSE Streaming
|
||
|
||
Keyword ist Primärsignal.
|
||
Vector ergänzt Semantik.
|
||
|
||
---
|
||
|
||
# 9. Locking & Concurrency
|
||
|
||
LockService verhindert:
|
||
|
||
- parallelen Ingest
|
||
- gleichzeitige Reindex-Vorgänge
|
||
- NDJSON-Korruption
|
||
|
||
Keine gleichzeitigen Mutationen erlaubt.
|
||
|
||
---
|
||
|
||
# 10. CLI Commands
|
||
|
||
mto:agent:ingest:run <jobId>
|
||
mto:agent:vector:ingest
|
||
mto:agent:vector:search
|
||
|
||
Alle Commands unter:
|
||
mto:agent:*
|
||
|
||
---
|
||
|
||
# 11. Failure Modes
|
||
|
||
- Vector index fehlt → vector ingest ausführen
|
||
- index_meta mismatch → Global Reindex
|
||
- exec deaktiviert → Async-Start schlägt fehl
|
||
- Lock aktiv → Parallel-Ingest blockiert
|
||
|
||
---
|
||
|
||
# 12. Non-Goals
|
||
|
||
- Kein Online-Learning
|
||
- Keine inkrementellen FAISS Updates
|
||
- Keine selbstverändernden Prompts
|
||
- Kein Auto-Merging von Chunks
|
||
|
||
Strukturänderungen → explizit + reindex.
|
||
|
||
---
|
||
|
||
# 13. Zusammenfassung
|
||
|
||
Dieses System ist:
|
||
|
||
- deterministisch
|
||
- reproduzierbar
|
||
- drift-sicher
|
||
- governance-stabil
|
||
- enterprise-ready
|
||
- job-basiert
|
||
- versionssicher
|
||
|
||
Wichtige Neuerung:
|
||
Neue Dokumente lösen jetzt automatisch einen IngestJob aus
|
||
(exakt derselbe Mechanismus wie bei Version-Aktivierung).
|
||
|
||
Kein HTTP-Ingest mehr.
|
||
Keine Inline-Rebuilds.
|
||
Alles läuft über das Job-System.
|