Handbücher · Eval Engineering

Build: Das Gate

Lektion 8/911 Min. LesezeitProfi

Lernziele

  • Du hängst eval_suite.py mit 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 push

Zeilen 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:

Das Gate mit altem und neuem Prompt (eigene Läufe, 14.11.2026)1/6
  1. 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?

Denkfrage

Jemand im Team setzt das Gate auf 0,95, weil die Suite gerade bei 96 Prozent steht. Was passiert?

Prüf dich selbst

  1. 1Welche Fälle gehören an den Anfang von golden.jsonl?
  2. 2Deine Suite lag in drei Läufen bei 92, 89 und 91 Prozent. Wo setzt du den Schwellenwert?
  3. 3Ein Pull Request kommt aus einem Fork. Was passiert im Job pr-gate?
  4. 4Warum steht die Minute im Zeitplan auf 30?

Selbst nachweisen

0 von 4 erledigt

Quellen

  1. Events that trigger workflows · GitHub, Stand: Nov. 2026

    schedule nur auf dem Standard-Branch, Verzögerung zur vollen Stunde, Abschaltung nach 60 Tagen, keine Secrets für Forks.

  2. Control the concurrency of workflows and jobs · GitHub, Stand: Nov. 2026

    concurrency und cancel-in-progress.

  3. actions/checkout · GitHub, v7.0.1, Juli 2026
  4. actions/setup-python · GitHub, v7.1.0, Okt. 2026
  5. actionlint · rhysd, v1.7.12, Stand: Nov. 2026

    Statische Prüfung für Workflow-Dateien.

  6. Pricing · Anthropic, Stand: Nov. 2026

    Opus 5.5: 4 / 20 US-Dollar, Sonnet 5.5: 2 / 10 US-Dollar pro Million Tokens Ein- und Ausgabe.

Dein Fortschritt bleibt nur in diesem Browser gespeichert.