Idee in 30 Sekunden
Agent-Logging beantwortet eine einfache Frage: Was genau ist wÀhrend eines Runs passiert.
DafĂŒr braucht man strukturierte Events mit Korrelation ĂŒber run_id und trace_id.
Ohne das sieht man in Incidents meist nur die finale Antwort, aber nicht den Weg dorthin.
Hauptproblem
Im klassischen Backend reichen oft ein paar Logs pro Request.
In Agentensystemen kann eine Anfrage Reasoning, Tool-Aufrufe, Retries und mehrere Modellschritte enthalten. Wenn nur das Finale geloggt wird, ist schwer zu erkennen, wo das System gebrochen ist.
In Production sieht das oft so aus:
- ein Nutzer meldet eine falsche Antwort;
- Kosten oder Latenz steigen in Wellen;
- im Log steht ein einzelner Fehler ohne Run-Kontext.
Deshalb brauchen Agenten keine zufĂ€lligen Logs, sondern strukturiertes Event-Logging ĂŒber den gesamten Run-Lifecycle.
Wie es funktioniert
Die Basisidee ist einfach: Jeder wichtige Schritt wird als eigenes strukturiertes Event gespeichert.
Minimum pro Event:
run_idundtrace_idzur Korrelation;event(was passiert ist);timestamp;status(ok/error) wo relevant;- zentrale Schrittfelder (tool, latency, stop_reason usw.).
Welche Events zuerst geloggt werden sollten
| Event | Was festgehalten werden sollte |
|---|---|
| run_started | run_id, trace_id, request_id, user_id |
| agent_step | step_type, step_index, tool |
| tool_call | tool_name, args_hash |
| tool_result | tool_name, latency_ms, status, error_class |
| llm_result | model, token usage, latency_ms, status |
| run_finished | stop_reason, total_steps, total_latency_ms |
In Production werden raw prompts und raw tool args meist nicht ohne Redaction geloggt. Oft wird stattdessen ein Hash oder eine anonymisierte Form gespeichert.
Wann einsetzen
Tiefes Logging ist nicht immer nötig.
FĂŒr einfache Single-Shot-Szenarien reichen manchmal minimale request -> response Logs.
Sobald aber Tools, Retries, mehrere Schritte oder höhere Kosten auftreten, wird es ohne strukturiertes Logging schwierig:
- Incidents zu debuggen;
- Kosten zu erklÀren;
- Alerts stabil zu konfigurieren.
Implementierungsbeispiel
Unten ein vereinfachtes Beispiel fĂŒr Structured Logging in Runtime und Tool-Gateway.
Im Beispiel werden raw args nicht geloggt: Es wird args_hash gespeichert.
agent_step protokolliert den Schritt selbst, wÀhrend tool_call und tool_result Start und Ergebnis des Tool-Aufrufs getrennt erfassen.
import hashlib
import json
import logging
import time
import uuid
logger = logging.getLogger("agent")
def stable_hash(value):
payload = json.dumps(
value,
sort_keys=True,
ensure_ascii=False,
default=str, # fuer datetime und komplexe Typen; in kritischen Systemen besser stabiles Format nutzen (z. B. ISO 8601)
).encode("utf-8")
return hashlib.sha256(payload).hexdigest()
def log_event(event, **fields):
logger.info(event, extra={"event": event, **fields})
def run_agent(agent, task, user_id=None, request_id=None):
run_id = str(uuid.uuid4())
trace_id = str(uuid.uuid4())
started_at = time.time()
steps = 0
stop_reason = "max_steps"
run_status = "ok"
log_event(
"run_started",
run_id=run_id,
trace_id=trace_id,
user_id=user_id,
request_id=request_id,
task_hash=stable_hash(task),
)
try:
for step in agent.iter(task): # step: reasoning oder tool execution
steps += 1
step_started_at = time.time()
step_type = step.type
tool_name = getattr(step, "tool_name", None)
log_event(
"agent_step",
run_id=run_id,
trace_id=trace_id,
step_index=steps,
step_type=step_type,
tool=tool_name,
)
if step_type == "tool_call":
args = getattr(step, "args", {})
log_event(
"tool_call",
run_id=run_id,
trace_id=trace_id,
tool=tool_name,
args_hash=stable_hash(args),
)
try:
result = step.execute()
latency_ms = int((time.time() - step_started_at) * 1000)
if step_type == "tool_call":
log_event(
"tool_result",
run_id=run_id,
trace_id=trace_id,
tool=tool_name,
latency_ms=latency_ms,
status="ok",
)
else:
token_usage = getattr(result, "token_usage", None)
log_event(
"llm_result",
run_id=run_id,
trace_id=trace_id,
step_type=step_type,
model=getattr(step, "model", None),
token_usage=token_usage,
latency_ms=latency_ms,
status="ok",
)
except Exception as error:
latency_ms = int((time.time() - step_started_at) * 1000)
result_event = "tool_result" if step_type == "tool_call" else "llm_result"
log_event(
result_event,
run_id=run_id,
trace_id=trace_id,
step_type=step_type,
tool=tool_name,
model=getattr(step, "model", None),
latency_ms=latency_ms,
status="error",
error_class=type(error).__name__,
error_message=str(error),
)
run_status = "error"
stop_reason = "tool_error" if step_type == "tool_call" else "step_error"
raise
if result.is_final:
stop_reason = "completed"
break
finally:
log_event(
"run_finished",
run_id=run_id,
trace_id=trace_id,
status=run_status,
stop_reason=stop_reason,
total_steps=steps,
total_latency_ms=int((time.time() - started_at) * 1000),
)
In Production gehen solche Events meist in ein zentrales Logging-System (z. B. ELK, Datadog oder ClickHouse) und werden fuer Dashboards und Alerts genutzt.
Dieses Beispiel reicht, um:
- problematische Tool-Calls zu finden;
- Latenz pro Schritt zu berechnen;
- zu verstehen, warum ein Run gestoppt hat.
Ein einzelner JSON-Logeintrag kann so aussehen:
{
"timestamp": "2026-03-21T15:17:00Z",
"event": "tool_result",
"run_id": "run_9fd2",
"trace_id": "tr_9fd2",
"tool": "search_docs",
"latency_ms": 410,
"status": "ok"
}
Typische Fehler
Auch wenn Logging vorhanden ist, bleiben Incidents oft schwer auswertbar wegen der typischen Fehler unten.
Es wird nur die finale Antwort geloggt
Ohne Zwischen-Events ist nicht sichtbar, wie der Agent zum Ergebnis kam. Damit dauert selbst ein einfacher Incident zu lange.
Keine stabilen IDs (run_id, trace_id)
Wenn Events nicht korrelieren, kann kein vollstĂ€ndiges Run-Bild rekonstruiert werden. In Production wird Debugging dann oft zur manuellen Suche ĂŒber mehrere Services.
Raw prompts oder raw args werden ohne Redaction geloggt
Das ist ein direkter Leak-Risiko fĂŒr personenbezogene oder sensitive Daten. Sicherer sind Hashes, redigierte Felder oder anonymisierte Versionen.
tool_result und stop_reason fehlen
Wenn tool_result und stop_reason fehlen, ist schwer zu erkennen, was genau gebrochen ist.
Diese Luecken maskieren oft Tool-Ausfall oder eine fruehe Phase von Tool-Spam.
Selbstcheck
Unten ist eine kurze Checkliste fuer Basis-Agent-Logging vor Release.
Fortschritt: 0/9
â Grundlegende Observability fehlt
Das System wird in production schwer zu debuggen sein. Starten Sie mit run_id, structured logs und tracing von tool calls.
FAQ
Q: Worin unterscheidet sich Logging von Tracing?
A: Logging beantwortet âwas ist passiertâ und protokolliert Events. Tracing zeigt âwie genau ist es passiertâ ueber Schrittfolge und Verknuepfungen.
Q: Was sollte zuerst geloggt werden, wenn kaum Logging existiert?
A: Starte mit Basis: run_id, trace_id, run_started, tool_call, tool_result, run_finished, stop_reason. Das reicht bereits fuer Basis-Debugging.
Q: Kann man Prompts vollstaendig loggen?
A: Standardmaessig besser nicht. In Production enthalten Prompts oft sensitive Daten. Sicherer sind Hash oder redigierte Versionen.
Q: Woran erkenne ich, dass Logging ausreicht?
A: Wenn du innerhalb von 5-10 Minuten die Ereignisfolge eines problematischen Runs rekonstruieren und den Fehlerpunkt finden kannst, funktioniert dein Basis-Logging.
Verwandte Seiten
Weiter zum Thema:
- Observability fuer KI-Agenten â Gesamtmodell fuer traces, logs und metrics.
- Agent Tracing â wie man den Run-Pfad Schritt fuer Schritt sieht.
- Verteiltes Agent-Tracing â wie Events zwischen Services verbunden werden.
- Debugging von Agent-Runs â praktische Incident-Analyse.
- Agent-Metriken â welche Kennzahlen fuer stabilen Betrieb wichtig sind.