Sichere APIs für KI-Agenten: Nachvollziehbare Schreibvorgänge
Sichere APIs für KI-Agenten nutzen eng begrenzte Operationen, idempotente Schreibvorgänge, hilfreiche Fehler und Anforderungs-IDs, die Kontrolle und Nachvollziehbarkeit bewahren.

Ein KI-Agent macht eine API nicht automatisch gefährlich. Eine API wird gefährlich, wenn sie weit gefasste Verben, unklare Ergebnisse und Fehler anbietet, die den Aufrufer zum Raten zwingen. Menschen gleichen das mit Kontext, Zurückhaltung und einer schnellen Nachricht im Chat aus. Ein Agent reagiert dagegen mit Wiederholungen und einem weiteren Tool-Aufruf. Aus einem harmlosen Timeout werden so zwei Rückerstattungen, zwei Deployments oder ein gelöschter Datensatz, den niemand anfassen wollte.
Sichere APIs für KI-Agenten begrenzen die erlaubte Aktion, machen wiederholte Schreibvorgänge harmlos und hinterlassen eine Spur, der später ein Mensch folgen kann. Das ist API-Design, keine Prompt-Arbeit. Ein Prompt kann einem Agenten sagen, dass er vorsichtig sein soll. Der Endpunkt muss eine Aktion trotzdem ablehnen, wenn sie außerhalb seines Vertrags liegt.
Ich habe Teams gesehen, die vor einen unklaren Verwaltungsendpunkt einen Freigabebildschirm setzten und das Kontrolle nannten. Das reicht nicht. Wenn ein freigegebener Aufruf «alles in diesem Konto ändern» bedeutet, muss ein Mensch unter Zeitdruck ein Bündel verborgener Folgen prüfen. Präzision gehört zuerst in die API. Dann gibt es für die Freigabe etwas Verständliches, das genehmigt werden kann.
Weit gefasste Verben zwingen Agenten zum Raten
Ein Agent sollte eine Operation aufrufen, deren Name, Eingaben und Nebenwirkungen in einen Satz passen. Breite Endpunkte zwingen ihn, Geschäftsregeln aus unklaren Feldern, alten Beispielen oder einer Fehlermeldung abzuleiten, die nur «bad request» sagt. Dort beginnt unsichere Improvisation.
Betrachte einen Endpunkt wie POST /admin/execute mit einem Payload, der action und beliebiges JSON enthält. Ein von Menschen geschriebener Client verwendet heute vielleicht nur fünf Aktionen. Der Endpunkt stellt jedoch jedem Aufrufer mit Zugriff alle aktuellen und künftigen Aktionen zur Verfügung. Der Server kann keine sinnvolle Berechtigungsgrenze ausdrücken, und ein Genehmiger kann ohne eine Prüfung des Payloads wie Quellcode nicht erkennen, was der Agent tun wird.
Ersetze ihn durch Operationen, die eine Zustandsänderung benennen:
POST /projects/{project_id}/deploymentserstellt ein Deployment aus einer angegebenen Revision.POST /invoices/{invoice_id}/refundserstellt eine Rückerstattung mit ausdrücklichem Betrag und Grund.POST /users/{user_id}/access-revocationsentzieht einem namentlich genannten Benutzer den Zugriff.POST /exportsstartet einen definierten Export mit ausdrücklich genannter Datenkategorie.
Auch diese Operationen können riskant sein. Entscheidend ist, dass jede dem Server einen konkreten Ort gibt, an dem er Regeln durchsetzen kann: gültige Übergänge, Betragsgrenzen, Besitz des Ziels, erforderliche Freigaben und ein Begründungsfeld an der richtigen Stelle.
Verwechsle eine generische CRUD-Schnittstelle nicht mit einer brauchbaren Agenten-Schnittstelle. PATCH /customers/{id} lädt dazu ein, jedes beschreibbare Feld zu ändern. Wenn billing_email routinemäßig geändert wird, die Änderung von tax_status aber einen Compliance-Prozess startet, gehören beide Änderungen nicht hinter denselben beiläufigen Patch. Erstelle für den folgenreichen Übergang eine eigene fokussierte Operation und richte ihr Eingabemodell an der Entscheidung aus.
Eine eng begrenzte Operation verbessert auch die Wiederherstellung. Wenn ein Agent sagt «Die Deployment-Anfrage ist abgelaufen», kann ein Operator nach genau einer Deployment-Erstellung suchen. Wenn er sagt «Der Admin-Befehl ist abgelaufen», muss der Operator zunächst herausfinden, welchen Befehl der Agent zusammengestellt hat.
Vorbedingungen in die Anfrage aufnehmen
Schreibvorgänge sollten die Bedingung nennen, unter der sie sinnvoll sind. Eine Anfrage zum Genehmigen einer Ausgabe kann den erwarteten Prüfstatus enthalten. Eine Anfrage zum Aktualisieren eines Dokuments kann die gelesene Version angeben. Wenn sich der Status geändert hat, sollte der Server den Schreibvorgang ablehnen, statt ihn stillschweigend auf eine andere Realität anzuwenden.
HTTP bietet dafür bereits nützliche Mechanismen. RFC 9110 definiert bedingte Anfragen über Header wie If-Match. Ein Server kann ein veraltetes Entity-Tag mit 412 Precondition Failed ablehnen. Du kannst auch ein Feld expected_version anbieten, wenn das besser zu deiner API passt. Die konkrete Wahl ist weniger wichtig als die Disziplin: Der Client muss die Version oder den Status nennen, den er ändern will.
Akzeptiere kein Client-Feld wie force: true als Ausweg aus jedem Konflikt. Dieses Feld wird schnell zu einer Möglichkeit für Agenten, genau die Sicherheitsprüfung zu umgehen, die du eingebaut hast. Reserviere eine Überschreibung für eine eigene Operation, eine andere Berechtigungsstufe und einen sichtbaren Audit-Eintrag.
Ein Schreibvorgang braucht eine eigene Identität neben dem HTTP-Versuch
Jeder nach außen sichtbare Schreibvorgang sollte eine vom Client gelieferte Idempotenz-ID haben. Der Server verwendet sie, um zu erkennen, dass mehrere Übermittlungsversuche dieselbe beabsichtigte Aktion ausdrücken.
Eine Anforderungs-ID und eine Idempotenz-ID lösen unterschiedliche Probleme. Ein Gateway oder Server erzeugt oft für jeden HTTP-Versuch eine Anforderungs-ID. Wenn die Verbindung abbricht, nachdem der Server den Schreibvorgang übernommen hat, die Antwort den Aufrufer aber noch nicht erreicht, erhält die Wiederholung eine neue Anforderungs-ID. Die Idempotenz-ID muss gleich bleiben, weil sich die beabsichtigte Schreibaktion nicht geändert hat.
Die übliche Fehlerfolge sieht so aus:
- Der Agent sendet eine Anfrage zum Erstellen einer Auszahlung.
- Dein Server speichert die Auszahlung und ruft einen externen Anbieter auf.
- Die Verbindung bricht ab, bevor der Agent die Erfolgsantwort erhält.
- Der Agent sieht ein unbekanntes Ergebnis und wiederholt die Anfrage.
- Dein Server erstellt eine weitere Auszahlung, weil er eine neue HTTP-Anfrage erkennt.
Die Wiederholungsrichtlinie hat den Fehler nicht verursacht. Die API hat ihn verursacht, indem sie Übermittlung mit Absicht gleichsetzte.
Verwende einen Header oder ein Anfragefeld, das der Client vor dem ersten Versuch erstellt und bis zu einer endgültigen Antwort beibehält. HTTP-Header heißen häufig Idempotency-Key, die Kennung muss jedoch kein Geheimnis sein. Eine zufällige UUID funktioniert gut. Leite sie nicht allein aus einem Zeitstempel ab und verwende keine Kennung, die bei unabhängigen Schreibvorgängen kollidieren kann.
Fingerabdruck und Ergebnis der Anfrage speichern
Der Server muss eine Idempotenz-ID an mehr als ein Statusflag binden. Speichere die Identität des Aufrufers, die Zielroute, einen kanonischen Fingerabdruck des semantisch relevanten Anfrage-Bodys und das vollständige Ergebnis, das für eine Wiederholung benötigt wird. Wenn derselbe Aufrufer mit derselben ID und demselben Fingerabdruck wiederholt, gib die ursprüngliche Antwort zurück. Wenn sich der Body unterscheidet, lehne die Anfrage mit einem Konflikt ab.
Der IETF-Entwurf «The Idempotency-Key HTTP Header Field» beschreibt diesen Header als Möglichkeit für Clients, nicht idempotente HTTP-Methoden fehlertolerant zu machen. Seine Warnung zur Eindeutigkeit ist wichtig: Der Client sollte einen Wert nicht für eine andere Anfrage wiederverwenden. Ich würde bei der Implementierung noch weiter gehen. Setze diese Regel serverseitig durch, weil Agenten Anfragen wiederholen, neu starten und gelegentlich einen Zustand wiederverwenden, den ein menschlicher Client verworfen hätte.
Ein kompakter Vertrag kann so aussehen:
POST /v1/projects/prj_48/deployments
Idempotency-Key: 8c8d77c1-4ef9-4fae-b0ba-5480f686ce4c
Content-Type: application/json
{
"revision": "a1b2c3d4",
"environment": "staging",
"expected_project_version": 17
}
Gib beim ersten akzeptierten Aufruf eine Ressource und beide Kennungen zurück:
{
"request_id": "req_01J8X7QK3JZ6",
"deployment": {
"id": "dep_01J8X7R5G2",
"state": "queued",
"revision": "a1b2c3d4",
"environment": "staging"
}
}
Wenn der Agent nach einem Timeout dieselbe Anfrage wiederholt, gib dieselbe dep_01J8X7R5G2 zurück, kein zweites Deployment. Wenn er environment in production ändert, aber die Kennung beibehält, gib einen Konflikt zurück, der die Behebung klar macht:
{
"error": {
"code": "idempotency_payload_mismatch",
"message": "This idempotency identifier belongs to a deployment request with different parameters.",
"request_id": "req_01J8X84S9P2V"
}
}
Bewahre Idempotenzdatensätze mindestens so lange auf, wie realistische Client-Wiederholungen und die Wiederherstellung von Jobs möglich sind. Eine sehr kurze Aufbewahrungsdauer erzeugt eine verspätete Dublette, die in der Produktion wie ein sporadischer Fehler aussieht. Wenn Speicherdruck ein Ablaufen erzwingt, dokumentiere das Zeitfenster klar und sorge dafür, dass Verbraucher ein dazu passendes Wiederholungsverhalten wählen.
Wiederholungen sind nur sinnvoll, wenn das Ergebnis ausreichend bekannt ist
Ein Agent sollte Transportfehler und ausgewählte vorübergehende Antworten wiederholen, aber niemals eine neue Aktion erfinden, um Unsicherheit zu umgehen. Deine Antwortklassen müssen diese Entscheidung ermöglichen.
RFC 9110 definiert 429 Too Many Requests und erlaubt Retry-After. Wenn du diesen Mechanismus sendest, halte dich daran. Ein Aufrufer kann die angegebene Zeit warten, seine Idempotenz-ID beibehalten und dieselbe Anfrage senden. Bei einem vorübergehenden Serverfehler solltest du eine 5xx-Antwort mit Anforderungs-ID zurückgeben und angeben, ob der Server die Operation angenommen hat. Verwende keinen unklaren 500-Fehler für eine Validierungsabweichung oder eine verweigerte Autorisierung. Damit bringst du Clients das falsche Wiederholungsverhalten bei.
Bei asynchronen Schreibvorgängen sind Annahme und Abschluss zwei verschiedene Tatsachen. Eine 202 Accepted-Antwort sollte eine Operationsressource zurückgeben, die die Arbeit und ihren Status nennt. Nach einem Timeout kann der Agent diese Ressource abfragen, statt einen Seiteneffekt erneut zu übermitteln.
{
"request_id": "req_01J8X9FW7GH2",
"operation": {
"id": "op_01J8X9FTVX",
"state": "running",
"status_url": "/v1/operations/op_01J8X9FTVX"
}
}
Die Statusressource braucht mehr als running und failed. Füge einen Endstatus, bei Erfolg einen Verweis auf das Ergebnis und einen öffentlichen Fehlercode hinzu, wenn der Worker den Auftrag nicht abschließen kann. Ein Deployment, das beispielsweise Gesundheitsprüfungen nicht besteht, sollte nicht wie ein API-Transportfehler aussehen. Der Agent muss einen Deployment-Fehler melden oder beheben. Einen Verbindungsfehler sollte er nur dann wiederholen, wenn der Server die Anfrage nie angenommen hat.
Vermeide automatische Wiederholungen für Aktionen, die E-Mails versenden, Geld abbuchen, Zugangsdaten austauschen oder ein externes System aufrufen, sofern dein Server die Deduplizierung nicht bis zur tatsächlichen Wirkung kontrolliert. Idempotenz in deiner Datenbank verhindert nicht zwei E-Mails, wenn ein Worker abstürzt, nachdem der E-Mail-Anbieter die Nachricht angenommen hat, aber bevor der Worker den Abschluss speichert. Verwende einen Outbox-Eintrag mit einer stabilen Deduplizierungsreferenz beim Anbieter, sofern dieser das unterstützt. Wenn das externe System nicht deduplizieren kann, mache die Operation beobachtbar und verlange nach einem unbekannten Ergebnis eine menschliche Entscheidung.
Fehler müssen dem Aufrufer sagen, wie er die Anfrage repariert
Nützliche Fehlermeldungen beschreiben den verletzten Vertrag, nicht die Verlegenheit des Servers. Ein Agent kann mit einem präzisen Fehler arbeiten. Mit einer HTML-Fehlerseite, einem Stacktrace oder «invalid input» nach einer Anfrage mit zehn Feldern kann er nicht sicher arbeiten.
Gib für jeden erwarteten Fehler ein einheitliches JSON-Format zurück. Enthalten sein sollten ein stabiler code für Programme, eine kurze message für Protokolle und Menschen, eine Anforderungs-ID sowie Details auf Feldebene, sofern diese sicher offengelegt werden können. RFC 9457, «Problem Details for HTTP APIs», bietet mit Feldern wie type, title, status, detail und instance eine Standardstruktur. Du musst nicht jedes Feld übernehmen, um die zentrale Aussage zu verstehen: Fehler sind Teil des API-Vertrags und kein beiläufiger Text.
Diese Antwort sagt einem Agenten genau, was er ändern muss:
{
"error": {
"code": "invalid_state_transition",
"message": "A refund can be created only for a paid invoice.",
"request_id": "req_01J8XAS2D8M4",
"details": {
"invoice_id": "inv_204",
"current_state": "draft",
"allowed_states": ["paid", "partially_paid"]
}
}
}
Diese Antwort führt zum Raten:
{
"error": "Request failed"
}
Die zweite Antwort schickt einen Agenten zurück zur Dokumentation, zum Quellcode oder zu Erkundungsaufrufen. Erkundungsaufrufe gegen eine Schreib-API sind der Weg, auf dem aus einem kleinen Fehler ein lauter Zwischenfall wird.
Platziere keine Geheimnisse in Fehlern. Spiegle keine Autorisierungs-Header, Zugriffstoken, signierten URLs, rohen Datenbankabfragen oder Antworten externer Dienste zurück, die Daten eines anderen Kunden enthalten könnten. Ein häufiges schlechtes Muster besteht darin, jede abgefangene Ausnahme zu verpacken und ihre Meldung an den Aufrufer zurückzugeben. Das erleichtert einen Tag lang die Fehlersuche und schafft jahrelang einen Offenlegungskanal.
Trenne ungültige Eingaben von unzureichender Berechtigung. 422 Unprocessable Content kann einen korrekt aufgebauten Payload beschreiben, der gegen eine Geschäftsregel verstößt. 403 Forbidden sollte sagen, dass die angeforderte Operation eine Berechtigung oder Freigabe erfordert, ohne Ressourcen offenzulegen, die der Aufrufer nicht prüfen darf. 404 Not Found kann sinnvoll sein, wenn du die Existenz einer Ressource absichtlich verbirgst. Lege die Semantik fest, dokumentiere sie und wende sie einheitlich an.
Ein guter Fehler sagt auch, wann eine Wiederholung sinnlos ist. invalid_state_transition, idempotency_payload_mismatch und approval_required sollten blinde Wiederholungen stoppen. rate_limited mit einer Wartezeit und upstream_temporarily_unavailable können zu einer kontrollierten Wiederholung einladen. Diese Unterscheidung verhindert mehr Schaden als ein ausgeklügelter Agent-Prompt.
Anforderungs-IDs machen aus einer strittigen Aktion eine Untersuchung
Gib jeder eingehenden Anfrage eine Anforderungs-ID zurück, sende sie im Antwort-Body oder Header mit und führe sie durch jeden internen Aufruf, jede Warteschlangennachricht, jeden Worker-Job und jeden externen Anbieteraufruf. Wenn ein Agent sagt, er habe keine Antwort erhalten, musst du zwei getrennte Fragen beantworten: Hat deine API die Aktion angenommen und was hat jede Komponente danach getan?
Erzeuge die Anforderungs-ID an der Vertrauensgrenze, wenn der Aufrufer keine liefert. Du kannst eine Korrelations-ID des Aufrufers für dessen eigene Ablage akzeptieren, darfst aber nicht zulassen, dass ein nicht vertrauenswürdiger Aufrufer deine serverseitig vergebene Kennung überschreibt. Bewahre beide auf, wenn das nützlich ist. Die Server-ID verankert deine Protokolle, die Aufrufer-ID verbindet eine Folge von Agentenentscheidungen.
Protokolliere strukturierte Ereignisse, statt Textzeilen zusammenzusetzen, die Operatoren später mit regulären Ausdrücken auswerten müssen. Halte mindestens Anforderungs-ID, authentifizierte Identität, Operationsnamen, Zielressource, gegebenenfalls die Idempotenz-ID, Autorisierungsentscheidung, Ergebnisstatus und Verweise auf erstellte Ressourcen fest. Redigiere Anfragefelder anhand eines Schemas, nicht durch einen nachträglichen Zeichenkettenfilter. Ein Feld namens token lässt sich leicht redigieren. Ein in beliebigem Text eingebettetes Geheimnis nicht.
Die Spur muss die Reihenfolge bewahren, ohne mehr zu behaupten, als sie beweist. Eine Anforderungs-ID kann zeigen, dass deine API einen Auftrag angenommen hat und ein Worker einen Anbieteraufruf gesendet hat. Sie kann nicht beweisen, dass ein Mensch die Aktion beabsichtigt hat, sofern dein System diese Entscheidung nicht separat festhält. Halte die Unterscheidung klar:
- Ein Korrelationsdatensatz verbindet Ereignisse, die zu einer Anfrage gehören.
- Ein Auditdatensatz sagt, wer oder was eine Aktion autorisiert hat und was das System getan hat.
- Ein Idempotenzdatensatz verhindert einen doppelten logischen Schreibvorgang.
Teams fassen diese Informationen oft in einer Datenbankzeile zusammen. Dann muss die Zeile Wiederholungen, Fehlersuche, Compliance-Prüfung und nutzerseitige Historie bedienen und erfüllt keine dieser Aufgaben sauber. Du kannst verwandte Verweise gemeinsam speichern, solltest aber die unterschiedlichen Bedeutungen im Datenmodell erhalten.
Bei risikoreicheren Aktionen solltest du die normalisierte Anfrage, den Autorisierungskontext, das Ergebnis der Richtlinien- oder Freigabeprüfung und einen Ergebnis-Digest in einem unveränderbaren Audit-Stream festhalten. Schütze diesen Stream vor dem normalen Anwendungskonto. Andernfalls kann ein kompromittierter Dienst genau die Historie umschreiben, die ihn entlarven würde.
Sallyport verfolgt für Agentenaktionen einen nützlichen Ansatz: Es speichert Agent-Sitzungen und einzelne Aufrufe in einem schreibblinden, verschlüsselten und hashverketteten Audit-Protokoll. sp audit verify prüft die Kette offline, ohne einen Tresorschlüssel zu benötigen. Deine API braucht trotzdem eigene Datensätze, weil ein Gateway zwar zeigen kann, dass es einen Aufruf weitergeleitet hat, aber nur dein Dienst die von ihm festgeschriebene Zustandsänderung kennt.
Der Authentifizierungsumfang macht eine unsichere Operation nicht sicher
Kurzlebige Zugangsdaten und begrenzte Berechtigungsumfänge verringern den möglichen Schaden, machen einen breiten Endpunkt aber nicht sicher. Ein auf ein Projekt beschränktes Token kann trotzdem jedes Deployment zerstören, alle erlaubten Daten exportieren oder jede verfügbare Verwaltungsaktion in diesem Projekt auslösen.
Binde die Autorisierung an Operation und Ziel. Wer ein Deployment erstellen darf, sollte nicht automatisch eines in die Produktion überführen dürfen. Wer den Zugriff eines Benutzers entziehen darf, sollte nicht die Berechtigung erhalten, dessen Abrechnungsprofil zu ändern, nur weil beides unter /users/{id} liegt.
Halte Zugangsdaten möglichst vom Agenten fern. Ein Agent, der ein Bearer-Token erhält, kann es in ein Protokoll, eine Debug-Datei, die Shell-Historie oder einen Aufruf eines externen Dienstes kopieren. Lege die Nutzung stattdessen hinter ein lokales Aktions-Gateway oder einen serverseitigen Broker, der die Zugangsdaten für eine freigegebene Operation auswählt. Der Agent übermittelt Absicht und Parameter. Die vertrauenswürdige Komponente fügt das Geheimnis erst beim externen Aufruf ein.
Dieses Design ersetzt nicht die Parameterprüfung. Wenn ein Agent url: https://anything.example angeben kann, kann ein HTTP-Helfer mit eingefügten Zugangsdaten zu einem Werkzeug für Geheimnisabfluss werden. Binde Zugangsdaten an benannte externe Systeme und Methoden. Prüfe Hosts auch nach Weiterleitungen, nicht nur davor. Bei SSH solltest du Zugangsdaten möglichst an bekannte Hosts und eine eingeschränkte Befehlsschnittstelle binden, statt beliebigen Fernzugriff auf eine Shell anzubieten.
Menschliche Freigaben haben ihren Platz, sollten aber eine kleine Aktion mit sichtbarem Ziel und sichtbaren Folgen abdecken. Eine Freigabe pro Sitzung beantwortet die Frage «Darf dieser Agent-Prozess überhaupt arbeiten?» Eine Freigabe pro Aufruf beantwortet die Frage «Darf er diese konkrete sensible Aktion jetzt ausführen?» Keine von beiden rettet einen Endpunkt, dessen Payload alles bedeuten kann.
Nebenläufigkeit braucht einen eindeutigen Verlierer
Idempotenz verhindert die doppelte Übermittlung einer Absicht. Sie löst nicht zwei unterschiedliche Absichten, die miteinander konkurrieren. Wenn zwei Agenten eine Rechnung im Status paid lesen und beide mit unterschiedlichen Idempotenz-IDs eine vollständige Rückerstattung senden, muss dein Server entscheiden, welche Anfrage gewinnt.
Verwende eine transaktionale Zustandsänderung, sofern dein Speichersystem das unterstützt. Die Aktualisierung sollte den erwarteten Status enthalten, und der Server sollte den Konflikt melden, wenn ein anderer Schreiber ihn zuerst geändert hat. Ein Versionsfeld, Entity-Tag oder bedingtes Update gibt der API die Möglichkeit, veraltete Absichten abzulehnen, statt sie nach einer Zustandsänderung anzuwenden.
Modelliere eine Rückerstattung beispielsweise als Operation auf dem verbleibenden erstattungsfähigen Betrag und nicht als blinden Befehl, der einem vom Client gelieferten Betrag vertraut. Prüfe in einer Transaktion den aktuell bezahlten Betrag, ziehe frühere Rückerstattungen ab, validiere den angeforderten Betrag, reserviere die neue Rückerstattung und erstelle den Rückerstattungsdatensatz. Ein separater asynchroner Worker kann den Zahlungsanbieter nach dieser Reservierung aufrufen. Bei einer Wiederholung setzt der Worker denselben Rückerstattungsdatensatz fort, statt einen neuen zu erstellen.
Sag Agenten nicht «erst prüfen, dann handeln», wenn das deine einzige Nebenläufigkeitskontrolle ist. Ein vorbereitender GET hilft dem Agenten, eine sinnvolle Anfrage zu bilden. Ein anderer Aufrufer kann den Status jedoch zwischen Lesen und Schreiben ändern. Der Schreibendpunkt ist für die Korrektheit zuständig, weil er den tatsächlichen Status beim Festschreiben sieht.
Gestalte auch die Stornierung mit derselben Sorgfalt. DELETE /operations/{id} sollte nicht versprechen, dass eine externe Aktion nie stattgefunden hat. Die Antwort sollte den tatsächlichen Stornostatus zurückgeben: Stornierung angefordert, vor der Weiterleitung storniert, vor der Stornierung abgeschlossen oder nach der Weiterleitung nicht mehr stornierbar. Agenten und Menschen brauchen eine Sprache, die die Grenze zwischen deinem System und dem externen Anbieter abbildet.
Teste unbekannte Ergebnisse, bevor Agenten sie in der Produktion entdecken
Eine Testsuite, die nur eine 200-Antwort prüft, bringt alle dazu, den schwierigsten Teil von Aktions-APIs zu ignorieren. Nimm Fehlerfälle in Vertragstests auf und führe sie an einer echten Dienstgrenze aus, nicht nur an einem simulierten Handler.
Teste für jede Schreiboperation eine Folge, bei der der Server die Wirkung festschreibt und der Client die Antwort verliert. Sende danach dieselbe Idempotenz-ID erneut und prüfe, ob der Server die ursprüngliche Ressource zurückgibt. Sende anschließend dieselbe ID mit geändertem Body und prüfe, ob der Server einen Konflikt zurückgibt, ohne eine weitere Ressource zu erstellen.
Teste parallele Anfragen mit unterschiedlichen Idempotenz-IDs gegen dieselbe Zustandsänderung. Prüfe, ob eine erfolgreich ist und die andere einen konkreten Fehler wegen eines veralteten Status oder einer Geschäftsregel erhält. Wenn beide in einer Testdatenbank erfolgreich sind, weil jeder Test allein läuft, hast du die entscheidende Eigenschaft nicht getestet.
Behandle den Fehlervertrag als Daten. Prüfe Statuscodes, stabile Fehlercodes, Feldnamen und das Vorhandensein einer Anforderungs-ID. Erstelle keine Snapshots nur für die englische Meldung. Du wirst die Formulierungen mit der Zeit verbessern. Clients sollten anhand von code und nicht anhand von Text verzweigen.
Führe zuletzt eine Übung für Operatoren durch. Wähle eine abgeschlossene Aktion, eine abgelehnte Aktion, einen Timeout mit erfolgreicher serverseitiger Festschreibung und einen asynchronen Fehler. Gib einem Entwickler nur die Anforderungs-IDs und bitte ihn, den Ablauf zu rekonstruieren. Wenn er über unabhängige Protokolle hinweg suchen, ein Agentenprotokoll prüfen und raten muss, welche Wiederholung welchen Datensatz erstellt hat, korrigiere die Instrumentierung, bevor du unbeaufsichtigte Schreibvorgänge zulässt.
Die erste zu reparierende Aktion ist meistens der weiteste Schreibendpunkt. Teile ihn in benannte Zustandsänderungen auf, verlange eine Idempotenz-ID und sorge dafür, dass die Antwort die resultierende Ressource identifiziert. Sobald dieser Vertrag existiert, können Agenten schnell handeln, ohne jedes Netzwerkproblem als Erlaubnis zu verstehen, etwas anderes zu versuchen.
FAQ
Wie mache ich eine bestehende API sicher für KI-Agenten?
Beginne mit schreibgeschützten Operationen und einer sehr kleinen Zahl von Schreiboperationen, deren Auswirkungen du genau benennen kannst. Gib jedem Schreibvorgang einen Idempotenzvertrag, eine stabile Anforderungs-ID und bei asynchronen Abläufen einen klaren Status-Endpunkt. Überlasse einem Agenten keine umfassende Admin-API in der Hoffnung, dass der Prompt für Zurückhaltung sorgt.
Was macht einen API-Endpunkt agentenfreundlich?
Ein agentenfreundlicher Endpunkt hat eine klar begrenzte, konkrete Wirkung. Seine Anforderungsstruktur macht ungültige Aktionen schwer formulierbar. «Rückerstattung für Rechnung erstellen» lässt sich leichter begrenzen als «beliebige Abrechnungsänderung ausführen». Der Endpunkt sollte die erstellte Ressource, ihren Status und die Anforderungs-ID zurückgeben, die sie erzeugt hat.
Warum brauchen KI-Agenten idempotente API-Schreibvorgänge?
Idempotenz bedeutet, dass der Server wiederholte Übermittlungen desselben logischen Schreibvorgangs als eine Operation behandelt. Das schützt vor Wiederholungen nach Timeouts, Verbindungsabbrüchen und Wiederherstellungsschleifen von Agenten. Eine vom Client erzeugte Idempotenz-ID muss an den Anforderungstext gebunden sein, nicht nur an einen Endpunkt.
Was sollte eine API tun, wenn ein Idempotenzschlüssel mit anderen Daten wiederverwendet wird?
Behandle eine wiederverwendete Idempotenz-ID mit einem anderen Anforderungstext als Fehler, normalerweise als HTTP 409 Conflict. Wenn du den geänderten Text stillschweigend akzeptierst, kann ein Client versehentlich das Ergebnis einer alten Aktion mit einer neuen Absicht verknüpfen. Speichere zusammen mit dem ursprünglichen Ergebnis einen Fingerabdruck der Anforderung und vergleiche ihn bei jeder Wiederholung.
Welches Fehlerformat sollte eine API an einen KI-Agenten zurückgeben?
Gib einen HTTP-Status, einen stabilen maschinenlesbaren Fehlercode, eine kurze verständliche Meldung und eine Anforderungs-ID zurück. Füge das fehlerhafte Feld nur dann hinzu, wenn dadurch keine sensiblen Daten offengelegt werden. Teile dem Aufrufer mit, was er als Nächstes sicher tun kann, etwa Eingaben korrigieren, warten oder einen anderen Berechtigungsweg verwenden.
Sind Anforderungs-IDs und Idempotenzschlüssel dasselbe?
Eine Anforderungs-ID identifiziert einen einzelnen Versuch, deine API aufzurufen. Eine Idempotenz-ID identifiziert einen beabsichtigten Schreibvorgang über mehrere Versuche hinweg. Bewahre beide auf: Operatoren brauchen die erste für Protokolle und Traces, während der Server die zweite benötigt, um doppelte Auswirkungen zu verhindern.
Wie sollte eine API lang laufende Aktionen eines Agenten behandeln?
Nein. Eine erfolgreiche HTTP-Antwort kann bedeuten, dass ein Warteschlangen-Worker den Auftrag angenommen hat, nicht dass die externe Wirkung abgeschlossen ist. Gib eine Job- oder Operationsressource mit einem eindeutigen Status zurück. Der Agent kann sie abfragen oder über einen kontrollierten Kanal eine Rückmeldung erhalten.
Sollten API-Fehlermeldungen interne Details zur Fehlersuche enthalten?
Gib keine rohen Datenbankfehler, Stacktraces, Antwortinhalte externer Dienste, Zugangsdaten oder internen Autorisierungsdetails zurück. Protokolliere diese Informationen serverseitig mit passenden Zugriffskontrollen und gib stattdessen einen stabilen öffentlichen Fehlercode zurück. Agenten brauchen genug Informationen, um eine Anfrage zu korrigieren, nicht eine Karte deiner Interna.
Reicht eine eingeschränkte Authentifizierung zur Kontrolle eines KI-Agenten aus?
Verwende Berechtigungsumfang und Endpunktdesign gemeinsam. Ein auf ein Projekt begrenztes Token kann trotzdem Schaden anrichten, wenn die API das Löschen jeder Ressource in diesem Projekt oder die Ausführung beliebiger Befehle erlaubt. Gib dem Agenten nur die benötigten Operationen und lass jede Operation Ziel und gewünschte Zustandsänderung prüfen.
Welche API-Tests sind für autonome Agenten am wichtigsten?
Teste doppelte Übermittlungen, Wiederholungen nach einem unbekannten Ergebnis, parallele Aktualisierungen, abgelaufene Zugangsdaten, fehlerhafte Kennungen und verzögert abgeschlossene Worker-Aufträge. Prüfe außerdem, ob ein Operator mithilfe der Anforderungs-ID den vollständigen Weg durch deine Systeme rekonstruieren kann. Der Erfolgsfall sagt fast nichts darüber aus, wie sich ein Agent unter Unsicherheit verhält.