Idee in 30 Sekunden
Write Access by Default ist ein Anti-Pattern, bei dem ein Agent write-tools standardmäßig erhält, ohne policy-gate und ohne Prüfung vor Ausführung.
Dadurch wird ein Modellfehler oder falsches Routing nicht nur zu einer falschen Antwort, sondern zu einer realen Änderung des externen Zustands.
Einfache Regel: write darf nicht "standardmäßig" sein, sondern nur über einen separaten kontrollierten Pfad mit expliziter Prüfung von Rechten, Kontext und Ausführungsbedingungen.
Beispiel für das Anti-Pattern
Das Team baut einen Support-Agenten, der den Bestellstatus liest und bei Bedarf ein Ticket schließen oder eine Mail senden kann.
Der Agent bekommt write-tools sofort, ohne eigene Prüfphase vor der Aktion.
decision = agent.decide_next_action(user_message)
# Route ist falsch, aber write ist trotzdem verfügbar
result = run_tool(decision.tool, decision.args)
return result
In diesem Setup fehlt der Basisschutz:
# kein deny-by-default für write-tools
# kein approval_required für riskante Aktionen
# kein idempotency_key für Wiederholungen
# kein harter tenant/env scope
Für diesen Fall braucht ihr ein policy-gate vor jedem write-Schritt:
if decision.tool in WRITE_TOOLS and not is_write_allowed(ctx, decision):
return stop("approval_required")
Wenn Bedingungen nicht erfüllt sind, darf der Run nicht in eine externe write-Aktion gehen.
In diesem Fall fügt Write Access by Default hinzu:
- Risiko unerwünschter Änderungen in externen Systemen
- duplizierte write-Operationen bei retries
- größerer blast radius in Multi-Tenant-Umgebungen
Warum es entsteht und was schiefläuft
Dieses Anti-Pattern entsteht oft, wenn ein Team den Agenten "maximal autonom" machen will und write-Zugriff öffnet, bevor Kontrollgrenzen stehen.
Typische Ursachen:
- Demo-Ansatz: erst alle Tools freigeben, Limits später
- keine klare Trennung von
read- undwrite-Routen - Zugriffsregeln stehen im Prompt, werden aber nicht im gateway erzwungen
- kein Pflicht-
idempotency_keyfür write-Operationen
Daraus folgen Probleme:
- unsichere side effects (Zustandsänderungen) - der Agent kann schreiben, wo er nur lesen sollte
- wiederholte Aktionen - retry oder loop wiederholt dieselbe write-Operation
- hoher blast radius - ohne harten scope trifft der Fehler den falschen tenant/env
- schwierige Incident-Analyse - schwer nachzuweisen, warum write erlaubt war
- Verlust von Vorhersehbarkeit - das Team kontrolliert nicht, wann das System zu write übergeht
Im Unterschied zu Blind Tool Trust liegt das Hauptproblem hier nicht in der Payload-Validierung, sondern im standardmäßig offenen write-Zugriff.
Typische Production-Signale für schwache write-Kontrolle:
- write-tools werden selbst in Szenarien aufgerufen, die read-only sein sollten
- in Logs gibt es viele write-Calls mit gleichem
args_hashoder ohneidempotency_key approval_requirederscheint fast nie, obwohl der write-Anteil hoch ist- blocked write attempts sind selten, obwohl das System regelmäßig risky actions vorschlägt
- Audit-Logs zeigen nicht, welche policy-Regel write erlaubt hat
- das Team kann nicht klar erklären, warum ein konkreter write in genau diesem run erlaubt war
- Fehler werden erst nach der externen Aktion entdeckt, nicht am policy-gate
Wichtig: Jeder write-call ändert externen Zustand und hat oft keinen einfachen rollback. Ohne deny-by-default und kontrollierten write-Pfad wird eine fehlerhafte inference zum Production-Incident.
Richtiger Ansatz
Startet mit einem read-first Modell: read-tools sind per Route verfügbar, write-Schritte laufen über separate Prüfung im policy-gate.
Praktischer Rahmen:
- setzt deny-by-default für alle write-tools durch
- trennt Routen in
read_onlyundwrite_candidate - verlangt approval für riskante write-Aktionen
- nehmt
tenant_idundenvnur aus authenticated context, nie aus model output - ergänzt
idempotency_keyfür jede write-Operation - loggt
stop_reasonund policy-gate Entscheidungen für jeden write-Schritt
WRITE_TOOLS = {"ticket.close", "refund.create", "email.send"}
def execute_action(user_message: str, ctx: dict):
decision = agent.next_action(user_message)
if decision.tool in WRITE_TOOLS:
if not is_write_allowed(ctx, decision): # policy gate: role, route allowlist, tenant/env scope
return stop("approval_required")
scoped_args = enforce_scope(
decision.args,
tenant_id=ctx["tenant_id"],
env=ctx["env"],
)
scoped_args["idempotency_key"] = make_idempotency_key(ctx["run_id"], decision)
return run_tool(decision.tool, scoped_args)
return run_tool(decision.tool, decision.args) # read-only tool from allowed set
In diesem Setup ist der write-Schritt kontrolliert: Das System führt sicher aus oder stoppt den Run transparent.
Schnelltest
Wenn diese Fragen mit "ja" beantwortet sind, habt ihr ein Risiko für das Anti-Pattern Write Access by Default:
- Kann ein write-tool ohne explizite policy/approval-Prüfung aufgerufen werden?
- Wiederholt retry manchmal dieselbe write-Aktion ohne
idempotency_key? - Kann das Team nicht schnell erklären, warum ein konkreter write erlaubt war?
Worin es sich von anderen Anti-Patterns unterscheidet
Blind Tool Trust vs Write Access by Default
| Blind Tool Trust | Write Access by Default |
|---|---|
| Hauptproblem: tool output wird ohne Validierung akzeptiert. | Hauptproblem: write-Zugriff ist standardmäßig offen. |
| Wann es entsteht: wenn parse/schema/invariant Checks vor Entscheidungen fehlen. | Wann es entsteht: wenn write nicht über deny-by-default und approval-gate läuft. |
Kurz gesagt: Blind Tool Trust betrifft Datenqualität vor der Aktion, Write Access by Default betrifft die Rechte für die Aktion selbst.
Agents Without Guardrails vs Write Access by Default
| Agents Without Guardrails | Write Access by Default |
|---|---|
| Hauptproblem: runtime-Grenzen und policy-Kontrolle fehlen insgesamt. | Hauptproblem: speziell write-Operationen haben keinen harten Zugriffskorridor. |
| Wann es entsteht: wenn dem System klare safety-policy für execution fehlt. | Wann es entsteht: wenn write als Standardpfad erlaubt ist statt als Ausnahme über policy-gate. |
Kurz gesagt: Agents Without Guardrails ist ein breiteres Problem von Ausführungsgrenzen, Write Access by Default konkret ein unsicheres Zugriffsmodell für write.
Tool Calling for Everything vs Write Access by Default
| Tool Calling for Everything | Write Access by Default |
|---|---|
| Hauptproblem: tools werden unnötig oft aufgerufen, selbst wenn es ohne geht. | Hauptproblem: sobald ein tool-call passiert, kann write ohne ausreichende Kontrolle durchgehen. |
Wann es entsteht: wenn kein stabiler no_tool-Pfad für einfache Fälle existiert. | Wann es entsteht: wenn das System read- und write-Zugriffsebenen nicht trennt. |
Kurz gesagt: Tool Calling for Everything erhöht die Anzahl der Calls, Write Access by Default erhöht den Preis jedes write-Fehlers.
Selbstcheck: Habt ihr dieses Anti-Pattern?
Schnellcheck für anti-pattern Write Access by Default.
Markiert die Punkte für euer System und prüft den Status unten.
Prüft euer System:
Fortschritt: 0/8
⚠ Es gibt Anzeichen für dieses Anti-Pattern
Verschieben Sie einfache Schritte in einen workflow und behalten Sie den Agenten nur für komplexe Entscheidungen.
FAQ
Q: Bedeutet das, dass Agenten gar keine write-Aktionen ausführen dürfen?
A: Nein. Write-Aktionen sind möglich, aber nur über einen kontrollierten Pfad: policy-gate, approval (wo nötig), scope enforcement und idempotency.
Q: Was ist der Unterschied zwischen policy-gate und approval?
A: Policy-gate ist deterministische Regelprüfung zur Laufzeit. Approval ist eine separate Bestätigung für eine konkrete riskante Aktion. Das sind unterschiedliche Kontrollschichten.
Q: Was ist das Minimum für den Start?
A: Startet mit deny-by-default für write, verpflichtendem idempotency_key, hartem tenant/env-scope und stop_reason-Logging für blockierte write-Versuche.
Was als Nächstes
Ähnliche anti-patterns:
- Blind Tool Trust - wenn das System auf unvalidiertem tool output handelt.
- Agents Without Guardrails - wenn execution ohne klare runtime-Grenzen läuft.
- Tool Calling for Everything - wenn tools ohne expliziten Bedarf aufgerufen werden.
Was ihr stattdessen bauen solltet:
- Allowed Actions - wie erlaubte Aktionen über explizite Regeln festgelegt werden.
- Tool Execution Layer - wo policy, scope und idempotency zentralisiert werden.
- Stop Conditions - wie ein run sicher gestoppt wird, wenn write nicht erlaubt ist.