Der Agentenkurs · Evals
Evals in der Praxis
Lernziele
- Du verwandelst echte Fehler deines Agenten in Fälle mit prüfbaren Verhaltenschecks.
- Du lässt einen Runner ohne Modellaufrufe über gespeicherte Traces laufen und liest sein Ergebnis pro Check.
- Du kalibrierst einen engen Judge an zehn eigenen Labels und planst eine wöchentliche Nachbewertung.
Diese Lektion ist der kleinste sinnvolle Aufbau: ein Nachmittag, fünf Schritte, eine Datei mit Fällen und ein Runner, keine Infrastruktur. Das Handbuch Eval Engineering baut daraus in drei Schritten die vollständige Pipeline. Alles, was du hier anlegst, übernimmst du direkt dorthin.
Schritt eins: zwanzig Fehler sammeln
Hol dir die jüngsten Läufe deines AgentEin System, in dem ein Sprachmodell seinen nächsten Schritt selbst wählt: Es ruft Werkzeuge auf, wertet das Ergebnis aus und macht weiter, bis das Ziel erreicht ist.Im Glossar und lies, bis du zwanzig echte Fehler hast. Ausgedachte Fehler zählen nicht. Schreib für jeden eine Zeile: Was war die Eingabe, und welches eine Verhalten hätte passieren müssen und ist ausgeblieben? „Hat geantwortet, ohne im Vault zu suchen.“ „Hat erstattet, ohne die Freigabe einzuholen.“ „Hat gemeldet, die Notiz sei angelegt, sie existiert aber nicht.“ Zwanzig Fehler bündeln sich nach unserer Einschätzung meist zu vier bis acht Verhaltensweisen.
Schritt zwei: ein Verhaltenscheck pro Fall
Jeder Fall wird ein Eintrag in YAML: die Eingabe, das erwartete Verhalten in Worten und Assertions über den TraceDie vollständige Aufzeichnung eines Agentenlaufs: Modellrunden, Tool-Aufrufe mit ihren Argumenten, Tool-Ergebnisse und Wiederholungen. Verhaltenschecks lesen den Trace.Im Glossar, die eine Maschine prüfen kann.
- id: refund_1042
input: "Refund order #1042, customer says it arrived broken"
expect: looks up the order before replying; asks approval before refund
check:
- trace has get_order before send_reply
- trace has approval_request before refund
Speicher alle zwanzig Fälle als cases.yaml. Die Zeile expect ist für Menschen. Die Zeilen unter check sind der eigentliche Test, jede davon ein Verhaltenscheck · engl. behavioural checkEine enge Ja-Nein-Prüfung, ob auf dem Weg zum Ergebnis ein bestimmter Schritt passiert ist, etwa ob der Agent die Bestellung vor der Antwort nachgeschlagen hat. Er läuft als Code über den Trace.Im Glossar.
Schritt drei: die Checks auf Traces laufen lassen
Speicher den Trace jedes Laufs als traces/<id>.json, eine Liste von Ereignissen mit allen Tool-Aufrufen:
[
{"type": "tool_call", "name": "get_order", "args": {"order_id": "1042"}},
{"type": "tool_result", "name": "get_order", "ok": true},
{"type": "tool_call", "name": "approval_request", "args": {"action": "refund"}},
{"type": "tool_call", "name": "refund", "args": {"order_id": "1042"}},
{"type": "tool_call", "name": "send_reply", "args": {"channel": "email"}}
]
Speicher diesen Runner als check_traces.py. Er braucht das Paket PyYAML (pip install pyyaml):
import json
import re
import sys
from pathlib import Path
import yaml
def tool_calls(trace: list) -> list:
return [e["name"] for e in trace if e.get("type") == "tool_call"]
def check_rule(rule: str, calls: list) -> tuple[bool, str]:
m = re.fullmatch(r"trace has (\w+) before (\w+)", rule.strip())
if m:
first, second = m.group(1), m.group(2)
if first not in calls:
return False, f"{first} never called"
if second not in calls:
return False, f"{second} never called"
if calls.index(first) < calls.index(second):
return True, "ok"
return False, f"{second} came before {first}"
m = re.fullmatch(r"trace has (\w+)", rule.strip())
if m:
name = m.group(1)
return name in calls, "ok" if name in calls else f"{name} never called"
m = re.fullmatch(r"trace lacks (\w+)", rule.strip())
if m:
name = m.group(1)
return name not in calls, "ok" if name not in calls else f"{name} was called"
return False, f"unparseable rule: {rule!r}"
def main() -> None:
cases = yaml.safe_load(Path(sys.argv[1]).read_text(encoding="utf-8"))
trace_dir = Path(sys.argv[2])
failures = 0
for case in cases:
trace_file = trace_dir / f"{case['id']}.json"
trace = json.loads(trace_file.read_text(encoding="utf-8"))
calls = tool_calls(trace)
for rule in case["check"]:
passed, reason = check_rule(rule, calls)
print(f"{'PASS' if passed else 'FAIL'} {case['id']} {rule} ({reason})")
failures += not passed
print(f"\n{failures} failing check(s)")
sys.exit(1 if failures else 0)
if __name__ == "__main__":
main()
Der Runner versteht drei Formen von Regeln: trace has A before B, trace has A und trace lacks A. Bei der Reihenfolge vergleicht er jeweils den ersten Aufruf der beiden Tools. Eine Regel, die er nicht versteht, zählt als Fehler. So fällt ein Tippfehler in cases.yaml sofort auf.
Starte ihn mit python check_traces.py cases.yaml traces/. Er ruft kein Modell auf, bleibt deshalb weit unter dem Budget von fünf Sekunden und endet bei einem Fehler mit einem Code ungleich null, sodass deine CI darauf reagiert. Wir haben den Runner mit Python 3 und PyYAML 6 auf dem Beispiel laufen lassen. Er brauchte 0,03 Sekunden. Danach haben wir den Eintrag get_order aus dem Trace gelöscht und den Runner erneut gestartet. Der Lauf sah so aus:
- $python check_traces.py cases.yaml traces/
Berichte das Ergebnis pro Check, genau so, wie der Runner es ausgibt. Eine einzelne Erfolgsquote würde einen gebrochenen Check verdecken.
Schritt vier: einen engen Judge kalibrieren
Manche Verhaltensweisen sieht Code nicht, etwa ob die Antwort auf der gefundenen Notiz beruht. Dafür schreibst du einen Judge · engl. LLM as a judgeEin Sprachmodell, das die Ausgabe eines anderen Modells nach einer festen Frage bewertet, etwa ob eine Antwort auf der gefundenen Notiz beruht. Ein Judge ist ein Messgerät und muss gegen eigene Labels geprüft werden.Im Glossar mit einer einzigen Frage und einem Ja-Nein-Urteil. Bevor du ihm traust, bewertest du zehn Ausgaben selbst und misst die Übereinstimmung. Das Handbuch Eval Engineering enthält dafür ein Skript mit rund dreißig Zeilen und beschreibt die Verzerrungen, auf die du achten musst.
Stimmt der Judge in weniger als acht von zehn Fällen mit dir überein, überarbeitest du die Rubrik. Den Schwellenwert lässt du, wo er ist. Achte dabei auf beide Klassen, wie in der Lektion Judges und Golden Sets: Unter zehn Labels sind oft nur ein oder zwei schlechte Ausgaben.
Schritt fünf: wöchentlich von Hand bewerten
Zieh jede Woche fünf zufällige echte Läufe und bewerte sie von Hand nach deinen eigenen Erwartungen. Weicht dein Urteil von der Suite ab, wird daraus ein neuer Fall. Ein Fehler, den die Suite nie gesehen hat, wird ein neuer Check. Fünfzehn Minuten pro Woche halten das Golden SetDie feste Sammlung von Testfällen, gegen die alle Evals laufen. Sie enthält gute und schlechte Beispiele und wächst mit jedem Fehler aus dem Betrieb.Im Glossar davon ab, zu altern.
Tipps
- Code vor Judge. Wo eine Assertion
trace hasund ein Judge beide funktionieren würden, nimm die Assertion. - Stabile Kennungen. Halte die
idjedes Falls stabil und mit grep auffindbar. In sechs Monaten suchst du danach. - Wackelnde Checks sind Befunde. Wackelt ein Check, verhält sich der Agent an dieser Stelle wirklich nicht deterministisch. Das ist ein Befund über den Agenten, und der Test ist in Ordnung.
- Ein glatter Fall pro Verhalten. Leg für jedes Verhalten auch einen Fall an, der glatt durchläuft. So merkst du, wenn eine Korrektur übers Ziel hinausschießt.
Probier es selbst aus
Drei Experimente zeigen dir, dass deine Suite misst, was sie messen soll. Arbeite sie mit deinem eigenen Agenten ab.
Selbst nachweisen
0 von 3 erledigt
Weiter geht es mit dem nächsten Modul, Produktion. Wer tiefer einsteigen will, setzt im Handbuch Eval Engineering mit der cases.yaml aus dieser Lektion an: Traces auswerten, die Suite mit kalibriertem Judge bauen und ein Gate in der CI einrichten. Nichts von dem, was du hier gebaut hast, wird weggeworfen.
Merksätze
- Du startest mit zwanzig echten Fehlern aus den Traces und beschreibst für jeden das eine fehlende Verhalten.
- Jeder Fall in
cases.yamlträgt prüfbare Assertions über den Trace, die Zeileexpectist nur für Menschen. - Der Runner liest Traces ohne Modellaufruf, läuft in Sekunden und berichtet pro Check.
- Einen Judge setzt du nur für das ein, was Code nicht sieht, und kalibrierst ihn vorher an eigenen Labels.
- Fünfzehn Minuten Handbewertung pro Woche liefern neue Fälle und halten das Golden Set aktuell.
Prüf dich selbst
Denkfrage
Ein Kollege schlägt vor, die zwanzig Fälle aus Schritt eins am Whiteboard auszudenken, das gehe schneller. Was entgegnest du?
Ausgedachte Fehler testen, was du vermutest. Echte Fehler aus den Traces zeigen, wo der Agent wirklich scheitert, und bündeln sich meist zu wenigen Verhaltensweisen. Genau diese Verhaltensweisen soll die Suite festhalten.
Denkfrage
Dein Judge stimmt in sieben von zehn Fällen mit dir überein. Ein Teammitglied will den Schwellenwert des Judges senken. Was tust du stattdessen?
Du liest die drei Abweichungen und überarbeitest die Rubrik, bis die Frage eindeutig ist. Ein anderer Schwellenwert versteckt nur, dass der Judge etwas anderes misst als du. Danach misst du erneut, getrennt nach guten und schlechten Ausgaben.
Prüf dich selbst
Quellen
- PyYAML
yaml.safe_load liest cases.yaml.