AEGIS, mein experimentelles Projekt, prüft jede Aktion eines KI-Agenten gegen ein formales Regelwerk, bevor sie ausgeführt wird. Bleibt der Guard nicht erreichbar oder ist die Aktion nicht eindeutig zu beurteilen, wird nicht gehandelt.
Die Architektur adressiert einen Punkt der Debatte um sogenannte Agentic AI, der oft im Hintergrund bleibt: Sprachmodelle wie GPT, Claude oder Llama führen selbst keine Aktionen aus. Sie schlagen Werkzeugaufrufe vor. Die tatsächliche Ausführung übernimmt der umgebende Host, also etwa eine Bibliothek, ein Plugin oder ein Kommandozeilen-Programm. AEGIS setzt an dieser Schnittstelle an.
Die Grenze entsteht nicht im Modell
Ein autonomer Agent verfügt über Werkzeuge, mit denen er Dateien lesen und schreiben, Shell-Befehle ausführen, HTTP-Anfragen senden oder Tickets bearbeiten kann. Das Modell besitzt diese Fähigkeiten nicht selbst. Es kann lediglich Tool-Calls formulieren. Ob daraus ein Effekt entsteht, entscheidet der Host.
Eine geläufige Methode besteht darin, dem Modell ein Werkzeug namens aegis_check bereitzustellen und ihm im System-Prompt aufzutragen, dieses vor jeder Aktion aufzurufen. Diese Methode ist eine Konvention. Sie kann brechen, wenn der Kontext groß wird oder das Modell den Hinweis übergeht. Eine harte Grenze entsteht erst dort, wo der Host die Werkzeuge tatsächlich ausführt.
Die Analogie zu klassischen Betriebssystemen liegt nahe. Ein Userspace-Prozess öffnet eine Datei nicht, indem er den Kernel sprachlich überzeugt. Er stellt einen Syscall ab, der Kernel prüft Parameter, Rechte und Zustand. AEGIS sitzt nach diesem Muster im Tool-Pfad des Hosts: nicht als Gesprächspartner des Modells, sondern als Syscall-Grenze.
Anatomie einer Anfrage
Der Übergang vom Modell-Vorschlag zur tatsächlichen Aktion ist als HTTP-Aufruf an einen lokalen Sidecar-Dienst realisiert. Der Endpunkt heißt POST /v1/check. Der Payload ist strukturiert und enthält keine natürliche Sprache:
{
"action_type": "shareIntelligence",
"agent_id": "intelligenceAgentInMission",
"proposition": {
"classification": "secret",
"recipient": "externalService"
},
"context": {
"tool": "send_external_message",
"session_id": "redteam-17"
}
}
Geprüft werden Agent, Aktionstyp, Proposition und optional ein Kontext. Der Host übersetzt den Tool-Aufruf in die formalen Konzepte der geladenen Domäne — im Beispiel die Domäne „IAMission" mit militärischen Geheimhaltungsregeln. AEGIS trägt das Adjektiv „deontisch", weil sein Regelwerk in der Logik der Pflicht arbeitet: Ein Vokabular aus erlaubten, verbotenen und gebotenen Handlungen.
Die Antwort fällt ähnlich knapp aus:
{
"decision": "FORBIDDEN",
"reason_type": "EXPLICIT_NORM",
"justification_chain": [
"IAMissionCode forbids sharing secret intelligence with externalService"
],
"norms_applied": [
"IAMissionCode:shareIntelligence-secret-external"
],
"action_type": "shareIntelligence",
"agent_id": "intelligenceAgentInMission",
"explanation": "FORBIDDEN by applicable IAMission rule"
}
Drei Verdicts kennt das System: PERMITTED führt aus, FORBIDDEN blockiert, UNDECIDABLE blockiert ebenfalls. Unklarheit gilt nicht als Erlaubnis.
Tool Calling allein ist keine Durchsetzung
Function Calling und Tool Use, wie sie OpenAI und Anthropic in ihren APIs definieren, sind die übliche Form der Schnittstelle zwischen Modell und Werkzeug. Ein enges Tool-Schema mit action_type als Aufzählungstyp und einer auf bekannte Felder begrenzten Proposition zwingt das Modell zu strukturierten Vorschlägen statt zu freiem Text.
Ein solches Schema reicht jedoch nicht, um Aktionen zu erzwingen. Stellt der Host neben aegis_check weitere ungeprüfte Werkzeuge bereit, kann der Agent diese auswählen. AEGIS unterscheidet daher zwischen Transparenz und Durchsetzung.
aegis_check als sichtbares Werkzeug ist Transparenz: Das Modell kann fragen, ob eine geplante Aktion erlaubt wäre, und seine Strategie anpassen. Durchsetzung liegt tiefer. In der Integration mit OpenCode, einem Open-Source-Coding-Agenten, habe ich sie an zwei Stellen beispielhaft verankert: Der permission.ask-Hook liefert das primäre Verdict, tool.execute.before greift als zweite Schicht. Im AEGIS-eigenen Orchestrator prüft eine Komponente namens ActionExecutor vor jedem Werkzeug-Aufruf, ob der Guard einverstanden ist.
Daraus folgt eine Architekturregel: Jedes Werkzeug, das eine Wirkung in der Außenwelt hat, läuft durch denselben Engpass. Auf die Tool-Wahl des Modells stützt sich die Architektur nicht.
MCP — Schnittstelle ohne automatische Durchsetzung
Anders fällt das Bild beim Model Context Protocol (MCP) aus, einer von Anthropic vorgeschlagenen Spezifikation für KI-Werkzeuge. Ein MCP-Server kann Tools und Ressourcen anbieten. AEGIS könnte diese Form nutzen und etwa check_action oder Zugriffsfunktionen wie read_via_broker über MCP exponieren.
Entscheidend ist die Frage, ob ein MCP-Server bestehende Werkzeuge des Hosts abfangen oder lediglich zusätzliche bereitstellen kann. Im ersten Fall sitzt AEGIS im Tool-Pfad. Im zweiten Fall läuft er parallel: Der Agent kann das AEGIS-Tool ignorieren und ein anderes wählen.
Der Host-Vertrag
Das Architekturprinzip von AEGIS lässt sich in einem Satz zusammenfassen:
Jeder wirksame Aktionspfad läuft durch eine formale, fail-closed, auditierbare Guard-Instanz.
Konkret heißt das: Jedes Werkzeug, das Dateien ändern, Daten nach außen senden oder über die Shell vergleichbare Wirkung erzielen kann, ist entweder durch den Guard abgesichert oder anderweitig begrenzt. Der Vergleich mit klassischen Datenbank-Perimetern liegt nahe — eine API ist nicht abgesichert, wenn daneben ein zweiter Zugang ohne Authentifizierung läuft.
Fail-closed bedeutet, dass der Host bei einem Ausfall der Guard-Verbindung keine Aktion ausführt. Eine Implementierung, die in solchen Fällen erlaubt, hat an dieser Stelle keinen Perimeter mehr. Das OpenCode-Plugin von AEGIS hinterlegt dieses Verhalten als Standardvorgabe.
Der Rejection Loop
Eine Aktion zu blockieren ist technisch trivial. Aufschlussreicher ist die Mechanik, die den Agent nach einer Ablehnung weiterarbeiten lässt — der sogenannte Rejection Loop. Er ist im Orchestrator von AEGIS implementiert und verteilt Information bewusst ungleich.
Ein Verdict trägt mehrere Felder. Neben der Entscheidung (PERMITTED, FORBIDDEN, UNDECIDABLE) klassifiziert ein reason_type den Grund nach einer Liste von neun Kategorien: EXPLICIT_NORM für eine konkret anwendbare Regel, CWA_NO_PERMISSION für eine unter der Closed-World-Annahme fehlende Erlaubnis, NO_JURISDICTION für Aktionen außerhalb jeder geladenen Domäne, UNRESOLVED_CONFLICT für widersprüchliche Normen, MORAL_AXIOM für nicht überschreibbare ethische Prinzipien, dazu vier weitere für Validierungs- und Laufzeitfehler. Dazu kommen eine justification_chain mit den Argumentationsschritten der Engine und norms_applied mit den Bezeichnern der beteiligten Regeln.
Diese Felder erreichen das Modell nicht alle. Der Orchestrator ruft eine Methode namens explain_safe() auf, die nur Entscheidung und Reason zurückgibt — ohne Normnamen, ohne Argumentationsschritte. Die vollständige Begründung mit justification_chain und norms_applied landet im Audit-Log, nicht im Chat-Verlauf. Eine Komponente namens RefusalRegistry erzeugt zusätzlich aus dem reason_type zwei verschiedene Texte: einen für menschliche Empfänger und einen für das Modell. Drei Adressaten, drei Detailstufen.
Der Loop selbst läuft folgendermaßen: Der Agent schlägt eine Aktion vor. Der Host übersetzt sie in eine Action. AEGIS prüft. Bei PERMITTED führt der Host die Aktion aus und liefert das Ergebnis zurück ans Modell. Bei FORBIDDEN führt der Host nichts aus, hängt eine Tool-Antwort an den Konversationsverlauf und ruft das Modell erneut. Bei UNDECIDABLE wird sofort an einen Menschen übergeben — die Schleife versucht keinen erneuten Aufruf, weil eine nicht entscheidbare Lage durch Wiederholung nicht entscheidbar wird.
Die Tool-Antwort, die das Modell bei einem FORBIDDEN mit Reason EXPLICIT_NORM zu sehen bekommt, hat folgende Form:
{
"decision": "FORBIDDEN",
"explanation": "Decision: FORBIDDEN\nReason: EXPLICIT_NORM",
"executed": false,
"suggestion": "Your proposed action was explicitly forbidden by a governing norm. Propose an alternative that does not violate the applicable rules."
}
Der suggestion-Text stammt aus einem festen Template-Satz, der nach reason_type indiziert ist. Bei CWA_NO_PERMISSION lautet der Hinweis sinngemäß, dass keine Erlaubnis gefunden wurde und unter Closed-World-Annahme das Fehlen einer Erlaubnis als Verbot zu lesen ist. Bei UNRESOLVED_CONFLICT empfiehlt das Template, an einen Menschen zu eskalieren.
Nicht jede Ablehnung erlaubt einen erneuten Versuch. Bei MORAL_AXIOM enthält der Suggestion-Text die explizite Anweisung „No override is possible. Do not retry. Inform the user." Bei INTERNAL_ERROR heißt der Text „Do not retry the same action. Escalate to a human operator." Der Loop unterscheidet damit zwischen Ablehnungen, die ein alternativer Vorschlag heilen kann, und Ablehnungen, die einen harten Stopp markieren. Im ersten Fall sieht das Modell nur den reason_type und den Suggestion-Text und kann auf dieser Basis einen alternativen Vorschlag formulieren. Im zweiten Fall liest es die Anweisung, nicht zu wiederholen — ob es ihr folgt, ist eine andere Frage, weshalb der Host zusätzlich nicht ausführt, was nicht erlaubt ist.
Der Orchestrator zählt die Ablehnungen mit. Überschreitet die Zahl eine konfigurierbare Schwelle — der Prototyp setzt sie auf drei — bricht der Loop ab. Der Host produziert eine letzte Nachricht der Form „Action forbidden after 3 attempts. [user_message] Escalating to human operator." und übergibt an einen Menschen. Eine zusätzliche Iterationsgrenze in der äußeren Schleife garantiert, dass der Loop in jedem Fall terminiert und nicht in einem endlosen Wechsel von Vorschlag und Ablehnung hängenbleibt.
Die Designerwägung hinter der Asymmetrie zwischen Audit, Modell und Mensch: Ablehnungen können selbst Information preisgeben. Eine Antwort der Form „verboten wegen Quelle X" bestätigt die Existenz von X. Wenn der Auditor den vollen Pfad sieht, das Modell den reason_type ohne Normnamen und der menschliche Empfänger nur einen generischen Satz, ist das keine stilistische Entscheidung, sondern eine Folge dieser Side-Channel-Überlegung.
Drei Beispiele
Drei Anwendungsfälle skizzieren das Verhalten:
Ein Coding-Agent will eine Datei löschen. AEGIS blockiert, weil die geladene Domäne Löschungen ausschließt. Der Agent reicht stattdessen einen Patch ein.
Ein Intelligence-Agent will geheime Daten an einen externen Dienst senden. AEGIS blockiert. Der Agent schlägt eine interne Zusammenfassung an einen autorisierten Empfänger vor.
Ein DevOps-Agent will einen riskanten Shell-Befehl ausführen. AEGIS blockiert. Der Agent baut eine getestete Variante.
Der Unterschied zu einem klassischen Permission-Prompt, der einen Menschen „Darf ich?" fragt, liegt im Adressaten der Anfrage. AEGIS fragt ein formales Regelwerk und liefert dem Agenten einen Grund. Ein Mensch wird erst beigezogen, wenn der Guard UNDECIDABLE antwortet oder die Schleife erschöpft ist.
Was AEGIS nicht prüft
AEGIS prüft nur die Aktionen, die der Host ihm vorlegt. Außerhalb dieser Grenze liegen ungeprüfte Werkzeuge, falsch übersetzte Tool-Argumente und Lücken in der formalen Regelbasis. Diese Punkte beschreiben die eigentlichen Anforderungen an eine Integration. Die Schnittstelle des Guard ist einfach: ein HTTP-Endpunkt, JSON hinein, Verdict heraus. Der Vertrag mit dem Host ist eng — nichts mit Wirkung läuft am Guard vorbei.