Skip to content

Ereignisreferenz

Diese Seite bietet eine vollständige Referenz zur Ereignishierarchie, zur Auswahl des richtigen Basisereignisses und einen Katalog aller verfügbaren Ereignisse.

Steuer-, Anzeige- und kombinierte Ereignisse

Das Framework unterscheidet zwischen Ereigniskategorien basierend auf deren Auswirkung auf den Workflow:

KategorieBasisklasseLöst Dispatcher ausAnwendungsfall
SteuerungControlEventJaWorkflow-Statusübergänge, Schrittabhängigkeiten
AnzeigeDisplayEventNeinUI-Updates, Streaming-Ausgabe, Observability
Steuerung und AnzeigeControlAndDisplayEventJaBeides: treibt Workflow voran UND wird in der UI angezeigt

Steuerereignisse (Control events) beeinflussen den Kontrollfluss des Workflows. Wenn ein ControlEvent veröffentlicht wird, evaluiert der Dispatcher alle Schritte, um festzustellen, ob neue Schritte ausgeführt werden sollen. Nur ControlEvent-Typen (oder Unterklassen) können Schritt-Eingabeanforderungen erfüllen.

Anzeigeereignisse (Display events) lösen den Dispatcher nicht aus. Verwenden Sie diese für hochfrequente Updates, die in der UI erscheinen sollen, aber keine erneute Schrittauswertung verursachen dürfen. Eine gestreamte LLM-Antwort kann Hunderte von ChunkEvent-Instanzen pro Minute emittieren; würde man diese zu Steuerereignissen machen, würde dies zu unnötigem Dispatcher-Overhead führen.

Kombinierte Ereignisse (Combined events) benötigen beide Verhaltensweisen – sie beeinflussen den Workflow UND erscheinen in der UI. Die meisten semantischen Ereignisse (LLMEvent, RetrieverEvent usw.) erben von ControlAndDisplayEvent.

python
from swiss_ai_hub.core.events.control.control_event import ControlEvent
from swiss_ai_hub.core.events.display.display_event import DisplayEvent
from swiss_ai_hub.core.events.control_and_display_event import ControlAndDisplayEvent

# Control event: triggers dispatcher, can satisfy step dependencies
class AnalysisCompleteEvent(ControlEvent):
    summary: str

# Display event: does NOT trigger dispatcher, UI-only
class ProgressUpdateEvent(DisplayEvent):
    percent_complete: float
    status_message: str

# Combined: triggers dispatcher AND displays in UI
class RetrieveEvent(ControlAndDisplayEvent):
    nodes: list[IngestedNode]

Ereignisse als Fluss-Carrier

Ereignisse dienen zwei unterschiedlichen Zwecken:

  1. Datenträger: Transportieren von Werten zwischen Schritten
  2. Flussträger: Steuern der Ausführungsreihenfolge unabhängig von Daten

Ein Schritt kann von einem Ereignis abhängen, um ausschliesslich die Ausführungsreihenfolge sicherzustellen, ohne Daten von diesem zu benötigen:

python
class PathA(ControlEvent):
    pass  # No fields — pure flow control

class PathB(ControlEvent):
    pass

@step()
async def decide(self, event: StartEvent) -> PathA | PathB:
    if condition():
        return PathA()
    return PathB()

@step()
async def handle_path_a(self, _: PathA) -> StopEvent:
    # Underscore signals: "I need this event for flow control, not data"
    return StopEvent()

Die Konvention _: EventType weist auf eine Abhängigkeit von der Existenz eines Ereignisses und nicht von dessen Inhalt hin. Dieses Muster ist wesentlich für:

  • Bedingte Verzweigung: Unterschiedliche Schritte werden basierend auf dem emittierten Ereignistyp ausgeführt.
  • Sequenzierung: Sicherstellen, dass Schritt B auf Schritt A wartet, ohne die Ausgabedaten von A zu benötigen.
  • Synchronisationsbarrieren: Warten auf ein Signal, dass die Arbeit abgeschlossen ist.

Ereignishierarchie

BaseEvent
├── ControlEvent                    # Triggers dispatcher
│   ├── StartEvent                  # Workflow entry points
│   │   └── UserMessageEvent        # User-initiated workflow
│   ├── StopEvent                   # Workflow termination
│   └── ExceptionEvent              # Error signaling

├── DisplayEvent                    # UI-only, no dispatcher trigger
│   ├── ChunkEvent                  # Streaming text chunks
│   ├── ThoughtEvent                # Agent reasoning display
│   └── CostEvent                   # Cost tracking display
│       └── LLMCostEvent            # LLM-specific costs

├── ControlAndDisplayEvent          # Both behaviors
│   ├── SemanticEvent               # OpenInference-compatible (OTEL/Phoenix/Langfuse)
│   │   ├── LLMEvent                # LLM invocation
│   │   │   └── LLMStopEvent        # Terminal LLM response
│   │   ├── RetrieverEvent          # Document retrieval
│   │   ├── RerankerEvent           # Result reranking
│   │   ├── EmbeddingEvent          # Embedding generation
│   │   ├── ToolEvent               # Tool invocation
│   │   ├── GuardEvent              # Guardrail evaluation
│   │   ├── ChainEvent              # Chain execution
│   │   └── AgentEvent              # Agent invocation
│   │
│   ├── HumanInTheLoopRequestEvent  # HITL requests
│   ├── HumanInTheLoopResponseEvent # HITL responses
│   ├── AgentInTheLoopRequestEvent  # AITL delegation
│   ├── AgentInTheLoopResponseEvent # AITL results
│   ├── BotInTheLoopRequestEvent    # BITL Teams/Slack requests
│   ├── BotInTheLoopResponseEvent   # BITL responses
│   │
│   ├── BaseRetrieveMemoryEvent     # Memory retrieval
│   │   ├── RetrieveUserMemoryEvent
│   │   └── RetrieveOrganizationMemoryEvent
│   ├── BaseStoreMemoryEvent        # Memory persistence
│   │   ├── StoreUserMemoryEvent
│   │   └── StoreOrganizationMemoryEvent
│   │
│   └── RouterEvent                 # LLM routing decisions

Auswahl des richtigen Basisereignisses

Wenn Sie ein benutzerdefiniertes Ereignis erstellen, erben Sie von der spezifischsten anwendbaren Basisklasse:

Wenn Ihr Ereignis darstellt...Erben Sie vonVorteile
Workflow-StartbedingungStartEventAls Einstiegspunkt erkannt
Benutzernachricht, die Workflow initiiertUserMessageEventChat-Verlauf, Locale, Benutzeridentität
Workflow-BeendigungStopEventSignalisiert Abschluss
Fehler/FehlschlagExceptionEventFehlerbehandlungsmuster
LLM-AufrufergebnisLLMEventToken-Zähler, Nachrichten, OpenInference-Spans
Terminale LLM-AntwortLLMStopEventKombiniert LLM-Daten mit Workflow-Beendigung
DokumentenabrufRetrieverEventAbgerufene Nodes, OpenInference-Spans
Reranking-OperationRerankerEventEingabe-/Ausgabe-Nodes, OpenInference-Spans
Embedding-GenerierungEmbeddingEventVektoren, Modellinformationen, OpenInference-Spans
Tool-/FunktionsaufrufToolEventTool-Name, Parameter, OpenInference-Spans
Guardrail-PrüfungGuardEventGuard-Ergebnis, OpenInference-Spans
Menschliche Genehmigung benötigtHumanInTheLoopRequestEventWorkflow-Aussetzung, UI-Eingabeaufforderung
Agenten-DelegationAgentInTheLoopRequestEventCross-Agent-Kommunikation
SpeicherabrufRetrieveUserMemoryEvent / RetrieveOrganizationMemoryEventSpeicher-Suchergebnisse
SpeicherspeicherungStoreUserMemoryEvent / StoreOrganizationMemoryEventSpeicherbestätigung
Streaming-Text-ChunkChunkEventEchtzeit-UI-Updates (nur Anzeige)
Agenten-Gedanke/ArgumentationThoughtEventTransparenzanzeige (nur Anzeige)
KosteninformationenLLMCostEventToken-Nutzung, Preisgestaltung (nur Anzeige)
Generischer Workflow-StatusControlAndDisplayEventLöst Dispatcher + UI-Anzeige aus
Generisches UI-UpdateDisplayEventNur UI, kein Dispatcher-Overhead

Semantische Ereignisse und OpenInference

SemanticEvent-Unterklassen implementieren die Methode to_semantic_convention(), die Attribute erzeugt, die mit der OpenInference-Spezifikation kompatibel sind. Dies ermöglicht die Integration mit:

  • Arize Phoenix: Trace-Visualisierung und Debugging
  • Langfuse: LLM-Observability und -Analysen
  • Jedem OpenTelemetry-kompatiblen System: Standard-Span-Attribute
python
from swiss_ai_hub.core.events.semantic import RetrieverEvent

# RetrieverEvent automatically exports OpenInference attributes:
# - openinference.span.kind: "RETRIEVER"
# - retrieval.documents.{i}.document.id
# - retrieval.documents.{i}.document.content
# - retrieval.documents.{i}.document.score

event = RetrieverEvent.from_nodes(retrieved_nodes)
otel_attributes = event.to_semantic_convention()

Beim Erstellen von Agents, die Observability benötigen, bevorzugen Sie semantische Ereignisse gegenüber generischen ControlAndDisplayEvent:

python
# Preferred: semantic event for observability
from swiss_ai_hub.core.events.semantic import RetrieverEvent

@step()
async def retrieve(self, event: UserMessageEvent) -> RetrieverEvent:
    nodes = await retriever.retrieve(event.user_query)
    return RetrieverEvent.from_nodes(nodes)  # OpenInference-compatible

# Discouraged: generic event loses observability benefits
class MyRetrieveEvent(ControlAndDisplayEvent):
    nodes: list[NodeWithScore]  # No OpenInference integration

Referenz der verfügbaren Ereignisse

Steuerereignisse (lösen Dispatcher aus)

EreignisModulZweck
ControlEventcontrol.ControlEventBasisklasse für alle Steuerereignisse
StartEventcontrol.start.StartEventWorkflow-Einstiegspunkt
StopEventcontrol.stop.StopEventWorkflow-Beendigung
ExceptionEventcontrol.exception.ExceptionEventFehler-Signalisierung

Anzeigeereignisse (nur UI)

EreignisModulZweck
DisplayEventdisplay.DisplayEventBasisklasse für Anzeigeereignisse
ChunkEventdisplay.ChunkEventStreaming-Textausgabe
ThoughtEventdisplay.ThoughtEventTransparenz der Agenten-Argumentation
CostEventcost.CostEventKostenverfolgung Basis
LLMCostEventcost.LLMCostEventLLM-Token-/Kostenberichterstattung

Semantische Ereignisse (OpenInference-kompatibel)

EreignisModulOpenInference Span-Typ
SemanticEventsemantic.SemanticEventBasisklasse (abstrakt)
LLMEventsemantic.llm.LLMEventLLM
LLMStopEventsemantic.llm.LLMStopEventLLM (terminal)
RetrieverEventsemantic.retriever.RetrieverEventRETRIEVER
RerankerEventsemantic.reranker.RerankerEventRERANKER
EmbeddingEventsemantic.embedding.EmbeddingEventEMBEDDING
ToolEventsemantic.tool.ToolEventTOOL
GuardEventsemantic.guard.GuardEventGUARDRAIL
ChainEventsemantic.chain.ChainEventCHAIN
AgentEventsemantic.agent.AgentEventAGENT

Interaktionsereignisse

EreignisModulZweck
UserMessageEventuser.UserMessageEventBenutzerinitiierter Workflow-Start
HumanInTheLoopRequestEventhuman_in_the_loop.requestBasisklasse für HITL-Anfragen
HumanInTheLoopInputRequestEventhuman_in_the_loop.requestPopup mit Texteingabefeld
HumanInTheLoopConfirmationRequestEventhuman_in_the_loop.requestJa/Nein-Schaltflächenauswahl
HumanInTheLoopChatRequestEventhuman_in_the_loop.requestChat-Nachricht (Fallback)
HumanInTheLoopResponseEventhuman_in_the_loop.responseBasisklasse für HITL-Antworten
AgentInTheLoopRequestEventagent_in_the_loop.requestAn einen anderen Agenten delegieren
AgentInTheLoopResponseEventagent_in_the_loop.responseErgebnis des delegierten Agenten
AgentInTheLoopExceptionEventagent_in_the_loop.exceptionFehler des delegierten Agenten
BotInTheLoopRequestEventbot_in_the_loop.requestNachricht an Teams/Slack-Kanal senden
BotInTheLoopResponseEventbot_in_the_loop.responseAntwort von Teams/Slack-Benutzer

HITL-Hilfsklassen (keine Ereignisse, sondern Workflow-Dienstprogramme):

HelferUI-Verhalten
HumanInTheLoopInputPopup-Dialog für die freie Texteingabe
HumanInTheLoopConfirmationJa/Nein-Schaltflächenauswahl
HumanInTheLoopChatNachricht im Chat-Stream (Fallback für einfache UIs/APIs)

Speicherereignisse

EreignisModulZweck
BaseRetrieveMemoryEventmemory.retrieveBasis für Speicherabruf
RetrieveUserMemoryEventmemory.retrieveBenutzerbezogener Speicherabruf
RetrieveOrganizationMemoryEventmemory.retrieveOrganisationsbezogener Speicherabruf
BaseStoreMemoryEventmemory.storeBasis für Speicherspeicherung
StoreUserMemoryEventmemory.storeBenutzerbezogene Speicherspeicherung
StoreOrganizationMemoryEventmemory.storeOrganisationsbezogene Speicherspeicherung
AddMemoryToChatHistoryEventmemory.historyErweiterter Chatverlauf

Guard-Ereignisse

EreignisModulZweck
GuardAcceptEventguard.GuardAcceptEventGuard akzeptiert
GuardRejectionEventguard.GuardRejectionEventGuard abgelehnt
AgentSuitabilityAcceptEventguardAgent kann Anfrage bearbeiten
AgentSuitabilityRejectEventguardAgent kann Anfrage nicht bearbeiten
ContextSufficientAcceptEventguardAusreichender Kontext verfügbar
ContextInsufficientRejectEventguardUnzureichender Kontext
SensitiveInfoAcceptEventguardKeine sensiblen Informationen erkannt
SensitiveInfoRejectEventguardSensible Informationen erkannt

Dienstprogramme-Ereignisse

EreignisModulZweck
RouterEventrouter.RouterEventLLM-Routingentscheidung
LanguageEventcommon.LanguageEventSpracherkennung
LimitChatHistoryEventcommon.LimitChatHistoryEventGekürzter Verlauf
StandaloneQuestionCondenserEventcommonFrage-Neuformulierung

Benutzerdefinierte Ereignisse

Benutzerdefinierte Ereignisse sind Pydantic-Modelle. Alle Felder erfordern Typannotationen:

python
from swiss_ai_hub.core.events.control.control_event import ControlEvent

class AnalysisCompleteEvent(ControlEvent):
    summary: str
    confidence: float
    findings: list[str]
    metadata: dict | None = None

Die Stop-Ereignis-Einschränkung

Kein Schritt darf von StopEvent oder einer seiner Unterklassen als Eingabeparameter abhängen. Wenn ein StopEvent emittiert wird, wird die Ausführung beendet und nachfolgende Schritte werden nicht geplant. Einzelheiten und das korrekte Muster finden Sie im Ausführungsmodell.

Gebaut mit ❤️ in der Schweiz 🇨🇭