Zum Hauptinhalt springen

Einheit 8 — Zustandsnormalisierung

Was du nach dieser Einheit weißt: Du verstehst warum Generative AI Agents verschachtelte Nachrichtenstrukturen erzeugen, warum das ein Problem ist und wie du mit SQL-Persistenz für saubere Zustände sorgst.


Das Problem: Verschachtelte Nachrichten​

In 42°OS fließt eine Nachricht von Agent zu Agent. Jeder Agent fügt seine Ausgabe hinzu. Das funktioniert gut — solange die Struktur flach bleibt:

{
"dateiname": "RE-2026-04523.pdf",
"kategorie": "Rechnung",
"rechnungsnummer": "RE-2026-04523"
}

Aber: Wenn ein Generative AI Agent oder ein JSON Merge Agent seine Ausgabe hinzufügt, entsteht oft eine verschachtelte Struktur:

{
"last_message": {
"last_message": {
"dateiname": "RE-2026-04523.pdf"
},
"generation": {
"kategorie": "Rechnung"
}
},
"generation": {
"rechnungsnummer": "RE-2026-04523",
"betrag": 640.00
}
}

Jetzt ist dateiname nicht mehr unter dateiname zu finden, sondern unter last_message.last_message.dateiname. Und nach dem nächsten Agent wird es last_message.last_message.last_message.dateiname.

📸 Screenshot: [Platzhalter — Run Inspector: Nachrichtenstruktur nach drei Generative AI Agents — tiefe Verschachtelung mit last_message.last_message.last_message]

Das hat Konsequenzen:

  • Pfade werden unvorhersehbar — Folge-Agents müssen wissen, in welcher Tiefe ein Feld liegt
  • Änderungen am Workflow brechen Pfade — fügst du einen Agent davor ein, verschiebt sich die gesamte Struktur
  • Debugging wird schwierig — die Nachricht ist kaum noch lesbar

📹 Video: [Platzhalter — Screencast: Verschachtelungsproblem in der Praxis — ein neuer Agent wird eingefügt und plötzlich stimmen die Pfade in allen folgenden Agents nicht mehr]


Die Lösung: Normalisierungspunkte​

Die Idee ist einfach: An definierten Stellen im Workflow schreibst du die relevanten Ergebnisse in eine Datenbank (SQLite über Internal Storage) — und der nächste Abschnitt liest nur die sauberen, flachen Daten aus der Datenbank. Die verschachtelte Nachrichtenstruktur wird damit irrelevant.

Generative AI Agent → SQL Write Agent → [Abschnittsgrenze] → SQL Read Agent → nächster Abschnitt

Vorher (ohne Normalisierung):​

{
"last_message": {
"last_message": { "dateiname": "RE-2026-04523.pdf" },
"generation": { "kategorie": "Rechnung" }
},
"generation": {
"rechnungsnummer": "RE-2026-04523",
"betrag": 640.00,
"kreditor": "Müller GmbH"
}
}

Nachher (nach Normalisierung in SQL und Rücklesen):​

{
"dateiname": "RE-2026-04523.pdf",
"kategorie": "Rechnung",
"rechnungsnummer": "RE-2026-04523",
"betrag": 640.00,
"kreditor": "Müller GmbH"
}

Flach, lesbar, vorhersehbar. Egal wie viele Agents vorher gelaufen sind — die Datenbank liefert immer dieselbe Struktur.

📸 Screenshot: [Platzhalter — Workflow-Designer: SQL Write Agent nach einem Generative AI Agent, gefolgt von einem SQL Read Agent am Anfang des nächsten Abschnitts]

📸 Screenshot: [Platzhalter — Run Inspector: Saubere, flache Nachricht nach dem Lesen aus der Datenbank]


Wann normalisieren?​

Nicht nach jedem Agent — das wäre übertrieben. Aber an diesen Stellen:

NormalisierungspunktWarum
Nach einem Generative AI AgentErzeugt generation-Verschachtelung
Nach einem JSON Merge AgentKann die Struktur verändern
An Abschnittsgrenzen (vor Source Agent)Saubere Übergabe an den nächsten Workflow
Vor komplexer WeiterverarbeitungWenn Folge-Agents auf stabile Pfade angewiesen sind

SQL Write: Was wird gespeichert?​

Du schreibst nicht die gesamte Nachricht in die Datenbank — sondern nur die Felder die du im weiteren Verlauf brauchst. Das ist gleichzeitig eine gute Übung um dir klar zu werden, welche Daten tatsächlich relevant sind.

Beispiel — SQL INSERT mit Liquid Templating:

INSERT INTO rechnungen (dateiname, kategorie, rechnungsnummer, betrag, kreditor)
VALUES (
'{{ last_message.last_message.dateiname }}',
'{{ last_message.generation.kategorie }}',
'{{ generation.rechnungsnummer }}',
{{ generation.betrag }},
'{{ generation.kreditor }}'
);

📸 Screenshot: [Platzhalter — SQL Agent Konfiguration: INSERT-Statement mit Liquid-Variablen die auf die verschachtelte Nachricht zugreifen]

Ja, die Pfade im INSERT sind verschachtelt — aber das ist das letzte Mal dass du dich mit der Verschachtelung auseinandersetzen musst. Ab dem SELECT sind die Daten flach.


SQL Read: Saubere Daten zurückholen​

Der nächste Abschnitt startet mit einem SQL SELECT:

SELECT dateiname, kategorie, rechnungsnummer, betrag, kreditor
FROM rechnungen
WHERE rechnungsnummer = '{{ rechnungsnummer }}';

Das Ergebnis ist ein flaches JSON-Objekt — unabhängig davon wie verschachtelt die Nachricht vorher war.


Vorteile auf einen Blick​

Ohne NormalisierungMit Normalisierung
Pfade werden mit jedem Agent tieferPfade sind immer flach
Einfügen eines Agents bricht FolgepfadeAbschnitte sind voneinander unabhängig
Debugging erfordert Pfad-ArchäologieDaten sind jederzeit in der DB einsehbar
Gesamter Zustand nur in der NachrichtZustand ist persistent (überlebt Fehler)

📹 Video: [Platzhalter — Screencast: Normalisierung Schritt für Schritt — Verschachtelte Nachricht → SQL Write → SQL Read → flache Nachricht]

Mehr dazu im Nachschlagewerk

Eine detaillierte Referenz zur Zustandsnormalisierung findest du in der Dokumentation unter Zustandsnormalisierung mit SQL-Persistenz.


Weiter: Übung — Teilnehmerliste abrufen, aufbereiten und abgleichen