Änderungen am API-Schema: Contract-Tests für sicherere Agenten
Änderungen am API-Schema können die Entscheidungen eines KI-Agenten verändern, ohne einen Fehler auszulösen. Contract-Tests prüfen Felder, Defaults, Antwortbedeutung und Wiederholungsversuche.

Ein Agent kann eine kleine API-Änderung schneller in einen echten Aktionsfehler verwandeln als ein von einem Menschen bedienter Client. Ein umbenanntes Antwortfeld kann dazu führen, dass er alle Ressourcen statt einer einzigen auswählt. Ein neu eingeführter Default-Wert kann eine Abfrage ausweiten. Ein geänderter Status kann wie eine Erlaubnis zum Wiederholen aussehen. Der Wiederholungsversuch kann dann eine Abbuchung, ein Deployment oder eine Löschanfrage erneut ausführen.
Das Gefährliche daran: Solche Fehler sehen in der herkömmlichen Überwachung oft gesund aus. Der Provider liefert HTTP 200. Der Client stürzt nicht ab. Der Agent gibt eine plausible Erklärung aus. Contract-Tests müssen prüfen, welche Bedeutung ein Agent API-Daten zuweist, nicht nur, ob sich das JSON parsen lässt.
Agentenentscheidungen machen Kompatibilität zu einer Sicherheitseigenschaft
Ein API-Client, den ein Mensch verwendet, fällt bei einer geänderten Antwort oft sichtbar aus. Ein Button zeigt eine leere Tabelle, ein Formularfehler erscheint und jemand untersucht das Problem, bevor die nächste Aktion erfolgt. Agenten wandeln eine Antwort dagegen häufig direkt in eine weitere Anfrage um. Das kann mehrmals geschehen, bevor jemand ein Protokoll sieht.
Betrachte einen Agenten, der zur Bereinigung GET /projects?state=inactive aufruft, aus jedem Element das Feld owner liest und vor dem Archivieren von Projekten außerhalb einer Allowlist eine Genehmigung einholt. Der Provider ändert später owner in owner_id, behält aber den alten Endpunkt und den Statuscode bei. Ein toleranter Parser ordnet dem fehlenden owner eine leere Zeichenkette zu. Wenn die Regel des Agenten besagt, dass ein leerer Besitzer für «nicht zugewiesen» steht, bereitet er eine viel umfassendere Archivierungsanfrage vor.
Das ist weder ein Authentifizierungsfehler noch ein Prompt-Fehler. Es ist ein Interpretationsfehler an der API-Grenze. Genau dort muss auch die Korrektur ansetzen.
Behandle jedes Feld, das eine dieser Entscheidungen beeinflusst, als Teil eines Sicherheitsvertrags:
- auf welches Objekt der Agent einwirken darf
- ob ein Objekt für die Aktion geeignet ist
- Umfang, Betrag oder Ziel der Aktion
- ob eine vorherige Aktion abgeschlossen oder fehlgeschlagen ist oder wiederholt werden muss
- ob der Agent vor dem Fortfahren eine Person fragen soll
Diese Unterscheidung ist wichtig, weil Transportkompatibilität viel schwächer ist als Verhaltenskompatibilität. Ein Dienst kann Endpunkt, Methode, Authentifizierungsschema und JSON-Syntax beibehalten und trotzdem die Entscheidung brechen, die auf die Antwort folgt. Teams bezeichnen das oft als nicht abwärtskompatibel, weil vorhandene SDKs die Antwort weiterhin deserialisieren. Für einen autonomen Aufrufer kann diese Bezeichnung gefährlich unvollständig sein.
Erstelle eine kleine Übersicht über alle Antwortwerte, die einen Aktionsselektor, eine Autorisierungsentscheidung oder einen Wiederholungszweig erreichen. Beginne nicht mit jeder Eigenschaft einer riesigen API-Spezifikation. Beginne mit den Werten, deren falsche Interpretation die Handlungsmöglichkeiten des Agenten verändert.
Ein Schema-Diff kann keine Verhaltenskompatibilität beweisen
Tools für Schema-Diffs erkennen wichtige Änderungen. Sie können aber nicht entscheiden, ob eine Änderung für einen bestimmten Agenten sicher ist. Sie vergleichen Deklarationen. Ein Agent hängt von Bedeutungen ab, die oft außerhalb dieser Deklarationen liegen.
Angenommen, ein Provider ändert limit von einem optionalen Parameter mit einem impliziten Default von 100 zu einem optionalen Parameter mit einem impliziten Default von 1000. Ein gewöhnlicher OpenAPI-Diff zeigt möglicherweise keine Änderung an einer Pflicht-Eigenschaft. Ein Agent, der limit auslässt, kann nun jedoch zehnmal so viele Objekte untersuchen und eine Sammelaktion über alle diese Objekte senden.
Die OpenAPI Specification beschreibt ein Schema Object als Obermenge des Vokabulars von JSON Schema und erklärt, dass seine Eigenschaften Informationen für Anfrage- und Antwortdaten liefern. Das ist nützlich für Dokumentation und Validierung. Es sagt jedoch nicht, dass state: "pending" einen Wiederholungsversuch erlaubt oder dass ein ausgelassenes limit weiterhin auf 100 begrenzt ist. Das sind Workflow-Aussagen. Deine Tests müssen sie in klaren Worten festhalten.
Auch die default-Annotation von JSON Schema zwingt einen Validator oder Client nicht dazu, einen Wert einzusetzen. Viele Entwickler nehmen das an. Die Dokumentation von JSON Schema behandelt default als Annotierungsdaten, nicht als Befehl, der eine Instanz verändert. Wenn deine Sicherheit von einem Wert abhängt, sende ihn ausdrücklich aus dem Client und teste die exakte ausgehende Anfrage. Erwarte nicht, dass eine Schema-Annotation ein ausgelassenes Feld rettet.
Verwende ein Diff-Tool als Warnsignal. Ordne danach jede gemeldete Änderung dem Aktionspfad zu, den sie beeinflussen kann:
- Ein umbenannter Bezeichner kann das ausgewählte Ziel ändern.
- Ein neuer Enum-Wert kann den Parser in einen ungetesteten Zweig führen.
- Eine Änderung des Default-Werts kann den Umfang ohne Änderung am Anfragecode verändern.
- Eine Änderung der Darstellung kann die Bedeutung von Abschluss oder Fehler umkehren.
Die umgekehrte Situation ist ebenfalls wichtig. Ein Diff-Tool meldet vielleicht ein zusätzliches beschreibendes Feld, das kein Agent liest. Das verdient eine Prüfung, aber keinen Produktionsstopp. Die Kompatibilitätsprüfung wird besser, wenn sie den Daten bis zu einer Entscheidung folgt, statt jede Zeile des Schemas als gleich riskant zu behandeln.
Contract-Tests müssen Anfragen und Entscheidungen festschreiben
Ein nützlicher Contract-Test hat zwei Hälften: Er prüft die Anfrage, die der Agent tatsächlich sendet, und anschließend die Aktion, die der Agent nach dem Lesen einer Provider-Antwort vorschlägt. Wird nur eine Hälfte getestet, bleibt ein großer blinder Fleck.
Bei Default-Werten solltest du eine echte HTTP-Anfrage an einem lokalen Testserver oder in einer Provider-Sandbox erfassen. Das folgende Python-Beispiel verwendet httpx.MockTransport, um eine ausgehende Anfrage zu prüfen. Es verhindert den häufigen Fehler, dass ein Client sich bei einer destruktiven Aktion stillschweigend auf einen Provider-Default verlässt.
import httpx
seen = []
def handler(request: httpx.Request) -> httpx.Response:
seen.append({
"method": request.method,
"path": request.url.path,
"query": dict(request.url.params),
})
return httpx.Response(200, json={"items": []})
client = httpx.Client(transport=httpx.MockTransport(handler))
response = client.get(
"https://api.example.test/projects",
params={"state": "inactive", "limit": "100"},
)
assert response.status_code == 200
assert seen == [{
"method": "GET",
"path": "/projects",
"query": {"state": "inactive", "limit": "100"},
}]
Die wichtige Assertion ist nicht die 200-Antwort. Es ist das ausdrücklich gesetzte limit. Wenn ein Refactoring diesen Parameter entfernt, schlägt der Test fehl, bevor ein neuer Default des Providers die Auswahl ausweiten kann.
Teste danach die Entscheidung. Halte die Planungsfunktion des Agenten vom Code für den HTTP-Aufruf getrennt. So kann der Test eine vorgeschlagene Aktion prüfen, ohne sie auszuführen.
from dataclasses import dataclass
@dataclass
class ArchivePlan:
project_ids: list[str]
requires_approval: bool
def plan_archives(items: list[dict], allowed_owners: set[str]) -> ArchivePlan:
targets = []
for item in items:
owner = item.get("owner")
if owner is None:
raise ValueError("provider response lacks owner")
if item["state"] == "inactive" and owner in allowed_owners:
targets.append(item["id"])
return ArchivePlan(targets, requires_approval=bool(targets))
items = [
{"id": "p17", "state": "inactive", "owner": "team-a"},
{"id": "p18", "state": "inactive", "owner": "team-b"},
]
plan = plan_archives(items, {"team-a"})
assert plan.project_ids == ["p17"]
assert plan.requires_approval is True
Dieser Test trifft eine Entscheidung, die toleranter Code oft vermeidet: Ein fehlendes owner löst einen Fehler aus. Bei einem Feld, das die Aktionsauswahl steuert, sollte der Prozess sicher abbrechen. Eine leere Zeichenkette, None oder ein vermuteter Ersatzwert kann den Ablauf zwar fortsetzen. Er ersetzt aber einen erkennbaren Integrationsfehler durch einen möglicherweise unsicheren Plan.
Halte Fixtures klein genug, damit ein Reviewer erkennt, warum jedes Element enthalten ist. Eine Fixture mit tausend Objekten kann der Produktion ähneln, verbirgt aber die Bedingung, die du eigentlich schützen wolltest.
Umbenannte Felder brauchen ein ausdrücklich festgelegtes Fehlerverhalten
Ein umbenanntes Feld sollte einen Aktionspfad stoppen, sofern du nicht während einer klar definierten Migration absichtlich beide Namen unterstützt. Stille Fallbacks wirken in einer Demo robust und schaffen in der Produktion ungeprüfte Bedeutungen.
Die schlimmste Variante sieht so aus:
owner = item.get("owner", "")
if owner not in blocked_owners:
archive(item["id"])
Wenn owner verschwindet, scheint jedes Element einen Besitzer zu haben, der nicht gesperrt ist. Der Parser tut genau das, was der Code verlangt. Der Entwickler wollte wahrscheinlich einen KeyError vermeiden. Diese kleine Bequemlichkeit macht aus fehlenden Daten eine Erlaubnis zu handeln.
Schreibe Tests für alle drei Situationen: das erwartete Feld, das alte Feld, falls du vorübergehend beide Namen unterstützt, und keines der beiden Felder. Der dritte Test muss festhalten, ob der Agent stoppt, das Objekt überspringt oder eine Klärung anfordert. Bei Zielidentität, Autorisierungsstatus und Aktionsumfang ist ein Stopp normalerweise die richtige Antwort.
Wenn du einen Alias unterstützt, muss seine Priorität offensichtlich und die Unterstützung zeitlich begrenzt sein:
def read_owner(item: dict) -> str:
if "owner" in item:
return item["owner"]
if "owner_id" in item:
return item["owner_id"]
raise ValueError("owner identity missing")
Auch dieser Code braucht einen Test für widersprüchliche Daten. Wenn beide Felder ankommen und nicht übereinstimmen, darfst du nicht stillschweigend eines bevorzugen. Löse einen Fehler aus und lass den Provider die Mehrdeutigkeit klären. Eine Kompatibilitätsschicht sollte eine bekannte alte Bedeutung erhalten, nicht bei widersprüchlichen Datensätzen einen Gewinner erfinden.
Teams argumentieren manchmal, tolerantes Parsen schütze vor der Weiterentwicklung eines Providers. Es schützt vor harmlosen Ergänzungen, wenn unbekannte Felder ignoriert werden. Es schützt nicht vor fehlenden Feldern, die eine Aktion steuern. In diesen Fällen ist das entgegengesetzte Verhalten nötig: Zusätzliche Informationen standardmäßig akzeptieren, aber fehlende erforderliche Bedeutung ablehnen.
Defaults und ausgelassene Werte brauchen getrennte Tests
Eine ausgelassene Eigenschaft, ein explizites null und ein expliziter Wert sind drei verschiedene Anfragen. Agenten verwischen diese Unterschiede oft, weil auch Serialisierer für allgemeine Zwecke sie verwischen.
Ein Anfrage-Builder kann dry_run auslassen, wenn sein interner Wert None ist. Der Provider interpretiert das möglicherweise als false. In einer späteren Version kann der Provider das Auslassen als «Kontoeinstellung verwenden» verstehen. Diese Kontoeinstellung ist für einen Mandanten false und für einen anderen true. Der Agentencode hat sich nicht geändert, die Aktion aber schon.
Ordne Optionen, die Entscheidungen beeinflussen, einer von zwei Kategorien zu. Bei Optionen mit bekanntem sicherem Verhalten sende den Wert jedes Mal. Bei Optionen, die eine Entscheidung durch einen Operator benötigen, verlange diese Entscheidung, bevor du die Anfrage erstellst. Vermeide bei destruktiven oder extern sichtbaren Aktionen eine dritte Kategorie namens «Der Server soll entscheiden».
Teste die Serialisierung mit einer Tabelle aus exakten Fällen. Entscheidend ist die Darstellung auf der Leitung, nicht nur das Sprachobjekt vor der Serialisierung.
| Absicht | Ausgehende Darstellung | Erwartete Bedeutung beim Provider |
|---|---|---|
| Inaktive Projekte lesen | state=inactive&limit=100 | Begrenzte Auswahl |
| Archivierung simulieren | {"dry_run": true} | Es wird nichts archiviert |
| Ein Projekt archivieren | {"project_ids":["p17"],"dry_run": false} | Nur p17 darf geändert werden |
| Keine Auswahl des Operators für den Modus | Anfrage wird lokal abgelehnt | Der Provider erhält nichts |
Sei auch bei Pagination strikt. Eine Antwort, die next_cursor ergänzt, kann einen Agenten dazu verleiten, automatisch jede Seite abzurufen. Für einen Bericht kann das sinnvoll sein, für einen Aktionsplaner aber riskant. Teste sowohl die maximale Objektzahl, die der Planer berücksichtigen darf, als auch die Bedingung, die eine zweite Seite erlaubt. Ein Cursor ist ein Mechanismus zum Fortsetzen, keine Zustimmung zu unbegrenztem Umfang.
Defaults des Providers sind auch in Antworten wichtig. Wenn eine API archivable nicht mehr sendet, sobald der Wert false ist, ändert Code wie if item.get("archivable", True) sein Verhalten in die unsichere Richtung. Bei einem Feld, das eine Berechtigung erteilt, solltest du einen ausdrücklichen Vergleich wie item.get("archivable") is True verwenden. Das ist weniger elegant und deutlich leichter zu prüfen.
Die Antwortvalidierung muss die Bedeutung bewahren, nicht nur die Form
Die Antwortvalidierung sollte fehlerhafte Daten von unbekannten, aber harmlosen Daten unterscheiden. Uneingeschränkte Strenge lässt Clients scheitern, wenn Provider neue Felder ergänzen. Uneingeschränkte Toleranz verwandelt fehlende Belege in Vermutungen.
Definiere ein schmales Antwortmodell für die Werte, die in die nächste Aktion einfließen. Lege für jeden Wert Typ, zulässige Zustände und die Frage fest, ob sein Fehlen den Workflow stoppt. Eine Projekt-ID braucht mehr als den Typ string: Der Agent braucht eine nicht leere, stabile Kennung, die später mit der Kennung in der Archivierungsanfrage übereinstimmt. Ein Status braucht mehr als den Typ string: Der Agent benötigt einen festgelegten Zustand mit dokumentierter Aktion für jedes mögliche Element.
Dieser Parser behandelt beispielsweise eine geänderte Statusdarstellung, ohne sich selbst die Erlaubnis für einen Wiederholungsversuch zu geben:
ALLOWED_STATES = {"queued", "running", "succeeded", "failed"}
def retryable(job: dict) -> bool:
status = job.get("status")
if status not in ALLOWED_STATES:
raise ValueError(f"unknown job status: {status!r}")
return status == "failed" and job.get("retry_allowed") is True
Wenn der Provider status von einer Zeichenkette in ein Objekt wie {"phase":"failed"} ändert, stoppt dieser Code. Das ist richtig, bis jemand entscheidet, wie die neue Darstellung dem bisherigen Workflow zugeordnet wird. Wenn der Provider cancelled ergänzt, ist ein Stopp ebenfalls richtig, bis das Team entscheidet, ob eine Stornierung endgültig ist, wiederholt werden darf oder einen Menschen benötigt.
Mache nicht jeden unbekannten Enum-Wert bei einer reinen Anzeige zu einem Notfall. Die Reaktion sollte zur Aktion passen. Ein Berichtsagent kann einen unbekannten Status kennzeichnen und fortfahren. Ein Agent, der einen Abrechnungsvorgang wiederholen oder eine Ressource löschen soll, muss stoppen, bevor er auf Basis eines nicht verstandenen Status handelt.
Teste auch Beziehungen zwischen Feldern. Eine Antwort kann strukturell gültig sein und trotzdem einen widersprüchlichen Zustand enthalten, etwa status: "succeeded" zusammen mit retry_allowed: true. Die Schema-Validierung drückt normalerweise nicht jede geschäftliche Invariante aus. Ein Contract-Test sollte festhalten, dass ein erfolgreicher Job keinen Wiederholungsplan erzeugt, unabhängig von einem fehlerhaften booleschen Wert.
Teste den gesamten Aktionspfad, nicht nur einen bequemen Mock
Unit-Tests für Parser sind notwendig. Sie beweisen aber nicht, dass der bereitgestellte Agent über seinen tatsächlichen Zugang und Ausführungspfad die beabsichtigte Anfrage sendet. Serialisierungsbibliotheken, Wrapper, Tool-Adapter und Wiederholungs-Middleware können das Verhalten auf eine Weise verändern, die ein direkter Funktionsaufruf nicht sichtbar macht.
Starte in CI einen lokalen Contract-Server, der Anfragen aufzeichnet und versionierte Fixtures zurückgibt. Richte die Tool-Konfiguration des Agenten auf diesen Server. Der Test sollte eine realistische Anweisung ausführen, auf den vorgeschlagenen Plan oder Aktionsdatensatz warten und die aufgezeichnete Abfolge prüfen: Methode, Pfad, Query, sicher prüfbare Header, Body und Anzahl der Aktionen.
Lege in dieser Umgebung keine echten Geheimnisse ab. Verwende ein Testkonto ohne Berechtigungen und prüfe, dass der Agent es nie in seinem Prompt, Tool-Ergebnis, Ausnahme-Text oder Trace erhält. Ein Test, der Anfrage-Header unvorsichtig protokolliert, kann genau die Offenlegung von Zugangsdaten reproduzieren, die er verhindern sollte.
Bei Agenten, die über Sallyport externe HTTP- oder SSH-Aufrufe ausführen, kann der Aktionspfad die Zugangsdaten vom Agenten fernhalten und trotzdem ein prüfbares Ergebnis liefern. Diese Grenze behebt jedoch keine falsche Interpretation einer Antwort. Führe Schema- und Entscheidungsverträge aus, bevor die externe Aktion erlaubt wird.
Nimm nicht nur erfolgreiche Antworten, sondern auch Fehler-Fixtures auf. Verwende exakt die Bedingungen, die Provider bei Umstellungen erzeugen: ein fehlendes Auswahlfeld, ein neues Enum-Element, ein leeres Ergebnis mit Fortsetzungscursor, eine Änderung des Content-Types und eine 200-Antwort mit einem Fehlerobjekt. Ein Fehlerkörper in einer 200-Antwort kommt besonders bei älteren APIs häufig vor. Wenn dein Parser annimmt, dass jede 200-Antwort die Erfolgsform enthält, kann er einen leeren Plan erzeugen oder eine Anfrage wiederholen, die bereits erfolgreich war.
Prüfe bei Wiederholungsversuchen das Idempotenzverhalten. Lass der Contract-Server zunächst nach der Aufzeichnung einer Anfrage eine Zeitüberschreitung zurückgeben und bei der Wiederholung eine zweite Antwort liefern. Der Test muss beweisen, dass der Client, sofern die API das unterstützt, ein Idempotenz-Token sendet oder stoppt und eine Bestätigung anfordert, wenn er nicht wissen kann, ob die erste Aktion abgeschlossen wurde. Das Wiederholen eines Lesevorgangs ist meist harmlos. Eine Überweisung, E-Mail, Bereitstellung oder Löschanfrage zu wiederholen ist es nicht.
Release-Gates sollten semantische Fehler blockieren
Führe Schema-Diffs, Provider-Contract-Tests und Agenten-Entscheidungstests im Änderungsprozess sowohl für API-Anbieter als auch für Agenten-Consumer aus. Ein Release-Prozess, der sie erst nach dem Deployment startet, macht aus den Tests lediglich eine Dokumentation des Vorfalls.
Verlange bei einer Provider-Änderung einen Prüfdatensatz, der vier konkrete Fragen beantwortet: Welche Annahmen der Consumer ändern sich? Wie war das alte Verhalten? Wie lange bleiben beide Verhaltensweisen unterstützt? Welche Fixture zeigt das neue Verhalten? Das ist weniger Aufwand, als einen Produktionsfehler mit unvollständigen Logs zu untersuchen.
Führe bei einer Agentenänderung vor dem Merge die vorhandene Suite mit Provider-Fixtures aus. Wenn der Agent jetzt ein neu hinzugefügtes Feld verwendet, ergänze Fixtures für dessen Fehlen und für Werte außerhalb des erwarteten Erfolgsfalls. Auch Änderungen am Prompt-Wortlaut können Tool-Argumente verändern. Teste deshalb den Tool-Aufruf des gesamten Agenten, statt anzunehmen, dass der Planer weiterhin dieselben Parameter auswählt.
Versionierte Fixtures machen Reviews praktikabel. Speichere eine Kennung wie projects-list-v1 zusammen mit dem erwarteten Anfrage-Antwort-Paar. Wenn ein Provider bewusst projects-list-v2 einführt, behalte die alte Fixture bis zum Ende der Migrationsregelung. Überschreibe nicht einfach das alte JSON und nenne die Tests aktuell. Sonst verlierst du den Nachweis, welche Kompatibilität du aufgegeben hast.
Ein gutes Gate meldet Fehler in operativer Sprache. «Erforderliches Feld owner fehlt, Planung der Archivierung gestoppt» sagt einem Reviewer, was passiert ist. «ValidationError at path items.0» ist besser als nichts, zwingt den Reviewer aber dazu, das Risiko während eines Releases selbst zu rekonstruieren.
Genehmigungsansichten können einen irreführenden Plan nicht korrigieren
Die menschliche Genehmigung bleibt eine gute Kontrolle für externe Aktionen. Sie kommt aber zu spät, wenn der Agent aus einem geänderten Vertrag den falschen Plan erstellt hat. Eine Person, die «847 inaktive Projekte archivieren» sieht, kann die Aktion ablehnen. Eine Person, die «Projekt p17 archivieren» sieht, kann nicht erkennen, ob p17 aus einem fehlenden owner-Feld, einem ausgeweiteten Default oder einem Parser stammt, der cancelled mit failed verwechselt hat.
Die Genehmigungsdatensätze sollten die Entscheidungsgrundlagen enthalten, die ein Mensch prüfen muss: Ziel-IDs, Anzahl, angeforderter Modus und die Antwortfelder, durch die das Ziel als geeignet eingestuft wurde. Halte den Datensatz kompakt. Unverarbeitetes JSON auf einer Genehmigungsseite verlagert die Parsing-Aufgabe nur vom Code auf eine müde Person.
Bewahre zusätzlich einen Trace auf, mit dem ein Entwickler die Aktion rekonstruieren kann. Erfasse die Provider-Antwort oder einen geschützten Digest davon, die Parser-Version, die Fixture-Version des Vertrags, die erzeugte Anfrage und die resultierende Antwort. Ein manipulationssicherer Audit-Trail hilft im Nachhinein. Er sollte aber auf die Entscheidungsgrenze verweisen, statt nur festzuhalten, dass ein HTTP-Aufruf stattgefunden hat.
Wenn ein API-Team das nächste Mal sagt, eine Antwortänderung sei kosmetisch, bitte es, die Agenten-Contract-Suite dagegen auszuführen. Wenn die Suite fehlschlägt, hängt an der Änderung ein konkretes Verhalten. Behebe das, bevor aus einer höflichen 200-Antwort eine unsichere Aktion wird.
FAQ
Kann ein kleines API-Feld-Umbenennen einen KI-Agenten unsicher machen?
Ja. Durch die Umbenennung eines Feldes kann ein Agent auf einen Fallback-Pfad wechseln, einen fehlenden Wert als sicher behandeln oder fehlerhafte Folgeanfragen senden. Die API kann dabei durchgehend 200 zurückgeben. Deshalb erkennen gewöhnliche Verfügbarkeitsprüfungen den Fehler nicht.
Reichen API-Response-Snapshots für die Sicherheit eines Agenten aus?
Snapshot-Tests helfen dabei, Änderungen zu bemerken. Sie erzeugen jedoch oft unübersichtliche Diffs und sagen wenig über das Verhalten aus. Nutze sie für eine gezielte Prüfung und ergänze sie dann um Assertions für die wenigen Felder und Beziehungen, die eine Aktion steuern.
Sollte ich Consumer-Driven Contracts oder OpenAPI-Tests verwenden?
Ein Consumer-Driven Contract passt oft besser, wenn ein Agenten-Workflow von einer bestimmten Provider-API abhängt. Er hält fest, was der Consumer benötigt. Ein Provider-Schema bleibt trotzdem nützlich, um die gesamte öffentliche Oberfläche zu dokumentieren.
Was ist für einen Agenten der Unterschied zwischen einem fehlenden JSON-Feld und null?
Ein fehlendes Feld bedeutet, dass der Produzent keine Information gesendet hat. Ein Feld mit dem Wert null bedeutet, dass der Produzent das Feld gesendet und angegeben hat, dass kein Wert existiert. Agenten sollten diese Zustände nicht gleich behandeln, sofern der Vertrag das nicht ausdrücklich vorsieht.
Sollten Contract-Tests unbekannte Antwortfelder ablehnen?
In der Regel nein. Unbekannte Felder tauchen häufig auf, wenn ein Provider neue Daten ergänzt. Wenn Clients sie ablehnen, werden sie unnötig fragil. Lehne sie nur dort ab, wo ein unbekanntes Feld eine sensible Aktion beeinflussen könnte oder die Antwort bewusst ein geschlossenes Befehlsvokabular bildet.
Wie teste ich einen geänderten API-Default-Wert?
Behandle einen neuen Default-Wert als Verhaltensänderung, sobald er Umfang, Pagination, Berechtigungen, Kosten, Löschvorgänge oder das Senden von Daten beeinflusst. Teste die Anfrage mit ausgelassenem Feld, denn dann übernimmt der Default des Providers die Kontrolle.
Wie teste ich den tatsächlichen API-Pfad, den ein Agent verwendet?
Teste die kleinste echte Abfolge: Agentenanfrage, Einfügen der Zugangsdaten oder Autorisierungsgrenze, Provider-Anfrage, Provider-Antwort, Parser und vorgeschlagene Aktion. Wenn du nur den letzten API-Aufruf mockst, bleiben Fehler bei Serialisierung oder Antwortinterpretation zwischen diesen Schritten verborgen.
Garantiert die JSON-Schema-Validierung ein sicheres Verhalten des Agenten?
Nein. Eine Schema-Validierung bestätigt, dass eine Nutzlast eine zulässige Struktur hat. Sie beweist nicht, dass der Agent das richtige Konto ausgewählt, einen Status richtig interpretiert oder eine Aktion auf die vorgesehenen Objekte beschränkt hat. Ergänze Assertions für diese Entscheidungen.
Was sollte ein API-Team tun, bevor es ein von Agenten verwendetes Feld entfernt?
Halte das alte Verhalten während des veröffentlichten Migrationszeitraums verfügbar, sende klare Hinweise zur Abkündigung und führe beide Vertragsversionen in CI aus, während die Clients umgestellt werden. Verwende einen Feldnamen nicht stillschweigend für eine andere Bedeutung.
Kann eine menschliche Genehmigung fehlerhafte API-Verträge ausgleichen?
Eine Genehmigung kann einen einzelnen Aufruf stoppen. Sie macht eine irreführende Anfrage für die genehmigende Person jedoch nicht verständlich. Führe die Schema-Prüfungen durch, bevor die Anfrage einen Menschen erreicht, und zeige bei der Genehmigung Details zu Ziel und Umfang an.