Health Checks für KI-Agenten: Liveness, Readiness und Synthetic Runs

Liveness und Readiness für KI-Agenten trennen, veraltete Prüfergebnisse erkennen und Fehler mit einem ausführbaren Python-Beispiel untersuchen.
Auf dieser Seite
  1. Idee in 30 Sekunden
  2. Hauptproblem
  3. Wie es funktioniert
  4. Liveness, Readiness und Synthetic Runs haben unterschiedliche Aufgaben
  5. Ausführbares Readiness-Beispiel
  6. Typische Production-Metriken fuer Health Checks
  7. Wie man den Health-Layer liest
  8. Wann einsetzen
  9. Implementierungsbeispiel
  10. Investigation
  11. Typische Fehler
  12. Es gibt nur Ping-/Verfuegbarkeitschecks
  13. Keine Checks fuer externe Abhaengigkeiten
  14. Keine Aufteilung nach workflow und release
  15. Keine Alerts auf health-score-Degradation
  16. Hoch-kardinale Labels
  17. Selbstcheck
  18. FAQ
  19. Verwandte Seiten

Idee in 30 Sekunden

Health checks fuer KI-Agenten zeigen, ob das System genau jetzt wirklich fuer Traffic bereit ist.

Sie helfen, Degradation vor dem Incident zu erkennen: langsame Tools, Timeouts, Queue-Probleme oder Ausfaelle im LLM-Layer.

Ohne health checks sieht man oft nur den Ausfall selbst, aber nicht die fruehen Signale davor.

Hauptproblem

Ein System kann formal "up" sein, aber praktisch bereits instabil laufen.

API antwortet, Runs starten, aber einzelne Schritte degradieren schon: timeout rate steigt, success rate faellt, queue time waechst. Ohne health checks wird das meist erst nach kaskadierendem Ausfall sichtbar.

Als Naechstes schauen wir, wie man diese Signale liest und findet, welche Komponente zuerst in Degradation geht.

In Production sieht das oft so aus:

  • nach aussen wirkt alles "funktionsfaehig", aber p95 latency ist schon ausserhalb SLO;
  • ein Tool liefert haeufiger Timeout, aber Ursache ist noch unklar;
  • synthetic run faellt frueher als Haupttraffic;
  • das Team reagiert erst nach partiellem Ausfall.

Darum sollte der Health-Layer separat ueberwacht werden und nicht nur ueber allgemeine Run-Metriken.

Wie es funktioniert

Health checks werden meist auf zwei Ebenen aufgebaut:

  • component checks (tool_available, llm_reachable, queue_ok, db_ok);
  • end-to-end checks (synthetic_run_ok, critical_workflow_ok).

Diese Signale beantworten: "Ist das System genau jetzt gesund?" Logs und Tracing werden gebraucht, um zu erklaeren, warum ein konkreter Check fehlgeschlagen ist.

Ein erreichbarer Prozess bedeutet noch keinen einsatzbereiten Workflow. Health Checks können einen Fehler vor den Nutzern erkennen; das hängt vom Prüfintervall und den abgedeckten Szenarien ab. Eine frühere Erkennung als durch Fehler- oder Latenzmetriken ist nicht garantiert.

Liveness, Readiness und Synthetic Runs haben unterschiedliche Aufgaben

  • Liveness: Muss der Prozess neu gestartet werden?
  • Readiness: Kann er neue Aufgaben annehmen?
  • Synthetic Run: Funktioniert ein ausgewähltes End-to-End-Szenario?

Kubernetes dokumentiert Liveness-, Readiness- und Startup-Probes.

Ein Support-Agent kann bei ausgefallener optionaler Suche eingeschränkt weiterarbeiten. Fehlt dagegen der Policy-Speicher zur Autorisierung von Aktionen, darf er betroffene Aufgaben nicht neu annehmen. Eine fehlgeschlagene kritische Prüfung wiegt schwerer als neun erfolgreiche optionale Prüfungen: Ein mittlerer health_score darf allein keinen Traffic freigeben.

Rufe nicht bei jedem Liveness-Probe ein externes LLM auf. Das verursacht Kosten; ein Providerausfall kann nutzlose Neustarts aller Replikate auslösen. Sammle Abhängigkeitsergebnisse separat mit Timeouts; Readiness liest einen aktuellen Snapshot. Synthetic Runs benötigen eigene Testdaten, ein Budget und Tools ohne Seiteneffekte (Zustandsänderungen) in Produktion.

Ausführbares Readiness-Beispiel

Speichere den Code als readiness_demo.py und starte python3 readiness_demo.py mit Python 3.10+. Er prüft die Annahmelogik, keine Netzwerk-Probes. Alle Zeitwerte stammen von derselben monotonen Prozessuhr; 30 Sekunden sind ein Beispiel, das zum Prüfintervall passen muss.

PYTHON
from dataclasses import dataclass


@dataclass(frozen=True)
class Check:
    ok: bool
    observed_at: float


def ready(checks, required, now, max_age=30.0):
    if not required or max_age <= 0:
        return False
    for name in required:
        check = checks.get(name)
        if check is None or not check.ok:
            return False
        if not 0 <= now - check.observed_at <= max_age:
            return False
    return True


required = ("queue", "policy_store")
checks = {
    "queue": Check(True, 100.0),
    "policy_store": Check(True, 100.0),
    "optional_search": Check(False, 100.0),
}
assert ready(checks, required, now=110.0)
assert not ready(checks, required, now=131.0)
assert not ready({}, required, now=110.0)
checks["policy_store"] = Check(False, 100.0)
assert not ready(checks, required, now=110.0)
print("readiness cases: 4 passed")

Erwartete Ausgabe: readiness cases: 4 passed. Geprüft werden eine optionale Abhängigkeit, veraltete Ergebnisse, fehlende Ergebnisse und eine ausgefallene kritische Abhängigkeit. Der echte Collector muss fehlgeschlagene Prüfungen erfassen und darf den Erfolgszeitpunkt nach einem Timeout nicht aktualisieren. Für bereits laufende Aufgaben ist eine eigene Abschluss- oder Recovery-Policy nötig.

Nach einem Fehlersignal folgt das Debugging des betroffenen Runs.

Typische Production-Metriken fuer Health Checks

MetrikWas sie zeigtWarum sie wichtig ist
health_check_pass_rateAnteil erfolgreicher health checksschnelle Systemzustands-Einschaetzung
health_check_latency_p95Ausfuehrungszeit der Checksfruehes Signal fuer Dependency-Degradation
tool_check_latency_p95Latenz von Checks fuer konkrete ToolsLokalisierung eines langsamen Tool-Layers
synthetic_run_success_rateErfolgsrate von synthetic runsKontrolle des realen E2E-Szenarios
degraded_component_countAnzahl degradierter KomponentenEinschaetzung des Problemumfangs
timeout_rateAnteil Timeouts in Checks und Runsfrueher Instabilitaets-Trigger
queue_time_p95wie lange ein Run in der Queue wartetSignal fuer fehlende Capacity
health_scoreaggregierter Gesundheitsindex (0..1)einfaches Signal fuer Alerts und Status Page

health_score wird meist auf Dashboard-/Health-Service-Ebene als Aggregat mehrerer Checks berechnet, nicht als eine "magische" Einzelmetrik.

Damit health-Metriken nuetzlich bleiben, werden sie meist nach release, region, workflow und Komponenten-Typ segmentiert.

Wichtig: keine hoch-kardinalen Felder (run_id, request_id, user_id) in Labels aufnehmen, sonst wird Metrik-Storage schnell ueberlastet.

Wie man den Health-Layer liest

Was geprueft wird -> was degradiert -> welche Komponente den workflow bricht. Diese drei Ebenen sollte man immer zusammen betrachten.

Wichtig sind Trends ueber Zeit und Unterschiede zwischen Releases, nicht ein einmaliger Ausfall eines einzelnen Checks.

Jetzt zu Signal-Kombinationen:

  • health_check_pass_rate down + timeout_rate up -> System geht in instabilen Modus;
  • synthetic_run_success_rate down + degraded_component_count up -> Problem beeinflusst bereits kritischen workflow;
  • queue_time_p95 up + run_count up -> Capacity fehlt, Skalierung noetig;
  • health_score down + error_rate up -> hohes Incident-Risiko in naechster Zeit;
  • tool_check_latency_p95 up + synthetic_run_success_rate down -> Bottleneck im externen Tool-Layer.

Wann einsetzen

Ein kompletter Satz health checks ist nicht immer noetig.

Fuer fruehe Prototypen kann ein einfacher API-Verfuegbarkeitscheck reichen.

Detaillierte health checks werden aber kritisch, wenn:

  • das System bereits in Production ist;
  • Stabilitaets-SLO/SLA gelten;
  • der Agent von mehreren externen Tools oder Queues abhaengt;
  • fruehe Alerts benoetigt werden, bevor ein Massenausfall startet.

Implementierungsbeispiel

Unten ist ein vereinfachter health-check-Zyklus im Prometheus-Stil. Das Beispiel zeigt den Basisansatz: Komponentenchecks, synthetic run und aggregierter health score.

Dies ist ein Instrumentierungsgerüst: Installiere prometheus-client und ergänze eigene Prüfungen mit Timeouts. Der aggregierte Score dient dem Überblick, nicht einer automatischen Readiness-Entscheidung.

PYTHON
import time
from dataclasses import dataclass
from prometheus_client import Counter, Gauge, Histogram

# perf_counter() wird fuer praezise monotone Latency-Messungen genutzt
HEALTH_CHECK_TOTAL = Counter(
    "agent_health_check_total",
    "Total health checks by check name and status",
    ["check", "status", "release"],
)

HEALTH_CHECK_LATENCY_MS = Histogram(
    "agent_health_check_latency_ms",
    "Health check latency in milliseconds",
    ["check", "release"],
    buckets=(10, 20, 50, 100, 250, 500, 1000, 2000),
)

SYNTHETIC_RUN_TOTAL = Counter(
    "agent_synthetic_run_total",
    "Total synthetic runs by status",
    ["status", "release"],
)

DEGRADED_COMPONENT_TOTAL = Counter(
    "agent_degraded_component_total",
    "Total degraded component detections",
    ["component", "reason", "release"],
)

HEALTH_SCORE = Gauge(
    "agent_health_score",
    "Aggregated health score in range 0..1",
    ["release"],
)


@dataclass
class CheckResult:
    ok: bool
    reason: str = "ok"


def run_health_checks(checks, run_synthetic, release="2026-03-22"):
    total = len(checks)
    failed = 0

    for check_name, check_fn in checks.items():
        started_at = time.perf_counter()
        status = "error"  # default for any failure path
        try:
            result = check_fn()  # -> CheckResult
            status = "ok" if result.ok else "fail"
            if not result.ok:
                failed += 1
                DEGRADED_COMPONENT_TOTAL.labels(
                    component=check_name,
                    reason=result.reason,
                    release=release,
                ).inc()
        except Exception as error:
            failed += 1
            DEGRADED_COMPONENT_TOTAL.labels(
                component=check_name,
                reason=type(error).__name__,
                release=release,
            ).inc()
        finally:
            HEALTH_CHECK_TOTAL.labels(check=check_name, status=status, release=release).inc()
            HEALTH_CHECK_LATENCY_MS.labels(check=check_name, release=release).observe(
                (time.perf_counter() - started_at) * 1000
            )

    try:
        synthetic_ok = run_synthetic()
        SYNTHETIC_RUN_TOTAL.labels(
            status="ok" if synthetic_ok else "fail",
            release=release,
        ).inc()
        if not synthetic_ok:
            failed += 1
    except Exception:
        SYNTHETIC_RUN_TOTAL.labels(status="error", release=release).inc()
        failed += 1

    # 1.0 = alle Checks erfolgreich, 0.0 = alles fehlgeschlagen
    # +1 fuer synthetic run
    denominator = total + 1
    health_score = max(0.0, 1.0 - (failed / max(1, denominator)))
    HEALTH_SCORE.labels(release=release).set(health_score)
    return health_score

Die folgenden Health-Metriken sind illustrative Werte, keine Messungen eines Produktionssystems:

Segmentpass_ratesynthetic_successhealth_scoreStatus
core workflow98.7%99.1%0.97ok
research workflow93.2%89.4%0.82warning
tool-heavy workflow87.1%80.6%0.74critical: incident risk

Investigation

Wenn ein health-Alert ausloest:

  1. Check oder workflow mit Degradation finden;
  2. problematische Runs im Tracing ansehen;
  3. timeout, stop_reason und tool failures in Logs pruefen;
  4. root cause finden (Tool, LLM, Queue, Routing, Release-Regression).

Typische Fehler

Auch wenn health checks vorhanden sind, bringen sie oft wenig wegen typischer Fehler unten.

Es gibt nur Ping-/Verfuegbarkeitschecks

API-Verfuegbarkeit garantiert nicht, dass der agentische workflow real funktioniert. Ohne synthetic run verpasst man versteckte Degradation leicht.

Keine Checks fuer externe Abhaengigkeiten

Wenn Tools, Queues oder DB nicht in health checks enthalten sind, kann das System bis zum ersten Incident "gesund" wirken. In so einer Lage ist schnelle Lokalisierung von Tool-Ausfall schwierig.

Keine Aufteilung nach workflow und release

Ohne das ist schwer erkennbar, welcher Release oder welches Szenario den Systemzustand verschlechtert hat.

Keine Alerts auf health-score-Degradation

Ohne Alerts werden health checks zu passiver Telemetrie. Dadurch verpasst man fruehe Signale von Multi-Agent-Chaos.

Hoch-kardinale Labels

run_id, request_id oder session_id in Labels ueberlasten Metrik-Backends schnell. Diese Daten besser in Logs und Tracing halten.

Selbstcheck

Unten ist eine kurze Checkliste fuer Basis-health-checks 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 health checks von normalen Metriken?
A: Metriken zeigen Trends, health checks geben eine schnelle "ist das System jetzt bereit oder nicht"-Antwort fuer konkrete Szenarien.

Q: Welches Minimum an health checks braucht man zum Start?
A: Starte mit llm_reachable, tool_available, queue_ok und einem synthetic run fuer kritischen workflow.

Q: Warum ist synthetic run so wichtig?
A: Er prueft den kompletten Ausfuehrungspfad, nicht nur einzelne Komponenten. Das bildet den realen Production-Zustand am besten ab.

Q: Wenn health score faellt, API aber noch antwortet - ist das schon Incident?
A: Das ist fruehe Degradation. Investigation sollte sofort starten, bevor das Problem zum Massenausfall wird.

Verwandte Seiten

Weiter zum Thema:

⏱️ 9 Min. Lesezeit • Aktualisiert 3. Oktober 2026Schwierigkeit: ★★★
Integriert: Production ControlOnceOnly
Make agent behavior observable with run timelines
Correlate actions and policy decisions using run events, timelines, logs, and metrics:
  • Budgets (Steps / Spend Caps)
  • Tool-Permissions (Allowlist / Blocklist)
  • Kill switch & Incident Stop
  • Idempotenz & Dedupe
  • Audit logs & Nachvollziehbarkeit
Integrierter Hinweis: OnceOnly ist eine Control-Layer für Production-Agent-Systeme.
Observability Hooks (Python SDK)
from onceonly import OnceOnly

client = OnceOnly(api_key="once_live_...")
run_id = "run_obs_042"

client.post_event(run_id=run_id, type="step_start", step="retrieve_context")
client.post_event(run_id=run_id, type="step_end", step="retrieve_context", status="ok")

timeline = client.get_run_timeline(run_id, limit=200, offset=0)
metrics = client.gov.agent_metrics("support-agent", period="day")

Autor

Nick — Engineer, der Infrastruktur für KI-Agenten in Produktion aufbaut.

Fokus: Agent-Patterns, Failure-Modes, Runtime-Steuerung und Systemzuverlässigkeit.

🔗 GitHub: https://github.com/mykolademyanov


Redaktioneller Hinweis

Diese Dokumentation ist KI-gestützt, mit menschlicher redaktioneller Verantwortung für Genauigkeit, Klarheit und Produktionsrelevanz.

Die Beispiele dienen Lernzwecken und können simulierte Tools und Daten verwenden. Prüfen Sie vor dem Produktionseinsatz Zuverlässigkeit, Sicherheit und Wiederherstellung in Ihrer eigenen Umgebung.