Zum Hauptinhalt springen

Code-Tool (Python)

Führt Python-Code aus, um Daten in einem Workflow zu transformieren, zu berechnen oder zu prüfen. Du bindest einen Workflow-Tool-Knoten an ein gespeichertes Tool vom Typ code_tool.

Überblick

Im Workflow-Designer liegt Logik häufig in einem Tool-Knoten. Wählst du dort ein Code-Tool, editierst du im zugehörigen Tool ein Python-Snippet (Monaco unterstützt Python). Nach dem Speichern führt die Plattform deinen Code serverseitig aus: Die Funktion heißt immer handler, ihr Argument data ist ein Dictionary aus den Eingaben, die du unter Ein (genauer: dem Eingabe-Schema im Tool-Editor) im UI definiert hast.

Das Rückgabe-Objekt muss zur Aus-Konfiguration deines Tools passen. Üblich sind ein Objekt result (deine fachlichen Daten) und console für optionale Begleittexte bei der Diagnose — sofern dein Schema im Editor genau so vorgibt. Abweichen die Keys oder Datentypen, schlägt der Lauf aus Sicht der Plattform fehl („Schema / Validierung”) und der Workflow nimmt seinen Fehlerpfad.

Zweck

Geeignet für: feste Berechnungen, Normalisierung, Filter, Datenprüfung und sonstige deterministische Schritte ohne freies LLM-Reasoning nach außen.

Nicht JavaScript

Der Editor erwartet Python, keine Browser-/Node-JavaScript-Schritte. Externe Systeme erreichst du über Integrationen oder andere Tool-Knoten im Workflow-Graphen, verkabelt dort, wo es passt — nicht durch „nachgebautes fetch“ nur in diesem Schritt.

Für KI-aufwändige Fälle

Freitext, Deutungen und offene Gesprächslogik sind besser einem Agenten- oder LLM-Knoten überlassen — das Code-Tool bleibt bewusst regelbasiert und auditier­bar.

Wann du einen Code-Tool-Knoten nutzen solltest

Sinnvoll, wenn:

  • Vorherige Schritte (z. B. Eingaben, andere Tools, Trigger) haben dir strukturierte Daten, die du weiterverarbeiten willst.
  • Du Berechnungen, Zuordnungen, Filter oder Validierungen brauchst, die nicht „raten“, sondern einem festen Regelwerk folgen.

Eher nicht ideal, wenn:

  • Du explorative oder sprachorientierte Arbeit brauchst → Agent / Knowledge / entsprechende Knoten nach eurem Setup.
  • Du eine neue externe Schnittstelle brauchst → zuerst Integration / eigenes Tool; im Code-Schritt nur auswerten, was über den Graphen schon angekommen ist.

So arbeitest du mit einem Code-Tool (im Produkt)

  1. Tool anlegen (oder Revision bearbeiten) und Typ code_tool wählen.
  2. Eingabe und Ausgabe dort pflegen — das sind die Feldlisten bzw. Schemas im Tool-Editor. Was du hier festlegst, steht später als Keys unter data bzw. muss beim return eingehalten werden.
  3. Python-Implementierung: def handler(data): oder async def handler(data): — Rückgabe als Dictionary passend zur Aus-Konfiguration.
  4. Workflow zeichnen: Tool-Knoten einfügen, dein Code-Tool aus der Bibliothek wählen und Ausgaben der Vorgänger per Kanten oder Schema-Mapping dort verbinden, wo die Oberfläche es anbietet.

Ohne gültiges Eingabe/Aus-Paar aus UI und Code gibt es keine belastbare Produktionslage — erst Editor, dann Knoten verkabeln.

Was dein Handler sieht

ElementKurz beschrieben
dataZusammenführung der Werte entsprechend eurer Ein-Felder nach dem Mapping aus dem Graphen
Optional asyncFür async/await in Python möglich, wenn du Bibliotheken brauchst, die asynchron sind — zurück kommt weiter ein passend strukturiertes Dictionary

print-Zeilen können eingeschränkt in einer Konsole/Begleitanzeige auftauchen — zuverlässig für Folgeschritte bleiben saubere result-Strukturen nach eurem Aus-Schema.

Signatur:

def handler(data: dict):
return {
"result": {...}, # fachlicher Inhalt laut Aus-Schema
"console": "", # wenn vorgesehen
}

Beispiele (visuelle Schemas + Code)

Schemas sind hier nicht als JSON, sondern als Feldtabellen und kleine Schaubilder dargestellt — im Tool-Editor setzt du die technische Form dort konsistent zur Tabelle um.

Zuverlässige Schemas

Gleiche Feldnamen + Typdisziplin in Ein, Aus und handler; sonst wird der Lauf abgebrochen.

Statistiken auf einer Zahlenliste

Eingabe (Ein)

FeldTypPflicht
scoresListe von Zahlenja

Visual:

Ein (Auszug)

scores ──► [zahl, zahl, zahl, …] (Pflicht)

Ausgabe unter result

FeldTypPflicht
averageZahlja
maxZahlja
minZahlja
gradeTextja

Zusätzlich je nach Aus-Schema häufig oberhalb: console als Textfeld (kann leer sein).

def handler(data):
scores = data.get("scores") or []
if not scores:
return {
"result": {"average": 0.0, "max": 0.0, "min": 0.0, "grade": "n/a"},
"console": "scores empty",
}

total = sum(scores)
average = total / len(scores)
maximum = max(scores)
minimum = min(scores)

if average >= 90:
grade = "A"
elif average >= 80:
grade = "B"
else:
grade = "C"

return {
"result": {
"average": round(average, 2),
"max": maximum,
"min": minimum,
"grade": grade,
},
"console": "",
}

Daten validieren & normalisieren

Eingabe (Ein)

FeldTypPflicht
emailTextja
amountZahlja

Visual:

email ───────► Zeichenfolge
amount ───────► Dezimalzahl
def handler(data):
email = data.get("email", "")
amount = float(data.get("amount", 0))

if "@" not in email:
raise ValueError("E-Mail-Adresse enthält kein gültiges @")

if amount <= 0:
raise ValueError("Betrag muss größer als 0 sein")

return {
"result": {
"email": email.strip().lower(),
"amount": round(amount, 2),
"validated": True,
},
"console": "",
}

Listen filtern & vereinheitlichen

Angenommene Ein-Struktur (vereinfacht)

FeldInhalt
customersListe von Einträgen mit u. a. firstName, lastName, email, status, totalSpent, id

Visual:

customers[] ──► { id, firstName, lastName, email, status, totalSpent, … }
def handler(data):
customers = data.get("customers") or []
active = [c for c in customers if c.get("status") == "active"]

processed = []
for customer in active:
first = customer.get("firstName", "")
last = customer.get("lastName", "")
processed.append({
"id": customer.get("id"),
"fullName": f"{first} {last}".strip(),
"email": (customer.get("email") or "").lower(),
"tier": "premium" if customer.get("totalSpent", 0) > 1000 else "standard",
})

premiums = sum(1 for row in processed if row["tier"] == "premium")
return {
"result": {
"customers": processed,
"total": len(processed),
"premium_count": premiums,
},
"console": "",
}

Datumsberechnungen (Standardbibliothek)

Eingabe (Ein)

FeldBeschreibung
eventsListe von Objekten mit mindestens timestamp als ISO‑Zeichenkette sowie beliebige weitere Keys

Visual:

events[] ────► jedes Objekt enthält timestamp (ISO‑8601 …)
└── weitere Felder optional mit durchgereicht
from datetime import datetime, timezone


def handler(data):
events = data.get("events") or []
now = datetime.now(timezone.utc)
enriched = []

for event in events:
iso = datetime.fromisoformat(event["timestamp"].replace("Z", "+00:00"))
delta_days = round((iso - now).total_seconds() / 86400, 2)
enriched.append({
**event,
"days_until_start": delta_days,
"is_upcoming": delta_days >= 0,
"localized": iso.astimezone().strftime("%A, %d.%m.%Y %H:%M"),
})

return {
"result": {
"events": enriched,
"total": len(enriched),
"next_count": sum(1 for item in enriched if item["is_upcoming"]),
},
"console": "",
}

Daten weiterreichen im Workflow

Im Canvas verbindest du Ausgaben vorgelagerter Knoten mit den Eingabenfeldern deines Code-Tools über die angebotenen Zuordnungen. Strukturiere result so klar, dass der nächste Knoten ohne Raten weiß, welchen Key er liest — mit der Oberflächen-Zuordnung, ohne separate Template-Sprache.

Robustheit und Lesbarkeit

  • Standardwerte: (data.get("feld") oder Default) verhindert None-Überraschungen.
  • Klar formulieren bei Regelbruch (ValueError), damit Fehlermeldungen im Betrieb wiedererkenbar bleiben.
  • Zu viel Geschäftslogik in einem Schritt: lieber über mehrere Knoten aufteilen statt einen «Gott-Handler» zu bauen.

Nächste Schritte