Files
MtoRagSystem/README.md
2026-05-11 19:05:52 +02:00

558 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# README.md
# RetrieX v1.6.0
> Hinweis: Das System wird fachlich als **RetrieX** bezeichnet.
> Im Repository existieren aus historischen Gründen noch einzelne Bezeichner wie `RAG`, `rag.zip` oder `RAG_SYSTEM_OVERVIEW.md`.
## Überblick
RetrieX ist ein dokumentenbasiertes Assistenzsystem auf Basis von Retrieval-Augmented Generation. Version 1.6.0 kombiniert den stabilisierten RAG-/Commerce-Kern mit einer produktionsnäheren Chat-/Admin-Architektur.
Das System beantwortet Nutzeranfragen nicht frei, sondern kombiniert:
- versionierte Wissensdokumente
- deterministische Ingest- und Indexierungslogik
- hybrides Retrieval mit Tag-Routing
- optionale Shopware-Live-Produktsuche
- YAML-gestützte Intent-, Language-, Vocabulary-, Prompt- und Commerce-Regeln
- LLM-basierte Antwortformulierung
- SSE-Streaming für die Browserausgabe
- getrennte Chat- und Adminbereiche mit Rollenmodell
- Admin-Benutzerverwaltung und Access-Denied-/Fehlerseiten
Der aktuelle Stand ist kein generischer Chatbot, sondern eine kontrollierte Wissens-, Antwort- und Betriebs-Pipeline.
---
## Technologiestack
### Backend
- PHP 8.2
- Symfony 7.4
- Doctrine ORM / Doctrine Migrations
- Symfony Messenger
- Symfony HttpClient
- Twig
### Python-Layer
- SentenceTransformers
- FAISS
- FastAPI
- uvicorn
### Zusätzliche Libraries
- `fivefilters/readability.php` für URL-Inhaltsauswertung
- `smalot/pdfparser` für PDF-Textgewinnung
- `league/commonmark` für Markdown-Rendering
---
## Kernidee des Systems
RetrieX trennt klar zwischen:
1. **Primärquellen**
Dokumente, Dokumentversionen, aktive System-Prompts, Modellkonfigurationen, optionale Shopware-Daten
2. **Index- und Retrieval-Ebene**
`index.ndjson`, `index_meta.json`, `index_runtime.json`, `vector.index`, `tags.ndjson`, `vector_tags.index`
3. **Orchestrierung**
Anfrageannahme, Kontextaufbau, URL-Analyse, Retrieval, Commerce-Erkennung, Shopquery-Reparatur, Prompt-Aufbau, Streaming
4. **Ausgabe**
Chat-Frontend, SSE-Stream, Statuskarten, Shopkarten, Quellenchips und kontextsensitive Folgeaktionen
5. **Betrieb und Governance**
Chat-/Admin-Security, Rollenmatrix, Userverwaltung, Fehlerseiten, Konfigurationsvalidierung, Source-Audits und Regressionstests
---
## Version 1.6.0 wesentliche Neuerungen gegenüber 1.5.x
### Chat- und Admin-Architektur
- Der Chat läuft über `App\Controller\Chat\ChatController`.
- `/` und `/chat` rendern `templates/chat/index.html.twig`.
- Die frühere statische `public/index.html` ist entfernt.
- Admin-Routen bleiben unter `/admin...` getrennt.
- Chat-Login und Chat-Logout laufen über `/chat/login` und `/chat/logout`.
### Rollen und Security
RetrieX nutzt weiterhin eine gemeinsame User-Entity, trennt aber die Bereichsrechte:
| Rolle | Zweck |
| --- | --- |
| `ROLE_CHAT_USER` | Zugriff auf Chat, Ask/SSE, History und Frontend-Messages |
| `ROLE_ADMIN_AREA` | Zugriff auf Adminbasis, Dashboard, Guides und Jobübersicht |
| `ROLE_EDITOR` | Dokumente, Versionen, Tags und Dokument-Ingest |
| `ROLE_KNOWLEDGE_ADMIN` | Modell-/Retrieval-Konfiguration lesen/testen und Ingest-Profile ansehen |
| `ROLE_SUPER_ADMIN` | Userverwaltung, Systembereiche, Logs, Reset/Delete, Global Reindex und kritische Umschaltungen |
Die Hierarchie ist in `config/packages/security.yaml` definiert. `ROLE_USER` ist nur technische Basisrolle und schaltet keinen Bereich allein frei.
### Admin-Benutzerverwaltung
`ROLE_SUPER_ADMIN` kann Benutzer im Adminbereich verwalten:
- Benutzerliste
- Benutzer anlegen
- Benutzer bearbeiten
- Rollen zuweisen
- Passwort setzen/zurücksetzen
- Benutzer aktivieren/deaktivieren
- Schutz gegen Selbst-Aussperren
- Schutz des letzten aktiven Super-Admins
Deaktivierte Benutzer werden beim Login über `ActiveUserChecker` blockiert und bestehende Sessions über `ActiveUserSessionSubscriber` beendet.
### Fehler- und Access-Denied-UX
Version 1.6.0 enthält konsistente Fehlerseiten für:
- 403 / fehlende Rolle
- 404 / Route nicht gefunden
- 500 / Serverfehler
- generische Fehlerfälle
Der `AccessDeniedHandler` zeigt bei falschem Bereich die benötigte Rolle, den aktuellen Benutzer und sinnvolle Rücksprung- bzw. Logout-Optionen.
### Commerce- und Follow-up-Präzision
Die Commerce-Logik wurde weiter gehärtet:
- Shopqueries entfernen stärker Sprach-, Satz- und Relationsrauschen.
- Tippfehlerkorrekturen aus `commerce.yaml` bleiben in der finalen Query erhalten.
- Direkte Produktnamen wie `chlor select sensor` bleiben erhalten.
- Modellkürzel wie `Testomat LAB CL` werden nicht mehr auf `testomat` reduziert.
- Exakte Zubehör-/Indikatorcodes wie `300` werden nicht mit Varianten wie `300 S` vermischt.
- Mehrprodukt-Follow-ups werden in Einzelqueries aufgeteilt.
- Preis-Folgeaktionen nutzen sichtbare Produktidentitäten inklusive Produktnummern.
- Schwache referenzielle Shopfragen wie „suche im Shop nach der Information“ können auf den letzten konkreten Produktanker aus der History zurückfallen.
- Wiederholende Folgeaktions-Loops werden unterdrückt, wenn die materialisierte Query identisch mit der aktuellen Query ist.
---
## Unterstützte Dokumentformate
Der verifizierte aktuelle Loader unterstützt:
- PDF
- TXT
- MD
Wichtig: Im aktuellen Code-Stand ist kein produktiver DOCX-Loader in der eigentlichen Ingest-Pipeline sichtbar. Dokumentation und Tests sollten deshalb bewusst nur die real verifizierten Formate nennen.
---
## Laufzeitfluss einer Browser-Anfrage
Der aktuelle Chat nutzt bevorzugt den Job-basierten SSE-Flow:
1. Frontend sendet `POST /ask-jobs` mit Prompt und optionalem Kontextflag.
2. `AskSseController` legt einen Antwort-Job an.
3. Frontend öffnet `GET /ask-sse/{jobId}`.
4. `AgentRunner` orchestriert die Anfrage.
5. Optional wird URL-Inhalt aus der Nutzerfrage extrahiert.
6. `NdjsonHybridRetriever` holt Wissenskontext.
7. Optional erkennt `CommerceIntentLite` Commerce-/Shop-Intent.
8. Shopquery wird optimiert, bereinigt, ggf. repariert und über Shopware gesucht.
9. `PromptBuilder` baut den finalen LLM-Prompt.
10. `OllamaClient` streamt die Modellantwort.
11. Chunks werden als SSE-Events ins Frontend gesendet.
12. Der Turn wird in der Gesprächshistorie persistiert.
Zusätzlich existiert weiterhin `POST /ask-sse` als direkter Streaming-Endpunkt.
---
## Gesprächskontext
`ContextService` verwaltet die Konversationshistorie dateibasiert.
Eigenschaften:
- Historie wird pro stabiler Client-ID gespeichert.
- abgeschlossene Turns werden append-only geschrieben.
- regulärer Kontext und Full-Context sind getrennt vorgesehen.
- Browser-Anfragen nutzen standardmäßig budgetierten bzw. regulären Kontext.
- Full-Context muss explizit über `fullContext` angefordert werden.
Aktuelle Standardwerte aus `config/retriex/runtime.yaml`:
- regulärer sichtbarer Kontext: letzte 25 Zeilen
- Full-Context: letzte 500 Zeilen
---
## URL-Auswertung
Wenn im Prompt eine URL vorkommt, extrahiert `UrlAnalyzer` den Inhalt der ersten URL.
Aktuelle Eigenschaften:
- Timeout-basiertes Laden
- `Readability`-basierte Extraktion des lesbaren Inhalts
- HTML wird entfernt
- Whitespace wird normalisiert
- Ausgabe wird auf maximal 5000 Zeichen begrenzt
Der extrahierte Text wird als zusätzlicher unterstützender Wissensblock in den finalen Prompt aufgenommen.
---
## Ingest- und Indexarchitektur
### Zielbild
RetrieX nutzt eine deterministische Ingest-Architektur mit NDJSON als operativer Wissensbasis und FAISS als Vektorindex.
### Zentrale Dateien
- `var/knowledge/index.ndjson`
- `var/knowledge/index_meta.json`
- `var/knowledge/index_runtime.json`
- `var/knowledge/vector.index`
- `var/knowledge/vector.index.meta.json`
- `var/knowledge/tags.ndjson`
- `var/knowledge/vector_tags.index`
- `var/knowledge/vector_tags.index.meta.json`
### `index.ndjson`
Operative Chunk-Basis des Systems:
- eine JSON-Zeile pro Chunk
- streamingfähig
- geeignet für append und full rewrite
- Grundlage für den Vector-Rebuild
### `index_meta.json`
Struktur-Metadaten des Index, u. a.:
- `index_version`
- `created_at`
- `chunk_size`
- `chunk_overlap`
- `embedding_model`
- `embedding_dimension`
- `scoring_version`
- weitere Strukturfelder aus der aktiven Index-Konfiguration
### `index_runtime.json`
Laufzeitdaten, u. a.:
- `chunk_count`
- `last_rebuild_at`
- optionale Commit-Marker wie `last_tags_rebuild_at`
---
## Dokument-Lifecycle
Der aktuelle Dokumentfluss ist technisch so aufgebaut:
1. Dokumentversion wird aktiviert oder ingestiert.
2. Guardrails prüfen die Strukturverträglichkeit.
3. Alte Chunks des Dokuments werden entfernt.
4. Neue Chunks werden streamingfähig geschrieben.
5. Der komplette Vektorindex wird neu gebaut.
6. Runtime-Stats werden atomar aktualisiert.
7. Status der Version wird auf `INDEXED` gesetzt.
Wichtige Eigenschaft:
- Pro Dokument gibt es fachlich eine aktive Version.
- Chunks sind abgeleitete Artefakte, keine Primärdaten.
---
## Ingest-Services
### `GuardrailValidator`
Prüft über `IndexMetaManager`, ob der aktuelle Index strukturell zur aktiven Konfiguration passt. Wenn relevante Strukturparameter geändert wurden, wird lokaler Ingest blockiert.
### `ChunkWriteService`
Kapselt die Schreibzugriffe auf den Chunk-Bestand:
- Gesamtanzahl zählen
- Chunks nach `document_id` kompaktieren
- neue Chunks anhängen
- vollständigen Rewrite durchführen
### `VectorRebuildService`
Führt den vollständigen FAISS-Rebuild aus und aktualisiert anschließend die Runtime-Metadaten.
### `IngestFlow`
Orchestriert:
- Dokument-Ingest
- Global Reindex
- Dokumentlöschung inklusive Rebuild
---
## Retrieval
Der aktive Retriever ist:
- `App\Knowledge\Retrieval\NdjsonHybridRetriever`
„Hybrid“ bedeutet im aktuellen Code eine orchestrierte Kombination aus mehreren Retrieval-Schritten.
### Aktuelle Retrieval-Pipeline
1. Query Cleaning
2. Query Enrichment
3. Intent-Erkennung
4. Katalog-/Listenrouting
5. Tag-Routing auf Kandidatendokumente
6. globale Vektorsuche
7. optionale gescopte Vektorsuche auf Kandidatendokumente
8. Fusion der Treffer
9. Selektion der finalen Chunk-IDs
10. Laden der finalen Chunk-Texte aus NDJSON
### Verwendete Bausteine
- `QueryCleaner`
- `QueryEnricher`
- `IntentLite`
- `SalesIntentLite`
- `CatalogIntentLite`
- `IntentRouteResolver`
- `TagRoutingService`
- `VectorSearchClient`
- `NdjsonChunkLookup`
### Besondere Logiken
- Listenfragen werden gesondert erkannt.
- Kataloganfragen können direkt einen Katalogblock statt regulärer Chunks liefern.
- globale und gescopte Treffer werden gefused.
- Chunk-Selektion ist dokument- und abstandsbegrenzt.
- Exakte Auswahlfragen, Tabellen-/Indikatorfragen und Grenzwertfragen haben eigene Präzisionspfade.
---
## Vektor-Layer
### Komponenten
- `python/vector/vector_ingest.py`
- `python/vector/vector_search.py`
- `python/vector/vector_service.py`
### Betriebsmodus
Der produktive Zugriff erfolgt primär über den HTTP-basierten Vector-Service.
Service-URL im aktuellen Default:
- `http://127.0.0.1:8090`
### Aufgaben des Vector-Service
- Embedding-Modell laden
- FAISS-Hauptindex laden
- Tag-Index laden
- Suchanfragen für Chunks beantworten
- Suchanfragen für Tags beantworten
- Reloads auf neue Indexstände ermöglichen
Der Python-Service hält Modell und Indizes persistent im RAM, um wiederholte Suchanfragen deutlich schneller zu bedienen.
---
## Prompt-Aufbau
`PromptBuilder` setzt den finalen LLM-Prompt aus diesen Blöcken zusammen:
1. **SYSTEM**
Aktiver System-Prompt aus der Datenbank
2. **CONVERSATION CONTEXT (authoritative)**
Gesprächshistorie des Nutzers
3. **LIVE SHOP RESULTS (authoritative for products)**
Shopware-Treffer, falls Commerce aktiv ist
4. **RETRIEVED KNOWLEDGE (supporting)**
Wissens-Chunks aus dem Retriever
5. **CONTENT FROM URL (supporting)**
Optional extrahierter URL-Inhalt
6. **USER QUESTION**
Aktuelle Nutzerfrage
Für Produktfragen behandelt das System Shopdaten explizit als führende Produktquelle. Fachliche Eignungsaussagen bleiben dennoch an RAG-/Kontextbelege und Prompt-Guardrails gebunden.
---
## Commerce- und Shopware-Integration
RetrieX besitzt eine optionale Shopware-Store-API-Integration.
### Aktivierung
Die Shop-Suche wird nur genutzt, wenn `CommerceIntentLite` eine passende Anfrage erkennt.
Mögliche Zustände:
- `none`
- `product_search`
- `advisory_product_search`
### Aktueller Shop-Flow
1. Commerce-Intent erkennen.
2. LLM erzeugt zunächst eine kurze Shop-Suchphrase.
3. `CommerceQueryParser` normalisiert und bereinigt die Query.
4. Follow-up-/History-/RAG-Anker können die Query ergänzen.
5. `SearchRepairService` kann fehlende oder zu enge Shopqueries reparieren.
6. `ShopwareCriteriaBuilder` baut Suchkriterien.
7. `StoreApiClient` ruft `/store-api/search` auf.
8. Ergebnisse werden zu `ShopProductResult` gemappt.
9. Ergebnisidentität und Rollenlogik filtern zu breite Treffer.
10. Ergebnisse fließen in Prompt, Statuskarten und Folgeaktionen ein.
### Wichtige Präzisionsregeln in v1.6.0
- Exakte Artikelnummern und Produktnummern werden bevorzugt.
- Exakte Zubehörcodes bleiben exakt.
- Produktlisten-Follow-ups werden in Einzelqueries aufgeteilt.
- Produktidentität wird über Name, URL, Artikelnummer und sichtbare Antwortprodukte abgesichert.
- Schwache Shop-Meta-Fragen dürfen auf konkrete History-Anker zurückfallen.
- Shop-only Antworten bleiben vorsichtig, wenn keine belastbare technische Eignung belegt ist.
---
## Antwort-Streaming
Die Browserausgabe erfolgt per Server-Sent Events.
### Eigenschaften des aktuellen SSE-Flows
- Job-basierter Stream über `/ask-jobs` und `/ask-sse/{jobId}`
- direkter Legacy-Stream über `POST /ask-sse`
- Reconnect-/Replay-Unterstützung über Event-IDs
- Stale-Job-Erkennung
- Output Buffer werden aktiv geleert
- Cookies werden vor Streamstart weitergereicht
- Chunks werden direkt als SSE `data:`-Zeilen übertragen
- Zeilenumbrüche bleiben erhalten
- am Ende wird ein `done`-Event gesendet
---
## Projektstruktur
Die zentralen Verzeichnisse im aktuellen Stand sind:
- `src/`
- `config/`
- `templates/`
- `migrations/`
- `python/`
- `public/`
- `var/`
- `bin/`
### Wichtige Bereiche in `src/`
- `Agent/`
- `Commerce/`
- `Config/`
- `Context/`
- `Controller/Chat/`
- `Controller/Admin/`
- `Index/`
- `Ingest/`
- `Intent/`
- `Knowledge/`
- `Routing/`
- `Security/`
- `Shopware/`
- `Tag/`
- `Vector/`
---
## Wichtige Commands
Verifizierte relevante Commands im aktuellen Stand:
- `mto:agent:chat`
- `mto:agent:ingest:run`
- `mto:agent:ingest:version`
- `mto:agent:vector:control`
- `mto:agent:vector:rebuild`
- `mto:agent:vector:health`
- `mto:agent:tags:export`
- `mto:agent:tags:rebuild`
- `mto:agent:tags:job:run`
- `mto:agent:tag:health`
- `mto:agent:system:rebuild`
- `mto:agent:config:validate`
- `mto:agent:config:audit-source`
- `mto:agent:config:audit-patterns`
- `mto:agent:config:dump-effective`
- `mto:agent:regression:test`
- `mto:agent:test:shop-search`
- `mto:agent:test-vector`
- `mto:agent:user:create`
### Vector-Service steuern
```bash
bin/console mto:agent:vector:control --status
bin/console mto:agent:vector:control --install --start --reload
```
### Empfohlene Standardchecks nach Patches
```bash
php bin/console cache:clear
php bin/console lint:yaml config/packages/security.yaml config/retriex
php bin/console lint:twig templates
php bin/console mto:agent:config:validate
php bin/console mto:agent:regression:test
php bin/console mto:agent:config:audit-source --details
php bin/console mto:agent:config:audit-patterns --details
```
---
## Developer Policies / Governance
Die YAML-only-Migration gilt als abgeschlossen, solange diese Checks grün bleiben:
```bash
php bin/console mto:agent:config:validate
php bin/console mto:agent:config:audit-source --details
php bin/console mto:agent:config:audit-patterns --details
php bin/console mto:agent:regression:test
```
Entwickler müssen `DEVELOPER_POLICIES.md` beachten.
Kernregeln:
- YAML unter `config/retriex/` ist die Source of Truth für konfigurierbares Verhalten.
- Keine neuen PHP-only-semantischen Defaults, Tokenlisten, Prompttexte, Matching-Regeln oder Business-Fallbacks.
- Neues konfigurierbares Verhalten muss über YAML ergänzt und explizit verdrahtet werden.
- Regression-sensitive Flows aus den stabilen 1.4.x/1.5.x/1.6.0-Baselines müssen geschützt bleiben.
- Core-Pattern- und Source-Audits sollen Domainlisten im PHP-Core verhindern.