Ereignisse
Ereignisse sind die grundlegenden Bausteine der Gesprächshistorie in ADK-Rust. Jede Interaktion mit einem Agenten — sei es eine Nutzernachricht, eine Agentenantwort oder eine Tool-Ausführung — wird als Ereignis aufgezeichnet. Ereignisse bilden ein unveränderliches Protokoll, das die vollständige Ausführungsspur einer Agentensitzung erfasst.
Überblick
Das Ereignissystem erfüllt mehrere kritische Zwecke:
- Gesprächshistorie: Ereignisse bilden die chronologische Aufzeichnung aller Interaktionen in einer Sitzung
- Zustandsverwaltung: Ereignisse tragen Zustandsänderungen über das Feld
state_delta - Artefaktverfolgung: Ereignisse protokollieren Artefaktoperationen über das Feld
artifact_delta - Agentenkoordination: Ereignisse ermöglichen Agentenübergaben und Eskalationen
- Debugging & Beobachtbarkeit: Ereignisse liefern eine vollständige Prüfspur des Agentenverhaltens
Ereignisstruktur
Ein Event repräsentiert eine einzelne Interaktion in einer Unterhaltung. ADK-Rust verwendet einen vereinheitlichten Event-Typ, der LlmResponse einbettet und dem in ADK-Go verwendeten Entwurfsmuster entspricht:
pub struct Event {
pub id: String, // Unique event identifier (UUID)
pub timestamp: DateTime<Utc>, // When the event occurred
pub invocation_id: String, // Links related events in a single invocation
pub branch: String, // For future branching support
pub author: String, // Who created this event (user, agent name, tool name)
pub llm_response: LlmResponse, // Contains content and LLM metadata
pub actions: EventActions, // Side effects and metadata
pub long_running_tool_ids: Vec<String>, // IDs of long-running tools
pub provider_metadata: HashMap<String, String>, // Provider-specific metadata
}
Die Struktur LlmResponse enthält:
pub struct LlmResponse {
pub content: Option<Content>, // The message content (text, parts, etc.)
pub usage_metadata: Option<UsageMetadata>,
pub finish_reason: Option<FinishReason>,
pub partial: bool, // True for streaming partial responses
pub turn_complete: bool, // True when the turn is complete
pub interrupted: bool, // True if generation was interrupted
pub error_code: Option<String>,
pub error_message: Option<String>,
}
Auf den Inhalt wird konsistent über event.llm_response.content zugegriffen:
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
println!("{}", text);
}
}
}
Wichtige Felder
-
id: Eine eindeutige UUID, die dieses spezifische Ereignis identifiziert. Wird für das Abrufen und die Sortierung von Ereignissen verwendet.
-
timestamp: Der Zeitstempel der UTC, zu dem das Ereignis erstellt wurde. Ereignisse werden in der Sitzung chronologisch geordnet.
-
invocation_id: Gruppiert Ereignisse, die zur gleichen Agentenaufruf gehören. Wenn ein Agent eine Nachricht verarbeitet, teilen alle erzeugten Ereignisse (Agentenantwort, Tool-Aufrufe, Unteragenten-Aufrufe) dieselbe invocation_id.
-
branch: Der Gesprächszweig, auf dem das Ereignis erzeugt wurde.
ParallelAgentplatziert jeden Unteragenten auf seinem eigenen Zweig ({parent}.{parallel_agent}.{sub_agent}) und versieht die von ihm ausgegebenen Ereignisse mit diesem Zweig, sodass Lesezugriffe auf die Historie eines Zweigs nicht das enthalten, was Geschwisterzweige erzeugt haben. Ein Ereignis ist von einem Zweig aus sichtbar, wenn sein eigener Zweig diesem Zweig entspricht oder ein Vorfahr davon ist; Geschwister und verschachtelte Nachfahren sind es nicht. Ein leerer Zweig bedeutet „nicht eingegrenzt“ und bleibt überall sichtbar, sodass Ereignisse ohne einen solchen Zweig unbeeinflusst bleiben. Siehe Workflow Agents. -
author: Identifiziert, wer das Ereignis erstellt hat:
- Nutzernachrichten: typischerweise "user" oder eine Nutzerkennung
- Agentenantworten: der Name des Agenten
- Tool-Ausführungen: der Name des Tools
- Systemereignisse: "system"
-
llm_response: Enthält den Nachrichteninhalt und die LLM-Metadaten. Greife über
event.llm_response.contentauf den Inhalt zu. Der TypContentkann Text, multimodale Bestandteile (Bilder, Audio) oder strukturierte Daten enthalten. Manche Ereignisse (wie reine Zustandsaktualisierungen) könnencontent: Nonehaben. -
llm_response.error_code / error_message: Werden gesetzt, wenn der Provider für den Turn einen terminalen Fehler gemeldet hat. Provider können einen Fehler innerhalb eines ansonsten erfolgreichen Stream-Elements melden — die Stream-Fehler von
adk-anthropic, das Fehlerereignis von OpenAI Responses und der OpenAI-Transport über websocket tun dies alle — daher unterscheiden diese Felder einen fehlgeschlagenen Turn von einem leeren.LlmAgenterzeugt zuerst das Ereignis, das sie trägt, und beendet dann den Lauf mit einemAdkError, dessen Codemodel.provider_errorist, wobei der eigene Code des Providers in den Fehlerdetails unterprovider_error_codesteht. Das Ereignis wird zuerst ausgegeben, damit der fehlgeschlagene Turn weiterhin beobachtbar und persistent bleibt, anstatt in einem Fehler zu verschwinden.Eine Kürzung wird nicht auf diese Weise gemeldet: Eine durch ein Token-Limit abgeschnittene Antwort trägt
finish_reason: FinishReason::MaxTokensund keinen Fehlercode. -
llm_response.interrupted: Die Generierung wurde unterbrochen (zum Beispiel ein Realtime-Turn, der vom Benutzer abgebrochen wurde, oder eine Tool-Bestätigung, die den Turn pausiert). Dies wird im Ereignis festgehalten, ist aber für sich genommen kein terminaler Fehler, sodass der Lauf nicht fehlschlägt.
// Distinguishing a failed turn from an empty one
if let Some(code) = &event.llm_response.error_code {
let detail = event.llm_response.error_message.as_deref().unwrap_or("no message");
eprintln!("provider reported {code}: {detail}");
}
EventActions
Die Struktur EventActions enthält Metadaten und Nebeneffekte, die mit einem Ereignis verbunden sind:
pub struct EventActions {
pub state_delta: HashMap<String, Value>, // State changes to apply
pub artifact_delta: HashMap<String, i64>, // Artifact version changes
pub skip_summarization: bool, // Skip this event in summaries
pub transfer_to_agent: Option<String>, // Transfer control to another agent
pub escalate: bool, // Escalate to human or supervisor
pub tool_confirmation: Option<ToolConfirmationRequest>, // Pending tool confirmation
pub tool_confirmation_decision: Option<ToolConfirmationDecision>, // Approval/denial
pub compaction: Option<EventCompaction>, // Context compaction summary
}
state_delta
Das Feld state_delta enthält Schlüssel-Wert-Paare, die Änderungen am Sitzungszustand darstellen. Wenn ein Ereignis an eine Sitzung angehängt wird, werden diese Änderungen in den Zustand der Sitzung übernommen.
Statusschlüssel können Präfixe verwenden, um den Geltungsbereich zu steuern:
app:key- Anwendungsbezogener Zustand (gemeinsam für alle Benutzer)user:key- Benutzerbezogener Zustand (gemeinsam für alle Sitzungen eines Benutzers)temp:key- Temporärer Zustand (zwischen Aufrufen gelöscht)- Kein Präfix - Sitzungsbezogener Zustand (Standard)
Beispiel:
let mut actions = EventActions::default();
actions.state_delta.insert("user_name".to_string(), json!("Alice"));
actions.state_delta.insert("temp:current_step".to_string(), json!(3));
artifact_delta
Das Feld artifact_delta verfolgt Änderungen an Artefakten. Schlüssel sind Artefaktnamen, und Werte sind Versionsnummern. Dadurch kann das System nachverfolgen, welche Artefakte während eines Ereignisses erstellt oder geändert wurden.
Beispiel:
actions.artifact_delta.insert("report.pdf".to_string(), 1);
actions.artifact_delta.insert("chart.png".to_string(), 2);
skip_summarization
Wenn true, wird dieses Ereignis aus Gesprächszusammenfassungen ausgeschlossen. Nützlich für interne Ereignisse, Debugging-Informationen oder ausführliche Tool-Ausgaben, die nicht Teil des Hauptgesprächsflusses sein sollten.
transfer_to_agent
Wenn auf einen Agentennamen gesetzt, wird die Kontrolle an diesen Agenten übertragen. Dies ermöglicht Multi-Agenten-Workflows, bei denen ein Agent an einen anderen übergeben kann. Der Ziel-Agent muss als Unteragent konfiguriert sein.
Beispiel:
actions.transfer_to_agent = Some("specialist_agent".to_string());
escalate
Wenn true, signalisiert dies, dass das Gespräch an einen menschlichen Bediener oder einen Supervisor-Agenten eskaliert werden soll. Das genaue Eskalationsverhalten hängt von der Implementierung deiner Anwendung ab.
Bildung der Gesprächshistorie
Ereignisse bilden die Gesprächshistorie, indem sie sich innerhalb einer Sitzung in chronologischer Reihenfolge ansammeln. Wenn ein Agent eine Anfrage verarbeitet:
- Ereignis für Nutzernachricht: Ein neues Ereignis wird mit der Eingabe des Benutzers erstellt
- Agentenverarbeitung: Der Agent erhält die Gesprächshistorie (alle vorherigen Ereignisse)
- Ereignis für Agentenantwort: Die Antwort des Agenten wird als neues Ereignis aufgezeichnet
- Ereignisse für Tool-Ausführungen: Jeder Tool-Aufruf kann zusätzliche Ereignisse erzeugen
- Zustandsaktualisierungen: Zustandsdeltas aus allen Ereignissen werden in den Sitzungszustand übernommen
Die Gesprächshistorie wird aufgebaut durch:
- Abrufen aller Ereignisse aus der Sitzung in chronologischer Reihenfolge
- Umwandeln des Inhalts jedes Ereignisses in das geeignete Format für das LLM
- Einbeziehen von Zustandsinformationen aus angesammelten Zustands-Deltas
- Herausfiltern von Ereignissen, die mit
skip_summarizationmarkiert sind, wenn angemessen
Ereignisablauf-Beispiel
Session Start
↓
[Event 1] User: "What's the weather in Tokyo?"
↓
[Event 2] Agent: "Let me check that for you."
↓
[Event 3] Tool (weather_api): {"temp": 22, "condition": "sunny"}
↓
[Event 4] Agent: "It's 22°C and sunny in Tokyo."
↓
Session State Updated
Jedes Ereignis baut auf den vorherigen auf und erzeugt so einen vollständigen Prüfpfad der Unterhaltung.
Arbeiten mit Ereignissen
Ereignisse aus einer Sitzung aufrufen
use adk_rust::session::{SessionService, GetRequest};
// Retrieve a session with its events
let session = session_service.get(GetRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: session_id.clone(),
num_recent_events: None, // Get all events
after: None,
}).await?;
// Access the events
let events = session.events();
println!("Total events: {}", events.len());
// Iterate through events (note: session events use llm_response.content)
for i in 0..events.len() {
if let Some(event) = events.at(i) {
println!("Event {}: {} by {} at {}",
event.id,
event.llm_response.content.as_ref().map(|_| "has content").unwrap_or("no content"),
event.author,
event.timestamp
);
}
}
Ereignisdetails untersuchen
// Get a specific event from session (uses llm_response.content)
if let Some(event) = events.at(0) {
// Check the author
println!("Author: {}", event.author);
// Check content (session events use llm_response.content)
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
println!("Text: {}", text);
}
}
}
// Check for state changes
if !event.actions.state_delta.is_empty() {
println!("State changes:");
for (key, value) in &event.actions.state_delta {
println!(" {} = {}", key, value);
}
}
// Check for agent transfers
if let Some(target) = &event.actions.transfer_to_agent {
println!("Transfers to: {}", target);
}
// Check for artifacts
if !event.actions.artifact_delta.is_empty() {
println!("Artifacts modified:");
for (name, version) in &event.actions.artifact_delta {
println!(" {} (v{})", name, version);
}
}
}
Ereignishistorie begrenzen
Bei langen Unterhaltungen möchten Sie möglicherweise nur die neuesten Ereignisse abrufen:
// Get only the last 10 events
let session = session_service.get(GetRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: session_id.clone(),
num_recent_events: Some(10),
after: None,
}).await?;
Wie Ereignisse ablaufen: Generierung und Verarbeitung
Zu verstehen, wie Ereignisse erstellt und verarbeitet werden, hilft zu verdeutlichen, wie das Framework Aktionen und Historie verwaltet.
Generierungsquellen
Ereignisse werden an unterschiedlichen Punkten im Lebenszyklus der Agentenausführung erstellt:
- Benutzereingabe: Der Runner verpackt Benutzernachrichten in ein Event mit
author = "user" - Agentenantworten: Agents liefern Event-Objekte zurück (setzen
author = agent.name()), um Antworten zu übermitteln - LLM-Ausgabe: Die Integrationsschicht des Modells übersetzt die Ausgabe von LLM (Text, Funktionsaufrufe) in Event-Objekte
- Tool-Ergebnisse: Nach der Ausführung eines Tools erzeugt das Framework ein Event, das die Tool-Antwort enthält
Verarbeitungsablauf
Wenn ein Ereignis generiert wird, folgt es diesem Verarbeitungspfad:
- Generierung: Ein Ereignis wird von seiner Quelle erstellt und ausgegeben (Agent, Tool oder Benutzereingabe-Handler)
- Runner empfängt: Der Runner, der den Agenten ausführt, empfängt das Ereignis
- SessionService-Verarbeitung: Der Runner sendet das Ereignis an das SessionService, das:
- Deltas anwenden: Mergt
state_deltain den Sitzungszustand und aktualisiert Artefaktaufzeichnungen - Metadaten finalisieren: Weist eindeutige
idzu, falls nicht vorhanden, und setzttimestamp - In Historie persistieren: Hängt das Ereignis an
session.eventsan
- Deltas anwenden: Mergt
- Stream-Ausgabe: Der Runner gibt das verarbeitete Ereignis an die aufrufende Anwendung zurück
Dieser Ablauf stellt sicher, dass Zustandsänderungen und Historie gemeinsam mit dem Kommunikationsinhalt konsistent aufgezeichnet werden.
// Conceptual flow
User Input → Runner → Agent → LLM → Event Generated
↓
SessionService
- Apply state_delta
- Record in history
↓
Event Stream → Application
Ereignistypen identifizieren
Wenn Sie Ereignisse vom Runner verarbeiten, sollten Sie identifizieren, mit welchem Ereignistyp Sie es zu tun haben:
Nach Autor
Das Feld author sagt Ihnen, wer das Ereignis erstellt hat:
match event.author.as_str() {
"user" => println!("User input"),
agent_name => println!("Response from agent: {}", agent_name),
}
Nach Inhaltstyp
Prüfen Sie das Feld llm_response.content, um den Payload-Typ zu bestimmen:
if let Some(content) = &event.llm_response.content {
// Check for text content
let has_text = content.parts.iter().any(|part| {
matches!(part, Part::Text { .. })
});
// Check for function calls (tool requests)
let has_function_call = content.parts.iter().any(|part| {
matches!(part, Part::FunctionCall { .. })
});
// Check for function responses (tool results)
let has_function_response = content.parts.iter().any(|part| {
matches!(part, Part::FunctionResponse { .. })
});
if has_text {
println!("Text message");
} else if has_function_call {
println!("Tool call request");
} else if has_function_response {
println!("Tool result");
}
}
Nach Aktionen
Prüfen Sie das Feld actions auf Steuersignale und Nebenwirkungen:
// State changes
if !event.actions.state_delta.is_empty() {
println!("Event contains state changes");
}
// Agent transfer
if let Some(target) = &event.actions.transfer_to_agent {
println!("Transfer to agent: {}", target);
}
// Escalation signal
if event.actions.escalate {
println!("Escalation requested");
}
// Context compaction
if let Some(compaction) = &event.actions.compaction {
println!("Compacted events from {} to {}",
compaction.start_timestamp, compaction.end_timestamp);
}
// Tool confirmation
if let Some(confirmation) = &event.actions.tool_confirmation {
println!("Tool {} awaiting confirmation", confirmation.tool_name);
}
// Skip summarization
if event.actions.skip_summarization {
println!("Skip this event in summaries");
}
Arbeiten mit Ereignis-Streams
Wenn Sie einen Agenten ausführen, erhalten Sie einen Stream von Ereignissen. So verarbeiten Sie ihn effektiv:
Ereignisse vom Runner verarbeiten
use adk_core::{SessionId, UserId};
use futures::StreamExt;
let mut stream = runner.run(
UserId::new("user_123")?,
SessionId::new("session_id")?,
user_input,
).await?;
while let Some(event_result) = stream.next().await {
match event_result {
Ok(event) => {
// Process the event
println!("Event from: {}", event.author);
// Extract text content
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
print!("{}", text);
}
}
}
// Check for state changes
if !event.actions.state_delta.is_empty() {
println!("\nState updated: {:?}", event.actions.state_delta);
}
}
Err(e) => {
eprintln!("Error: {}", e);
break;
}
}
}
Funktionsaufrufe extrahieren
Wenn das LLM ein Tool anfordert, enthält das Ereignis Informationen zum Funktionsaufruf:
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::FunctionCall { name, args, thought_signature, .. } = part {
println!("Tool requested: {}", name);
println!("Arguments: {}", args);
if let Some(sig) = thought_signature {
println!("Thought signature: {} bytes", sig.len());
}
// Your application might dispatch tool execution here
// based on the tool name and arguments
}
}
}
Funktionsantworten extrahieren
Nachdem ein Tool ausgeführt wurde, wird das Ergebnis in einer Funktionsantwort zurückgegeben:
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::FunctionResponse { function_response, .. } = part {
println!("Tool result from: {}", function_response.name);
println!("Response: {}", function_response.response);
// Process the tool result
// The LLM will use this to continue the conversation
}
}
}
Erstklassige Tool-Accessoren (empfohlen)
Das Durchlaufen von content.parts und das Abgleichen von Part-Varianten funktioniert, aber beim Aufbau von UIs
stellt der Event-Typ typisierte, renderbereite Accessors bereit, sodass Sie nie Teil-
Interna berühren. Sie sind der empfohlene Weg, Tool-Aktivität aus einem
EventStream zu konsumieren:
// A model requested one or more tools.
for call in event.tool_calls() {
println!("→ {} {}", call.name, call.args); // call.call_id correlates this call
}
// A tool finished — surfaces the output of ANY tool, streaming or not.
for result in event.tool_results() {
println!("✓ {} returned {}", result.name, result.response);
}
tool_calls() gibt Vec<ToolCallView> zurück und tool_results() gibt
Vec<ToolResultView> zurück:
pub struct ToolCallView<'a> { pub call_id: Option<&'a str>, pub name: &'a str, pub args: &'a Value }
pub struct ToolResultView<'a> { pub call_id: Option<&'a str>, pub name: &'a str, pub response: &'a Value }
Beide Ansichten sind für Ereignisse leer, die keine Tool-Aktivität enthalten, sodass eine UI
sie bei jedem Ereignis bedingungslos aufrufen kann. tool_results() ist das, was die
Ausgabe eines Tools erstklassig macht: Ein One-Shot-Tool (read_file, ein Wetter-API) hat keine
Streaming-Ausgabe, aber sein Ergebnis kommt dennoch als gewöhnliches Ereignis an, das Sie
rendern können — nicht nur bash-artige Tools.
Korrelation. Verwenden Sie call_id, um ein Ergebnis (und alle Fortschritts-Chunks, siehe
unten) seinem ursprünglichen Aufruf zuzuordnen. Anbieter, die keine Call-IDs angeben (z. B. Gemini),
lassen es auf None; fallen Sie in diesem Fall auf name zurück.
Streaming-Tool-Fortschritt
Langlaufende Tools (ein Shell-Befehl, ein Build, ein Download) können der UI Zwischen-
ausgabe während ihrer Ausführung senden, statt den Benutzer auf das finale Ergebnis warten zu lassen. Ein Tool ruft
ToolContext::emit_progress auf:
// inside Tool::execute, as output arrives:
ctx.emit_progress("stdout", &format!("{line}\n")).await;
ctx.emit_progress("stderr", &warning).await;
Das Framework leitet jeden Chunk als Teilereignis auf demselben
EventStream wie alles andere weiter — kein separater Kanal, kein Scraping von Logs.
Erkennen und leiten Sie diese Ereignisse mit tool_progress_stream() weiter:
while let Some(event) = stream.next().await {
let event = event?;
if let Some(stream_name) = event.tool_progress_stream() { // "stdout" | "stderr" | custom
// render a live terminal line from event.llm_response.content (role "tool")
continue;
}
// ... handle tool_calls(), tool_results(), and model text as usual
}
Fortschrittsereignisse sind als partial = true markiert (damit sie niemals mit einer
finalen Antwort verwechselt werden) und tragen die ursprüngliche Call-ID in provider_metadata
(Schlüssel adk_core::TOOL_PROGRESS_CALL_ID_KEY), sodass Sie sie mit dem richtigen
tool_calls() / tool_results()-Eintrag gruppieren können. Die Standard-emit_progress-
Implementierung ist ein No-Op, daher sind Tools, die nicht streamen, nicht betroffen.
Zusammengefügt sieht ein vollständiger Tool-Lebenszyklus im Stream so aus:
tool_calls() → open a card (name + args, correlated by call_id)
tool_progress_stream()→ live stdout/stderr lines stream into the card
tool_results() → finalize the card with the tool's output
Genau dieses Muster verwendet das streaming_bash-Beispiel, um sowohl
Streaming-Tools (bash) als auch One-Shot-Tools (read_file, grep, glob) aus einem
einzigen Datenstrom über websocket darzustellen.
Häufige Ereignismuster
Hier sind typische Ereignisfolgen, auf die Sie stoßen werden:
Einfache Text-Interaktion
[Event 1] author="user", content=Text("Hello")
[Event 2] author="assistant", content=Text("Hi! How can I help?")
Ablauf der Tool-Verwendung
[Event 1] author="user", content=Text("What's the weather?")
[Event 2] author="assistant", content=FunctionCall(name="get_weather", args={...})
[Event 3] author="assistant", content=FunctionResponse(name="get_weather", response={...})
[Event 4] author="assistant", content=Text("It's sunny and 72°F")
Zustandsaktualisierung
[Event 1] author="assistant", content=Text("I've saved your preference")
actions.state_delta={"user_theme": "dark"}
Agenten-Übergabe
[Event 1] author="router", content=Text("Transferring to specialist")
actions.transfer_to_agent=Some("specialist_agent")
[Event 2] author="specialist_agent", content=Text("I can help with that")
Ereignis-Metadaten und Kennungen
Ereignis-ID
Jedes Ereignis hat eine eindeutige id (UUID) zur präzisen Identifikation:
println!("Event ID: {}", event.id);
Aufruf-ID
Die invocation_id gruppiert alle Ereignisse von einer einzelnen Benutzeranfrage bis hin zur finalen Antwort:
// All events in one interaction share the same invocation_id
println!("Invocation: {}", event.invocation_id);
// Use this for logging and tracing
log::info!("Processing event {} in invocation {}", event.id, event.invocation_id);
Zeitstempel
Ereignisse werden für die chronologische Reihenfolge mit Zeitstempeln versehen:
println!("Event occurred at: {}", event.timestamp.format("%Y-%m-%d %H:%M:%S"));
Bewährte Vorgehensweisen
-
Unveränderlichkeit von Ereignissen: Ereignisse sollten nach ihrer Erstellung niemals geändert werden. Sie bilden ein unveränderliches Prüfprotokoll.
-
Zustandsverwaltung: Verwenden Sie
state_deltafür alle Zustandsänderungen, statt den Zustand direkt zu ändern. Dadurch wird sichergestellt, dass Änderungen im Ereignisprotokoll nachverfolgt werden. -
Aussagekräftige Autoren: Setzen Sie klare, beschreibende Autorennamen, damit Ereignisprotokolle leichter zu verstehen sind.
-
Selektive Zusammenfassung: Verwende
skip_summarizationfür ausführliche oder interne Ereignisse, die den Gesprächsverlauf aufblähen würden. -
Gruppierung von Aufrufen: Behalte für alle Ereignisse, die während eines einzelnen Agentenaufrufs erzeugt werden, dieselbe
invocation_idbei, um die logische Gruppierung zu erhalten. -
Artefaktverfolgung: Aktualisiere
artifact_deltaimmer, wenn Artefakte erstellt oder geändert werden, um die Konsistenz zu wahren. -
Stream-Verarbeitung: Behandle Fehler bei der Verarbeitung von Ereignisströmen immer. Ereignisse können aufgrund von LLM-Fehlern, Tool-Fehlern oder Netzwerkproblemen fehlschlagen.
-
Inhaltsprüfung: Prüfe immer, ob
llm_response.contentSomeist, bevor du auf Teile zugreifst. Manche Ereignisse (wie reine Statusaktualisierungen) haben möglicherweise keinen Inhalt. -
Pattern Matching: Verwende Rusts Pattern Matching, um verschiedene Ereignistypen und Inhaltsteile elegant zu behandeln.
-
Protokollierung: Verwende
invocation_id, um alle Ereignisse innerhalb einer einzelnen Benutzerinteraktion für Debugging und Beobachtbarkeit zu korrelieren.
Verwandte Dokumentation
- Sitzungen - Sitzungsverwaltung und Lebenszyklus
- Zustandsverwaltung - Arbeit mit Sitzungszustand
- Kontextkompaktierung - Ereigniszusammenfassung mit gleitendem Fenster
- Artefakte - Verwaltung binärer Daten
- Multi-Agenten-Systeme - Agentenübergaben und Koordination
- Callbacks - Ereignisse abfangen und ändern
Vorherige: ← Artefakte | Nächste: Telemetry →