Der Aufruf, der richtig geformt war und nichts bedeutete
Der Werkzeugaufruf bestand jede Prüfung, die wir hatten. Das JSON parste, die Feldnamen stimmten, die Typen passten, und die Auftragsnummer darin verwies auf nichts. Unsere Validierung hatte eine Frage beantwortet, die niemand gestellt hatte.
Was bestand und was brach
Ein Kunde wollte die Lieferadresse eines Auftrags ändern. Der Schritt, der eine Anfrage in einen Vorgang übersetzt, erzeugte einen Aufruf unserer Änderungsfunktion mit wohlgeformter Nutzlast, und das Zielsystem wies ihn ab, weil die Auftragskennung nicht existierte.
Jede Prüfung zwischen Modell und System hatte bestanden. Das ist der unangenehme Teil: Wir hatten eine Validierung gebaut, die bestätigt, dass ein Argument wie eine Auftragsnummer aussieht, ohne zu bestätigen, dass es eine ist — und das sind völlig verschiedene Zusicherungen.
Zwei Fragen, die wie eine aussehen
Form und Referenz. Die Form fragt, ob der Wert eine Zeichenkette des richtigen Musters und der richtigen Länge ist. Die Referenz fragt, ob das Benannte existiert und das ist, was der Nutzer meinte. Ein Schema beantwortet das Erste und kann das Zweite strukturell nicht beantworten.
Sobald wir das ausgesprochen hatten, war die Behebung offensichtlich und die Auslassung peinlich. Das Modell sollte aus einem Gespräch eine Kennung erzeugen — das ist ein Nachschlagen — und wir hatten seine Antwort akzeptiert, ohne selbst nachzuschlagen.
Die Forschung zu treuen Aufrufen
Wang und Kollegen veröffentlichten in jenem Sommer eine Arbeit zur treuen und effizienten Erzeugung von API-Aufrufen, die die Lücke zwischen einer Ausgabe, die eine Spezifikation erfüllt, und einer Ausgabe, die die Absicht hinter der Anfrage korrekt wiedergibt, adressiert.
Mitgenommen haben wir die Trennung statt eines bestimmten Verfahrens: Die Form eines Aufrufs zu erzwingen und sicherzustellen, dass der Aufruf das Richtige bedeutet, sind verschiedene Probleme — und ein System, das nur in das Erste investiert, erzeugt sehr zuverlässig wohlgeformten Unsinn.
| Prüfung | Was sie sagen kann |
|---|---|
| JSON-Schema | Die Nutzlast hat die richtige Form |
| Aufzählung erlaubter Werte | Die Aktion ist eine, die wir unterstützen |
| Nachschlagen im führenden System | Die Kennung existiert |
| Rückfrage beim Nutzer | Es ist die, die er meinte |
Was wir heute tun
Das Modell erzeugt keine Kennungen. Es erzeugt eine Beschreibung dessen, worauf der Nutzer sich bezog, und ein deterministischer Schritt löst diese Beschreibung gegen das Auftragssystem auf. Liefert die Auflösung nichts oder mehr als einen Treffer, fragt der Assistent, statt zu raten.
Der letzte Fall war häufiger als gedacht. Etwa jede zwölfte Anfrage bezieht sich mehrdeutig auf einen Auftrag, und vorher löste das Modell die Mehrdeutigkeit still und selbstsicher auf. Heute sieht der Nutzer zwei Aufträge und wählt — richtig und schneller als eine später entdeckte Fehländerung.
Warum wir blindes Wiederholen abgeschafft haben
Unser erster Behelf war, die Ablehnung zurückzuspielen und das Modell erneut versuchen zu lassen. Das funktioniert oft genug, um verlockend zu sein, und hat einen bestimmten Fehler: Auf eine Ablehnung hin erzeugt ein Modell eine andere plausible Kennung, statt zu schließen, dass es keine kennt.
Wir wiederholen heute nur, wenn der Fehlschlag Information trägt, mit der das Modell etwas anfangen kann, etwa ein fehlendes Pflichtfeld. Eine Ablehnung mit der Bedeutung kein solcher Datensatz beendet den Versuch und führt zur Auflösung oder zu einem Menschen — es gibt nichts, was sich durch mehr Anstrengung korrigieren ließe.
Das Argument, das kein Schema fängt
Das verbleibende Risiko ist ein Argument, das existiert, wohlgeformt ist und falsch ist. Eine gültige Auftragsnummer, die einem anderen Kunden gehört, besteht Form und Nachschlagen und ist trotzdem der falsche Aufruf, und keine rein lokale Prüfung fängt das.
Dafür nutzen wir Rechte statt Validierung. Die Zugangsdaten, unter denen der Schritt arbeitet, sehen und ändern nur die Datensätze des anfragenden Kunden — eine Kennung außerhalb dieses Bereichs scheitert an der Systemgrenze statt in unserer Logik. Minimale Rechte leisten hier, was Validierung nicht kann.
Was es gekostet hat
Ein zusätzliches Nachschlagen je Vorgang, ein Lesezugriff auf ein System, mit dem wir ohnehin sprechen, und eine zusätzliche Gesprächsrunde in den mehrdeutigen Fällen. Die Latenz stieg um einige Dutzend Millisekunden, und die Quote falscher Ziele auf unserem Referenzset ging auf null.
Der größere Preis war gedanklich. Es verlangte zu akzeptieren, dass nicht das Modell entscheidet, welcher Datensatz gemeint ist — was nach weniger Fähigkeit klingt und in Wahrheit eine Korrektur daran ist, wo diese Fähigkeit von Anfang an hingehörte.
Was wir nicht behaupten
Wir behaupten nicht, die Auflösung beseitige die Klasse. Ein Nutzer kann den falschen Auftrag selbstsicher beschreiben, und unser System löst ihn getreu auf — ein richtiges Ergebnis aus einer falschen Prämisse, das nur eine Rückfrage fängt.
Wir behaupten auch nicht, Schemata seien das falsche Werkzeug. Sie sind notwendig und tun ihre Arbeit. Die Behauptung ist enger: Sie beantworten eine Frage nach der Form, und ein System, das ein bestandenes Schema für einen bestandenen Aufruf hält, hat den Teil nicht geprüft, der scheitert.
