# API-Antworten für einen sichereren KI-Agent-Kontext minimieren

KI-Agents brauchen keine Kopie jedes Objekts, mit dem sie arbeiten. Sie benötigen genug Informationen, um die nächste Entscheidung zu treffen, die Aktion auszuführen und über das Ergebnis zu berichten. Wenn eine API einem Agenten, der nur eine ID und einen Status braucht, einen vollständigen Kundendatensatz, eine Rechnung, ein Ticket, eine Repository-Einstellung oder ein Incident-Objekt zurückgibt, hat die API das Problem der Datenoffenlegung bereits vergrößert.

Das wird leicht übersehen, weil die Anfrage möglicherweise nur lesend, authentifiziert und per TLS übertragen wurde. Nichts davon ändert, was danach passiert. Die Antwort kann in ein Agent-Transkript, eine Tool-Spur, eine Modellanfrage, einen lokalen Cache, einen Fehlerbericht oder eine Warteschlange für die menschliche Prüfung gelangen. Wenn der Agent die Antwort lesen kann, solltest du davon ausgehen, dass sie nun im Agent-Kontext enthalten ist.

Die praktische Lösung heißt Minimierung von API-Antworten: Definiere für jede Agent-Aufgabe die kleinste nützliche Antwort, mache diese Form leicht abrufbar und behandle umfangreiche Daten als Ausnahme, die von Menschen geprüft werden muss. Es geht nicht darum, JSON schöner aussehen zu lassen. Es geht darum, die Zahl der Orte zu verringern, an denen personenbezogene, finanzielle und betriebliche Daten nach einem routinemäßigen automatisierten Aufruf auftauchen können.

## Auch ein authentifizierter Lesezugriff kann viel zu viel offenlegen

Lesezugriff verhindert Änderungen. Er verhindert aber nicht das Kopieren, Zusammenfassen, Zitieren oder versehentliche Weiterleiten von Daten an ein anderes Tool. Teams bezeichnen einen Agenten oft als «nur lesend», als wäre damit das Risiko geklärt. Tatsächlich ist nur eine Risikoklasse abgedeckt.

Stell dir einen Agenten vor, der überfällige Rechnungen erkennen und eine Folgeaufgabe eröffnen soll. Er braucht Rechnungs-ID, Konto-ID, Fälligkeitsdatum, Betrag, Währung und Inkassostatus. Ein herkömmlicher Rechnungs-Endpunkt liefert möglicherweise zusätzlich Rechnungs- und Lieferadressen, Steueridentifikationsnummern, Referenzen des Zahlungsdienstleisters, Beschreibungen einzelner Positionen, eine interne Notiz eines Finanzmitarbeiters und die vollständige Zahlungshistorie. Jedes zusätzliche Feld schafft eine weitere Tatsache, die der Agent wiederholen kann, obwohl er sie nicht braucht.

Bei Betriebsdaten gibt es dasselbe Problem. Für die Prüfung, ob ein Deployment abgeschlossen ist, braucht eine Aufgabe möglicherweise Servicename, Build-ID, Status und Fehlerkategorie. Ein vollständiger Umgebungsexport mit Hostnamen, internen Adressen, Befehlsausgaben, Incident-Kommentaren oder nicht verwandter Konfiguration ist dafür kaum nötig.

Die oft verwischte Unterscheidung ist wichtig: Autorisierung beantwortet die Frage, ob ein Aufrufer auf eine Ressource zugreifen darf. Minimierung beantwortet, wie viel von dieser Ressource der Aufrufer für diese konkrete Aufgabe erhält. Ein Token mit Leserechten für `invoice:123` kann korrekt autorisiert sein und trotzdem eine unsichere Darstellung dieser Rechnung erhalten.

RFC 9110 der IETF beschreibt Repräsentationen als Informationen, die den aktuellen oder gewünschten Zustand einer Ressource wiedergeben sollen. Es verlangt keine einzige maximal umfangreiche Repräsentation pro Ressource. Dieser Spielraum ist für das Design hilfreich. Eine Ressource kann eine Zusammenfassung, eine operative Darstellung und eine Finanzdarstellung haben, sofern die API jeden Vertrag klar definiert.

Verlass dich nicht auf eine Prompt-Anweisung wie «Ignoriere personenbezogene Daten». Prompts beeinflussen das Verhalten, die Form der Antwort begrenzt die Offenlegung. Wenn ein Endpunkt eine Wohnadresse liefert, hat der Agent sie bereits erhalten, bevor er entscheiden kann, sie zu ignorieren.

## Beginne mit der Aufgabe, die der Agent erledigen muss

Ein sicherer Antwortvertrag beginnt mit der Entscheidung, die ein Agent treffen muss, nicht mit einem vorhandenen Datenbankmodell. Beschreibe die Aufgabe in einem Satz und liste anschließend die Fakten auf, die die Aktion verändern. Alles andere muss seine Anwesenheit rechtfertigen.

Ein Agent, der fehlgeschlagene Build-Jobs erneut ausführt, könnte beispielsweise diese Antwort benötigen:

```json
{
  "job_id": "job_4821",
  "state": "failed",
  "retryable": true,
  "failure_class": "transient_dependency",
  "attempts_remaining": 1
}
```

Für die Entscheidung, ob ein erneuter Versuch erlaubt ist, braucht er nicht das vollständige Build-Log. Wenn später ein Mensch Diagnosedaten benötigt, sollte ein separater Endpunkt mit kleinerem Nutzerkreis und einem klaren Abrufgrund diese Daten liefern. Ein Log-Endpunkt sollte außerdem begrenzte Bereiche unterstützen, denn vollständige Logs enthalten häufiger als viele zugeben Tokens, Kundeneingaben, Pfade und Konfigurationsfragmente.

Erstelle vor Änderungen an den Endpunkten eine kleine Aufgabenmatrix. Sie erzwingt Gespräche, die sonst vage bleiben:

| Agent-Aufgabe | Felder für die Entscheidung | Felder für die Aktion | Standardmäßig ausgeschlossene Felder |
| --- | --- | --- | --- |
| Support-Folgeaufgabe erstellen | Ticket-ID, Priorität, Kategorie | Konto-ID, Zuständigkeitswarteschlange | Nachrichtentext, Anhänge, interne Notizen |
| Job erneut ausführen | Job-ID, Status, erneut ausführbar | Retry-Token oder Job-ID | vollständiges Log, Umgebungswerte |
| Überfällige Rechnung markieren | Rechnungs-ID, Fälligkeitsdatum, Betrag, Status | Konto-ID | Adresse, Steuerdaten, Zahlungsreferenzen |
| Servicezustand prüfen | Service-ID, Status, Fehlerklasse | Incident-ID | Hostdetails, Rohdiagnose |

Ein Feld gehört nur dann in die Antwort, wenn es den vom Agenten gewählten Pfad verändert, in der Aktionsanfrage auftaucht oder in seinem Bericht für den Nutzer erscheinen muss. «Es könnte später nützlich sein» ist kein guter Grund. Mit dieser Begründung wachsen Listen-Endpunkte auf fünfzig Felder an, während niemand weiß, wer davon abhängt.

Die Übung zeigt außerdem Felder, die berechnet statt offengelegt werden sollten. Ein Agent braucht keinen Gehaltsdatensatz, um zu erfahren, ob eine Ausgabengenehmigung durch einen Vorgesetzten erforderlich ist. Gib `approval_required: true` zurück. Er braucht auch nicht jede Berechtigung, um zu wissen, ob ein Deployment fortgesetzt werden darf. Gib `deployment_permitted: false` und einen stabilen Grundcode zurück.

Das ist keine Sicherheit durch Verschleierung. Es ist ein bewusster API-Vertrag, der Aufrufern das benötigte Ergebnis liefert, ohne ihnen den zugrunde liegenden Datensatz zu übergeben.

## Standardobjekte sollten Zusammenfassungen sein, keine Datenbankzeilen

Das zuverlässigste Design liefert bei gewöhnlichen Listen- und Suchaufrufen standardmäßig eine sichere Zusammenfassung. Detaillierte Darstellungen sollten explizit angefordert, separat autorisiert und selten sein. Wenn jeder Aufrufer eine einschränkende Abfrageoption kennen muss, wird das irgendwann schiefgehen, besonders wenn eine Bibliothek eine bequeme Methode hinzufügt, die diese Option weglässt.

Eine Kundenzusammenfassung könnte so aussehen:

```json
{
  "id": "cus_7f31",
  "display_name": "Northwind Parts",
  "account_state": "active",
  "open_invoice_count": 2,
  "support_tier": "standard"
}
```

Gib `email`, `phone`, Straßenadresse, Steueridentifikationsnummer, Metadaten zum Zahlungsinstrument oder Freitextnotizen nicht zurück, nur weil eine Kundenzeile diese Felder enthält. Einige davon können für eine Abrechnungsanwendung erforderlich sein. In einen Zusammenfassungsvertrag für einen Operations-Agenten gehören sie nicht.

Es gibt zwei praktikable Muster. Ein separater Zusammenfassungs-Endpunkt wie `GET /customers/{id}/summary` ist eindeutig und leicht zu prüfen. Ein Projektionsparameter wie `GET /customers/{id}?view=summary` kann funktionieren, wenn es eine feste, dokumentierte Menge von Ansichten gibt. Beide Varianten sind besser als ein Endpunkt, der alles zurückgibt und jeden Client auffordert, Unbenötigtes zu ignorieren.

Vermeide bei Zugangsdaten für Agents einen allgemeinen Schalter wie `expand=*` oder `include=all`. Beim Debugging wird er zum bequemsten Weg und bleibt anschließend in Produktion, weil seine Entfernung riskant erscheint. Wenn eine Detaildarstellung notwendig ist, benenne sie nach der Aufgabe: `view=collections`, `view=deployment_status` oder `view=case_triage`. Aufgabennamen erzwingen eine Designprüfung. «Alle» umgeht sie.

Ein häufiger Einwand lautet, separate Ansichten würden Code duplizieren. Ein Teil des Mapping-Codes wird tatsächlich doppelt vorhanden sein. Die Kosten sind jedoch gering verglichen mit der Untersuchung, warum ein Tool-Transkript eine Steueridentifikationsnummer oder eine interne Incident-Notiz enthält. Die Mapping-Schicht ist außerdem der richtige Ort, um Zuständigkeiten zu dokumentieren und zu testen, dass eine Agent-Ansicht sensible Spalten ausschließt.

## Feldauswahl braucht eine Allowlist, keinen Parser-Trick

Ein `fields`-Parameter kann Antworten deutlich verkleinern, aber nur, wenn der Server ihn als strikte Allowlist behandelt. Ein lockerer Parser macht aus einer Komfortfunktion eine Schnittstelle zur Datenextraktion.

Diese Anfrage ist sinnvoll:

```text
GET /v1/invoices?state=overdue\u0026fields=id,account_id,due_date,amount,currency,collection_state\u0026limit=25
```

Der Server sollte nur Felder zurückgeben, die für diesen Endpunkt und diese Zugangsdaten erlaubt sind. Fordert ein Aufrufer `billing_address` oder `payment_reference` an, muss die Anfrage mit einer klaren Fehlermeldung abgelehnt werden. Füge sensible Felder nicht stillschweigend hinzu und akzeptiere keine beliebigen verschachtelten Pfade wie `customer.*`.

Ein Antwortvertrag könnte das Verhalten genau festlegen:

```json
{
  "error": {
    "code": "unsupported_field",
    "message": "Field 'payment_reference' is not available in the agent invoice view",
    "allowed_fields": [
      "id",
      "account_id",
      "due_date",
      "amount",
      "currency",
      "collection_state"
    ]
  }
}
```

Auch die Fehlermeldung selbst braucht Disziplin. Sie darf niemals den Wert des abgelehnten Feldes, Daten aus benachbarten Datensätzen, einen Stacktrace, unverarbeiteten Abfragetext eines anderen Dienstes oder einen Datenbankfehler enthalten. Fehlerantworten werden oft zu einer versehentlichen zweiten API, besonders wenn Entwickler sie zur Beschleunigung eines Incidents besonders ausführlich machen.

Für GraphQL gilt dieselbe Prüfung. Clients können scheinbar nur die Felder anfordern, die sie benennen, was hilfreich ist. Ein Schema kann jedoch weiterhin sensible Felder offenlegen, verschachtelte Beziehungen können die Zahl der Datensätze vervielfachen und Aliase können eine einzelne Anfrage schwer nachvollziehbar machen. Begrenze Tiefe und Komplexität, deaktiviere Introspection je nach Umgebung oder schränke sie ein und autorisiere Felder statt nur Objekte der obersten Ebene. Noch wichtiger: Erstelle ein Agent-Schema oder persistierte Abfragen für die wenigen freigegebenen Aufgaben. Ein breites Schema mit einer höflichen Anweisung ist keine enge Schnittstelle.

Die OWASP API Security Top 10 weist auf eine fehlerhafte Autorisierung auf Eigenschaftenebene von Objekten hin. Häufig geht es dabei um einen Aufrufer, der eine Eigenschaft abruft, auf die er niemals zugreifen dürfte. Bei Agents kommt eine weitere Fehlerquelle hinzu: Der Aufrufer darf technisch zugreifen, aber die Aufgabe braucht das Feld nicht und sollte es nicht in den Modellkontext verteilen. Behalte beide Prüfungen bei. Frage zuerst: «Darf dieses Credential das Feld lesen?» Danach folgt: «Warum braucht diese Aufgabe es jetzt?»

## Paginierung begrenzt die Menge, Filter bestimmen die Relevanz

Eine Antwort mit zehn Datensätzen ist nicht automatisch klein. Wenn jeder Datensatz ein großes verschachteltes Objekt oder ein langes Textfeld enthält, teilt die Paginierung das Leck nur in übersichtliche Seiten auf.

Verwende Filter, die die Aufgabe des Agents ausdrücken. Ein Collections-Agent sollte überfällige Rechnungen in einem bestimmten Status und Zeitraum abfragen. Er sollte nicht jede Rechnung auflisten und lokal entscheiden, welche relevant ist. Ein Deployment-Agent sollte nach einem einzelnen Service und dem aktuellen Release fragen, nicht jede Umgebung abfragen und anschließend im Ergebnis suchen.

Auch die Form einer Cursor-Paginierung muss sorgfältig gewählt werden. Ein Cursor sollte undurchsichtig sein und keine E-Mail-Adresse, keinen Kontonamen, keine unverschlüsselten Filterwerte und keinen internen Datenbankschlüssel enthalten, der die Sortierung verrät. Clients schreiben Cursor in Logs und Tickets. Behandle sie als Daten, die weitergegeben werden.

Halte Seitenlimits für Agent-Zugangsdaten konservativ. Ein kleines Limit senkt nicht nur den Token-Verbrauch. Es schafft einen Haltepunkt, an dem der Agent eine Zusammenfassung prüfen, einen relevanten Datensatz auswählen und gezielt nachfassen kann. Diese Abfolge ist sicherer, als die vollständige Kontohistorie zu laden, nur weil eine Aufgabe mit den Worten «Untersuche diesen Kunden» begonnen hat.

Verwechsle einen Such-Endpunkt nicht mit der Berechtigung, jedes passende Detail zurückzugeben. Die Suche sollte normalerweise eine Ergebniskarte liefern: stabile ID, Bezeichnung, Status und eventuell einen Treffergrund. Nach der Auswahl eines Datensatzes kann der Aufrufer eine erlaubte Detailansicht laden. Dieses Muster mit zwei Aufrufen wirkt weniger bequem als ein riesiges Ergebnisobjekt, macht die Übertragung sensibler Informationen jedoch sichtbar und prüfbar.

## Freitext und verschachtelte Datensätze brauchen eine eigene Grenze

Strukturierte Felder lassen sich leichter klassifizieren als Texte, die Menschen geschrieben haben. Freitextfelder nehmen Namen, Telefonnummern, versehentlich eingefügte Zugangsdaten, Anschuldigungen, Gesundheitsdaten, Rechtsberatung und interne Meinungen auf. Die `description` eines Tickets wirkt bei einer Schema-Prüfung harmlos, bis man eine echte Woche von Tickets liest.

Behandle Kommentare, Notizen, Beschreibungen, Anhänge, Logs und Nachrichtentexte für autonome Abläufe standardmäßig als sensibel. Gib stattdessen eine Kategorie, eine kurze serverseitig erzeugte Klassifizierung oder eine Anzahl zurück, wenn das für die Auswahl einer Aktion genügt. Ein Agent braucht beispielsweise möglicherweise `has_customer_reply: true` und `latest_message_at`, nicht die Nachricht selbst.

Bitte das Modell nicht, beliebigen Text nach dem Abruf zu schwärzen. Dieser Ansatz ist beliebt, weil er einen einzigen umfangreichen Endpunkt zu erhalten scheint. Er scheitert aus zwei Gründen. Erstens ist der Rohinhalt bereits in den Agent-Kontext gelangt, bevor die Schwärzung stattfindet. Zweitens ist eine vom Modell erzeugte Schwärzung probabilistisch. Ein Teil eines Namens, eine Kontonummer oder ein Zitat kann erhalten bleiben.

Wenn eine Aufgabe tatsächlich Text benötigt, setze der Anfrage harte Grenzen. Lade eine Nachricht anhand ihrer ID statt eines vollständigen Threads. Fordere eine bekannte, serverseitig erzwungene Zeichenbegrenzung an. Entferne Anhänge, sofern ein Nutzer diesen konkreten Abruf nicht genehmigt hat. Gib bei einer Kürzung an, was der Client erhält, etwa mit `content_truncated: true`, damit der Agent fehlende Details nicht erfindet.

Verschachtelte Daten erzeugen eine leisere Variante desselben Problems. Eine Antwort mit `customer`, `contacts`, `invoices`, `payments` und `events` kann im Anwendungscode wie ein einziges Objekt wirken. Für die Offenlegung handelt es sich um ein Bündel unabhängiger Datensätze. Verlange separate Endpunkte oder explizite, erlaubte Erweiterungen für jede Beziehung. Teste anschließend die schlimmste gewöhnliche Anfrage, nicht nur den erfolgreichen Pfad mit einem einzelnen, sparsamen Datensatz.

## Fehlerbehandlung und Observability können das Leck wiederherstellen

Teams beschränken oft die erfolgreiche Antwort und kopieren anschließend die ursprüngliche Nutzlast in Debug-Logs, Trace-Attribute, Wiederholungswarteschlangen und Ausnahmeberichte. Die Daten wurden damit nur verschoben, ihre Offenlegung aber nicht verringert.

Prüfe den gesamten Aufrufpfad. Untersuche mindestens den Agent-Tool-Wrapper, den Debug-Modus des HTTP-Clients, den Request-Recorder, die Konfiguration des verteilten Tracings, den Fehlerdienst, die Job-Warteschlange, die lokale Transkriptspeicherung und den Support-Ablauf. Orte, die behaupten, «nur Metadaten» zu protokollieren, sollten direkt getestet werden, statt ihnen einfach zu vertrauen.

Führe einen Canary-Datensatz durch eine Nichtproduktionsumgebung. Gib ihm auffällige Testwerte in Feldern, die niemals in den Agent-Kontext gelangen dürfen, etwa `CANARY_BILLING_ADDRESS_927` und `CANARY_INTERNAL_NOTE_927`. Führe die tatsächliche Agent-Aufgabe aus und suche anschließend in jedem erlaubten Log- und Trace-Speicher nach diesen Zeichenfolgen. Wiederhole den Test für eine fehlgeschlagene Anfrage, einen Timeout und eine fehlerhafte Antwort. Tests des erfolgreichen Pfads übersehen die meisten versehentlich erfassten Nutzdaten.

Ein nützliches Aufrufjournal zeichnet die Aktion auf, ohne den Inhalt zu duplizieren:

```json
{
  "time": "2025-03-08T14:03:12Z",
  "caller": "release-agent",
  "operation": "GET /v1/jobs/{id}/retry-status",
  "resource_id": "job_4821",
  "response_view": "retry_status",
  "field_set": ["job_id", "state", "retryable", "failure_class"],
  "result_count": 1,
  "outcome": "200"
}
```

Speichere Kennungen nur dort, wo deine eigenen Aufbewahrungs- und Zugriffsregeln dies erlauben. In Systemen mit höherem Risiko solltest du stattdessen eine referenzierte Kennung oder eine kurzlebige Korrelations-ID speichern. Auch ein Hash kann Daten offenlegen, wenn der ursprüngliche Wert aus einem kleinen, leicht erratbaren Bereich stammt. Bezeichne Hashing daher nicht als Schwärzung, ohne zu berücksichtigen, was ein Angreifer ausprobieren kann.

Bereinige ausgehende Fehlermeldungen an der Servergrenze. Ein Datenbanktreiber kann ein fehlgeschlagenes SQL-Fragment offenlegen. Ein vorgelagerter Dienst kann einen vollständigen Datensatz in einer Fehlerhülle senden. Deine API sollte solche Fehler auf stabile öffentliche Codes abbilden, detaillierte Diagnosen in einem eingeschränkten Speicher aufbewahren und Agenten standardmäßig keinen Antwortkörper in Fehlermeldungen zurückgeben.

## Fähigkeit und Offenlegung im Agent-Gateway trennen

Ein Aktions-Gateway sollte das Credential verwalten und die Anfrage ausführen. Es darf jedoch nicht jede Antwort, die diesem Credential zur Verfügung steht, automatisch als geeigneten Agent-Kontext behandeln. Geheimnisisolierung und Antwortminimierung lösen unterschiedliche Teile desselben Aufrufs.

Sallyport bewahrt API- und SSH-Geheimnisse in seinem verschlüsselten Tresor auf und gibt dem Agenten die Ergebnisse der Aktion zurück, ohne das Geheimnis selbst offenzulegen. Das schützt das Credential. Der API-Eigentümer muss trotzdem entscheiden, ob das Ergebnis einen unnötigen Kontodatensatz, eine Befehlsausgabe oder ein überflüssiges Betriebsdetail enthält.

Gib jeder Agent-Aufgabe nach Möglichkeit eine benannte Anfragevorlage. Die Vorlage legt Methode, Host, Pfadstruktur, erlaubte Abfragefelder, Seitenlimit und zulässige Antwortansicht fest. Eine Vorlage für den Release-Status kann eine einzelne Service-ID akzeptieren und ein kurzes Statusobjekt zurückgeben. Sie sollte nicht allein deshalb eine beliebige URL und einen beliebigen `fields`-Ausdruck akzeptieren, weil beides leicht durchzureichen ist.

Hier verursacht das Denken in allgemeinen Proxys Probleme. Ein generischer HTTP-Forwarder kann in der Entwicklung nützlich sein, aber er kann nicht zwischen «Prüfe dieses Deployment» und «Lade jedes Artefakt-Log herunter» unterscheiden. Lege die Absicht in die aufrufbare Aktion. Wenn eine neue Aufgabe mehr Daten benötigt, muss eine API-Änderung oder eine neue Vorlage erforderlich sein. Diese Reibung ist beabsichtigt: Jemand muss erklären, warum die zusätzlichen Daten in den Kontext gelangen müssen.

Die menschliche Freigabe hat bei Ausnahmen weiterhin ihren Platz. Wenn ein Agent für die Lösung eines Falls den Inhalt einer einzelnen Supportnachricht benötigt, kann ein Mensch genau diesen Aufruf freigeben, nachdem Ziel und Umfang sichtbar gemacht wurden. Die Freigabe sollte nicht zum normalen Ersatz für enge Antworten werden. Menschen bestätigen bekannte Karten besonders während eines Incidents schnell, und wiederkehrende Freigaben bringen sie dazu, nicht mehr genau hinzusehen.

## Das Fehlen von Feldern als Teil des Vertrags testen

Die meisten API-Tests prüfen, ob erwartete Felder vorhanden sind. Für Agent-APIs braucht es zusätzlich Tests, die das Fehlen verbotener Felder bestätigen, auch wenn der Code einen Fallback-Pfad nimmt.

Halte neben jeder Antwortansicht einen Test für verbotene Felder. Verwende realistische Feldnamen, einschließlich verschachtelter Beziehungen und Freitext. Der Test sollte fehlschlagen, wenn eine spätere Serialisierung durch ORM-Standards, ein gemeinsames DTO oder eine eager geladene Beziehung ein weiteres Feld hinzufügt.

```python
forbidden = {
    "email",
    "phone",
    "billing_address",
    "tax_id",
    "payment_reference",
    "internal_note",
    "attachments",
}

body = get_invoice_agent_view("inv_1042")
assert forbidden.isdisjoint(body.keys())
assert "customer" not in body
assert "events" not in body
```

Dieser einfache Test erfasst nur Felder der obersten Ebene. Ergänze Serialisierungstests, die den gesamten JSON-Baum durchlaufen, und teste Listen-, Such-, Fehler- und Export-Endpunkte getrennt. Das größte Leck entsteht oft bei einer Sammlungsantwort, die den vollständigen Detail-Serializer wiederverwendet, weil dadurch ein paar Zeilen Code eingespart wurden.

Vertragstests sollten außerdem Grenzen für die Antwortgröße prüfen. Ein striktes Byte-Limit passt nicht für jedes Objekt, aber eine angemessene Obergrenze warnt, wenn jemand ein unbegrenztes Textfeld oder eine Beziehung hinzufügt. Kombiniere die Prüfung mit einem Fixture, das lange Notizen und viele untergeordnete Datensätze enthält. Sonst vermittelt der Test eine falsche Sicherheit.

Prüfe Änderungen mit drei direkten Fragen: Welche Agent-Aufgabe braucht dieses Feld? Welche Antwortansicht enthält es? Welcher Test beweist, dass es überall sonst fehlt? Kann der Autor diese Fragen nicht beantworten, sollte das Feld nicht in einen breit aufrufbaren Endpunkt aufgenommen werden.

## Ausnahmeabrufe sichtbar und zeitlich begrenzt machen

Manche Aufgaben benötigen tatsächlich sensible Details. Betrugsprüfung, Kontowiederherstellung, Sicherheitsuntersuchungen und schwierige Supportfälle können nicht vollständig mit Zusammenfassungen bearbeitet werden. Die Lösung ist nicht, das Gegenteil vorzugeben. Der Abruf muss ausdrücklich, kurzlebig und auf den genauen Datensatz begrenzt sein.

Verwende einen separaten Endpunkt oder eine Aktion, die eine stabile Datensatz-ID und einen angegebenen Zweck entgegennimmt. Gib nur den kleinsten benötigten Ausschnitt zurück, etwa ein einzelnes Feld einer bestrittenen Zahlung oder eine ausgewählte Kundennachricht. Gewähre keinen vollständigen Kontoexport, nur weil derselbe Fall eine einzelne strittige Belastung enthält.

Fordere bei risikoreicheren Abrufen die Freigabe des einzelnen Aufrufs durch einen Menschen und protokolliere Aufrufer, Zweck, Ansicht, Datensatzreferenz und Ergebnis. Halte den Audit-Eintrag getrennt vom sensiblen Antwortkörper. Du musst wissen, dass ein Abruf stattgefunden hat, ohne eine weitere beiläufige Kopie der Information zu erzeugen.

Eine ausgereifte API macht den sicheren Weg zum einfachsten Weg. Zusammenfassungsansichten sollten klare Namen, gute Dokumentation und stabile Felder haben. Umfangreiche Detail-Endpunkte sollten bewusst wirken, weil sie mehr Verantwortung tragen. Wenn dein Agent regelmäßig ein sensibles Feld benötigt, normalisiere die Ausnahme nicht. Überprüfe das Aufgabendesign und frage, ob eine serverseitige Entscheidung oder ein abgeleiteter, geschwärzter Wert ausreichen würde.

Die erste sinnvolle Prüfung gilt meist einem Listen-Endpunkt, nicht dem Endpunkt, vor dem sich ohnehin alle fürchten. Nimm eine echte Agent-Aufgabe, markiere jedes von ihr verwendete Feld und vergleiche diese Liste mit der empfangenen Antwort. Der ungenutzte Teil ist deine nächste API-Änderung.
