35 min

Den Datensatz destillieren

Die unbequemen Fälle sind die halbe Miete: kein Werkzeug nötig, Pflichtangabe fehlt. Ohne sie ruft der nachtrainierte Spezialist auf alles etwas auf.

Meilenstein Ein Datensatz aus echten Läufen des großen Modells liegt vor, durchs Gatter gefiltert, mit S4- und S5-Fällen darin.

Woher kommen die Trainingsbeispiele? Kapitel 03 hat gezeigt, dass der Spezialist das richtige Werkzeug meistens findet und die Felder falsch füllt. Also braucht er Beispiele dafür, wie diese Felder aussehen. Viele davon, und zwar in der Notation, in der er später antworten soll.

Erfinden ist der falsche Weg. Ein ausgedachter Datensatz enthält die Fälle, an die jemand gedacht hat, und das Modell kann hinterher auch nur die.

Die drei Quellen

Ein Trainingsbeispiel hat drei Bestandteile, und jeder kommt woanders her:

BestandteilQuelle
Die WerkzeuglisteDie elf Schemata aus den Sim-Welten, unverändert
Die AnfrageVorlagen mit gefüllten Platzhaltern, aus anfragen.py
Der AufrufDas große Modell, gefiltert durchs Gatter

Die mittlere Zeile ist ein Zugeständnis, und es gehört ausgesprochen. Echte Nutzeranfragen wären besser, weil sie schief sind. Unvollständig. Halb formuliert, manchmal in der falschen Sprache. Der Kurs hat sie nicht, also erzeugt er sie aus Vorlagen und variiert dabei Formulierung, Kennungen, Firmen und Zeiten. Für die Beschriftung ändert das nichts, denn die kommt so oder so vom großen Modell.

("get_events", ["What is in the calendar {kal}?", "Show the appointments of {kal}.",
 "Read the events of {kal}.", "I want to see {kal}'s schedule.",
 "Pull the entries of calendar {kal}.", "List everything booked in {kal}.",
 "Show the events of {kal} between {t1} and {t2}.", …]),

Ein Viertel der Werkzeugfälle bekommt einen verkleinerten Katalog, also vier Werkzeuge statt elf. Sonst lernt der Spezialist nebenbei, dass immer dieselben elf Deklarationen dastehen, und bricht ein, sobald ein Katalog anders aussieht. In diesem Lauf sind das 42 von 337 Beispielen.

Das Gatter filtert, nicht das Auge

Das große Modell beschriftet, aber es hat nicht das letzte Wort. Jeder Aufruf läuft durch dieselben Prüfungen, die im Betrieb vor der Ausführung stehen:

def durchs_gatter(aufruf):
    """Weißliste, Schema, Pflichtfelder, Enums. Gibt einen Grund zurück oder None."""
    w = NACH_NAME.get(aufruf["name"])
    if not w:
        return f"unbekanntes Werkzeug: {aufruf['name']}"
    schema = w["function"]["parameters"]
    args = aufruf["args"]
    fremd = set(args) - set(schema["properties"])
    if fremd:
        return f"unbekannte Argumente: {sorted(fremd)}"
    fehlend = [f for f in schema.get("required", []) if f not in args]
    if fehlend:
        return f"Pflichtangabe fehlt: {fehlend}"
    for k, v in args.items():
        if k in ENUMS and v not in ENUMS[k]:
            return f"{k}={v} ist kein zulässiger Wert"
        if k.endswith("_id") and len(str(v)) != 36:
            return f"{k} sieht nicht wie eine uuid aus"
    return None

Zehn Beispiele sind daran hängengeblieben, zehn von 371. Das große Modell arbeitet also sauber. Und trotzdem wären diese zehn ohne Gatter im Datensatz gelandet und hätten dem Spezialisten beigebracht, was das große Modell falsch macht. Destillation vererbt Fehler, wenn niemand hinsieht.

Die unbequemen Fälle

Jetzt der Teil, den naive Datensätze auslassen, weil in ihm nichts passiert.

Bei einer Anfrage, die kein Werkzeug braucht, gibt es keinen Aufruf zu lernen. Bei einer Anfrage mit fehlender Pflichtangabe auch nicht. Beide sind trotzdem Trainingsbeispiele, nur mit einem Text als Ziel statt eines Aufrufs:

F: Read that contact for me.
T: I'd be happy to, but I need the contact's ID (the UUID) to read it.
   If you only know the name, tell me the name and I'll find the ID first.

F: Create an event called Jour fixe.
T: I can create the event "Jour fixe", but I'm missing the required start
   and end times.

Die Ziele werden auf zwei Sätze gekürzt. Ein Spezialist soll absagen, nicht essayieren, und ein 270-Millionen-Parameter-Modell, das auf Absätzen trainiert wird, fängt an, Absätze zu schreiben.

Und die Aufnahmebedingung ist streng: Nur Fälle, in denen auch das große Modell stillgehalten hat, kommen hinein. Ruft es auf, wird der Fall verworfen. Sonst stünde im Datensatz ein Aufruf unter einer Anfrage, die keinen erlaubt - also der Fehler, den das Training doch gerade austreiben soll.

Was am Ende dasteht

behalten: 337 von 371
nach Gattung: {'werkzeug': 260, 'doppelt': 36, 'kein_werkzeug': 30, 'pflicht_fehlt': 11}
verworfen: {'gatter': 10, 'pflicht_fehlt:hat_aufgerufen': 8,
            'pflicht_fehlt:ohne_antwort': 10, 'werkzeug:kein_aufruf': 3,
            'doppelt:nur_einer': 3}

Sieh dir die vierte Zeile an. Von den 29 Anfragen mit fehlender Pflichtangabe überleben elf. Acht sind rausgeflogen, weil das große Modell selbst aufgerufen hat. Bei „Delete the contact of Mr Oltmanns“ schickt es ein list_contacts los, um die Kennung zu suchen. Vernünftig geplant, für diese Gattung unbrauchbar. Zehn weitere hatten gar keinen Text, weil das Modell sein Tokenbudget im Nachdenken verbraucht hat.

Damit stellt sich die Gattung, auf die es am meisten ankommt, mit 3,3 % des Datensatzes vor. Wenig. Und das ist keine Nachlässigkeit, sondern der Befund: Die unbequemen Fälle sind nicht nur die, die man vergisst, sie lassen sich auch am schlechtesten ernten, weil das Lehrermodell ausgerechnet dort selbst unentschieden ist.

Ob elf Beispiele reichen, entscheidet die Prüfbank im nächsten Kapitel. Die Vermutung vorweg: eher nicht.

Wie das Beispiel aussieht, das trainiert wird

Kein JSON, keine Chat-Nachricht. Was das Modell zu sehen bekommt, ist das, was der Inferenz-Server ihm später hinlegt, gerendert mit derselben Vorlage:

<bos><start_of_turn>developer
You are the tool layer of Simhaven. …<start_function_declaration>…<end_function_declaration><end_of_turn>
<start_of_turn>user
Read contact efca05dd-9fc4-43a7-a5fe-186bc1eda055.<end_of_turn>
<start_of_turn>model
<start_function_call>call:get_contact{contact_id:<escape>efca05dd-9fc4-43a7-a5fe-186bc1eda055<escape>}<end_function_call><end_of_turn>

Warum das wichtig ist, steht im nächsten Kapitel. Kurz gesagt: Wer den Prompt zum Training anders baut als im Betrieb, trainiert ein Format, das bei dir nie ankommt.