Zum Hauptinhalt springen

Nachbearbeitungsskripte

Kurzfassung: Nachbearbeitungsskripte ermöglichen es Ihnen, LLM-generierte Antworten zu transformieren, zu filtern oder zu modifizieren, bevor sie an Benutzer gesendet werden. Es gibt drei Modi: Standard (für nicht gestreamte Antworten), Streaming (pro Chunk-Verarbeitung) und Erweitertes Streaming (volle Kontrolle über den Ereignisstrom). Aktivieren Sie sie in jedem LLM-fähigen Knoten, indem Sie "Nachbearbeitungsskript" umschalten und Ihren Modus auswählen, wenn Streaming aktiviert ist.

Nachbearbeitungsskripte geben Ihnen die programmatische Kontrolle über Bot-Antworten, nachdem sie vom LLM generiert wurden, aber bevor sie den Benutzer erreichen. Dies ist nützlich für Inhaltsfilterung, Formatierung, Hinzufügen dynamischer Elemente oder Implementierung benutzerdefinierter Antwortlogik.

Warum Nachbearbeitungsskripte verwenden?

Nachbearbeitungsskripte ermöglichen Ihnen:

  • Inhalte zu filtern — Unerwünschte Wörter, Phrasen oder Muster zu entfernen oder zu ersetzen
  • Antworten zu formatieren — Einheitliches Styling anzuwenden, Interpunktion hinzuzufügen oder Text umzugestalten
  • Dynamische Elemente hinzuzufügen — Zeitstempel, Benutzernamen oder kontextuelle Informationen einzufügen
  • Geschäftslogik zu implementieren — Unternehmensspezifische Regeln auf Antworten anzuwenden
  • Daten zu transformieren — Formate zu konvertieren, Begriffe zu übersetzen oder Ausgaben zu normalisieren
  • Qualitätskontrolle — Antwortlänge zu validieren, erforderliche Elemente zu überprüfen

Nachbearbeitung aktivieren

Um die Nachbearbeitung auf einem Knoten zu aktivieren:

  1. Öffnen Sie einen beliebigen LLM-fähigen Knoten (Antwort, Wissen, Formular oder Aktion mit aktiviertem LLM)
  2. Schalten Sie den Nachbearbeitungsskript-Schalter um, um ihn zu aktivieren
  3. Schreiben Sie Ihre Verarbeitungslösung im erscheinenden Code-Editor

Nachbearbeitungsskript-Umschalter

Hinweis: Nachbearbeitungsskripte sind knotenspezifisch. Jeder Knoten hat sein eigenes Skript, das nur auf Antworten angewendet wird, die von diesem Knoten generiert werden.

Nachbearbeitungsmodi

Wenn Streaming für einen Knoten aktiviert ist, können Sie zwischen verschiedenen Nachbearbeitungsmodi wählen. Jeder Modus bietet ein unterschiedliches Maß an Kontrolle darüber, wie Antworten verarbeitet werden.

Wichtig: Diese Nachbearbeitungsmodi gelten derzeit für das Standard-LLM-Streaming (stream_utter). Strukturiertes Streaming über a_stream_call_response_model(...) + stream_response_model(...) führt derzeit keine Nachbearbeitungsskripte aus (default, stream oder advanced_stream).

Standardmodus (Nicht-Streaming)

Wann verwenden: Wenn Streaming deaktiviert ist oder wenn Sie die vollständige Antwort auf einmal verarbeiten müssen.

Im Standardmodus erhält Ihr Skript die gesamte Antwort, nachdem das LLM sie fertig generiert hat. Dies ist der einfachste Ansatz und funktioniert gut, wenn Sie den vollständigen Kontext sehen müssen, bevor Sie Änderungen vornehmen.

Skriptvorlage:

from shared import RemoteLLMTrackerApi
from shared import Processor
from typing import Optional
from loguru import logger

class processor(Processor):
async def run(self, tracker_api: RemoteLLMTrackerApi, value: str) -> Optional[str]:
"""
Verarbeiten der vollständigen LLM-Antwort.

Args:
tracker_api: API zum Zugriff auf den Konversationsstatus, Slots und Verlauf
value: Der vollständige Antworttext vom LLM

Returns:
Der modifizierte Antworttext oder None, um das Original zu verwenden
"""
# Beispiel: Eine Signatur zu jeder Antwort hinzufügen
processed = value + "\n\n— Ihr Assistent"
return processed

Wichtige Punkte:

  • Erhält die vollständige Antwort als einzelnen String
  • Gibt den modifizierten String zurück oder None, um das Original beizubehalten
  • Hat vollen Zugriff auf tracker_api für Slots, Verlauf und LLM-Aufrufe
  • Am besten für Transformationen geeignet, die den vollständigen Kontext benötigen

Beispielanwendungsfälle:

  • Hinzufügen von Signaturen oder Haftungsausschlüssen
  • Inhaltsfilterung mit Kontextbewusstsein
  • Antwortvalidierung und -korrektur
  • Formatkonvertierungen (Markdown zu Klartext usw.)

Streaming-Modus

Wann verwenden: Wenn Streaming aktiviert ist und Sie jeden Chunk verarbeiten möchten, sobald er eintrifft, während Sie eine geringe Latenz beibehalten.

Im Streaming-Modus wird Ihr Skript für jeden Chunk von Text aufgerufen, sobald er vom LLM generiert wird. Dies ermöglicht es Ihnen, Antworten in Echtzeit mit minimaler Verzögerung zu verarbeiten und anzuzeigen.

Um den Streaming-Modus zu verwenden:

  1. Aktivieren Sie Streaming in den LLM-Einstellungen
  2. Aktivieren Sie Nachbearbeitungsskript
  3. Wählen Sie Streaming aus dem Modus-Umschalter

Nachbearbeitungsskript-Streaming-Umschalter

Skriptvorlage:

from shared import RemoteLLMTrackerApi
from shared import StreamProcessor
from loguru import logger

class processor(StreamProcessor):
async def run(self, tracker_api: RemoteLLMTrackerApi, chunk_text: str) -> str:
"""
Verarbeiten jedes Streaming-Chunks, sobald er eintrifft.

Args:
tracker_api: API zum Zugriff auf den Konversationsstatus
chunk_text: Ein einzelner Chunk von Text aus der Streaming-Antwort

Returns:
Der verarbeitete Chunk-Text
"""
# Beispiel: In Großbuchstaben umwandeln
return chunk_text.upper()

Wichtige Punkte:

  • Wird einmal pro Chunk aufgerufen (kann von einem einzelnen Token bis zu ein paar Wörtern reichen - normalerweise ein einzelnes Token)
  • Muss schnell zurückkehren, um die Streaming-Leistung aufrechtzuerhalten
  • Begrenzter Kontext — Sie sehen nur einen Chunk auf einmal
  • Änderungen sind sofort für den Benutzer sichtbar

Beispielanwendungsfälle:

  • Einfache Texttransformationen (Groß-/Kleinschreibung ändern, Zeichen ersetzen)
  • Echtzeit-Wortfilterung
  • Hinzufügen von Präfixen oder Formatierungen zu Chunks
  • Leichte Inhaltsbereinigung

Warnung: Vermeiden Sie schwere Verarbeitung im Streaming-Modus. Jeder Chunk sollte in Millisekunden verarbeitet werden, um ein reibungsloses Streaming-Erlebnis zu gewährleisten.


Erweitertes Streaming-Modus

Wann verwenden: Wenn Sie die volle Kontrolle über den Streaming-Prozess benötigen, einschließlich Pufferung, Neu-Chunken oder komplexen Transformationen, die sich über mehrere Chunks erstrecken.

Im erweiterten Streaming-Modus erhält Ihr Skript den gesamten Ereignisstrom als asynchronen Generator. Sie haben die vollständige Kontrolle darüber, welche Ereignisse dem Benutzer wann übermittelt werden.

Um den erweiterten Streaming-Modus zu verwenden:

  1. Aktivieren Sie Streaming in den LLM-Einstellungen
  2. Aktivieren Sie Nachbearbeitungsskript
  3. Wählen Sie Erweitertes Streaming aus dem Modus-Umschalter

Nachbearbeitungsskript-Streaming-Umschalter

Skriptvorlage:

from shared import RemoteLLMTrackerApi, LLMStreamedUtteranceRunningEventPayload
from shared import AdvancedStreamProcessor
from typing import AsyncGenerator

class processor(AdvancedStreamProcessor):
async def run(
self,
tracker_api: RemoteLLMTrackerApi,
event_stream: AsyncGenerator
) -> AsyncGenerator:
"""
Verarbeiten des vollständigen Streaming-Ereignisstroms.

Args:
tracker_api: API zum Zugriff auf den Konversationsstatus
event_stream: Asynchroner Generator, der Streaming-Ereignisse liefert

Yields:
Modifizierte Ereignisse, die an den Benutzer gesendet werden
"""
complete_text = ""

async for event in event_stream:
if isinstance(event.payload, LLMStreamedUtteranceRunningEventPayload):
if event.payload.text is not None:
# Manipulieren Sie event.payload.text, um die Antwort zu ändern
complete_text += event.payload.text

# Beispiel: Pufferung, bis wir einen vollständigen Satz haben
# dann alles auf einmal freigeben

# Geben Sie das Ereignis aus, um es an den Benutzer zu senden
yield event

Wichtige Punkte:

  • Volle Kontrolle über den Ereignisstrom
  • Kann Ereignisse puffern, verzögern oder modifizieren
  • Kann die gesamte Antwort sehen, während sie aufgebaut wird
  • Komplexer, aber extrem leistungsstark

Beispielanwendungsfälle:

Satz-für-Satz-Streaming

Puffern Sie Chunks, bis Sie einen vollständigen Satz haben, und geben Sie ihn dann frei:

from shared import RemoteLLMTrackerApi, LLMStreamedUtteranceRunningEventPayload
from shared import AdvancedStreamProcessor
from typing import AsyncGenerator

class processor(AdvancedStreamProcessor):
async def run(self, tracker_api: RemoteLLMTrackerApi, event_stream: AsyncGenerator) -> AsyncGenerator:
buffer = ""
sentence_endings = {'.', '!', '?'}

async for event in event_stream:
if isinstance(event.payload, LLMStreamedUtteranceRunningEventPayload):
if event.payload.text is not None:
buffer += event.payload.text

# Überprüfen, ob wir einen vollständigen Satz haben
while any(end in buffer for end in sentence_endings):
# Finden Sie das erste Satzende
min_idx = len(buffer)
for end in sentence_endings:
idx = buffer.find(end)
if idx != -1 and idx < min_idx:
min_idx = idx

# Geben Sie den vollständigen Satz aus
sentence = buffer[:min_idx + 1]
buffer = buffer[min_idx + 1:]

event.payload.text = sentence
yield event
continue

# Unvollständige Sätze nicht ausgeben
continue

yield event

Inhaltsfilterung mit Kontext

from shared import RemoteLLMTrackerApi, LLMStreamedUtteranceRunningEventPayload
from shared import AdvancedStreamProcessor
from typing import AsyncGenerator

class processor(AdvancedStreamProcessor):
async def run(self, tracker_api: RemoteLLMTrackerApi, event_stream: AsyncGenerator) -> AsyncGenerator:
forbidden_phrases = ["vertraulich", "nur intern", "nicht teilen"]
buffer = ""

async for event in event_stream:
if isinstance(event.payload, LLMStreamedUtteranceRunningEventPayload):
if event.payload.text is not None:
buffer += event.payload.text

# Überprüfen Sie auf verbotene Phrasen im angesammelten Text
for phrase in forbidden_phrases:
if phrase.lower() in buffer.lower():
# Ersetzen Sie die Phrase
buffer = buffer.lower().replace(phrase.lower(), "[REDACTED]")

event.payload.text = buffer
buffer = ""

yield event

Zugriff auf den Konversationskontext

Alle Nachbearbeitungsskripte haben Zugriff auf das tracker_api-Objekt, das Folgendes bietet:

Slot-Werte abrufen

# Einen bestimmten Slot-Wert abrufen
user_name = tracker_api.get_slot("user_name")

# Alle Slots abrufen
all_slots = tracker_api.slots

Konversationsverlauf abrufen

# Konversationsverlauf abrufen
history = tracker_api.get_history()

# Die neueste Benutzernachricht abrufen
latest_message = tracker_api.get_latest_user_message()

Zusätzliche LLM-Aufrufe durchführen

# Einen zusätzlichen LLM-Aufruf durchführen, falls erforderlich
response = await tracker_api.a_call_llm(
messages=[
{"role": "system", "content": "Sie sind ein hilfreicher Assistent."},
{"role": "user", "content": "Fassen Sie dies zusammen: " + value}
]
)

Vergleich der Modi

FunktionStandardStreamingErweitertes Streaming
Streaming-UnterstützungNeinJaJa
EmpfängtVollständiger TextEinzelner ChunkEreignisstrom
LatenzeinflussHoch (wartet auf vollständige Antwort)NiedrigVariabel (Ihre Kontrolle)
Verfügbarer KontextVollständige AntwortEinzelner ChunkAkkumulierende Antwort
KomplexitätEinfachEinfachKomplex
AnwendungsfallVolltext-TransformationenPro-Chunk-VerarbeitungBenutzerdefinierte Streaming-Logik

Beste Praktiken

1. Halten Sie es schnell

Nachbearbeitung fügt Latenz hinzu. Halten Sie Ihre Skripte effizient:

# Gut: Einfache, schnelle Operation
return value.replace("AI", "Assistent")

# Vermeiden: Schwere Operationen im Streaming-Modus
# response = await some_slow_api_call(value) # Machen Sie dies nicht pro Chunk!

2. Randfälle behandeln

Berücksichtigen Sie immer leere oder unerwartete Eingaben:

async def run(self, tracker_api, value: str) -> Optional[str]:
if not value or not value.strip():
return value

# Ihre Verarbeitungslösung hier
return processed_value

3. Gründlich testen

Testen Sie Ihre Skripte mit verschiedenen Eingaben:

  • Leere Antworten
  • Sehr lange Antworten
  • Antworten mit Sonderzeichen
  • Antworten in verschiedenen Sprachen

4. Wählen Sie den richtigen Modus

  • Verwenden Sie Standard, wenn Sie den vollständigen Kontext benötigen und Streaming nicht kritisch ist
  • Verwenden Sie Streaming für einfache, schnelle Pro-Chunk-Operationen
  • Verwenden Sie Erweitertes Streaming nur, wenn Sie komplexe Streaming-Kontrolle benötigen

Unterstützte Knoten

Nachbearbeitungsskripte sind auf allen LLM-fähigen Knoten verfügbar:

KnotentypStandardmodusStreaming-ModusErweitertes Streaming
Antwort (LLM-Typ)
Wissen (RAG)
Formular
Aktion (LLM aktiviert)

Hinweis: Aktionsknoten unterstützen nur die Nachbearbeitung im Standardmodus, da sie typischerweise Antworten programmatisch anstelle von Streaming an Benutzer verarbeiten.


Nachbearbeitungsagent (Bot-Ebene)

Zusätzlich zu knotenspezifischen Nachbearbeitungsskripten können Sie einen Nachbearbeitungsagenten auf Bot-Ebene aktivieren. Dieser Agent läuft auf allen LLM-Antworten über alle Knoten hinweg und wird typischerweise für Sicherheitsüberwachung und Inhaltsmoderation verwendet.

Um den Nachbearbeitungsagenten zu aktivieren:

  1. Öffnen Sie die LLM-Einstellungen in einem beliebigen Knoten
  2. Schalten Sie Nachbearbeitungsagent aktiviert um

Der Nachbearbeitungsagent:

  • Läuft nach knotenspezifischen Nachbearbeitungsskripten
  • Kann unsichere Antworten blockieren und Alternativen bereitstellen
  • Wird im Skripte-Abschnitt unter agents/post_processing/ konfiguriert

Hinweis: Wenn der Nachbearbeitungsagent aktiviert ist, wird das Streaming für diesen Knoten automatisch deaktiviert, um dem Agenten die Bewertung der vollständigen Antwort zu ermöglichen.


Fehlerbehebung

Skript läuft nicht

  • Stellen Sie sicher, dass der Nachbearbeitungsskript-Umschalter aktiviert ist
  • Überprüfen Sie, ob Ihr Skript die richtige Vorlagenstruktur befolgt
  • Stellen Sie Ihre Änderungen bereit (Skripte werden mit dem Bot bereitgestellt)

Streaming-Modus nicht verfügbar

  • Aktivieren Sie zuerst Streaming in den LLM-Einstellungen
  • Der Modusauswähler erscheint nur, wenn sowohl Streaming als auch Nachbearbeitungsskript aktiviert sind

Leistungsprobleme

  • Vermeiden Sie schwere Verarbeitung im Streaming-Modus
  • Verwenden Sie den Standardmodus für komplexe Transformationen
  • Überprüfen Sie auf Endlosschleifen im erweiterten Streaming-Modus

Antwort nicht modifiziert

  • Stellen Sie sicher, dass Ihre run-Methode einen Wert zurückgibt (nicht None, es sei denn, dies ist beabsichtigt)
  • Überprüfen Sie auf Ausnahmen in Ihrem Code (sehen Sie sich die Protokolle auf Fehler an)
  • Vergewissern Sie sich, dass das Skript gespeichert und bereitgestellt ist

Verwandte Dokumentation

  • Flow — Erfahren Sie mehr über das Erstellen von Flows und Knoten
  • Skripte — Verwalten Sie benutzerdefinierte Skripte und Agenten
  • Error Flow — Behandeln Sie Fehler in Ihrem Bot