Handbücher · Eval Engineering
Build: Das Gate
Lernziele
- Du hängst
eval_suite.pymit einem Workflow für GitHub Actions an jeden Pull Request und an einen nächtlichen Lauf. - Du wählst einen Schwellenwert aus drei eigenen Läufen, der Rauschen von echten Rückschritten trennt.
- Du führst ein Scoreboard, das die Quote jeder Nacht als Zeile im Repository festhält.
Eine Suite, die nur läuft, wenn jemand daran denkt, läuft bald gar nicht mehr. Diese Lektion hängt eval_suite.py aus Build: Die Suite in GitHub Actions. Eine Teilmenge prüft jeden Pull Request, die volle Suite läuft jede Nacht, und die Quote landet in einem Scoreboard, das im Repository liegt. Die Grundsätze dahinter stehen im Abschnitt zur CI in Agenten-Evals.
Der Workflow
Speichere die Datei als .github/workflows/evals.yml. Leg vorher ANTHROPIC_API_KEY als Secret des Repositorys an.
name: evals
on:
pull_request:
schedule:
- cron: "30 2 * * *"
concurrency:
group: evals-${{ github.ref }}
cancel-in-progress: true
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
jobs:
pr-gate:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- run: pip install anthropic==2.8.0
- name: Run the smoke subset
run: python eval_suite.py golden.jsonl --limit 15 --threshold 0.9
nightly:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- run: pip install anthropic==2.8.0
- name: Run the full suite
run: python eval_suite.py golden.jsonl --threshold 0.9
- name: Append to the scoreboard
if: always()
run: |
rate=$(python -c "import json; print(f\"{json.load(open('results.json'))['pass_rate']:.0%}\")")
echo "| $(date -u +%Y-%m-%d) | ${rate} | ${GITHUB_SHA::7} |" >> scoreboard.md
git config user.name "eval-bot"
git config user.email "actions@users.noreply.github.com"
git add scoreboard.md
git commit -m "scoreboard: nightly eval run"
git pushZeilen 3-6
Jeder Pull Request und ein Zeitplan um 2:30 Uhr UTC. GitHub verzögert geplante Läufe zur vollen Stunde am stärksten, deshalb steht die Minute auf 30.
Drei Regeln von GitHub betreffen diesen Workflow direkt. Geplante Läufe starten nur auf dem Standard-Branch. In öffentlichen Repositorys schaltet GitHub sie ab, wenn 60 Tage lang nichts passiert ist. Und Pull Requests aus Forks bekommen keine Secrets. Dort fehlt also der API-Schlüssel, und das Gate scheitert beim ersten Aufruf des Modells.
Wir haben den Workflow mit actionlint 1.7.12 geprüft, ohne Befund. Den Schritt für das Scoreboard haben wir in einem lokalen Test-Repository nachgestellt: Er hängte die Zeile an, committete und pushte. Das Gate selbst haben wir lokal mit beiden Fassungen des Prompts aufgerufen:
- Dateiapp.pyFassung ohne die drei Sätze aus der letzten Lektion
Hast du aus der Kurslektion Evals in der Praxis auch check_traces.py, hängst du ihn als weiteren Schritt in das Gate. Er ruft kein Modell auf und kostet nur Sekunden.
Den Schwellenwert wählen
Setz den Schwellenwert unter deine aktuelle Quote. Fälle mit Judge schwanken. Selbst unsere Code-Fälle schwankten, weil das Produkt nicht jedes Mal gleich antwortet: Derselbe alte Prompt erreichte auf der Teilmenge einmal 53 und einmal 47 Prozent. Eine Suite bei 90 Prozent zeigt ohne jede Änderung auch mal 87. Ein Gate bei genau 90 macht aus diesem Rauschen rote Builds, denen niemand mehr traut.
Lass die volle Suite dreimal laufen, nimm die schlechteste Zahl und setz das Gate ein paar Punkte darunter. Wie viele Punkte das sind, hängt von der Zahl der Fälle ab. Bei 21 Fällen ist ein einzelner Fall schon fast 5 Punkte wert:
Wie viele Fehlschläge lässt der Schwellenwert zu?
- Erlaubte Fehlschläge
- 1
- Ein Fall entspricht
- 6,7 Prozentpunkten
Beispielwerte. Unsere Teilmenge hat 15 Fälle: Bei 90 % darf genau ein Fall scheitern. Stell den Schwellenwert auf 94 und sieh, wie das Gate jede Abweichung rot macht.
Unsere drei Läufe nach der Korrektur lagen alle bei 100 Prozent. Mit 0,9 lässt das Gate auf der Teilmenge einen Ausreißer durch und schlägt beim zweiten an. Heb die Latte erst, wenn eine echte Verbesserung eine Woche lang in den nächtlichen Läufen hält.
Schreib die Modell-IDs fest in den Code. Ein Alias, der sich unter dir verschiebt, ist eine Änderung. Sie soll als Pull Request kommen und das Gate passieren wie jede andere. Darum stehen in app.py und eval_suite.py vollständige IDs wie claude-opus-5-5.
Kosten im Griff
Der Job für Pull Requests nimmt die ersten 15 Fälle. Halte dort die billigsten und aussagekräftigsten Fälle: Code-Fälle aus deinen größten Fehlerarten. Die Reihenfolge in golden.jsonl kostet nichts, Aufrufe des Judges kosten Geld und Zeit. Die volle Suite mit allen Judge-Fällen läuft einmal pro Nacht, egal wie viel im Repository los ist. cancel-in-progress verhindert, dass Force-Pushes doppelte Läufe stapeln.
In unseren Läufen kostete die volle Suite mit 21 Fällen zwischen 9 und 13 Cent, nach Listenpreis (Stand: Nov. 2026). Der größte Teil entfiel auf die Ausgabe-Tokens des Produkts. Ein Monat nächtlicher Läufe liegt damit bei rund drei bis vier US-Dollar, dazu einige Cent pro Pull Request. Werden die nächtlichen Kosten spürbar, ist die Suite über die Version für einen Nachmittag hinausgewachsen. Welche Fälle ihren Platz verdienen, zeigt der Abschnitt zu Stichprobengrößen in Evals entwerfen.
Das Scoreboard
Leg scoreboard.md einmal von Hand an:
# Eval scoreboard
| date | pass rate | commit |
|---|---|---|
Der nächtliche Job hängt eine Zeile an und committet sie, auch nach einem roten Lauf. Eine schlechte Zahl im Verlauf ist eine Tatsache, eine fehlende Zeile ist ein Rätsel. Unser nachgestellter Lauf schrieb diese Zeile:
| 2026-11-14 | 52% | 49b593e |
Das Scoreboard macht die Zahl zur sichtbaren Geschichte in jedem Klon des Repositorys. Sinkt sie, zeigen git log scoreboard.md und die Logs der Nacht, an welchem Tag und mit welchem Commit es geschah. Liest du dann neue Traces, schließt sich das Schwungrad aus Warum Evals: Traces lesen, Fehler als Fälle festhalten, ein Gate davor, die Zahl beobachten. Ab jetzt stößt die CI es jede Nacht an.
Merksätze
- Eine Teilmenge aus Code-Fällen prüft jeden Pull Request, die volle Suite mit Judge läuft jede Nacht.
- Der Schwellenwert liegt unter der schlechtesten von drei Quoten. Wie viel darunter, hängt von der Zahl der Fälle ab.
- Modell-IDs und SDK-Version stehen fest im Code, damit jeder Wechsel durch das Gate muss.
- Geplante Läufe starten nur auf dem Standard-Branch, und Pull Requests aus Forks bekommen keine Secrets.
- Das Scoreboard bekommt jede Nacht eine Zeile, auch nach einem roten Lauf.
Prüf dich selbst
Denkfrage
Warum committet der nächtliche Job das Scoreboard auch nach einem roten Lauf?
Ein roter Lauf ist eine Messung wie jede andere. Fehlt die Zeile, weißt du später nicht, ob die Suite schlecht war oder gar nicht lief. Mit der Zeile zeigen git log scoreboard.md und das Log der Nacht, wann die Quote sank und mit welchem Commit.
Denkfrage
Jemand im Team setzt das Gate auf 0,95, weil die Suite gerade bei 96 Prozent steht. Was passiert?
Bei 15 Fällen entspricht ein Fall fast 7 Prozentpunkten. Schon ein einziger wackelnder Fall drückt die Quote auf 93 Prozent, und der Pull Request wird rot, ohne dass sich etwas geändert hat. Nach einigen solchen Fehlalarmen ignoriert das Team das Gate.
Prüf dich selbst
Selbst nachweisen
0 von 4 erledigt
Quellen
- Events that trigger workflows
schedule nur auf dem Standard-Branch, Verzögerung zur vollen Stunde, Abschaltung nach 60 Tagen, keine Secrets für Forks.
- Control the concurrency of workflows and jobs
concurrency und cancel-in-progress.
- actions/checkout
- actions/setup-python
- actionlint
Statische Prüfung für Workflow-Dateien.
- Pricing
Opus 5.5: 4 / 20 US-Dollar, Sonnet 5.5: 2 / 10 US-Dollar pro Million Tokens Ein- und Ausgabe.