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.
Geeignet für: feste Berechnungen, Normalisierung, Filter, Datenprüfung und sonstige deterministische Schritte ohne freies LLM-Reasoning nach außen.
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.
Freitext, Deutungen und offene Gesprächslogik sind besser einem Agenten- oder LLM-Knoten überlassen — das Code-Tool bleibt bewusst regelbasiert und auditierbar.
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)
- Tool anlegen (oder Revision bearbeiten) und Typ
code_toolwählen. - Eingabe und Ausgabe dort pflegen — das sind die Feldlisten bzw. Schemas im Tool-Editor. Was du hier festlegst, steht später als Keys unter
databzw. muss beimreturneingehalten werden. - Python-Implementierung:
def handler(data):oderasync def handler(data):— Rückgabe als Dictionary passend zur Aus-Konfiguration. - 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
| Element | Kurz beschrieben |
|---|---|
data | Zusammenführung der Werte entsprechend eurer Ein-Felder nach dem Mapping aus dem Graphen |
Optional async | Fü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.
Gleiche Feldnamen + Typdisziplin in Ein, Aus und handler; sonst wird der Lauf abgebrochen.
Statistiken auf einer Zahlenliste
Eingabe (Ein)
| Feld | Typ | Pflicht |
|---|---|---|
scores | Liste von Zahlen | ja |
Visual:
Ein (Auszug)
scores ──► [zahl, zahl, zahl, …] (Pflicht)
Ausgabe unter result
| Feld | Typ | Pflicht |
|---|---|---|
average | Zahl | ja |
max | Zahl | ja |
min | Zahl | ja |
grade | Text | ja |
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)
| Feld | Typ | Pflicht |
|---|---|---|
email | Text | ja |
amount | Zahl | ja |
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)
| Feld | Inhalt |
|---|---|
customers | Liste 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)
| Feld | Beschreibung |
|---|---|
events | Liste 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)verhindertNone-Ü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
- Workflow Grundlagen: Workflows Überblick · Canvas-Aufbau
- Weitere Knoten: Knotenkatalog