Asynchrone API-Jobs zuverlässig für KI-Agenten gestalten
Ein Agent startet Ihre Video-Transkodierung, erhält 202 Accepted und eine Auftrags-ID – und meldet trotzdem sofort Erfolg. Der nächste Schritt versucht dann, eine Datei zu lesen, die noch nicht existiert.
Apidog noch heute ausprobieren
Langlaufende Operationen teilen einen einfachen Request-/Response-Vertrag in zwei Phasen: Start und Abschluss. Ohne einen eindeutigen Vertrag behandeln Agenten ein 2xx als abgeschlossen, pollen in teuren Schleifen oder halten einen Gesprächszug minutenlang offen.
Dieser Leitfaden zeigt, wie Sie asynchrone Endpunkte, Tool-Wrapper und Tests so gestalten, dass Agenten zuverlässig warten, Fehler korrekt behandeln und keine Jobs verlieren. Für fehlgeschlagene API-Aufrufe lesen Sie auch den Beitrag zur Fehlerbehebung für KI-Agenten.
Apidog ist besonders nützlich, wenn Sie gezielt prüfen wollen, ob ein Agent einen vier Minuten laufenden und anschließend fehlschlagenden Job korrekt behandelt.
Warum Agenten asynchrone Vorgänge falsch handhaben
Drei Muster verursachen die meisten Fehler:
-
Ein
2xxwird als Erfolg interpretiert.202 Acceptedbedeutet laut HTTP-Semantik-Spezifikation, dass die Anfrage zur Verarbeitung angenommen wurde – nicht, dass sie abgeschlossen ist. - Polling im Modellkontext ist teuer. Alle zwei Sekunden über vier Minuten abzufragen erzeugt 120 Modell-Turns. Das verbraucht Kontext und Budget. Warum das schnell eskaliert, erklärt der Beitrag zum Heraushalten von Tool-Antworten aus dem Kontextfenster.
- Auftrags-IDs gehen verloren. Ein gestarteter Job ist Zustand. Wird seine ID in einem langen Gespräch komprimiert oder vergessen, kann der Agent den Job nicht mehr verfolgen.
Antworten so formulieren, dass ein Modell sie nicht missversteht
Verlassen Sie sich nicht nur auf den HTTP-Status. Sagen Sie im Response-Body ausdrücklich, dass der Job noch läuft und welches Tool als Nächstes verwendet werden soll.
{
"status": "processing",
"job_id": "job_7f21c",
"message": "The transcode has STARTED and is NOT complete. Do not report success. Check status with getJobStatus(job_id) after at least 30 seconds.",
"poll_after_seconds": 30,
"estimated_duration_seconds": 240,
"status_url": "/v1/jobs/job_7f21c"
}
Für Modelle sind drei Elemente entscheidend:
- Eine klare Aussage wie „nicht abgeschlossen“.
- Das konkret benannte nächste Tool.
- Eine Mindestwartezeit.
Googles AIP-151 für langlaufende Operationen empfiehlt ein konsistentes Operation-Objekt mit done, error und response. Übernehmen Sie dieses Muster für alle langsamen Endpunkte, damit Agenten ein einheitliches Abfragemodell lernen.
Auch Statusantworten sollten eindeutig sein:
{
"job_id": "job_7f21c",
"status": "processing",
"done": false,
"progress_percent": 45,
"elapsed_seconds": 108,
"poll_after_seconds": 45,
"message": "Still processing. Do not proceed to the next step."
}
Bei Erfolg sollte das Ergebnis direkt enthalten sein, wenn es klein genug ist:
{
"job_id": "job_7f21c",
"status": "succeeded",
"done": true,
"result": {
"output_url": "https://cdn.example.com/out/7f21c.mp4",
"duration_seconds": 372
}
}
Polling gehört in den Tool-Wrapper, nicht in die Denk-Schleife
Lassen Sie den Agenten ein Tool aufrufen, das auf ein finales Ergebnis wartet. Der Agent sieht dann einen Aufruf und eine abschließende Antwort – nicht dutzende Polling-Turns.
import time
def start_and_await_transcode(client, source_url, max_wait=600):
job = client.post("/v1/transcode", json={"source_url": source_url}).json()
job_id = job["job_id"]
delay = job.get("poll_after_seconds", 5)
waited = 0
while waited < max_wait:
time.sleep(delay)
waited += delay
status = client.get(f"/v1/jobs/{job_id}").json()
if status.get("done"):
if status["status"] == "succeeded":
return {"status": "succeeded", "result": status["result"]}
return {"status": "failed", "error": status.get("error")}
delay = min(int(delay * 1.5), 60)
return {
"status": "timed_out",
"job_id": job_id,
"message": f"Still running after {max_wait}s. Job {job_id} continues in the background.",
}
Dieses Muster verhindert Kontextverschwendung, vergessene Job-IDs und endlose Wartezeiten. Verwenden Sie exponentiellen Backoff mit einer Obergrenze; Amazons Leitfaden zu Timeouts, Wiederholungen und Backoff mit Jitter ist eine gute Grundlage für die Abstimmung.
Beachten Sie zwei Regeln:
- Begrenzen Sie die Wartezeit immer.
- Geben Sie bei einem Timeout immer
job_idzurück.
Unterscheiden Sie außerdem klar zwischen succeeded, failed und timed_out. Ein Modell sollte drei verschiedene Ergebnisse sehen, nicht einen mehrdeutigen Abschluss.
Für Jobs, die Stunden dauern, ist blockierendes Polling ungeeignet. Stellen Sie stattdessen zwei Tools bereit:
-
startJob()startet den Job und speichert diejob_id. -
getJobStatus(job_id)prüft den Fortschritt später.
Speichern Sie laufende Jobs außerhalb des Gesprächs, einschließlich Job-ID, zugehöriger Aufgabe und Startzeit.
Wann Polling, Webhooks oder SSE sinnvoll sind
Nutzen Sie Polling, wenn Jobs Sekunden bis wenige Minuten dauern, der Agent auf das Ergebnis warten muss oder kein öffentlicher Endpunkt verfügbar ist. Mehr dazu: Webhooks vs. Polling.
Nutzen Sie Webhooks, wenn Jobs Stunden dauern, der Agent nach dem Start weiterarbeiten soll oder viele parallele Jobs Polling ineffizient machen. Dafür brauchen Sie:
- einen öffentlich erreichbaren Empfänger,
- Signaturprüfung,
- Wiederholungs- und Fehlerbehandlung,
- einen Mechanismus, der den Agenten beim Callback wieder aktiviert.
Die Grundlagen behandeln die Beiträge zum Entwerfen zuverlässiger Webhooks und zur Webhook-Signaturprüfung.
Eine praktische Zwischenlösung sind Server-Sent Events (SSE): Der Client hält die Verbindung offen und erhält Fortschritt per Push, ohne selbst einen öffentlichen Webhook-Endpunkt bereitzustellen. Das eignet sich besonders für interaktive Agenten. Siehe: Streaming von API-Antworten mit SSE.
Unabhängig vom Transport muss die Abschlussbehandlung idempotent sein. Webhooks können erneut zugestellt werden, Polling-Aufrufe können sich überschneiden. Ein zweites Erfolgssignal darf den nachgelagerten Schritt nicht erneut starten. Details dazu finden Sie unter Idempotenz für KI-Agenten.
Den langsamen Pfad gezielt testen
Lokale Stubs antworten oft in Millisekunden. Dadurch erleben Agenten im Test nie die Zustände, die in Produktion auftreten. Bauen Sie deshalb diese vier Szenarien bewusst nach:
-
Wirklich langsamer Job: Der Status-Endpunkt liefert mehrfach
processing, danachsucceeded. Prüfen Sie Polling, Backoff und Rückgabe. -
Später Fehler: Der Endpunkt liefert mehrmals
processing, dannfailedmit Fehler-Body. Der Agent muss den Fehler melden. -
Timeout: Der Mock liefert länger als
max_waitden Statusprocessing. Das Tool musstimed_outplus intakte Job-ID zurückgeben. - Doppelte Fertigstellung: Liefern Sie Erfolg zweimal – etwa durch einen Webhook-Retry oder überlappende Polls. Der nachgelagerte Schritt darf nur einmal laufen.
In Apidog können Mocks abhängig von Anfrageanzahl oder Steuerungsparametern unterschiedliche Status zurückgeben. Speichern Sie alle Szenarien und führen Sie sie in CI aus. Der umfassendere Ansatz steht im Leitfaden zum API-Vertragstesting.
Drei typische Jobs
- Berichtserstellung: Ein Finanz-Agent startet einen Export, der 90 Sekunden dauert. Ein naives Tool gibt die Job-ID zurück; der Agent meldet zu früh Erfolg und erzeugt einen defekten Download-Link. Ein blockierender Wrapper wartet und gibt die echte URL zurück.
-
Massenimporte: Ein Ops-Agent importiert 20.000 Datensätze. Der Job endet nach acht Minuten mit Fehlern ab Zeile 14.000.
done: truebedeutet hier nicht vollständigen Erfolg. Geben Sie Zählungen und abgelehnte Zeilen explizit zurück. - Modelltraining und CI-Builds: Ein 40-minütiger Build sollte nicht einen Gesprächszug offen halten. Starten Sie den Job, speichern Sie die ID dauerhaft, beenden Sie den Turn und lassen Sie eine geplante Prüfung oder einen Callback die Nachverfolgung auslösen. Für Zustandsübergaben zwischen Läufen siehe Übergabe und Kontextweitergabe bei Multi-Agenten.
Teilergebnisse explizit modellieren
Viele lange Jobs enden weder vollständig erfolgreich noch vollständig fehlgeschlagen. Modellieren Sie diesen Zustand direkt:
{
"job_id": "job_a11f",
"status": "completed_with_errors",
"done": true,
"summary": {
"processed": 20000,
"succeeded": 19860,
"failed": 140
},
"errors_url": "/v1/jobs/job_a11f/errors?limit=50",
"message": "Import finished. 140 rows failed and were not written. Review errors before reporting success."
}
Die Zählungen stehen inline, damit der Agent sofort entscheiden kann. Fehlerdetails liegen hinter einer limitierten URL, damit Hunderte Fehlerobjekte nicht ungefragt im Kontext landen.
Timeouts brauchen eine verantwortliche Person
Ein Timeout mit Job-ID ist nur dann nützlich, wenn jemand den Zustand später prüft. Leiten Sie blockierte Jobs in die Warteschlange weiter, die Ihr Team bereits überwacht.
Bei Sharkly bleibt ein blockiert endender Lauf mit Ausführungszustand und Ergebnis an der zugehörigen Aufgabe; der Posteingang trennt menschliche Antworten und Prüfungen von normalen Updates. Entscheidend ist nicht das konkrete Tool, sondern ein klarer Verantwortlicher für „läuft noch, später prüfen“.
Checkliste
- Jeder langsame Endpunkt liefert Job-ID, Status-URL und eine klare Aussage, dass die Arbeit noch nicht abgeschlossen ist.
- Statusantworten enthalten ein boolesches Feld
done. - Polling liegt im Tool-Wrapper, mit Backoff und fester Warteobergrenze.
- Timeouts geben immer die Job-ID zurück.
- Erfolg, Fehler und Timeout sind unterschiedliche Rückgabewerte.
- Jobs, die länger als wenige Minuten dauern, werden außerhalb des Gesprächs gespeichert.
- Abschlusslogik ist idempotent – für Polling und Webhooks.
- Langsame Jobs, späte Fehler, Timeouts und doppelte Abschlüsse werden in CI getestet.
Wenn Antwortformulierung und Tool-Wrapper stimmen, werden langlaufende Operationen für Agenten zu einem normalen Vertrag: Tool aufrufen, warten, Ergebnis erhalten. Laden Sie Apidog herunter, um Mocks für langsame Jobs zusammen mit Ihren Tests zu erstellen.
Häufig gestellte Fragen
Sollte ein asynchroner Start 202 oder 200 zurückgeben?
Verwenden Sie 202 Accepted: Es beschreibt korrekt, dass Verarbeitung noch aussteht. Für Agenten reicht der Statuscode allein aber nicht aus. Der Body muss ebenfalls eindeutig sagen, dass der Job noch nicht abgeschlossen ist.
Wie lange sollte ein Tool-Wrapper warten?
Setzen Sie die Obergrenze knapp über den realistischen Worst Case des Endpunkts, typischerweise zwei bis zehn Minuten. Darüber ist ein Start-/Status-Tool mit dauerhafter Job-Aufzeichnung besser geeignet.
Welches Polling-Intervall ist sinnvoll?
Beginnen Sie mit poll_after_seconds, wenn der Server diesen Hinweis liefert. Erhöhen Sie den Abstand anschließend schrittweise, etwa um den Faktor 1,5, mit einer Obergrenze von rund 60 Sekunden. Ein festes Ein-Sekunden-Polling verschwendet Anfragen und kann Limits auslösen. Siehe: Leitfaden zur Überschreitung von Ratenbegrenzungen.
Kann ein Agent während des Wartens andere Arbeit erledigen?
Nur wenn Ihr Orchestrator parallele Tool-Aufrufe unterstützt. Dann kann der Agent unabhängige Arbeit erledigen und später den Jobstatus prüfen. Andernfalls ist ein blockierender Wrapper einfacher und zuverlässiger als ein selbst gebauter Scheduler.
Wie verhindere ich vorzeitige Erfolgsmeldungen?
Sagen Sie im Start-Response ausdrücklich, dass der Job nicht abgeschlossen ist. Geben Sie done: false zurück und liefern Sie das eigentliche Ergebnis ausschließlich über den Abschluss- oder Status-Endpunkt.
Funktionieren Webhooks für lokal laufende Agenten?
Nicht direkt, weil der lokale Rechner keinen öffentlichen Endpunkt anbietet. Nutzen Sie in der Entwicklung einen Tunnel, wie im Leitfaden zum Testen von localhost-APIs mit Webhook-Diensten, oder verwenden Sie Polling, bis der Agent öffentlich erreichbar läuft.


Top comments (0)