TL;DR
Ein Prompt ist kein KI-Feature. Das Feature ist die Kette aus Output-Schema, Prompt, Modell, Tools und Eval-Set, und jedes Glied hängt an jedem anderen. Dieses Paket ist der Agent Contract. Anfangen würde ich beim Eval-Set: hundert echte Altfälle, bevor die erste Zeile Prompt entsteht.
- Format gültig heißt nicht Antwort richtig. Die Fachlichkeit muss als Text ins Modell, so konkret, wie man sie einem Praktikanten erklären würde.
- Eine Prompt-Änderung ist ein unsichtbares Deployment. Versioniert wird das ganze Paket, und die Evals laufen über die ganze Strecke.
- Unsicherheit steht als Feld im Ergebnis: Konfidenz, offene Fragen, Belegstellen. Sonst wird aus einer Einschätzung eine Tatsache.
Eine Mail an die Stadt Köln, wie ich selbst schon eine geschrieben habe. Formlos, zwei Absätze, im Anhang ein Foto vom Platz und ein handgezeichneter Lageplan. Jemand will ein Nachbarschaftsfest machen, Samstagnachmittag, mit Musik und einem Stand mit Getränken. Wer ist zuständig? Das Ordnungsamt, und wenn ja, welche Abteilung? Die Straßenverkehrsbehörde, weil die Straße gesperrt werden muss? Oder macht das Transparent aus dem letzten Absatz daraus eine Versammlung? Die braucht keine Genehmigung, sondern eine Anzeige bei der Polizei.
Diese Frage beantwortet in der Stadt heute ein Mensch, und zwar einer, der weiß, wie das Haus geschnitten ist. Kann ein Sprachmodell das? Ja. Wer die Mail in ein Chatfenster kopiert, bekommt in drei Sekunden eine kluge Antwort, mit Begründung, freundlich formuliert. Da fängt das Problem an. Die Antwort ist ein Absatz Fließtext, und der Rest der Software kann mit einem Absatz Fließtext nichts anfangen. Kein Fachverfahren nimmt “Das klingt nach einer Sondernutzung, ich würde es ans Ordnungsamt geben” als Eingabe.
Das ist der Moment, in dem aus einem Prompt ein KI-Feature werden muss. Der Unterschied lässt sich an diesem einen Agenten zeigen, der nichts weiter tut, als eine Mail der richtigen Stelle zuzuordnen.
Struktur erzwingen
Der erste Schritt ist der offensichtliche: Das Modell soll nicht erzählen. Es soll ausfüllen. Ein Output-Schema legt fest, was zurückkommt. Die federführende Stelle als Aufzählung aus den Stellen, die es in Köln tatsächlich gibt, dazu die Liste der Stellen, die beteiligt werden müssen. Sperrung nötig: ja, nein oder unklar. Besucherzahl, Aufbauten, und jeder Anhang mit seinem Dokumenttyp.
“Antworte als JSON” in den Prompt zu schreiben reicht dafür nicht. Dann kommt “Klar, hier ist dein JSON:” zurück, und der Parser steigt beim ersten Buchstaben aus. Erzwingen heißt: Das Schema geht mit an den Anbieter, die Antwort wird dagegen validiert, und passt sie nicht, wird der Aufruf mit dem Fehler wiederholt. Die gängigen Werkzeuge können das inzwischen.1

Damit steht das erste Glied der Kette: Der Code, der das Ergebnis weiterverarbeitet, passt zum Schema. Wandert ein Feld, bricht der Code. Das ist noch nichts Besonderes, das ist eine Schnittstelle.
Format gültig, Antwort falsch
Nehmen wir an, der erste Testlauf sieht so aus: Schema eingehalten, jedes Feld ausgefüllt, der Parser zufrieden. Und die Antwort ist trotzdem falsch. Das Modell hat die Mail dem Ordnungsamt zugeordnet und die Sperrung der Straße gleich mit. In Köln liegt die Sondernutzung der Straße aber bei einem anderen Amt als das Fest selbst. Und ab einer Größe, die im Haus festgelegt ist, verlangt die Stadt ein Sicherheitskonzept, das in der Mail fehlt. Zwei Fehler, beide im gültigen Format.

Das Modell konnte das nicht wissen. Es kennt die Welt, also Ordnungsämter, Straßenfeste, sogar den Unterschied zwischen Versammlung und Veranstaltung. Es kennt nicht das Haus: welches Amt hier die Straße vergibt, ab welcher Größe hier ein Sicherheitskonzept fällig wird. Das steckt im Kopf des Kollegen, der das seit vielen Jahren macht.
Dieses Wissen muss ins Modell, als Text: in den Prompt oder als Tool, etwa ein Katalog der Stellen mit dem, wofür jede zuständig ist. Ich bitte Fachleute in solchen Fällen um eine Liste: Schreibt auf, wie ihr es einem Praktikanten am ersten Tag erklären würdet. Ab welcher Größe braucht ein Fest ein Sicherheitskonzept? Woran erkennt man, dass eine Skizze ein Lageplan ist und kein Sicherheitskonzept, obwohl beide eine Zeichnung enthalten? In den Häusern, in denen ich das bisher gesehen habe, fehlten diese Sätze jedes Mal. Und fehlende fachliche Beschreibungen ersetzt kein leistungsfähigeres Modell. Ein Modell ohne diese Beschreibungen rät. Es rät gut, aber es rät.
Damit hängt das zweite Glied am ersten: Das Schema passt zum Prompt, sonst nützt das Feld für die federführende Stelle nichts. Der Parser prüft nur das Format.
Prompt passt zum Modell
Das dritte Glied merkt man erst, wenn man es anfasst. Der Prompt, der mit einem großen Modell aus der Cloud sauber läuft, versagt mit einem kleineren Modell auf eigener Hardware oft. Das kleine Modell denkt weniger von selbst mit und braucht klarere Ablaufregeln und mehr Beispiele. Modelltausch ist kein Schalter. Wer nur das Modell tauscht und Prompt und Tools stehen lässt, bekommt ein anderes Produkt.
Tools verändern die ganze Kette
Bis hierhin liest der Agent nur. Mit Tools fängt er an zu handeln, und das verändert alles davor: Die Beschreibung jedes Tools landet im Prompt, das Ergebnis des Aufrufs braucht ein Feld im Schema, und jedes Modell geht anders damit um.
Für den Zuordnungs-Agenten liegen zwei Tools nahe. Ein lesendes: Liegt der genannte Platz im Stadtgebiet, und ist er öffentliche Fläche oder Privatgrund? Auf Privatgrund braucht das Fest keine Sondernutzung, und die Zuordnung ist eine andere. Und ein schreibendes: eine Rückfrage an den Absender schicken, wenn etwas fehlt. Im Code sehen beide gleich aus, ein Funktionsaufruf. Eine falsche Abfrage kostet einen Versuch. Eine verschickte Mail holt niemand zurück, und sie trägt den Absender der Stadt. Deshalb werden Lese- und Schreibrechte getrennt, und je Tool wird entschieden, ob das Modell es allein aufrufen darf. Wer Tools vergibt, entscheidet, was das System anrichten kann.

Fünf Glieder, ein Vertrag
Fünf Dinge, die zusammenpassen müssen: Output-Schema, Prompt, das Modell mit seinem Anbieter, erlaubte Tools und das Eval-Set, also geprüfte Altfälle mit bekanntem Ausgang. Ändert sich Schema, Prompt, Modell oder Tool-Ausstattung, muss das Zusammenspiel neu geprüft werden. Ändert sich das Eval-Set, ändert sich der Maßstab dieser Prüfung.
Ruben Vitt und ich nennen dieses Paket auf ai-systems-architecture.com den Agent Contract. Contract-first statt Prompt-first ist das Prinzip, der Agent Contract ist das Artefakt dazu. Ein Vertrag hat zwei Seiten. Auf der einen das KI-Feature, das verspricht: Ich liefere diese Form. Ich benutze nur diese Werkzeuge. Und ich bin gegen diese hundert Fälle geprüft, mit dieser Trefferquote. Auf der anderen Seite das Fachverfahren, das die Ergebnisse weiterverarbeitet und sich darauf verlässt. Es ist nicht Teil des Vertrags, es ist die Gegenpartei: Es muss zum Schema passen, und das Schema gehört zum Vertrag. Der Contract beschreibt, welche Ergebnisse und Aktionen erlaubt sind. Durchsetzen muss das die Implementierung dahinter, mit Validierung, Tool-Freigaben und der Weiterleitung an einen Menschen.
So könnte der Contract des Zuordnungs-Agenten aussehen, Version 1, mit Beispielzahlen:
| Bestandteil | Inhalt |
|---|---|
| Output-Schema | stelle aus der Liste der Kölner Ämter, beteiligte als Liste, sperrung mit ja, nein oder unklar, dazu konfidenz, offene_fragen, belegstellen und je Anhang ein dokumenttyp |
| Prompt | Fassung 3 vom 4. August, mit dem Stellenkatalog und den Praktikanten-Sätzen zu Sicherheitskonzept und Lageplan |
| Modell | Anbieter, Modellname und Modellstand vom Juli, Temperatur 0 |
| Tools | Lesend: Flächenauskunft der Stadt. Schreibend: keins. Die Rückfrage an den Antragsteller entsteht als Entwurf, verschickt wird sie woanders |
| Eval-Set | 112 Anfragen aus 2024 und 2025 mit bekannter Zuständigkeit, davon 9 ohne Veranstaltungsbezug. Trefferquote dieser Version 91 Prozent, bei Konfidenz “hoch” 97 Prozent |
Ob das eine Datei im Repository ist, ein Datensatz in einer Datenbank oder eine Maske in einem eigenen Werkzeug, ist Implementierungssache. Entscheidend ist, dass es eine Einheit ist, die ein Team gemeinsam prüft, freigibt und in einem halben Jahr noch nachvollziehen kann.
Evals über die ganze Strecke
Das Eval-Set ist das Glied, das die anderen vier zusammenhält. Wie testet man etwas, das jedes Mal ein bisschen anders antwortet? Nicht mit einem Unit-Test auf den Prompt. Man sammelt echte Altfälle: hundert Anfragen der letzten Jahre, mit dem, was am Ende tatsächlich zuständig war. Dazu eine Beschwerde und eine Spam-Mail, die mit Veranstaltungen nichts zu tun haben. Diese Fälle laufen durch den kompletten Contract, und am Ende wird verglichen. Am Anfang liest ein Mensch die Ergebnisse. Später kann ein zweites Modell die weichen Fälle vorsortieren. Was durchfällt, wird zum neuen Testfall.
Manches davon ist binär. Ist die Anfrage bei der richtigen Stelle gelandet, ja oder nein, das lässt sich zählen. Vieles ist es nicht. Ist die Begründung fachlich tragfähig, ist die Rückfrage an den Bürger freundlich? Das ist ein Spektrum, und da braucht es die Fachleute wieder. Die Frage ist nicht mehr “funktioniert es”, sondern “wie oft nicht, und was passiert dann”.

Diese Zahl ist der praktische Nutzen des Eval-Sets. Es sagt für jede Version des Agenten, wie oft er richtig liegt, und im Rückblick auch, was die Sicherheit wert ist, die der Agent selbst angibt. Erst damit gibt es eine Schwelle, ab der ein Ergebnis ohne Menschen weiterlaufen darf. Wo die Schwelle liegt, ist eine Abwägung aus zwei Achsen: dem möglichen Schaden und der Zeit, die ein Mensch zum Beurteilen braucht. Wie diese Schleife in die Pipeline kommt und wie Produktionsfehler zu Testfällen werden, steht bei Ruben: Evals in die CI und Vom Incident zum Regressionstest.
Unsicherheit gehört in den Vertrag
Ein Detail, das ich für das wichtigste am ganzen Schema halte: Der Agent muss sagen dürfen, dass er nicht sicher ist. Als Feld, nicht als Nebensatz. Konfidenz. Offene Fragen. Belegstellen, also die Sätze aus der Mail, aus denen er sein Urteil gelesen hat. Die Konfidenz ist davon das schwächste Feld. Sprachmodelle halten sich fast immer für sicher, und was ihr “hoch” wert ist, weiß man erst aus dem Eval-Set. Die Belegstellen sind der härtere Anker: Ob die zitierten Sätze wirklich in der Mail stehen, kann der Code prüfen. Ob sie die Zuordnung tragen, nicht. Auch das ist wieder Format gegen Inhalt.
Ohne diese Felder wird aus einer wackligen Einschätzung eine Tatsache, sobald sie im Fachverfahren steht. Mit ihnen kann der Code dahinter entscheiden, nach einer Regel, die an Beispielen geprüft ist und nicht der Selbsteinschätzung des Modells überlassen bleibt. Konfidenz über der Schwelle, keine offene Frage: weiter. Offene Frage, ob eine Sperrung nötig ist, weil die Mail es nicht sagt: nachfragen statt raten. Konfidenz unter der Schwelle, weil die Mail nach Versammlung klingt: zum Sachbearbeiter, bevor irgendetwas weiterläuft. Das Modell fällt das Urteil. Der Vertrag legt fest, was mit einem unsicheren Urteil passiert.
Versioniert als Ganzes
Bleibt die Frage, was passiert, wenn sich etwas ändert. Und es ändert sich ständig. Jemand schärft eine Formulierung im Prompt, weil Versammlungen zu oft als Veranstaltung durchgingen. Aus Sicht des Fachverfahrens ist nichts passiert, kein Release, kein Ticket. Aus Sicht des Bürgers hat sich das Verhalten der Stadt geändert. Eine Prompt-Änderung ist ein unsichtbares Deployment.
Deshalb bekommt der Contract die Versionsnummer. Contract v1: dieses Schema, dieser Prompt, dieses Modell, diese Tools, dieses Eval-Set, und die Zahl, die dabei herauskam. Contract v2: das Modell ist neu, alles andere gleich, und die Evals laufen noch einmal über die ganze Strecke, bevor v2 einen einzigen echten Fall sieht. Wenn mich in einem halben Jahr jemand fragt, mit welchem Stand die Anfrage vom 3. Juli bearbeitet wurde, ist die Antwort eine Versionsnummer.
Dazu gehören zwei Dinge, die man leicht vergisst. Das Eval-Set läuft nicht nur beim Versionswechsel. Ein Anbieter zieht über Nacht seinen Filter für Bildinhalte nach, und ein Ablauf, der gestern Fotos verarbeitet hat, verweigert sie heute. Gleicher Modellname, gleicher Prompt, keine Änderung auf der eigenen Seite. Deshalb läuft das Eval-Set jede Nacht gegen die eingefrorene Version. Und es wird selbst mitversioniert, denn vergleichbar sind zwei Versionen nur, wenn beide gegen denselben Referenzsatz gelaufen sind. Und die Belegkette: Der Zustand im Fachverfahren speichert das Was, nicht das Warum. Ins Protokoll gehören Vertragsversion, Modellversion und die Belegstellen aus der Mail, revisionssicher und getrennt vom Fachdatensatz.
Für die Arbeit mit Fachbereichen heißt das: Engineering liefert die Form. Schema, Tools, Versionierung, das ist Handwerk. Der Fachbereich liefert die Maßstäbe: die Praktikanten-Liste und die Altfälle mit bekanntem Ausgang. Und das Urteil, ob eine Begründung trägt, kann sowieso nur der Fachbereich fällen. Fehlt eines von beiden, produziert das System valide Fehler, und niemand merkt es.
Deshalb würde ich mit dem Eval-Set anfangen: echte Anfragen mit fachlich geprüften Sollantworten, bevor irgendjemand die erste Zeile Prompt schreibt. Der erste Prompt trifft dann auf einen Maßstab. Ob seine Antwort überzeugend klingt, ist egal. Wie oft sie falsch ist, steht als Zahl da.
Quellen
-
Spring AI reicht das Schema mit
useProviderStructuredOutput()an die native strukturierte Ausgabe des Anbieters durch und prüft die Antwort mitvalidateSchema(), das bei Verstößen den Fehler an den Prompt hängt und bis zu dreimal neu anfragt. Das Vercel AI SDK liefert mitOutput.objectein typisiertes Objekt oder einen Fehler, die Wiederholung baut man dort selbst. ↩