Zum Inhalt springen

Modul XII — Qualität, Evals & Testing

Modul XII beantwortet eine einzige Frage — macht mein Agent immer noch das Richtige? —, indem es Kandidaten-Outputs gegen versionierte Golden-Suites bewertet (scoring) und das Ergebnis als kanonischen, modulübergreifenden Nachweis ausgibt. Es ist ein Modul der Intelligence-Schicht: es misst, es führt das untersuchte Subjekt nicht aus und es agiert nicht auf der Infrastruktur. Diese Seite ist die Referenz dafür, was das Evals-Modul heute leistet, und für seine ehrlichen Grenzen.

XII ist eine Mess-, keine Ausführungsschicht. Ein Kandidaten-Output erreicht es bereits fertig erzeugt — aus der Testing-Sandbox (Modul XVII), aus CI, inline in der Anfrage oder als gesampletes Signal aus einer realen Session — und XII bewertet ihn gegen die Fälle einer Suite. Das einzige Modell, das XII jemals aufruft, ist der Judge (für den llm_judge-Scorer); es führt niemals den untersuchten Agenten oder das Modell selbst aus. Outputs zu erzeugen ist Aufgabe der Sandbox, nicht von XII.

Das Scorer-Set ist austauschbar. Deterministische, reine Built-ins decken die gängigen Verträge ab — exact, contains, not_contains, regex, json_valid, json_equal und numeric_range. Daneben steht ein llm_judge-Scorer, der über den Judge-Port ein Modell aufruft, um anhand einer Rubrik zu bewerten.

Eine Suite ist ein versioniertes Golden-Dataset: sie enthält ihre Fälle, einen Default-Scorer, einen Bestehensschwellenwert und einen Regressionsschwellenwert. Fälle sind append-only und unveränderlich pro Version — die Korrektur eines Falls prägt eine neue suite_version, niemals eine Bearbeitung an Ort und Stelle, sodass das Dataset, das ein vergangenes Urteil erzeugt hat, stets rekonstruierbar ist.

Ein Run bewertet jeden Fall einer Suite, aggregiert einen score und eine pass_rate und persistiert drei Dinge: append-only Nachweise pro Fall, ein veränderbares Run-Aggregat und ein zentrales EvalResult — das kanonische Artefakt (Suite, SubjectKind, SubjectID, Score, Passed, OccurredAt, Metrics), das Compliance (XIII) und die UI lesen, ohne die eigenen Tabellen von XII zu kennen. Runs werden synchron ausgeführt; der SSE-Stream eines Runs gibt den persistierten Run wieder (Frames pro Fall, dann eine Zusammenfassung), er löst nichts aus. Eine Regression ist ein Vergleich mit einem Baseline-Run. Liegt der Score-Abfall über der regression_threshold der Suite und schließt das 95%-Intervall der Pass-Rate-Differenz (Newcombe, Differenz von Wilson-Intervallen) null aus, setzt der Run regressed und schreibt ein zentrales Finding (Kind = eval_regression). Ein Abfall über dem Schwellenwert, dessen Intervall null enthält, wird als inconclusive_noise markiert und nicht als Regression; der Vergleich zeigt das Intervall und beide Nenner, sodass kleine Suites weniger Findings auslösen. Die automatische Baseline ist der letzte abgeschlossene Run derselben Suite und desselben Subjekts, bei gesetzter Variante auch derselben Variante, ohne als inconclusive_noise markierte Runs. Dieser Run kann eine andere Suite-Version, ein anderes Modell oder einen anderen Scorer nutzen, und der Vergleich meldet nicht, was sich geändert hat. Nach einem Wechsel der Suite-Version übergeben Sie eine explizite Baseline oder pinnen eine (POST /baselines). Das Finding wird nach bestem Bemühen auf dem Bus als finding.reported ausgegeben, damit Delivery-Module (Health/Benachrichtigungen) es routen. Auf der Leseseite aggregieren Scorecards Pass-Rate, mittleren Score und Trend pro Subjekt und exportieren als CSV/JSON.

Der Kandidaten-Output wird niemals persistiert — aus keiner Quelle. Ein Ergebnis pro Fall speichert nur einen Einweg-Detail-Hash und ein geklammertes, bereinigtes Label für die UI; die Maskierung erledigt der Handler vor der Speicherung, sie wird niemals vom Store vorausgesetzt. Der Monitor bewertet Verhaltenssignale einer realen Session — ihren Zustand, die Finding-Anzahl, die maximale Schwere und Token-/Kostenwerte (aus den zentralen Signalen Session, Finding und CostRecord) — und niemals den rohen Output-Text, den die Plattform überhaupt nicht persistiert. Golden-Fixtures sind die eine begrenzte Ausnahme: betreiberautorisiert, opt-in, nicht-produktive Inhalte, vom Handler vor dem Schreiben geklammert, damit eine Suite tatsächlich ausgeführt werden kann.

Judge-Kalibrierung, Bias-Minderung und das CI-Regressions-Gate

Abschnitt betitelt „Judge-Kalibrierung, Bias-Minderung und das CI-Regressions-Gate“

Den Urteilen des Judge wird erst vertraut, nachdem sie gemessen wurden. Ein menschlich gelabeltes Kalibrierungs-Set (erstellt mit der geführten Session olivares evals label) speist einen Kalibrierungs-Run, der den Judge gegen die menschliche Referenz misst: prozentuale Übereinstimmung mit ihrem 95%-Wilson-Intervall, Cohens Kappa (Übereinstimmung allein ist unter Klassenungleichgewicht nicht vertretbar), Sensitivität/Spezifität mit ihren Nennern und eine Verbosity-Bias-Korrelation. Der Report ist append-only Nachweis; das Ziel — Übereinstimmung ≥ 0,85 und ein definiertes Kappa ≥ 0,6 — kann pro Run angehoben, aber niemals gesenkt werden. Ein Set, dessen menschliche Labels alle „pass” lauten, kann keine zufallskorrigierte Übereinstimmung messen und zertifiziert nichts.

Bias-Minderung ist eingebaut und gemessen: der Judge-Prompt erzwingt die Begründung vor dem Urteil (die Analyse wird im Flug verworfen — Minimal-data) und weist an, Länge nicht zu belohnen; der opt-in paarweise Modus des A/B-Vergleichs bewertet jeden geteilten Fall zweimal mit vertauschter Präsentationsreihenfolge, erklärt einen Sieger nur, wenn beide Reihenfolgen übereinstimmen, und berichtet die gemessene position_consistency-Rate.

Das Regressions-Gate (POST /gate, CLI evals gate) verwandelt all dies in ein blockierendes CI-Urteil: eine Regression gegenüber der Baseline, eine Pass-Rate unter dem Suite-Schwellenwert oder ein unkalibrierter Judge lässt das Gate scheitern (Exit 1); ein fehlender Judge-Credential degradiert zu einer deklarierten Warnung, niemals zu einem stillen Pass. Der Seed des Gates wählt die Fälle der Stichprobe; er macht ein entferntes Modell nicht deterministisch. Ein Treffer im Urteils-Cache (Schlüssel: Inhalt, Judge-Modell-Pin und Prompt-Version) gibt das gespeicherte Urteil zurück. Ein Fehltreffer und jeder gewöhnliche llm_judge-Run außerhalb dieses Gates rufen den entfernten Judge erneut auf und können abweichen. Die FinOps-Vorprüfung läuft nur auf diesem Gate. Gilt für die Judge-Aufrufe kein FinOps-Budget, das blockiert oder drosselt, erlaubt das Gate die Ausgabe. Ist der Budgetspeicher nicht lesbar, verweigert das Gate die Ausgabe und scheitert mit budget_blocked. Ein Budget, das blockiert oder drosselt, stoppt die Ausgabe. Der einzige Ausweg aus einem gescheiterten Gate ist das gesteuerte Override — Admin-Stufe, schriftliche Begründung, auditiert —, das das effektive Urteil ändert, das CI erneut prüft, niemals das aufgezeichnete. Jede berichtete Rate kommt mit ihrem Nenner und 95%-Intervall, ebenso der Regressionsvergleich. Siehe docs/EVAL-METHODOLOGY.md im Repository für die vollständige Methodik und Quellen.