Technischer Deep Dive für Arbeitgeber – Narraboros Engine.
Narraboros ist eine neuro-symbolische Engine für interaktive Literatur mit einer strengen Architekturregel: Laravel und MySQL besitzen die Zustands- und Logikhoheit, das Sprachmodell ist ein zustandsloser Renderer. Das LLM erhält pro Zug einen neu zusammengestellten, relationalen Weltzustands-Snapshot als Single-Shot-Prompt – es gibt keinen akkumulierenden Chatverlauf. Das Modell kann Weltzustände ausschließlich über strukturierte, schema-gebundene Tool-Calls vorschlagen; die Übernahme in die Datenbank erfolgt über das Backend. Die Grenze ist ehrlich mitzudenken: Konsistenz hängt weiterhin von der Auswahl der Kontextdaten, den Backend-Prüfungen und dem Verhalten des Modells ab. Die Architektur macht Zustandsfehler aber sichtbar, überprüfbar und korrigierbar, statt sie im Prompt zu verstecken.
Turn-Lifecycle im Detail
Getrennte Laravel-Pipelines bereiten den Kontext vor und verarbeiten die Modellantwort nach.
Die Orchestrierung ist vollständig per Ereignis-System erweiterbar: Dritt-Code kann Pipeline-Stages vor dem Aufruf ergänzen oder umordnen, ohne den Kern zu ändern.
Prompt-Architektur
Statischer Teil
Unveränderliche Regie-Regeln (Erzähler-Haltung, Pacing-Protokolle, Agency-Split, Zustandsformate). Pro Anfrage aus einer Blade-View gerendert und als System-Instruktion übergeben; laut Code-Dokumentation durch Kompaktierung etwa halbiert.
Dynamischer Teil
Pro Zug wird der Snapshot über eine geordnete Pipeline von Stages aufgebaut: PII-Scrub, Purge volatile States, History, Config, Area-Location, Faktvalidierung, Charaktertabellen, aktive Szene, Story-Engine, Beziehungen, Memory-System, RNG-Block – abschließend ein Cleanup-Schritt.
Auszug aus der Produktions-Codebasis (PromptBuilder)
$dynamicPipelines = [
DynamicPiiScrubber::class, // PII-Filterung vor Prompt & Persistenz
DynamicPurgeVolatile::class, // Abgelaufene Zustände verwerfen
DynamicLoadHistoryLog::class, // Verdichtete Turn-Historie
DynamicConfig::class,
DynamicLoadAreaLocation::class, // Zonen-Kanon & Grenzen
DynamicValidateFacts::class, // Faktvalidierung gegen DB
DynamicTableChar::class,
DynamicActiveScene::class,
DynamicRunStoryEngine::class,
DynamicLoadRelationship::class,
DynamicLoadMemorySystem::class,
DynamicFormatRngBlock::class, // Server-Entropie für diesen Zug
];
Die gerenderten Prompt-Teile werden vor dem Versand maschinell kompaktiert (Normalisierung, Entfernen von Leerzeilen und Formatter-Artefakten), damit der Kontext pro Zug dicht und planbar bleibt.
Selbsteinschätzung des Modells zu Konsistenzrisiken.
Fehlt der narrativetext, gilt der Zug als nicht erzählt und die gesamte Nachverarbeitungspipeline wird übersprungen. Safety-Einstellungen und Provider-Optionen werden payload-seitig gesetzt, nicht im Freitext.
Relationaler Weltzustand (MySQL)
Kern-Tabelle story_states mit den Feldern story_id, category, key, value, expires_at und ttl_counter. Die Kategorien und ihre Lebenszyklen sind als Zustandsmodell in der Engine vorgesehen:
Defensives Parsing: LLM-Ausgaben werden nicht blind ĂĽbernommen. FĂĽr beobachtete Namensabweichungen des Modells bei Kategorien und Keys sind Reparatur-Maps vorgesehen, die Abweichungen normalisieren, bevor sie die Datenbank erreichen.
Auszug aus der Produktions-Codebasis (Orchestrator)
$isPermanent = Str::startsWith($category, 'char_');
$canBeDeleted = !$isPermanent;
if ($action === 'delete_value' && !$canBeDeleted) {
return $this->actionLog(
"Löschung des permanenten States (Kategorie: {$category}) für {$key} blockiert."
);
}
Hinweis zur Präzision: set_value setzt expires_at derzeit auf ein Jahr nach der Änderung, auch bei char_*. Ob und wie dieser Zeitstempel zur Bereinigung oder Kontextauswahl verwendet wird, ist aus den vorliegenden Dateien nicht ersichtlich.
Serialisierung: Komplexe Zustände werden über ein Shorthand-Format ([key=value][key2=value2] Beschreibung) als lineare Strings übertragen. Der Parser im Backend trennt System-Präfixe strikt vom Erzähltext; Klammern im Prosatext bleiben unberührt.
Guardrails & SchutzmaĂźnahmen
Eingabe-Einordnung
Nutzertext wird per Prompt-Regel ausschlieĂźlich als player_intent (Handlungsabsicht der Spielfigur) behandelt; Anweisungen im Freitext sollen die Engine-Logik nicht erreichen. Das ist eine Prompt-Leitlinie in Kombination mit Backend-PrĂĽfung, kein formaler Sicherheitsnachweis.
PII-Scrubbing
Eigene Pipeline-Stufe zur Filterung realer Identifikatoren vor Prompt-Ăśbergabe und Persistenz.
Strukturierter RĂĽckkanal
Zustandsänderungen laufen als strukturierte Felder über das Tool-Schema in die Nachverarbeitungspipeline – das Modell hat keinen direkten Schreibzugriff auf die Datenbank.
Safety-Konfiguration
Content-Filter-Kategorien werden pro Payload gesetzt und sind vom Nutzer nicht ĂĽberschreibbar.
Resilienz & Fehlerbehandlung
Kapselung: Der Modell-Aufruf läuft in einer rescue()-Klammer; im Fehlerfall wird der Zustand am Story-Modell vermerkt (request_exception), das Anfrage-Flag zurückgesetzt und der Ergebnis-Cache verworfen.
Fehler-Typisierung: Der Orchestrator definiert eine Klassifikation von API-Fehlern (Rate-Limit, Timeout, Safety-Block, Ăśberlast, Verbindungsfehler) ĂĽber HTTP-Code und Fehlertext.
AusfĂĽhrungs-Budget: Pro Zug wird das PHP-AusfĂĽhrungslimit an ein 30-Sekunden-Budget plus Puffer gekoppelt.
Anfrage-Flag & Cache: request_at markiert die in Bearbeitung befindliche Anfrage pro Geschichte; verarbeitete Ergebnisse werden stundenweise gecacht, vor einem neuen Zug verworfen.
Kosten- & Kontext-Engineering
Kontextdisziplin: Kein wachsender Chatverlauf – der Token-Umfang pro Zug ist an den Snapshot gebunden und planbar. Dauerhaft gespeicherte Fakten und verdichtete Runden-Zusammenfassungen können wachsen, sind aber kuratierte Daten.
Prompt-Kompaktierung: Statischer Kern laut Code-Dokumentation ca. halbiert; der dynamische Prompt wird vor Versand maschinell verdichtet.
Per-Nutzer-Modellkonfiguration: Modell und Payload-Optionen werden pro Nutzer aufgelöst; die produktseitige Abrechnungseinheit (Narra pro Runde) ist Teil der Produktdokumentation.
Entropie aus dem Server: RNG-Werte stammen aus Laravel; das Modell dokumentiert Auswahl und Nutzung der Werte in einer eigenen BegrĂĽndungsspur.
Telemetrie & Drift-Ăśberwachung
Modell-seitige drift_telemetry und serverseitige Tool-Telemetrie pro Zug.
Heuristische Aufmerksamkeits-Risikoanalyse des zusammengestellten Prompts (derzeit als Debug-Instrument ausgelegt).
Qualitätssicherung
Die Pipeline-Architektur (jede Stufe eine isolierte Klasse mit definiertem Ein- und Ausgabedatum) ist deterministisch testbar: LLM-Adapter lassen sich in Unit- und Feature-Tests durch Mocks ersetzen, sodass Zustandskonsolidierung, defensives Parsing und Guardrail-Prüfungen ohne API-Kosten und reproduzierbar geprüft werden können. Debug-Flags schalten Prompt-Inspektion im Betrieb frei.
Compliance (DSGVO / EU AI Act)
Laut Projektspezifikation: EU-Hosting der Inferenz ĂĽber Google Cloud Vertex AI (EU-Region) inkl. Auftragsverarbeitung, Zero-Data-Retention-Policy fĂĽr die API-Calls, PII-Scrubbing als Pipeline-Stufe (im Code eingebunden) sowie kryptografische Kennzeichnung generierter Ausgaben (C2PA fĂĽr Bilder, signierte JSON-LD-Manifeste fĂĽr Text, Metadaten in PDF-Exporten). Diese Punkte folgen der Spezifikation und sind anhand der vorliegenden CodeauszĂĽge nicht geprĂĽft.
Ehrliche Einordnung: Grenzen des Ansatzes
Probabilistisch bleibt probabilistisch: Mikro-Details (Atmosphäre, erfundene Requisiten, Dialog) sind generativ. Makrofakten wie Bereichsgrenzen, Inventar und gespeicherte Veränderungen werden im Backend geführt und dem Modell als Kontext bereitgestellt; ihre korrekte Übernahme in die Erzählung bleibt prüfbedürftig.
Soft-Fails by Design: Scheitern ist diegetisch inszeniert (klemmendes Schloss), nicht hart blockiert – ein bewusster Produktentscheid.
Reparatur-Maps wachsen mit beobachteten Modellfehlern: Defensives Parsing ist ein lebendes System, kein statisches Schema.