Die Messlatte
Eine Prüfbank ist kein Benchmark-Aufbau, sondern zweiundvierzig feste Erwartungswerte und eine Schleife.
Meilenstein S1 bis S5 laufen strukturell bewertet durch, und das große Modell steht mit 95,2 % gelungener Aufträge als Messlatte fest.
Wie viel Aufbau braucht eine Prüfbank? Kapitel Zusammenspiel sagt: keinen. Feste Erwartungswerte und eine Schleife, mehr nicht. Beides steht in diesem Kapitel, und du kannst es abtippen.
Die fünf Stufen, mit Fällen gefüllt
| Stufe | Was sie prüft | Fälle |
|---|---|---|
| S1 | Format und Grundverdrahtung, ein Werkzeug zur Wahl | 8 |
| S2 | Auswahl aus allen elf Werkzeugen | 12 |
| S3 | Zwei unabhängige Aufrufe zugleich | 6 |
| S4 | Anfragen, die kein Werkzeug brauchen | 8 |
| S5 | Pflichtangabe fehlt in der Anfrage | 8 |
Zweiundvierzig Fälle. Wenig für einen Benchmark. Genug für eine Prüfbank, weil du jeden einzelnen von Hand gesetzt hast und ihn im Zweifel nachrechnen kannst, ohne raten zu müssen, was er eigentlich prüfen sollte.
Ein Fall ist eine Zeile JSON. nur schränkt den Katalog ein, was ausschließlich
S1 tut; alle anderen Stufen sehen alle elf:
{"id":"S2-7","stufe":"S2",
"frage":"Set the status of the contact 11d3e7b0-4c52-4a1e-9b8f-0d6a3f2c5e10 to kunde.",
"erwartet":[{"name":"update_contact",
"args":{"contact_id":"11d3e7b0-4c52-4a1e-9b8f-0d6a3f2c5e10","status":"kunde"}}]}
Und die unbequemen Stufen erwarten schlicht nichts:
{"id":"S5-2","stufe":"S5","frage":"Delete the contact of Mr Rutkowski.","erwartet":[]}
{"id":"S4-2","stufe":"S4","frage":"What does CRM stand for?","erwartet":[]}
Warum zwei Stufen, wenn die Erwartung dieselbe ist? Weil sie Verschiedenes verlangen. S4 fragt etwas, wofür es kein Werkzeug gibt. S5 fragt etwas, wofür es eines gibt, nennt aber die Pflichtangabe nicht - dort muss das Modell sein eigenes Nichtwissen bemerken, und das ist erfahrungsgemäß deutlich schwerer, als einen Katalog zu überblicken.
Bewertet wird strukturell, nie als Text
Der häufigste Fehler beim Bau einer Prüfbank? Der Textvergleich. Ein Aufruf ist kein String. Er ist ein Name plus ein Wörterbuch, und zwei Argumente in anderer Reihenfolge sind derselbe Aufruf.
def passt(ist, soll):
if ist["name"] != soll["name"] or ist["args"] is None:
return False
# Pflicht: jedes erwartete Argument steht mit dem erwarteten Wert da.
for k, v in soll["args"].items():
if str(ist["args"].get(k, "")).strip() != str(v):
return False
# Kein zusätzliches, nicht erwartetes Argument (erfundene Filter zählen als falsch).
return set(ist["args"]) == set(soll["args"])
Die zweite Prüfung ist strenger, als sie aussieht. Absicht. Ein Modell, das auf
„zeig mir alle Kontakte“ ein list_contacts mit erfundenem Firmenfilter
schickt, hat nicht fast richtig geantwortet - es hat die Trefferliste
stillschweigend beschnitten, und ein stillschweigend beschnittenes Ergebnis ist
im Betrieb schlimmer als eine Fehlermeldung, weil niemand es bemerkt.
Bei mehreren erwarteten Aufrufen darf ein Ist-Aufruf nicht zwei Soll-Schritte decken:
def bewerte(ist_liste, soll_liste):
offen = list(ist_liste)
treffer = 0
for soll in soll_liste:
for i, ist in enumerate(offen):
if passt(ist, soll):
treffer += 1
offen.pop(i)
break
return treffer, len(offen)
Die vier Kennzahlen
Welche Zahlen sagen dir etwas? Die vier aus dem Kapitel, plus eine fünfte, die aus S4 und S5 fällt:
k = {
"formkorrekt": ..., # Anteil der Ausgaben, aus denen sich ein Aufruf lesen lässt
"richtig_je_schritt": ..., # Werkzeug UND Argumente getroffen, über alle Schritte
"auftraege_gelungen": ..., # alle Schritte eines Falls richtig, nichts überzählig
"schritte_je_auftrag": ..., # gemittelte Zahl abgesetzter Aufrufe
"stillgehalten": ..., # Anteil der S4/S5-Fälle ohne jeden Aufruf
}
Die dritte ist die härteste und die einzige, die am Ende zählt. Gerechnet wird sie als alle Schritte gelungen, nie als drei von vier. Ein Agent, der bei drei von vier Schritten richtig liegt, hat den Auftrag nicht erledigt.
stillgehalten steht daneben, weil du sonst Über-Aufrufen nicht siehst. Ein
Modell, das auf jede Anfrage etwas aufruft, sieht in S1 bis S3 hervorragend aus.
Die erste Messung
python3 messen.py --url http://localhost:8009/v1/chat/completions \
--modell qwen3.8-27b --temp 0.0 --n 1 --tag gross
Ergebnis für qwen3.8-27b, ein 27-Milliarden-Parameter-Modell auf demselben
Rechner:
| Kennzahl | Wert |
|---|---|
| Formkorrekte Aufrufe | 100,0 % |
| Richtige Aufrufe je Schritt | 96,9 % |
| Aufträge gelungen | 95,2 % |
| Schritte je Auftrag | 0,81 |
| Stillgehalten (S4 + S5) | 93,8 % |
| Median je Anfrage | 6,42 s |
Nach Stufen: S1 100 %, S2 91,7 %, S3 100 %, S4 100 %, S5 87,5 %.
Zwei Fälle gingen schief, und beide sind lehrreich. Bei S2-9 sollte der Raum
besprechung gebucht werden, das Modell schickte room: "raum" - den
Kalenderschlüssel aus dem Auftakt statt den Namen aus der Anfrage. Bei S5-8
(„Put the appointment into the calendar tomorrow morning“) rief es
list_calendars und get_events auf, statt nachzufragen. Es fing an zu planen,
wo eine Rückfrage richtig gewesen wäre.
Das ist die Messlatte. Neunzig Prozent aufwärts, und teuer.
Warum diese Zahl vor dem Feintuning stehen muss
Sie ist der einzige Grund, warum die nächsten drei Kapitel etwas bedeuten. Ein nachtrainiertes Modell mit 88 % ist ein Erfolg, wenn der Ausgangswert bei 74 lag, und ein Rückschritt, wenn er bei 95 lag. Ohne die Zahl bleibt alles Weitere Gefühl.