Zum Hauptinhalt springen

Formularvalidierungsskript

Kurzfassung: Formularvalidierungsskripte werden ausgeführt, nachdem alle individuellen Feldvalidierungen auf einem Formular-Knoten bestanden wurden, um eine Validierung über mehrere Felder hinweg, Wertänderungen und Formularablehnungen mit LLM-Feedback zu ermöglichen. Verwenden Sie sie, um Beziehungen zwischen Feldern zu validieren (z. B. Enddatum > Startdatum), Werte vor dem Speichern zu transformieren oder ganze Formulare mit beschreibenden Fehlermeldungen abzulehnen, die das LLM zur Wiederholung anleiten.

Ein Formularvalidierungsskript ist ein benutzerdefiniertes Python-Skript, das auf Formularebene ausgeführt wird, nachdem alle individuellen Extraktionsfeldvalidierungen bestanden wurden. Im Gegensatz zu Feldvalidierungsskripten, die einzelne Werte isoliert validieren, können Formularvalidierungsskripte auf alle extrahierten Werte gleichzeitig zugreifen, was sie ideal für komplexe Validierungslogik macht, die mehrere Felder umfasst.

Warum Formularvalidierungsskripte verwenden?​

Formularvalidierungsskripte geben Ihnen präzise Kontrolle über die endgültige Validierungsstufe der Formular-Extraktion. Anstatt nur Felder einzeln zu validieren, können Sie:

  • Validierung über mehrere Felder hinweg - Stellen Sie sicher, dass Beziehungen zwischen mehreren Feldern gültig sind (z. B. Enddatum nach Startdatum, Passwortbestätigung stimmt mit Passwort überein)
  • Werttransformation - Validierte Werte vor dem Speichern ändern oder anreichern (z. B. Gesamtsummen berechnen, Formate standardisieren)
  • Durchsetzung von Geschäftsregeln - Komplexe Geschäftslogik anwenden, die mehrere Feldwerte erfordert
  • Formularablehnung - Das gesamte Formular mit einer beschreibenden Fehlermeldung ablehnen, die an das LLM zur Wiederholung zurückgegeben wird
  • Dynamische Validierung - Gesprächsverlauf oder externe Daten zur Validierung des Formulars verwenden

Wann Formularvalidierung vs. Feldvalidierung verwenden​

Verwenden Sie Formularvalidierungsskripte, wenn:

  • Sie Beziehungen zwischen mehreren Feldern validieren müssen
  • Die Validierungslogik von Kombinationen von Werten abhängt
  • Sie mehrere Felder basierend auf anderen Feldwerten ändern möchten
  • Geschäftsregeln die Bewertung der vollständigen Formulardaten erfordern

Verwenden Sie Feldvalidierungsskripte (auf individuellen Extraktionsfeldern), wenn:

  • Die Validierung für jedes Feld unabhängig ist
  • Jedes Feld isoliert validiert werden kann
  • Sie möchten, dass die Validierung ausgeführt wird, sobald das LLM dieses spezifische Feld extrahiert

Best Practice: Beginnen Sie mit der Feldvalidierung für einfache Überprüfungen und fügen Sie die Formularvalidierung nur hinzu, wenn Sie Logik über mehrere Felder hinweg benötigen. Dies hält Ihre Validierung modular und einfacher zu warten.

Erstellen eines Formularvalidierungsskripts​

Schritt 1: Öffnen Sie Ihren Formular-Knoten​

  1. Navigieren Sie zu Inhalt → Flows
  2. Öffnen Sie den Flow, der Ihren Formular-Knoten enthält
  3. Klicken Sie auf den Formular-Knoten, dem Sie eine Validierung hinzufügen möchten

Formular-Knoten-Editor

Schritt 2: Formularvalidierung aktivieren​

  1. Scrollen Sie nach unten zum Abschnitt Formularvalidierungsskript am unteren Rand des Formular-Knoten-Editors
  2. Schalten Sie den Formularvalidierung aktiv-Schalter um, um ihn zu aktivieren
  3. Der Code-Editor erscheint mit einer Standardvorlage

Formularvalidierungsabschnitt

Schritt 3: Schreiben Sie Ihre Validierungslogik​

Die Standardvorlage bietet die grundlegende Struktur:

from shared import RemoteLLMTrackerApi
from shared import FormValidator
from loguru import logger
from typing import Any

class form_validator(FormValidator):
async def run(
self,
tracker_api: RemoteLLMTrackerApi,
validated_slots: dict[str, Any]
) -> dict[str, Any]:
"""
Formularvalidierung auf Formularebene, die nach dem Bestehen aller Feldvalidierungen ausgeführt wird.

Args:
tracker_api: Voller Zugriff auf Gesprächsverlauf, Slots, LLM-Aufrufe
validated_slots: Dict von slot_name -> validated_value

Returns:
Das validierte (und möglicherweise modifizierte) Slots-Dict

Raises:
ValueError: Wenn die Validierung fehlschlägt, mit beschreibender Fehlermeldung
"""
# Beginnen Sie hier mit dem Codieren

# Beispiel-Validierungslogik
is_valid = True

if not is_valid:
# Standard-Formular-Agent gibt diesen Fehler an das LLM
raise ValueError("Formularvalidierung fehlgeschlagen")

return validated_slots

Schritt 4: Speichern und Bereitstellen​

  1. Klicken Sie auf Speichern, um Ihr Skript als Entwurf zu speichern
  2. Klicken Sie auf Bereitstellen, um Ihr Validierungsskript zu aktivieren
  3. Das Skript wird nun jedes Mal ausgeführt, wenn dieser Formular-Knoten die Extraktion abschließt

Hinweis: Wie andere Skripte unterstützen Formularvalidierungsskripte den Entwurfsmodus und das Versionsmanagement. Siehe Skripte für Details zur Verwaltung von Skriptversionen.

Wie Formularvalidierung funktioniert​

Ausführungsablauf​

Wenn ein Formular-Knoten Daten extrahiert, folgt der Validierungsprozess dieser Sequenz:

1. Benutzer gibt Eingaben ein
↓
2. LLM extrahiert Feldwerte (Werkzeugaufruf)
↓
3. Pydantic-Typvalidierung (automatische Typkonvertierung)
↓
4. Einzelne Feldvalidierungen werden ausgeführt (falls aktiv)
↓
5. ✨ Formularvalidierungsskript wird ausgeführt (falls aktiv) ✨
↓
6. Werte werden in Slots gespeichert ODER Formular wird mit Fehler abgelehnt

Erfolgsszenario​

Wenn Ihr Formularvalidator das validated_slots-Dict zurückgibt, ohne eine Ausnahme auszulösen:

  1. Alle Slots werden mit ihren (möglicherweise modifizierten) Werten gespeichert
  2. Der Formular-Knoten wird erfolgreich abgeschlossen
  3. Ein FormValidationSuccessEvent wird in den Ereignispuffer gesendet
  4. Der Bot fährt mit dem nächsten Knoten im Flow fort

Fehlerszenario​

Wenn Ihr Formularvalidator eine ValueError auslöst:

  1. Alle Slots für dieses Formular werden auf None zurückgesetzt (außer dem speziellen __form__-Slot)
  2. Die Fehlermeldung aus der ValueError wird an das LLM zurückgesendet
  3. Ein FormValidationErrorEvent wird in den Ereignispuffer gesendet
  4. Das LLM erhält den Fehler als Funktionsaufruf-Feedback und kann mit korrigierten Werten erneut versuchen

Beispiel-Fehlerablauf:

# Ihr Validator löst einen Fehler aus
raise ValueError("Enddatum muss nach dem Startdatum liegen. Bitte geben Sie gültige Daten an.")

# LLM erhält: "Fehler beim Ausführen von book_appointment mit den folgenden Fehlern:
# - __form__: Enddatum muss nach dem Startdatum liegen. Bitte geben Sie gültige Daten an."

# LLM antwortet dem Benutzer: "Entschuldigung, aber das Enddatum muss nach dem Startdatum liegen. Könnten Sie bitte ein gültiges Enddatum angeben?"

Häufige Anwendungsfälle​

1. Validierung über mehrere Felder hinweg​

Validieren Sie Beziehungen zwischen mehreren Feldern:

async def run(self, tracker_api, validated_slots):
# Datumsbereichsvalidierung
if validated_slots['end_date'] < validated_slots['start_date']:
raise ValueError(
"Das Enddatum muss nach dem Startdatum liegen. "
"Bitte geben Sie gültige Daten an."
)

# Passwortbestätigung
if validated_slots.get('password') != validated_slots.get('password_confirm'):
raise ValueError(
"Das Passwort und das Bestätigungspasswort stimmen nicht überein. "
"Bitte versuchen Sie es erneut."
)

# Menge vs. Verfügbarkeit
if validated_slots['quantity'] > validated_slots['available_stock']:
raise ValueError(
f"Es sind nur {validated_slots['available_stock']} Einheiten verfügbar. "
f"Bitte reduzieren Sie Ihre Menge."
)

return validated_slots

2. Werttransformation​

Ändern Sie Werte vor dem Speichern:

async def run(self, tracker_api, validated_slots):
# Abgeleitete Werte berechnen
num_days = (validated_slots['end_date'] - validated_slots['start_date']).days
validated_slots['total_price'] = num_days * validated_slots['daily_rate']

# Textwerte normalisieren
validated_slots['email'] = validated_slots['email'].lower().strip()
validated_slots['country_code'] = validated_slots['country_code'].upper()

# Telefonnummern formatieren
phone = validated_slots['phone_number'].replace('-', '').replace(' ', '')
validated_slots['phone_number'] = f"+1-{phone[:3]}-{phone[3:6]}-{phone[6:]}"

return validated_slots

3. Bedingte Validierung​

Anwenden von Validierungsregeln basierend auf anderen Feldwerten:

async def run(self, tracker_api, validated_slots):
# Länderspezifische Validierung
if validated_slots['country'] == 'US':
if not validated_slots.get('zip_code'):
raise ValueError(
"Postleitzahl ist für US-Adressen erforderlich. "
"Bitte geben Sie Ihre Postleitzahl an."
)
if len(validated_slots['zip_code']) != 5:
raise ValueError(
"US-Postleitzahlen müssen 5 Ziffern haben. "
"Bitte geben Sie eine gültige Postleitzahl an."
)

# Altersbasierte Validierung
if validated_slots['age'] < 18:
if not validated_slots.get('parent_consent'):
raise ValueError(
"Elterliche Zustimmung ist für Benutzer unter 18 Jahren erforderlich. "
"Bitte bestätigen Sie die elterliche Zustimmung."
)

return validated_slots

4. Externe API-Validierung​

Externe Dienste aufrufen, um Formulardaten zu validieren:

async def run(self, tracker_api, validated_slots):
import aiohttp

# Überprüfen, ob die E-Mail bereits registriert ist
email = validated_slots['email']
async with aiohttp.ClientSession() as session:
async with session.get(
f"https://api.example.com/check-email?email={email}"
) as response:
if response.status == 200:
data = await response.json()
if data['exists']:
raise ValueError(
f"Die E-Mail {email} ist bereits registriert. "
"Bitte verwenden Sie eine andere E-Mail oder melden Sie sich an."
)

# Adresse mit Geocoding-API validieren
address = validated_slots['address']
# ... Validierungslogik

return validated_slots

5. Komplexe Geschäftsregeln​

Umfassende Geschäftslogik implementieren:

async def run(self, tracker_api, validated_slots):
# Preisstufenberechnung
quantity = validated_slots['quantity']
base_price = validated_slots['unit_price']

if quantity >= 100:
discount = 0.20 # 20% Rabatt
elif quantity >= 50:
discount = 0.10 # 10% Rabatt
elif quantity >= 10:
discount = 0.05 # 5% Rabatt
else:
discount = 0

validated_slots['discount_percent'] = discount * 100
validated_slots['total_price'] = quantity * base_price * (1 - discount)

# Kreditlimit validieren
customer_credit_limit = tracker_api.get_slot("customer_credit_limit")
if customer_credit_limit:
if validated_slots['total_price'] > customer_credit_limit:
raise ValueError(
f"Ihr Bestellwert (${validated_slots['total_price']:.2f}) "
f"übersteigt Ihr Kreditlimit (${customer_credit_limit:.2f}). "
"Bitte reduzieren Sie Ihre Bestellmenge oder kontaktieren Sie den Vertrieb."
)

return validated_slots

Best Practices​

1. Halten Sie die Validierungslogik einfach und fokussiert​

Ihr Formularvalidator sollte zuverlässig und leicht verständlich sein:

Gut:

# Klare, zielgerichtete Überprüfungen
if validated_slots['end_date'] < validated_slots['start_date']:
raise ValueError("Enddatum muss nach dem Startdatum liegen")

if validated_slots['age'] < 18:
raise ValueError("Sie müssen 18 Jahre oder älter sein, um sich zu registrieren")

Vermeiden:

# Übermäßig komplexe verschachtelte Logik
if (validated_slots['field1'] and
(validated_slots['field2'] or validated_slots['field3']) and
not validated_slots.get('field4', None) and
some_complex_calculation(validated_slots) > threshold):
# Schwer zu verstehen und zu warten

2. Schreiben Sie klare Fehlermeldungen​

Fehlermeldungen werden an das LLM zurückgegeben, das sie verwendet, um den Benutzer zu führen. Machen Sie sie konversationell und spezifisch:

Gut:

raise ValueError(
"Das Enddatum (15. Juni) muss nach dem Startdatum (20. Juni) liegen. "
"Bitte geben Sie ein gültiges Enddatum an, das nach dem 20. Juni liegt."
)

Vermeiden:

raise ValueError("Ungültiger Datumsbereich")  # Zu vage
raise ValueError("end_date <= start_date") # Zu technisch

3. Behandeln Sie fehlende optionale Felder​

Überprüfen Sie immer, ob optionale Felder existieren, bevor Sie sie validieren:

# Sicher - überprüft, ob das Feld existiert
if validated_slots.get('optional_field'):
# Validieren Sie das optionale Feld
pass

# Unsicher - wird KeyError auslösen, wenn das Feld nicht existiert
if validated_slots['optional_field']: # ❌ Nicht so machen
pass

4. Wichtige Validierungsereignisse protokollieren​

Verwenden Sie Protokollierung, um Validierungsprobleme zu debuggen:

from loguru import logger

async def run(self, tracker_api, validated_slots):
logger.info(f"Formularvalidierung gestartet mit {len(validated_slots)} Feldern")

try:
# Validierungslogik
if some_condition:
logger.warning("Validierung fehlgeschlagen: Bedingung X nicht erfüllt")
raise ValueError("...")

logger.info("Formularvalidierung erfolgreich")
return validated_slots
except Exception as e:
logger.error(f"Formularvalidierungsfehler: {e}")
raise

5. Minimieren Sie externe API-Aufrufe​

Externe API-Aufrufe erhöhen die Latenz und potenzielle Fehlerquellen. Verwenden Sie sie sparsam:

Überlegen:

  • Kann die Validierung mit lokalen Daten durchgeführt werden?
  • Ist der API-Aufruf für jede Formulareinreichung notwendig?
  • Was passiert, wenn die API langsam oder nicht verfügbar ist?

Wenn Sie APIs verwenden müssen:

# Zeitüberschreitungen festlegen
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=5)) as session:
try:
async with session.get(url) as response:
# Antwort verarbeiten
pass
except asyncio.TimeoutError:
logger.warning("API-Zeitüberschreitung, fortfahren ohne Validierung")
# Entscheiden: Validierung fehlschlagen oder fortfahren?

6. Ändern Sie Slots nicht direkt über tracker_api​

Obwohl Sie Zugriff auf tracker_api.set_slot() haben, vermeiden Sie es, dies in Formularvalidierungen zu verwenden. Ändern Sie stattdessen das validated_slots-Dict:

Gut:

# Das zurückgegebene Dict ändern
validated_slots['calculated_field'] = some_value
return validated_slots

Vermeiden:

# Slots nicht direkt im Validator setzen
tracker_api.set_slot('calculated_field', some_value) # ❌

Warum? Der Formular-Agent verwaltet die Slot-Zuweisung. Direkte Änderungen der Slots können zu einem inkonsistenten Zustand führen.

7. Testen Sie Randfälle​

Berücksichtigen und testen Sie Szenarien wie:

  • Alle Felder auf Mindestwerten
  • Alle Felder auf Höchstwerten
  • Grenzbedingungen (z. B. genau gleiche Daten)
  • Leere optionale Felder
  • Sonderzeichen in Textfeldern
  • Sehr große oder sehr kleine Zahlen

8. Verwenden Sie Typ-Hinweise​

Typ-Hinweise verbessern die Lesbarkeit des Codes und fangen Fehler ab:

from typing import Any
from datetime import datetime

async def run(
self,
tracker_api: RemoteLLMTrackerApi,
validated_slots: dict[str, Any]
) -> dict[str, Any]:
start_date: datetime = validated_slots['start_date']
end_date: datetime = validated_slots['end_date']

# Ihre Validierungslogik mit klaren Typen
return validated_slots

Fehlertypen und Behandlung​

ValueError - Validierung fehlgeschlagen​

Verwenden Sie ValueError, wenn die Validierung aufgrund von Geschäftslogik fehlschlägt:

if condition_not_met:
raise ValueError("Beschreibende Nachricht für das LLM")

Ergebnis:

  • Alle Formularslots werden auf None zurückgesetzt
  • Fehlermeldung wird an das LLM gesendet
  • FormValidationErrorEvent wird gesendet
  • LLM kann mit korrigierten Werten erneut versuchen

Andere Ausnahmen - Ausführungsfehler​

Jeder andere Ausnahmetyp zeigt einen Skriptfehler an:

# Nicht behandelte Ausnahme
result = some_api_call() # Löst ConnectionError aus

Ergebnis:

  • Alle Formularslots werden auf None zurückgesetzt
  • Generische Fehlermeldung wird gesendet
  • FormValidationErrorEvent wird mit Ausführungsfehlerstatus gesendet
  • Fehler wird zur Fehlerbehebung protokolliert

Best Practice: Fangen und behandeln Sie erwartete Ausnahmen, indem Sie sie in ValueError mit benutzerfreundlichen Nachrichten umwandeln:

try:
result = await external_api_call()
except aiohttp.ClientError as e:
logger.error(f"API-Aufruf fehlgeschlagen: {e}")
raise ValueError(
"Ihre Informationen können derzeit nicht überprüft werden. "
"Bitte versuchen Sie es in einem Moment erneut."
)

Überwachung und Debugging​

Ereignisse​

Das System sendet Ereignisse, die Sie überwachen können:

Erfolgsevent:

FormValidationSuccessEvent(
payload=FormValidationSuccessPayload(
form_name="book_appointment",
validated_slots={
"start_date": "2024-06-01",
"end_date": "2024-06-15",
# ... andere Slots
}
)
)

Fehlerevent:

FormValidationErrorEvent(
payload=FormValidationErrorPayload(
form_name="book_appointment",
validation_status=ValidationFailureStatus(
message="Enddatum muss nach dem Startdatum liegen",
value={...} # Die versuchten Slot-Werte
),
failed_slots={
"start_date": "Fehler bei der Validierung des Formulars",
"end_date": "Fehler bei der Validierung des Formulars",
"__form__": "Enddatum muss nach dem Startdatum liegen"
}
)
)

Debugging-Tipps​

  1. Verwenden Sie Protokolle: Fügen Sie logger.info()-Anweisungen hinzu, um die Ausführung zu verfolgen
  2. Ereignis überprüfen: Überwachen Sie Ereignisse in der Historie
  3. Im Entwicklungs-Chat testen: Verwenden Sie den Entwicklungs-Chat, um Randfälle zu testen
  4. Fehlermeldungen überprüfen: Überprüfen Sie, ob Fehlermeldungen klar und umsetzbar sind
  5. Skriptsyntax validieren: Stellen Sie sicher, dass Ihr Python-Code keine Syntaxfehler hat, bevor Sie ihn bereitstellen

Verwandte Funktionen​

Feldvalidierung​

Für feldspezifische Validierung verwenden Sie Validierungsskripte auf individuellen Extraktionsfeldern:

# Auf dem Extraktionsfeld selbst
if "@example.com" not in value:
raise ValueError("E-Mail muss aus der example.com-Domain stammen")

Siehe Extraktionsfelder für Details.

Fehlerflüsse​

Wenn die Formularvalidierung wiederholt fehlschlägt, ziehen Sie in Betracht, einen Fehlerfluss auszulösen, um die Situation elegant zu handhaben:

# In einem Aktionsknoten nach mehreren fehlgeschlagenen Versuchen
failed_attempts = tracker_api.get_slot("form_failed_attempts") or 0
if failed_attempts > 3:
# Fehlerfluss auslösen oder an einen Menschen eskalieren
tracker_api.set_slot("escalate_to_human", True)

Häufig gestellte Fragen​

Q: Was passiert, wenn mein Validator abstürzt?​

Wenn Ihr Validator eine unerwartete Ausnahme (nicht ValueError) auslöst, behandelt das System dies als Ausführungsfehler:

  • Alle Slots werden auf None zurückgesetzt
  • Eine generische Fehlermeldung wird gesendet
  • Der Fehler wird zur Fehlerbehebung protokolliert
  • Die Formular-Extraktion kann erneut versuchen

Q: Kann ich das LLM von innerhalb des Validators aufrufen?​

Ja, Sie haben Zugriff auf die vollständige tracker_api, einschließlich LLM-Aufrufen:

response = await tracker_api.a_call_llm(messages=[...])

Verwenden Sie dies jedoch sparsam, da es Latenz und Komplexität hinzufügt.

Q: Wie teste ich meinen Formularvalidator?​

Verwenden Sie den Entwicklungs-Chat (siehe Entwicklungs-Chat):

  1. Testen Sie mit gültigen Eingaben, um den Erfolg sicherzustellen
  2. Testen Sie mit ungültigen Eingaben, um Validierungsfehler auszulösen
  3. Überprüfen Sie, ob Fehlermeldungen klar und hilfreich sind
  4. Überprüfen Sie, ob geänderte Werte korrekt gespeichert werden

Q: Kann ich die Formularvalidierung vorübergehend deaktivieren?​

Ja, schalten Sie den Formularvalidierung aktiv-Schalter im Formular-Knoten-Editor um. Dadurch können Sie die Validierung deaktivieren, ohne Ihr Skript zu löschen.

Q: Was ist der Unterschied zwischen Formularvalidierung und Feldvalidierung?​

FunktionFeldvalidierungFormularvalidierung
UmfangEinzelnes FeldAlle Felder
WannNach jeder FeldextraktionNach allen extrahierten Feldern
ZugriffNur aktueller FeldwertAlle Feldwerte
Verwendung fürUnabhängige FeldüberprüfungenBeziehungen über mehrere Felder hinweg

Q: Kann ich auf den Gesprächsverlauf zugreifen?​

Ja, verwenden Sie tracker_api.get_history(), um auf den vollständigen Gesprächsverlauf zuzugreifen:

history = tracker_api.get_history()
user_messages = [turn.content for turn in history if turn.role == 'user']

Verwandte Dokumentation​

  • Extraktionsfelder - Erfahren Sie mehr über das Erstellen und Verwalten von Extraktionsfeldern
  • Formular-Knoten - Verstehen Sie, wie Formular-Knoten funktionieren
  • Skripte - Allgemeine Skriptverwaltung und Best Practices
  • Fehlerfluss - Validierungsfehler mit Fehlerflüssen handhaben
  • Entwicklungs-Chat - Testen Sie Ihre Formularvalidierungsskripte

Brauchen Sie Hilfe?​

Wenn Sie Probleme mit der Formularvalidierung haben:

  1. Überprüfen Sie die Protokolle auf Fehlermeldungen und Stack-Traces
  2. Stellen Sie sicher, dass Ihr Skript keine Syntaxfehler hat
  3. Testen Sie zuerst mit einfacher Validierungslogik, dann fügen Sie Komplexität hinzu
  4. Überprüfen Sie den Abschnitt Best Practices