396 lines
6.5 KiB
Markdown
396 lines
6.5 KiB
Markdown
# mitho AI Agent – Developer README
|
||
Enterprise Hybrid RAG System (Symfony + NDJSON + FAISS + Persistent Vector Service)
|
||
|
||
Stand: Februar 2026
|
||
Status: Produktiv stabil – Job-basierte Ingest-Architektur + Persistenter Vector-Service 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)
|
||
- Persistenter Python Vector-Service (FastAPI + Uvicorn)
|
||
- 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
|
||
- Retrieval läuft über einen persistenten Service (kein Python-Spawn pro Anfrage)
|
||
|
||
---
|
||
|
||
# 2. Architekturprinzipien
|
||
|
||
## 2.1 Determinismus
|
||
|
||
- Gleiche Dokumente + gleiche Konfiguration → identisches `index.ndjson`
|
||
- Gleiches `index.ndjson` → identisches FAISS
|
||
- Gleiche Query → identisches Retrieval-Ergebnis
|
||
|
||
## 2.2 Governance
|
||
|
||
- Eine aktive Version pro Dokument
|
||
- Keine impliziten Index-Änderungen
|
||
- Strukturänderungen erzwingen Global Reindex
|
||
- Keine Selbstmodifikation durch KI
|
||
|
||
## 2.3 Skalierbarkeit
|
||
|
||
- NDJSON (streamingfähig)
|
||
- Kein RAM-basiertes JSON-Array
|
||
- Zielgröße > 200k Chunks
|
||
- FAISS Full Rebuild ist deterministisch
|
||
|
||
---
|
||
|
||
# 3. Wissensspeicher
|
||
|
||
## 3.1 index.ndjson
|
||
|
||
Single Source of Truth.
|
||
|
||
- 1 JSON-Objekt pro Zeile
|
||
- Streaming-Append
|
||
- Deterministische Compaction by `document_id`
|
||
|
||
Beispielstruktur:
|
||
|
||
```json
|
||
{
|
||
"chunk_id": "uuid",
|
||
"document_id": "uuid",
|
||
"document_version_id": "uuid",
|
||
"text": "...",
|
||
"meta": { ... }
|
||
}
|
||
```
|
||
|
||
Regeln:
|
||
|
||
- Keine JSON-Array-Datei
|
||
- Keine Mutation einzelner Chunks
|
||
- Nur Append + deterministische Entfernung per `document_id`
|
||
|
||
---
|
||
|
||
## 3.2 index_meta.json
|
||
|
||
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.index.meta.json`
|
||
- `vector_tags.index`
|
||
- `vector_tags.index.meta.json`
|
||
|
||
FAISS wird IMMER vollständig aus `index.ndjson` gebaut.
|
||
|
||
Keine Partial Updates.
|
||
Kein inkrementelles Vector-Append.
|
||
|
||
---
|
||
|
||
# 4. Persistenter Vector-Service
|
||
|
||
Retrieval läuft nicht mehr über:
|
||
|
||
- Symfony Process
|
||
- `exec()`
|
||
- `python vector_search.py` pro Anfrage
|
||
|
||
Sondern über:
|
||
|
||
**FastAPI + Uvicorn (persistent im RAM)**
|
||
|
||
## 4.1 Eigenschaften
|
||
|
||
Beim Start lädt der Service:
|
||
|
||
- Embedding-Modell
|
||
- Chunk-Index
|
||
- Tag-Index
|
||
- ID-Mappings
|
||
|
||
Diese bleiben dauerhaft im RAM.
|
||
|
||
Kein Modell-Reload pro Anfrage.
|
||
Kein Disk-Reload pro Anfrage.
|
||
Kein Python-Spawn pro Anfrage.
|
||
|
||
## 4.2 Endpoints
|
||
|
||
- `GET /health`
|
||
- `POST /search-chunks`
|
||
- `POST /search-tags`
|
||
- `POST /reload`
|
||
|
||
## 4.3 Reload-Mechanismus
|
||
|
||
Nach Global Reindex:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8090/reload
|
||
```
|
||
|
||
Lädt:
|
||
|
||
- Chunk-Index neu
|
||
- Tag-Index neu
|
||
- Modell nur wenn `embedding_model` geändert wurde
|
||
|
||
Kein Neustart nötig.
|
||
Keine Downtime.
|
||
|
||
---
|
||
|
||
# 5. Score-Gates (Routing-Sicherheit)
|
||
|
||
## 5.1 Tag-Gate
|
||
|
||
Tags steuern Routing.
|
||
|
||
Empfohlener Mindestscore:
|
||
|
||
`MIN_SCORE ≈ 0.70`
|
||
|
||
Schützt vor:
|
||
|
||
- zufälligen semantischen Treffern
|
||
- falschem Dokumentrouting
|
||
|
||
## 5.2 Chunk-Gate
|
||
|
||
Chunks sind Kontext.
|
||
|
||
Weicher Gate:
|
||
|
||
`MIN_SCORE ≈ 0.50`
|
||
|
||
Optional: relativer Score zum besten Treffer.
|
||
|
||
---
|
||
|
||
# 6. 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
|
||
|
||
---
|
||
|
||
# 7. 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
|
||
|
||
## 7.1 Job-Typen
|
||
|
||
- `DOCUMENT_VERSION_ACTIVATE`
|
||
- `DOCUMENT`
|
||
- `GLOBAL_REINDEX`
|
||
|
||
## 7.2 Job-Status
|
||
|
||
- `QUEUED`
|
||
- `RUNNING`
|
||
- `COMPLETED`
|
||
- `FAILED`
|
||
- `ABORTED`
|
||
|
||
CLI-Ausführung:
|
||
|
||
```bash
|
||
php bin/console mto:agent:ingest:run <jobId>
|
||
```
|
||
|
||
---
|
||
|
||
# 8. Hybrid Retrieval
|
||
|
||
Flow:
|
||
|
||
User Query
|
||
→ Keyword Retrieval
|
||
→ Tag Vector Search
|
||
→ Dokumentfilter
|
||
→ Chunk Vector Retrieval
|
||
→ Score Fusion
|
||
→ NDJSON Lookup
|
||
→ Context Builder
|
||
→ LLM
|
||
→ SSE Streaming
|
||
|
||
Keyword bleibt Primärsignal.
|
||
Vector ergänzt Semantik.
|
||
|
||
---
|
||
|
||
# 9. Locking & Concurrency
|
||
|
||
LockService verhindert:
|
||
|
||
- parallelen Ingest
|
||
- gleichzeitige Reindex-Vorgänge
|
||
- NDJSON-Korruption
|
||
|
||
Keine gleichzeitigen Mutationen erlaubt.
|
||
|
||
---
|
||
|
||
# 10. Vector Control (Production Safe)
|
||
|
||
Ein zentrales Kommando steuert:
|
||
|
||
- Dependency-Check
|
||
- Auto-Install (opt-in)
|
||
- Service Start
|
||
- Service Stop
|
||
- Reload
|
||
- Status
|
||
- Health-Check
|
||
- PID-Management
|
||
|
||
## Command
|
||
|
||
`mto:agent:vector:control`
|
||
|
||
## Beispiele
|
||
|
||
Status:
|
||
|
||
```bash
|
||
bin/console mto:agent:vector:control
|
||
```
|
||
|
||
Install + Start:
|
||
|
||
```bash
|
||
bin/console mto:agent:vector:control --install --start
|
||
```
|
||
|
||
Stop:
|
||
|
||
```bash
|
||
bin/console mto:agent:vector:control --stop
|
||
```
|
||
|
||
Reload:
|
||
|
||
```bash
|
||
bin/console mto:agent:vector:control --reload
|
||
```
|
||
|
||
## Production-Safety
|
||
|
||
- PID-File unter `var/run/vector_service.pid`
|
||
- SIGTERM Stop mit Timeout
|
||
- Optional SIGKILL (`--force`)
|
||
- Health-Check mit Retry-Mechanismus
|
||
- Kein automatisches Install ohne Flag
|
||
|
||
---
|
||
|
||
# 11. CLI Commands
|
||
|
||
- `mto:agent:ingest:run <jobId>`
|
||
- `mto:agent:vector:control`
|
||
- `mto:agent:test`
|
||
- `mto:agent:chat`
|
||
|
||
Alle Commands unter:
|
||
|
||
`mto:agent:*`
|
||
|
||
---
|
||
|
||
# 12. Failure Modes
|
||
|
||
Vector Service nicht erreichbar
|
||
→ `vector:control --start`
|
||
|
||
Reload Endpoint fehlt
|
||
→ falsche Service-Version
|
||
|
||
index_meta mismatch
|
||
→ Global Reindex
|
||
|
||
Lock aktiv
|
||
→ Parallel-Ingest blockiert
|
||
|
||
---
|
||
|
||
# 13. Non-Goals
|
||
|
||
- Kein Online-Learning
|
||
- Keine inkrementellen FAISS Updates
|
||
- Keine selbstverändernden Prompts
|
||
- Kein Auto-Merging von Chunks
|
||
- Kein Vector-Append im Runtime
|
||
|
||
Strukturänderungen → explizit + Reindex.
|
||
|
||
---
|
||
|
||
# 14. Zusammenfassung
|
||
|
||
Dieses System ist:
|
||
|
||
- deterministisch
|
||
- reproduzierbar
|
||
- drift-sicher
|
||
- governance-stabil
|
||
- enterprise-ready
|
||
- job-basiert
|
||
- versionssicher
|
||
- persistent im Retrieval
|
||
- ohne Spawn-Overhead
|
||
- reload-fähig ohne Downtime
|
||
|
||
Wichtige Neuerungen:
|
||
|
||
- Persistenter Vector-Service ersetzt CLI-Spawn
|
||
- Score-Gates verhindern falsches Routing
|
||
- Reload-Endpoint vermeidet Neustarts
|
||
- Production-Safe Control Command integriert
|
||
- Vollständige Trennung von Ingest und Runtime |