Eine abhängigkeitsfreie Bewertung von LLMs mit einem Richter, dem man wirklich vertrauen kann
Erstellen Sie eine einfache Bewertungsmethode für große Sprachmodelle anhand echter Protokolle, Code-Überprüfungen sowie eines einzigen Bewertungskriteriums, kalibrieren Sie anschließend diesen Bewertungsmechanismus anhand menschlicher Etiketten, damit seine Ergebnisse aussagekräftig sind.
Unit-Tests funktionieren, weil deterministischer Code jedes Mal das gleiche Ergebnis liefert: Man prüft, ob eine Funktion vier zurückgibt – und das tut sie immer. Die Ausgabe von Sprachmodellen ändert bei jedem Aufruf die Formulierungen, sodass es keinen erwarteten String gibt, mit dem verglichen werden könnte. Deshalb wenden Teams oft eine Bewertungsplattform an, die ein anderes Modell zur Auswertung der Ergebnisse verwendet. Genau bei diesem Bewertungsmodell hören die meisten Evaluierungen stillschweigend auf, etwas zu messen – schließlich hat niemand bestätigt, dass es mit menschlichen Beurteilungen übereinstimmt. Dieser Leitfaden erstellt innerhalb weniger Stunden eine vollständige Bewertung mithilfe reinen Python und widmet seinen wichtigsten Abschnitt der Kalibrierung des Bewertungsmodells, damit die ermittelten Werte vertretbar sind.
Die drei Bestandteile jeder Bewertung
Wenn man die Tools weglässt, besteht eine Bewertung aus drei Komponenten, von denen keine eine Bibliothek benötigt:
- Ein Datensatz mit Eingaben, idealerweise aus tatsächlichem Gebrauch stammend und nicht erfunden.
Dashboards, Überwachungsfunktionen sowie gehostete Datensätze sind praktische Erweiterungen, die auf diesen Komponenten basieren. Einige davon sind tatsächlich nützlich, doch der Kern des Systems passt in etwa achtzig Zeilen Python – und solch kurzer Code wird weiterhin funktionieren, lange nachdem eine bestimmte Plattform geändert oder verschwunden ist.
Schritt 1: Sammeln Sie hundert echte Eingaben
Nehmen Sie die Eingaben aus Ihren Produktionsprotokollen. Vermeiden Sie synthetische Beispiele, Fälle, bei denen Sie bereits wissen, dass sie erfolgreich sind, sowie aufbereitete Beispiele. Hundert Fälle reichen aus, um echte Probleme aufzuzeigen, und sind gleichzeitig zahlreich genug, um sie später manuell zu kennzeichnen – was sich als unerlässlich erweist. Fügen Sie absichtlich schwierige und ungewöhnliche Eingaben hinzu: Ein Datensatz mit einfachen Fällen liefert eine konstante Bewertung, selbst wenn sich Ihr System verschlechtert.
Das Laden dieser Daten ist unkompliziert:
import json
with open("requests.jsonl") as f:
cases = [json.loads(line) for line in f][:100]
Beachten Sie, dass das Auswählen der ersten hundert Zeilen alles enthält, was sich zufällig an der Spitze der Datei befindet – dies kann alles aus einem bestimmten Tag oder von einem Kunden stammen. Durch Mischen der Daten vor dem Auswählen oder durch Stichprobenahme über verschiedene Zeitperioden erhält man eine repräsentativere Sammlung.
Falls Sie noch keine Protokolle haben, erstellen Sie die hundert Fälle selbst – rechnen Sie jedoch damit, dass die Ergebnisse zunächst besser aussehen als in Wirklichkeit, bis echter Traffic sie ersetzt.
Schritt 2: Trennen von Code-Überprüfungen und Urteilsentscheidungen
Das ist der Schritt, den Teams am häufigsten überspringen – und er prägt alles, was danach kommt. Viele Eigenschaften können deterministisch überprüft werden, und diese sollten niemals an ein Modell gesendet werden:
- Die Ausgabe ist gültiges JSON.
- Eine Kategorie gehört zu einer bekannten Menge.
- Eine Zahl liegt im zulässigen Bereich.
- Notwendige Felder sind vorhanden.
- Die Antwort bleibt unter der Längengrenze.
Jede dieser Punkte stellt eine Aussage dar. Die folgende Funktion (in Python, unabhängig von der möglichen Beschriftung) führt einige davon aus und gibt ein Dictionary mit benannten Ergebnissen zurück:
def code_checks(output):
checks = {}
try:
parsed = json.loads(output)
checks["valid_json"] = True
checks["has_fields"] = all(k in parsed for k in ("answer", "confidence"))
except json.JSONDecodeError:
checks["valid_json"] = False
checks["has_fields"] = False
checks["under_limit"] = len(output) < 2000
return checks
Durch die Rückgabe benannter Überprüfungen anstelle eines einzigen Booleschen Werts kann man erkennen, welche Eigenschaft fehlschlug, wenn etwas schiefging. Was nach den deterministischen Überprüfungen übrig bleibt, ist der Teil, der Urteilsvermögen erfordert: Beantwortet die Antwort tatsächlich die eigentliche Frage, führt sie Fakten ein, die im Ausgangstext nicht vorhanden sind, oder weigert sie sich, obwohl sie es tun sollte? Für diese Eigenschaften braucht man einen Urteiler, und ein Urteiler benötigt Validierung.
Schritt 3: Schreiben Sie einen Urteiler, der eine Sache bewertet
Geben Sie jeder Urteilveranlassung genau ein Kriterium. Eine Bewertungsmatrix, die gleichzeitig fünf Eigenschaften abfragt, führt zu einem gemischten Urteil, und wenn dieses fehlschlägt, lässt sich nicht erkennen, welche Eigenschaft gefehlt hat. Der untenstehende Urteiler überprüft eine einzige Eigenschaft, unbegründete Behauptungen und verlangt ein festes Antwortformat:
JUDGE = """You are grading one property of a response.
PROPERTY: Does the response contain any claim that is not supported by the
source text provided?
SOURCE:
{source}
RESPONSE:
{response}
Answer with exactly one word, PASS or FAIL, then a new line, then one
sentence explaining your verdict. Do not explain anything else."""
def judge(source, response, call_model):
out = call_model(JUDGE.format(source=source, response=response))
verdict = out.strip().split("\n")[0].strip().upper()
return verdict == "PASS", out
Die Formatvorgabe ist genauso wichtig wie das Kriterium selbst. Die Anforderung, dass in der ersten Zeile nur ein Wort – PASS oder FAIL – steht, macht die Auswertung einfach. Freiformulierte Urteile weisen von Aufruf zu Aufruf unterschiedliche Strukturen auf, und wenn ein Parsing-Fehler als Erfolg gewertet wird, werden alle anschließend gemeldeten Ergebnisse unbemerkt überhöht. Diese Implementierung geht auf Nummer sicher: Alles andere als der exakte Wert PASS, einschließlich PASS. oder eines in Formatierungen eingebetteten Urteils, gilt als Misserfolg. Es lohnt sich, zu protokollieren, wie oft das vorkommt, denn ein Anstieg an unverarbeitbaren Antworten ist an sich bereits ein Signal.
Schritt 4: Alles ausführen und die Rohausgabe aufbewahren
Speichern Sie die vollständige Ausgabe sowie die Erklärung des Bewerters für jeden Fall – nicht nur das Urteil. Wenn sich eine Punktzahl ändert, möchten Sie wissen, was genau geändert hat, und ein gespeichertes Boolesches Wert sagt Ihnen das nicht mit.
results = []
for case in cases:
output = call_model(case["prompt"])
passed, reasoning = judge(case["source"], output, call_model)
results.append({
"id": case["id"],
"output": output,
"code_checks": code_checks(output),
"judge_pass": passed,
"judge_reasoning": reasoning,
})
rate = sum(r["judge_pass"] for r in results) / len(results)
print(f"{rate:.1%} pass on {len(results)} cases")
Die Schleife protokolliert die deterministischen Überprüfungen zusammen mit dem Ergebnis des Urteilsverdieners, obwohl die Gesamtrate nur den Urteilsverdiener berücksichtigt. In der Praxis sollten beide Werte angegeben werden, da eine Antwort, die die JSON-Validierung nicht bestanden hat, unabhängig von der Meinung des Urteilsverdieners als fehlerhaft gilt. Beachten Sie außerdem, dass hier dieselbe call_model-Funktion zur Erstellung und Bewertung verwendet wird; es ist üblich, für den Urteilsverdiener ein anderes oder leistungsstärkeres Modell zu nutzen, doch egal welches Sie wählen – der nächste Schritt ist entscheidend dafür, dass das System vertrauenswürdig wird.
Zurzeit haben Sie einen Prozentsatz – dieser bedeutet aber noch nichts.
Schritt 5: Kalibrierung des Urteilsverdieners anhand eigener Etiketten
Das ist der Schritt, den die meisten Anleitungen weglassen, und er dauert etwa dreißig Minuten. Wählen Sie fünfzig der hundert Fälle aus und versehen Sie jeden davon selbst mit dem Etikett PASS oder FAIL, ohne zunächst auf das Urteil des Urteilsverdieners zu schauen. Vergleichen Sie anschließend die beiden Etikettensätze:
agree = sum(1 for r, human in zip(results[:50], human_labels)
if r["judge_pass"] == human)
print(f"judge agrees with me on {agree}/50 = {agree/50:.0%}")
both_fail = sum(1 for r, h in zip(results[:50], human_labels)
if not r["judge_pass"] and not h)
judge_fails = sum(1 for r in results[:50] if not r["judge_pass"])
human_fails = sum(1 for h in human_labels if not h)
print(f"judge caught {both_fail}/{human_fails} of the failures I found")
print(f"judge flagged {judge_fails - both_fail} things I considered fine")
Die Skript gibt drei Werte an: die Gesamtabstimmung, wie viele Ihrer Fehler auch vom Richter erkannt wurden, sowie wie viele Fälle der Richter falsch beurteilte, die Sie für akzeptabel hielten. Der Code geht davon aus, dass human_labels eine Liste von Booleschen Werten im selben Verhältnis wie die ersten fünfzig Ergebnisse ist, und er führt zu einem Division durch Null, wenn Sie überhaupt keine Fehler gefunden haben – was bereits darauf hindeutet, dass Ihr Datensatz zu einfach ist.
Warum die reine Abstimmung irreführt
Die Gesamtabstimmung ist der weniger aussagekräftige Wert, obwohl sie am häufigsten zitiert wird. Wenn neunzig Prozent Ihrer Fälle bestehen, erreicht ein Richter, der bei allem „PASS“ antwortet, eine Gesamtabstimmung von neunzig Prozent, obwohl er eigentlich nichts erkennt hat.
Der wichtige Wert: erkannte Fehler
Was Ihre Aufmerksamkeit verdient, ist der Anteil an Ihren eigenen FAIL-Labeln, die auch vom Urteilsverfasser markiert wurden. In Klassifizierungsbegriffen handelt es sich dabei um die Trefferquote des Urteilsverfassers bezüglich der Fehlerklasse. Ein Urteilsverfasser, der zwei von Ihren elf Fehlern erkennt, bewertet eigentlich nichts; er genehmigt alles lediglich mit einer überzeugenden Begründung. Die dritte Größe, die Falschalarme, ist ebenfalls wichtig, denn ein Urteilsverfasser, der gute Antworten markiert, zwingt Sie dazu, Dinge „zu reparieren“, die nie defekt waren.
Wenn Sie und der Urteilsverfasser sich nicht einigen
Lesen Sie jeden Fall, in dem sich Ihr Label vom des Urteilsverfassers unterscheidet. Es gibt nur drei Erklärungen, und jede hat ihre eigene Lösung.
Die Bewertungskriterien sind unklar
Der Urteilsverfasser irrt, weil die Eigenschaftsbeschreibung Interpretationsspielraum lässt. Präzisieren Sie sie. Ein guter Test ist, ob Sie die Eigenschaft in einem Satz ausdrücken können, den ein neuer Kollege genauso anwenden würde wie Sie.
Ihre eigenen Etiketten sind falsch
Dies tritt häufiger auf, als man erwarten würde. Die menschliche Klassifizierung weicht in etwa fünfzig Fällen ab, insbesondere bei grenzwertigen Beispielen gegen Ende einer Sitzung. Etikettieren Sie die umstrittenen Fälle mit neuem Blick, bevor Sie den Urteilsfäller beschuldigen.
Die Eigenschaft ist von Natur aus subjektiv
Manche Eigenschaften können nicht einheitlich von irgendjemandem beurteilt werden. Wenn das der Fall ist, wird kein Urteilsfäller zuverlässig sein. Teilen Sie die Eigenschaft in kleinere, überprüfbare Untereigenschaften auf oder akzeptieren Sie, dass sie nicht bewertet werden kann.
Iterieren Sie: Passen Sie die Bewertungskriterien an, benennen Sie ggf. neu und führen Sie den Vorgang erneut durch, bis der Bewertende genügend Fehler feststellt, die es rechtfertigen, die Zahl in einem Treffen zu verteidigen. Anschließend frieren Sie die Bewertungskriterien ein und speichern deren Version zusammen mit jedem zukünftigen Ergebnis. Mit unterschiedlichen Bewertungskriterien bewertete Durchläufe können nicht miteinander verglichen werden. Wie man einen Bewertenden langfristig gesund hält, wenn er kontinuierlich in der Produktion eingesetzt wird, erfahren Sie unter „Managing LLM as a Judge as a Living Production System“.
Was die kalibrierte Bewertung Ihnen bietet
Das Ergebnis ist eine Zahl, die Sie neben einer Änderung eintragen und der Sie vertrauen können. Bevor Sie einen Prompt ändern, ein Modell austauschen oder einen Abrufschritt verändern, nehmen Sie eine Messung vor; danach wieder eine. Der Unterschied enthält Informationen nur deshalb, weil Sie zuerst bestätigt haben, dass das Messinstrument mit einer Person übereinstimmt.
Weil der Code nur von der Funktion abhängt, die Ihr Modell aufruft, funktioniert er weiterhin einwandfrei, wenn Sie den Anbieter wechseln oder sich das Tool-Ökosystem verändert – was mehr ist, als man von den meisten empfohlenen Methoden für diese Aufgabe sagen kann.
Beschränkungen einer Bewertung mit hundert Fällen
Drei Einschränkungen sollten Sie vor dem Einsatz dieses Ansatzes verstehen.
Kleine Regressionen sind unsichtbar
Ein Rückgang von 91 auf 89 Prozent entspricht zwei Fällen aus hundert, was bei dieser Stichprobengröße nicht von Rauschen zu unterscheiden ist. Um kleine Effekte zu erkennen, benötigen Sie entweder viel mehr Daten oder einen gepaarten Vergleich: Führen Sie beide Versionen mit denselben Eingaben durch und zählen Sie nur die Fälle, bei denen das Ergebnis sich änderte. Gepaarte Vergleiche beseitigen den größten Teil der Variationen, die durch die Schwierigkeit der Fälle entstehen.
Manuelles Beschriften ist nicht skalierbar
Manuelle Beschriftungen werden ab einigen hundert Zeilen unpraktisch, und die Qualität nimmt im Laufe einer Sitzung ab. Ihre Beurteilung im Fall vierundvierzig unterscheidet sich von der im Fall zwei, was eigentliche Fehler in der Kalibrierung verursacht. Die Beschriftung in mehreren kurzen Sitzungen anstelle einer langen verringert diese Abweichung.
Kalibrierung verfällt
Ein Richter, der anhand der heutigen Ergebnisse validiert wurde, gilt möglicherweise nicht für morgen. Wenn Sie das Modell hinter Ihrer Funktion ändern, ändern sich auch seine Fehlermuster, weshalb der Richter erneut validiert statt wiederverwendet werden muss. Es handelt sich dabei um mühsame Arbeit – und genau das unterscheidet eine Messung von einem Ritual.
Zwei Ergänzungen nach dem Ausführen
- Versionieren Sie alles. Speichern Sie die Version des Modells sowie die Version der Bewertungskriterien zusammen mit jedem Ergebnis. Eine Bewertung ohne eine dieser Informationen kann aus demselben Grund nicht mit einer anderen verglichen werden – genauso sagt eine Vergleichsgröße ohne ihre dazugehörigen Parameter nur wenig aus.
- Bewahren Sie die Streitfälle auf. Die Fälle, in denen Sie und der Bewertungsexperte unterschiedlicher Meinung waren, sind die aussagekräftigsten Zeilen in der gesamten Übung. Sie erneut nach jeder Änderung der Bewertungskriterien auszuführen, ist der schnellste Weg, herauszufinden, ob die Änderung hilfreich war.
Die hier gezeigten Beispiele legen den Schwerpunkt auf Klarheit statt auf maximale Robustheit in der Umsetzung. Betrachten Sie sie als Vorlage, die Sie lesen und anpassen sollten, indem Sie nach Bedarf Wiederholungsversuche, Fehlerbehandlung und Persistenzfunktionen hinzufügen.
Kernpunkte
- Eine Bewertung umfasst ein Datensatz, einen Generierer und einen Scorer; alles Weitere sind optionale Hilfsmittel.