Zum Hauptinhalt springen

Übung: Fehlersuche im laufenden Workflow

Was du in dieser Übung lernst: Du bekommst einen Workflow, der vier Fehler enthält — jeder davon typisch, jeder davon ohne Fehlermeldung. Du findest sie ausschließlich mit den MCP-Werkzeugen und reparierst sie in der richtigen Reihenfolge.

Alle vier Fehler haben eines gemeinsam: towelscript_check meldet valid: true. Genau das macht sie gefährlich.

Der Patient

module academy

flow kontaktanfrage_defekt {
node eingang: form {
secret: "academy-kurs6-debug"
form_fields: '[{"name":"freitext","label":"E-Mail-Text","type":"textarea","rows":8,"required":true}]'
}

node extrahieren: ai {
model: "gus:tav"
output_format: "json"
prompt_template: """Extrahiere den Absender aus dem folgenden E-Mail-Text.
Gib ausschliesslich ein JSON-Objekt zurueck, ohne Einleitung und ohne Markdown.

Zielschema:
{"name": "Vor- und Nachname", "company": "Firmenname", "email": "E-Mail-Adresse oder null"}

E-Mail-Text:
{{ freitext }}"""
}

node pruefen: filter {
expected_receive_period_in_days: 365
keep_message: true
rules: [
{ type: "field==value", value: "ja", path: "email_gueltig" }
]
}

node anlegen: http.post {
post_url: "https://69cde52533a09f831b7c9fa5.mockapi.io/api/v1/contacts"
method: "post"
content_type: "json"
payload {
name: "{{ last_message.name }}",
company: "{{ last_message.company }}",
email: "{{ last_message.email }}"
}
}

eingang -> extrahieren -> pruefen -> anlegen
}

Die Absicht dahinter: Freitext entgegennehmen, Absender per KI extrahieren, nur Kontakte mit gültiger E-Mail-Adresse durchlassen, Kontakt in der API anlegen.

Teil 1: Statische Analyse

Aufgabe 1 — Prüfen, ohne zu deployen

Lass den Quelltext durch alle drei Prüfwerkzeuge laufen. Was fällt auf?

Mögliche Lösung anzeigen

towelscript_check:

{ "valid": true, "errors": [], "warnings": [],
"stats": { "lines": 38, "nodes": 4, "flows": 1, "modules": 1 } }

Vier Nodes, keine Fehler, keine Warnungen. Sieht gut aus.

towelscript_graph:

{ "flows": [ { "name": "kontaktanfrage_defekt",
"nodes": [ … vier Stück … ],
"edges": [] } ] }

edges: [] — bei vier Nodes in einer Kette erwartest du drei Kanten. Das ist Fehler 1.

towelscript_compile bestätigt es: links: [], und beim Post-Node stehen name, company und email flach neben post_url statt unter payload.

Die Ursache ist die Blockschreibweise payload { statt payload: { — sie zieht die Schlüssel flach und verhindert, dass die Verbindungszeile ausgewertet wird.

Aufgabe 2 — Fehler 1 beheben und erneut prüfen

Mögliche Lösung anzeigen
    payload: {
name: "{{ last_message.name }}",
company: "{{ last_message.company }}",
email: "{{ last_message.email }}"
}

Danach liefert graph:

"edges": [
{ "from": "eingang", "to": "extrahieren", "kind": "data" },
{ "from": "extrahieren", "to": "pruefen", "kind": "data" },
{ "from": "pruefen", "to": "anlegen", "kind": "data" }
]

Drei Kanten bei vier Nodes. Korrekt.

Merke: Fehler 1 musste zuerst weg. Solange die Agents nicht verbunden sind, produziert ein Testlauf keine Daten — und ohne Daten findest du die restlichen Fehler nicht.

Teil 2: Einzelne Agents prüfen

Aufgabe 3 — Den Post-Agent im Dry-Run testen

Teste die Post-Konfiguration virtuell, mit einer Payload, wie sie der KI-Agent liefern würde:

{
"name": "Dr. Anke Reinhardt",
"company": "Nordwerk GmbH",
"email": "a.reinhardt@nordwerk-pt.example",
"last_message": { "freitext": "Hallo zusammen, …" },
"workflow_run_id": "abc-123"
}

Was steht im Full request?

Mögliche Lösung anzeigen
body: "{\"name\":\"\",\"company\":\"\",\"email\":\"\",
\"last_message\":{\"freitext\":\"Hallo zusammen, …\"},
\"workflow_run_id\":\"abc-123\"}"

Zwei Probleme in einem Log.

Fehler 2 — falscher Liquid-Pfad. name, company und email sind leer. Der Generative AI Agent legt bei output_format: "json" die extrahierten Felder direkt auf oberster Ebene ab. Unter last_message steht die eingehende Payload — also nur freitext. {{ last_message.name }} greift ins Leere.

Richtig ist der direkte Pfad:

    payload: {
name: "{{ name }}",
company: "{{ company }}",
email: "{{ email }}"
}

Fehler 3 — fehlendes no_merge. Im Body stehen last_message und workflow_run_id, die dort nichts zu suchen haben. Ohne no_merge: true hängt der Post Agent die komplette eingehende Payload an den Request an.

    no_merge: true

Mit beiden Korrekturen:

body: "{\"name\":\"Dr. Anke Reinhardt\",
\"company\":\"Nordwerk GmbH\",
\"email\":\"a.reinhardt@nordwerk-pt.example\"}"
Hinweis zum Dry-Run virtueller Agents

Im Log eines virtuellen Post Agents tauchen zusätzlich key, something und custom_field_key auf. Das sind die Standardoptionen des Agent-Typs, die bei virtuellen Läufen mit hineingemischt werden. Bei einem real deployten Agent kommen sie nicht vor — nicht davon irritieren lassen.

Teil 3: Den echten Lauf beobachten

Aufgabe 4 — Deployen und ausführen

Deploye den korrigierten Stand und führe ihn mit einem realistischen E-Mail-Text aus. Prüfe danach: Ist ein Kontakt in der API angekommen?

Was passieren sollte

Nichts kommt an. Die API hat keinen neuen Kontakt.

Aufgabe 5 — Herausfinden, wo die Kette abreißt

Mögliche Lösung anzeigen

workflow_messages zeigt Nachrichten von eingang und von extrahieren — aber keine von pruefen.

agent_messages auf den KI-Agent bestätigt, dass die Extraktion funktioniert hat:

{
"name": "Dr. Anke Reinhardt",
"company": "Nordwerk Präzisionstechnik GmbH",
"email": "a.reinhardt@nordwerk-pt.example",
"last_message": { "freitext": "…" }
}

Der Filter lässt also nichts durch. Ein Blick auf seine Regel:

rules: [
{ type: "field==value", value: "ja", path: "email_gueltig" }
]

Fehler 4 — die Filterregel prüft ein Feld, das es nicht gibt. Der Prompt fordert name, company und email an — von email_gueltig steht dort nichts. Das Feld existiert in keiner Nachricht, die Bedingung ist nie erfüllt, der Filter blockt alles.

Es gibt zwei saubere Lösungen. Entscheide dich bewusst:

A — Das Feld erzeugen. Erweitere Zielschema und Prompt um das Feld und passe die Regel an den tatsächlichen Datentyp an:

Zielschema:
{"name": "…", "company": "…", "email": "…",
"email_gueltig": "true wenn die E-Mail ein @ und eine Domain mit Punkt enthaelt, sonst false"}

B — Auf dem vorhandenen Feld prüfen. Statt eines abgeleiteten Kennzeichens direkt die Adresse prüfen:

rules: [
{ type: "regex", value: "@", path: "email" }
]

Variante B ist die robustere: ein Feld weniger, das die KI erfinden kann. Das ist genau die Abwägung aus Kurs 5, Einheit 7 — LLM oder Regel.

Aufgabe 6 — Reparieren und mit denselben Daten nachtesten

Korrigiere den Filter und teste erneut — ohne das Formular neu auszufüllen.

Mögliche Lösung anzeigen
  1. workflow_update mit dem korrigierten Quelltext — mit name und description, sonst heißt der Workflow danach „Workflow"
  2. workflow_messages aufrufen und die ID der ursprünglichen Eingangsnachricht heraussuchen
  3. message_reemit mit dieser ID
{ "success": true, "message": "Message 29213 re-emitted as 29215" }

Danach agent_logs auf den Post-Agent:

Received response status 201

Und in der API steht der Kontakt.

Der Vorteil gegenüber einem neuen Formulareintrag: identische Eingangsdaten. Du vergleichst die Reparatur gegen exakt denselben Fall, der vorher gescheitert ist.

Teil 4: Nachbereiten

Aufgabe 7 — Die vier Fehler einordnen

Trage zusammen, welches Werkzeug jeden Fehler gefunden hat.

Mögliche Lösung anzeigen
#FehlerGefunden durchSymptom
1payload { statt payload: {towelscript_graphedges: []
2Liquid-Pfad last_message.nameagent_test_run → Logleere Felder im Body
3no_merge fehltagent_test_run → LogFremdfelder im Body
4Filterregel auf nicht existierendes Feldworkflow_messages + workflow_showKette bricht am Filter ab

Zwei Beobachtungen:

  • towelscript_check hat keinen einzigen der vier Fehler gefunden. valid: true heißt: der Text lässt sich lesen. Mehr nicht.
  • Die Fehler mussten in dieser Reihenfolge behoben werden. Ohne Verbindungen keine Nachrichten, ohne Nachrichten kein Filter-Verhalten zu beobachten. Fehlersuche ist schichtweise: erst Struktur, dann einzelne Agents, dann der Fluss.

Aufgabe 8 — Aufräumen

Lösche deinen Testkontakt aus der API und exportiere den Workflow, bevor du ihn löschst.

Daraus eine Regel machen

Die vier Fehler sind keine Einzelfälle, sondern die vier häufigsten. Nimm sie in deine CLAUDE.md auf:

## TowelScript-Regeln
- Verschachtelte Optionen IMMER mit Doppelpunkt: `payload: { … }`
- Nach jeder Änderung `towelscript_graph` prüfen: edges = nodes − 1
- Bei `ai` mit `output_format: "json"` liegen die Felder OBEN, nicht unter `last_message`
- Post Agent: `no_merge: true`, wenn nur die Payload-Felder gesendet werden sollen
- Filterregeln nur auf Felder, die nachweislich in einer echten Nachricht vorkommen
- `workflow_update` immer mit `name` und `description`

Was du jetzt kannst

  • Fehler finden, die keine Fehlermeldung erzeugen
  • Statische Prüfung, Einzeltest und Laufbeobachtung in der richtigen Reihenfolge einsetzen
  • Aus einem Full request-Log auf die Ursache schließen
  • Eine Reparatur gegen exakt denselben Fall verifizieren, der vorher gescheitert ist

Weiter: Einheit 11 — Sicherheit und Grenzen