Fall 1 von 6 · eigenes Werkzeug Stand 02.09.2026

Die Schleuse

Ein Gateway, durch das alle meine Projekte ihre Modellaufrufe schicken. Es ist selbst kein Agent. Es ist die Schicht, die jeder Agent und jeder Workflow hier braucht, und die in den üblichen Schaubildern nicht vorkommt: Budget, Region, Anonymisierung, Warteschlange, Spur.

Befund

Infrastruktur  Kein Agent, sondern der Lauf-Teil aus Abschnitt 06 des Grundlagendokuments, einmal gebaut für alle Projekte. Eine Anwendung nennt eine Aufgabe, nicht einen Anbieter.

Läuft auf einer Testinstanz auf dem eigenen Server. Ein Produktivziel gibt es noch nicht, und das steht hier, weil eine Seite über Nachvollziehbarkeit sonst wenig wert wäre.

01

Aufgabe

Jedes Projekt, das ein Sprachmodell braucht, schickt eine versionierte Aufgabe: „fasse dieses Transkript zusammen“, „bewerte diese Musiktitel“, „beantworte diese Frage nur aus diesen Passagen“. Die Schleuse wählt Anbieter und Modell, fällt bei Fehlern auf den nächsten Anbieter zurück, prüft das Budget, prüft die Region, anonymisiert wo gefordert und protokolliert jeden Versuch. Die Anwendung erfährt davon nichts, außer dem Ergebnis.

Technisch: PHP, eine SQLite-Datenbank, kein Framework. Ein Webprozess für synchrone Aufrufe, ein Hintergrundprozess für die Warteschlange. Angebunden sind ein deutscher Anbieter, zwei amerikanische, ein Modell auf eigener Maschine und der Anonymisierer als eigener Dienst.

02

Vorfrage

Die vier Bedingungen, angewandt auf das, was die Schleuse selbst tut.

  • NEINWeg unbekannt? Nein. Prüfen, wählen, aufrufen, wiederholen, protokollieren: immer dieselbe Kette. Ein Modell entscheidet hier nichts über den Ablauf. Damit ist es ein Workflow, und die Prüfung endet.

Das ist der Punkt: die Teile, die einen Agenten im Betrieb halten, sind selbst keine Agenten. Sie sind Regeln, und Regeln sollen deterministisch laufen.

03

Bauform

Auslöser, Lauf, Rückgabe.

AuslöserEin Aufruf über HTTP mit dem Schlüssel des Projekts. Synchron, wenn die Antwort in Sekunden kommt. Sonst wird die Aufgabe eingereiht, die Anwendung bekommt sofort eine Vorgangsnummer und fragt später nach.
WarteschlangeJeder Auftrag trägt einen Idempotenz-Schlüssel: dasselbe Einreihen zweimal liefert denselben Auftrag zurück statt doppelter Arbeit. Zustände sind eingereiht, läuft, erledigt, tot. Ein gescheiterter Auftrag kommt mit wachsendem Abstand zurück in die Reihe und wird nach der eingestellten Zahl von Versuchen tot, nicht ewig wiederholt. Ein Auftrag, dessen Bearbeiter verschwunden ist, wird nach Ablauf seiner Frist zurückgeholt. Inhalte werden nach Ablauf gelöscht, und das Löschen hängt nicht an einem gesunden Hintergrundprozess allein.
LaufBudget prüfen, Region prüfen, Anbieterkette abarbeiten, Antwort gegen das Ausgabeformat prüfen, Ergebnis zurückgeben. Zwei getrennte Wiederholungsbudgets: eines für Transportfehler beim selben Anbieter, eines für Antworten, die das Format verfehlen. Ein Formatfehler geht in der Regel sofort zum nächsten Anbieter, weil ein Modell, das die Form einmal verfehlt, sie meist wieder verfehlt.
RückgabeEin fester Umschlag mit Inhalt, Anbieter, Modell, Verbrauch, Abbruchgrund, ob die Antwort abgeschnitten wurde, ob eine Ersatzroute nötig war, und Laufzeit. Der Umschlag ist ein Vertrag: er wächst, aber er ändert sich nicht still.
04

Die fünf Grenzen, die hier stecken

Das ist die Checkliste aus Abschnitt 05 des Grundlagendokuments, als Code.

Budget vor dem Lauf

Jedes Projekt hat ein Tagesbudget in Token, jeder Kunde eines dazu. Die kleinere Grenze gilt. Geprüft wird vor dem Aufruf, gegen das Maximum, das die Aufgabe anmeldet, nicht hinterher gegen das, was sie gebraucht hat. Ist das Budget erschöpft, antwortet die Schleuse mit „später“ und einer Uhrzeit, eingereihte Aufträge warten bis zum nächsten Tag, ohne einen Versuch zu verbrauchen. Wie sich das anfühlt, wenn es zuschlägt, steht bei der Musikbibliothek.

Region als harte Grenze

Eine Aufgabe darf deklarieren, in welcher Region ihre Daten verarbeitet werden dürfen. Wo ein Anbieter verarbeitet, steht in der Umgebung der Maschine, nicht im Code, weil dasselbe lokale Modell in Frankfurt ein EU-Verarbeiter ist und anderswo nicht. Geprüft wird, bevor die Anbieterkette abgearbeitet wird. Ein Anbieter außerhalb wird nie erreicht, egal wie die Kette sortiert ist. Ein Anbieter ohne bekannte Region gilt als unbekannt und ist draußen. Bleibt keiner übrig, heißt der Fehler „kein zulässiger Anbieter“ und nicht „vorübergehend nicht verfügbar“, weil eine Wiederholung hier nie gelingen kann.

Anonymisierung je Anbieter

Ein Projekt oder sein Kunde kann fordern, dass vor bestimmten Anbietern anonymisiert wird. Beide dürfen fordern, beide Forderungen gelten: Vorgaben verschärfen, sie weichen nicht auf. Entschieden wird je Anbieter, nicht je Anfrage. Eine Ersatzroute erbt die Einstellung nicht, sondern wird neu geprüft, sonst hinge der Schutz davon ab, wer gerade ausgefallen ist. Der Anbieter bekommt Platzhalter, die Anwendung bekommt Klartext zurück. Die Zuordnungstabelle dazwischen ist der Schlüssel zur Re-Identifizierung. Sie lebt nur im Speicher des einen Aufrufs: nicht im Protokoll, nicht in der Datenbank, nicht in der Antwort. Nachgeprüft: nach mehreren Läufen mit Klarnamen steht in keiner Tabelle einer davon.

Ein Schutz, der ausfällt, fällt laut aus

Antwortet der Anonymisierer nicht, bricht der Aufruf ab: „Anonymisierung war gefordert, der Dienst hat nicht geantwortet, es wurde nichts gesendet.“ Kein Durchreichen, kein Ausweichen auf den nächsten Anbieter. Das Gegenteil, ein Schutz, der bei Ausfall den Originaltext weitergibt, sieht im Betrieb aus wie ein Schutz, der funktioniert. Genau das tut ein älterer Prototyp von mir bis heute.

Die Spur

Jeder Anbieter-Versuch ist eine Zeile: Projekt, Kunde, Auftrag, Aufgabe, Anbieter, Modell, Status, Latenz, vier Token-Arten, Abbruchgrund, Ersatzroute, Fehler, ob anonymisiert wurde. Was nicht darin steht: der Wortlaut des Prompts und der Antwort. Ein Protokoll, das Inhalte dupliziert, ist ein zweiter Datenspeicher mit den Rechten eines Logs. Ein übersprungener Anbieter steht mit Begründung drin, ob wegen der Region oder wegen einer fehlenden Freigabe, damit ein Ausschluss nie wie ein Fehler aussieht.

05

Ein Durchstich: der Recall

Die Aufgabe, die am häufigsten mit „dafür braucht es eine Vektor-Datenbank“ beantwortet wird, gebaut ohne eine.

Ich arbeite seit Monaten mit einem Programmierassistenten, und jede Sitzung hinterlässt ein Transkript. Die Frage „wann habe ich das schon einmal gelöst, und wie“ war lange nur mit Suchen im Dateisystem zu beantworten. Der Recall beantwortet sie in zwei Schritten:

  1. 01Volltextsuche. Alle Transkripte liegen in einem Volltextindex auf dem eigenen Server. Die Frage liefert die zehn passendsten Passagen, nummeriert, mit Projekt, Sitzung und Datum. Kein Modell beteiligt, das Ergebnis ist bei gleicher Frage gleich.
  2. 02Ein Modellaufruf. Frage und Passagen gehen als Aufgabe durch die Schleuse, Region EU, weil Transkripte echte Namen enthalten. Der Auftrag an das Modell: antworte ausschließlich aus den Passagen, belege jede Aussage mit der Passagennummer, und wenn die Antwort nicht darin steht, sag wörtlich „In den Passagen nicht enthalten“. Keine Pfade, keine Befehle, keine Namen erfinden, auch keine plausiblen.

Das Ergebnis ist eine Antwort mit Quellen, erreichbar aus dem Assistenten selbst, aus einer kleinen Webseite, aus der Kommandozeile und aus dem Chat-Dienst des Anbieters. Der Recall hat einen eigenen Schlüssel mit eigenem Tagesbudget, damit seine Kosten von denen der Musikbibliothek getrennt bleiben. Und er war der Fall, an dem sich zeigte, dass die Geduldslogik nur der Stapel braucht: kleine Einzelanfragen liefen selbst während der Lastwellen des Anbieters in etwa zwei Sekunden.

Ehrlich dazuDie Anti-Halluzinations-Regel wurde getestet und hat bestanden. Eine Messlatte mit zehn echten Fragen und bekannter richtiger Antwort gibt es für den Recall nicht. Er wird nach Gefühl beurteilt, und das ist genau der Zustand, vor dem das Grundlagendokument warnt.
06

Messlatte

Für die Schleuse selbst gibt es drei Prüfläufe, die nach jeder Änderung laufen: Verträge und Validierung, Nebenläufigkeit der Warteschlange, und die Verwaltung über HTTP gegen eine Wegwerf-Datenbank. Sie kosten nichts, weil sie keinen Anbieter erreichen. Was sie nicht messen: ob ein Anbieter gut urteilt. Das habe ich getrennt gemessen, an über tausend Musiktiteln, und die Kurzfassung steht hier.

1.078Titel, von vier Modellen bewertet, 20. bis 22.08.2026
7,9Rauschboden: Abstand zweier Spitzenmodelle voneinander
13,8Abstand des deutschen Anbieters vom Spitzen-Konsens
18,1Abstand des kleinen amerikanischen Modells
~87 sje Titel beim deutschen Anbieter, mit elf Timeouts in einem Lauf

Das Urteil des deutschen Anbieters liegt näher am Konsens der Spitzenmodelle als das kleine amerikanische Modell. Bezahlt wird also Verfügbarkeit, nicht Urteilskraft. Der ganze Lauf mit Grafik: Hetzner AI Experiments im Praxistest.

07

Was schiefging

Datiert, weil ein Fehler ohne Datum eine Anekdote ist.

August 2026 · zweimal derselbe Fehler

Ein Parameter, den der Anbieter aus seiner Schnittstelle entfernt hatte, stand bei mir als gleichwertige Einstellung zur Wahl. Erst die Temperatur, dann das Denkbudget. Beides führte zu abgewiesenen Anfragen. Seitdem nimmt jeder Anbieter den Transport als austauschbare Schicht, und jede Einstellung hat einen Test, der die gesendete Nutzlast prüft. Ein Review ersetzt den Test nicht: beide Male war der Code gelesen worden.

August 2026 · eine Antwort, die nicht ankam, galt als endgültig

Denkende Modelle liefern eine leere Antwort, solange sie denken. Die Schleuse hielt das für eine kaputte Konfiguration und stoppte die Kette, statt weiterzufallen. Regel seitdem: endgültig sind nur Zugangsdaten und abgewiesene Anfragen. Alles andere ist vorübergehend.

20.08.2026 · der Webserver davor kappte nach 60 Sekunden

Lange Stapelanfragen an denkende Modelle brachen ab, und die Schleuse sah einen Transportfehler. Ursache war nicht der Anbieter, sondern der eigene Reverse-Proxy. Stapel laufen seitdem direkt gegen den Dienst, nicht durch den Proxy.

14.08.2026 · ein Schlüssel, der buchstäblich „$KEY“ hieß

Beim Anlegen der Umgebungsdatei über die Shell wurde der Variablenname wörtlich in die Datei geschrieben. Aufgefallen ist es nicht, weil der Testaufruf denselben Fehler machte und beide zusammenpassten. Eine Prüfung, die den kaputten Stand als Referenz nimmt, beweist nichts.

Offen · die Klassifikationsaufgabe hat kein Vokabular

Derselbe Text ergab bei einem Spitzenmodell „Zahlungserinnerung“, bei einem kleinen „bill payment reminder“, bei einem dritten „negativ“. Ohne feste Labelmenge ist die Aufgabe nachgelagert nicht auswertbar. Fällig vor dem ersten echten Verbraucher, danach wäre die Labelmenge ein öffentlicher Vertrag.

08

Was absichtlich fehlt, und was noch fehlt

Kein Prompt-Inhalt im Protokoll

Absichtlich. Das Protokoll ist für Kosten und Fehlersuche, nicht für Inhalte.

Keine Modellwahl durch die Anwendung

Absichtlich. Anbieter und Modell sind Konfiguration, nie Teil einer Anfrage. Ein Betreiber, der Kandidaten vergleicht, bekommt einen eigenen Eingang.

Keine harte Mandantentrennung

Noch nicht. Der Kunde ist Zurechnung und Begrenzung, keine Zugriffsgrenze. Wer sie braucht, braucht zusätzlich eine Zuordnung, welches Projekt für welchen Kunden arbeiten darf.

Kein Produktivziel

Noch nicht. Die Schleuse läuft auf der Testinstanz. Der Weg auf einen Produktivserver ist eine Entscheidung, keine technische Frage.

 

Quellen

Regeln für den Code: ai-core/AGENTS.md. Betrieb und Schnittstelle: ai-core/README.md. Aufgabenverträge: ai-core/config/tasks.php. Vier Befundberichte in der Reihenfolge ihrer Entstehung: BEFUND-review.md, BEFUND-nachpruefung.md, BEFUND-nachpruefung-2.md, BEFUND-probelauf.md. Messung der Anbieter: BENCHMARK-hetzner-experiments.md. Recall: Repo transkript-recall, dort PLAN.md; Aufgabe recall.v1 in den Aufgabenverträgen. Werkstattbericht mit sechs Messprotokollen im Wortlaut: Wie ich arbeite.