Idee in 30 Sekunden
Agent-Metriken zeigen den Zustand des Systems ueber viele Runs hinweg, nicht nur in einem Einzelfall.
Sie beantworten: ist das System stabil, steigen die Kosten, und wo beginnt die Degradation.
Ohne Metriken werden Probleme meist zu spaet sichtbar: nach Nutzerbeschwerden oder Budget-Ueberschreitung.
Hauptproblem
Logs und Tracing erklaeren einen konkreten Incident gut.
In Production braucht man aber Trends: was mit latency, token usage, error rate und tool calls zwischen Releases passiert. Ohne Metriken kann das System schrittweise degradieren und lange unbemerkt bleiben.
In Production sieht das meist so aus:
- die durchschnittliche Antwortzeit wirkt normal, aber p95 steigt bereits;
- Token-Kosten springen nach einem Release in Wellen;
- die Zahl der tool calls pro Run waechst;
- das Team merkt das Problem erst nach einem Incident.
Genau deshalb sind Metriken ein eigenes Observability-Signal: sie helfen, Anomalien frueh zu erkennen und vor groesseren Ausfaellen zu reagieren.
Wie es funktioniert
Metriken sind aggregierte numerische Signale, die das Systemverhalten ueber die Zeit zeigen.
Ueblich sind drei Metrik-Ebenen:
- Run-Ebene (
run_count,success_rate,stop_reason); - Schritte und Tools (
tool_calls_per_run,tool_error_rate,step_count); - Kosten und Geschwindigkeit (
token_usage,cost_per_run(wird austoken_usageim Dashboard oder per Metrik-Query berechnet),latency_p50/p95).
Metriken geben ein Fruehsignal, wenn das System zu degradieren beginnt. Logs beantworten "was ist passiert", und Tracing beantwortet "wie genau ist es in einem konkreten Run passiert".
Typische Production-Metriken fuer Agenten
| Metrik | Was sie zeigt | Wozu sie dient |
|---|---|---|
| run_count | Anzahl der Runs pro Zeitraum | Kontrolle von Last und Traffic-Volumen |
| success_rate | Anteil erfolgreicher Runs | schnelle Stabilitaetspruefung |
| latency_p50 / latency_p95 | typische und langsame Schwanz-Latenz | Erkennung von Performance-Degradation |
| token_usage_per_run | wie viele Tokens ein Run verbraucht | Kontrolle der LLM-Kosten |
| cost_per_run | geschaetzte Kosten eines Runs | Budgetkontrolle und Kostenprognose |
| tool_calls_per_run | wie oft ein Run Tools aufruft | Erkennung ueberfluessiger oder zyklischer Aufrufe |
| tool_error_rate | Haeufigkeit von Tool-Fehlern | fruehe Erkennung instabiler Abhaengigkeiten |
| stop_reason_distribution | Verteilung der Run-Abbruchgruende | Kontrolle von Limits und typischen Fehlern |
Damit Metriken nuetzlich sind, werden sie meist nach release, model oder tool segmentiert.
Wichtig: keine hoch-kardinalen Felder (run_id, request_id, user_id) als Labels verwenden, sonst wird das Metrik-Storage schnell ueberlastet.
Wann einsetzen
Ein breites Metrik-Set ist nicht immer noetig.
Fuer fruehe Prototypen reichen manchmal einfache Zaehler fuer Runs und Fehler.
Kritisch werden Metriken, wenn:
- das Agentensystem bereits in Production ist;
- SLOs fuer latency oder Qualitaet gelten;
- Token- und Tool-Kosten kontrolliert werden muessen;
- Releases haeufig sind und Regressionen vor Incidents sichtbar sein sollen.
Implementierungsbeispiel
Unten ist ein vereinfachtes Beispiel fuer Runtime-Instrumentierung im Prometheus-Stil. In realen Systemen gelten dieselben Prinzipien fuer Datadog, Grafana Cloud, CloudWatch und andere Plattformen.
import time
from prometheus_client import Counter, Histogram
RUN_TOTAL = Counter(
"agent_run_total",
"Total number of agent runs",
["status", "stop_reason", "release"],
)
# success_rate = RUN_TOTAL{status="ok"} / RUN_TOTAL
RUN_LATENCY_MS = Histogram(
"agent_run_latency_ms",
"Run latency in milliseconds",
["release"],
buckets=(100, 250, 500, 1000, 2000, 5000, 10000),
)
STEP_COUNT = Histogram(
"agent_steps_per_run",
"Number of steps per run",
["release"],
buckets=(1, 2, 4, 8, 12, 16, 24, 32),
)
TOOL_CALL_TOTAL = Counter(
"agent_tool_call_total",
"Total tool calls",
["tool", "status", "release"],
)
TOOL_ERROR_TOTAL = Counter(
"agent_tool_error_total",
"Total tool errors by class",
["tool", "error_class", "release"],
)
LLM_ERROR_TOTAL = Counter(
"agent_llm_error_total",
"Total LLM step errors by model and class",
["model", "error_class", "release"],
)
TOOL_LATENCY_MS = Histogram(
"agent_tool_latency_ms",
"Tool call latency in milliseconds",
["tool", "release"],
buckets=(20, 50, 100, 250, 500, 1000, 2000, 5000),
)
TOKEN_USAGE_TOTAL = Counter(
"agent_token_usage_total",
"Total LLM tokens",
["model", "token_type", "release"],
)
def observe_llm_usage(model, token_usage, release):
# die meisten LLM-Provider liefern token usage in der Antwort
if not token_usage:
return
TOKEN_USAGE_TOTAL.labels(model=model, token_type="prompt", release=release).inc(
token_usage.get("prompt_tokens", 0)
)
TOKEN_USAGE_TOTAL.labels(model=model, token_type="completion", release=release).inc(
token_usage.get("completion_tokens", 0)
)
def run_agent(agent, task, release="2026-03-21"):
started_at = time.time()
steps = 0
stop_reason = "max_steps"
run_status = "ok"
try:
for step in agent.iter(task):
steps += 1
step_type = step.type
result = None # kann bei unbekannten Schritt-Typen None bleiben (durch den Check unten abgesichert)
if step_type == "tool_call":
tool_name = getattr(step, "tool_name", "unknown")
tool_started_at = time.time()
try:
result = step.execute()
TOOL_CALL_TOTAL.labels(tool=tool_name, status="ok", release=release).inc()
TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
(time.time() - tool_started_at) * 1000
)
except Exception as error:
TOOL_CALL_TOTAL.labels(tool=tool_name, status="error", release=release).inc()
TOOL_ERROR_TOTAL.labels(
tool=tool_name,
error_class=type(error).__name__,
release=release,
).inc()
TOOL_LATENCY_MS.labels(tool=tool_name, release=release).observe(
(time.time() - tool_started_at) * 1000
)
run_status = "error"
stop_reason = "tool_error"
raise
else:
try:
result = step.execute()
observe_llm_usage(
model=getattr(step, "model", "unknown"),
token_usage=getattr(result, "token_usage", None),
release=release,
)
except Exception as error:
LLM_ERROR_TOTAL.labels(
model=getattr(step, "model", "unknown"),
error_class=type(error).__name__,
release=release,
).inc()
run_status = "error"
stop_reason = "step_error"
raise
if result and result.is_final:
stop_reason = "completed"
break
finally:
RUN_TOTAL.labels(status=run_status, stop_reason=stop_reason, release=release).inc()
RUN_LATENCY_MS.labels(release=release).observe((time.time() - started_at) * 1000)
STEP_COUNT.labels(release=release).observe(steps)
In Production fliessen diese Metriken in Dashboards und Alerts.
So koennen diese Metriken zusammen in einem realen Dashboard aussehen:
| Metrik | Aktueller Wert | Trend | Status |
|---|---|---|---|
| latency_p95 | 2.4s | +38% in 30 Min | warning: ueber SLO |
| tool_error_rate | 7.2% | +4.1pp in 15 Min | critical: alert |
| token_usage_per_run | 8.9k | +22% nach Release | warning: Anomalie |
| success_rate | 91.4% | -5.3pp in 1 Stunde | warning: Rueckgang |
Fuer error_class ist ein normalisiertes Wertewoerterbuch besser, um unnoetige Kardinalitaet zu vermeiden.
Zum Beispiel kann eine Metrikzeile so aussehen:
agent_tool_call_total{tool="search_docs",status="error",release="2026-03-21"} 47
Typische Fehler
Selbst wenn Metriken vorhanden sind, bringen sie oft wenig wegen typischer Fehler unten.
Nur Durchschnittswerte, ohne p95/p99
Der Durchschnitt versteckt den langen Schwanz langsamer Runs.
Fuer Production ist das Minimum p50 und p95.
Hoch-kardinale Labels
Labels wie run_id oder user_id erhoehen die Last auf dem Metrik-Backend stark.
Besser segmentieren nach release, model, tool.
Keine stop_reason-Metriken
Ohne stop_reason-Verteilung ist schwer zu verstehen, warum Runs mit max_steps oder tool_error enden.
Das maskiert oft Tool-Ausfall und fruehe Signale einer Budget-Explosion.
Keine Alerts auf zentrale Anomalien
Metriken ohne Alerts werden zu passiven Charts. Ohne Alerts uebersieht man leicht Tool-Spam oder einen starken Einbruch der Erfolgsrate nach einem Release.
Selbstcheck
Unten ist eine kurze Checkliste fuer Basis-Metriken von Agenten 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 unterscheiden sich Metriken von Logs und Tracing?
A: Metriken zeigen Trends und Systemzustand ueber die Zeit. Logs erklaeren Ereignisse, und Tracing zeigt den Pfad eines konkreten Runs.
Q: Welches Minimum an Metriken braucht man fuer den ersten Production-Release?
A: Starte mit run_count, success_rate, latency_p95, tool_error_rate, token_usage_per_run und stop_reason_distribution.
Q: Warum reicht nur durchschnittliche latency nicht aus?
A: Der Durchschnitt versteckt lange langsame Runs. p95 zeigt reale Nutzer-Degradation deutlich frueher.
Q: Welche Labels brechen Metrik-Storage am haeufigsten?
A: Alles mit hoher Kardinalitaet: run_id, request_id, user_id, komplette Prompts oder raw args.
Verwandte Seiten
Weiter zum Thema:
- Observability fuer KI-Agenten â Gesamtmodell aus Tracing, Logging und Metriken.
- Agent-Logging â welche Events in Runtime erfasst werden sollen.
- Agent Tracing â wie man den Pfad eines Runs Schritt fuer Schritt sieht.
- Semantisches Logging fuer Agenten â wie Events fuer Analytics vereinheitlicht werden.
- Cost Monitoring fuer KI-Agenten â wie production cost kontrolliert wird.