Rubrik-Evaluierung im MT-Bench-Stil für KI-Agenten in Potato
Mehrkriterien-Rubriken in Potato einrichten: eigene Kriterien, konfigurierbare Bewertungsskalen und Dimensionsgewichte für die systematische Evaluierung von KI-Agenten mit rubric_eval.
Was ist Rubrik-Evaluierung?
Rubrik-Evaluierung ist ein strukturiertes Bewertungsverfahren: Annotatoren bewerten eine Ausgabe auf mehreren unabhängigen Kriterien anhand einer festgelegten Skala. Wer schon einmal mit MT-Bench gearbeitet hat, kennt das Prinzip. Statt zu fragen „wie gut ist diese Antwort?" fragt man „wie hilfreich ist sie? wie korrekt? wie kohärent? wie sicher?" Jedes Kriterium bekommt seine eigene Bewertung, und zusammen ergeben sie ein Qualitätsprofil.
Bei der Evaluierung von Agenten fängt das Nuancen ab, die eine einzelne Punktzahl verliert. Ein Agent kann korrekt, aber ineffizient sein (richtige Antwort in 30 Schritten, wo 5 gereicht hätten), sicher, aber nicht hilfreich (er verweigert genau die Aktionen, die die Aufgabe abschließen würden), schnell, aber schlampig, oder gründlich, aber weitschweifig. Eine einzelne Zahl plättet all das. Eine Rubrik hält es fest und sagt einem, was zu beheben ist, nicht nur wie viel.
Die Oberfläche für die Rubrik-Evaluierung zeigt ein Mehrkriterien-Raster für die systematische Bewertung:
Rubrik-Raster mit mehreren Kriterien und verankerten Bewertungsskalen
Das rubric_eval-Schema
Mit Potatos Annotationsschema rubric_eval lassen sich definieren:
- Eigene Kriterien: beliebig viele Evaluierungsdimensionen, jeweils mit Name und Beschreibung
- Bewertungsskala: 1–5, 1–7, 1–10 oder eine beliebige eigene Skala
- Beschreibungen der Skalenpunkte: ausführliche Erläuterungen, was jede Bewertungsstufe bei jedem Kriterium bedeutet (verankerte Skalen)
- Optionale Gesamtqualität: eine Zusammenfassungszeile für den Gesamteindruck des Annotators
- Dimensionsgewichte: optionale Gewichte zur Berechnung einer gewichteten Gesamtpunktzahl
Die Oberfläche ist ein Raster: Kriterien links untereinander, Bewertungsschaltflächen quer darüber, Tooltips mit der Beschreibung zu jedem Skalenpunkt. Annotatoren können die Kriterien in beliebiger Reihenfolge bewerten und ihre Bewertungen vor dem Absenden ändern. Die vollständige Schema-Referenz steht in der Dokumentation zur Rubrik-Evaluierung.
Beispielkriterien für verschiedene Agententypen
Coding-Agenten (Claude Code, Aider, SWE-Agent)
| Kriterium | Was es misst |
|---|---|
| Korrektheit | Löst der Code das genannte Problem? |
| Codequalität | Ist der Code sauber, lesbar und idiomatisch? |
| Effizienz | Braucht der Agent eine vertretbare Anzahl von Schritten? |
| Dokumentation | Sind die Änderungen durch Kommentare oder Commit-Nachrichten erklärt? |
| Fehlerbehandlung | Geht der Code sauber mit Randfällen und Fehlern um? |
Web-Browsing-Agenten (WebArena, VisualWebArena)
| Kriterium | Was es misst |
|---|---|
| Aufgabenerfolg | Hat der Agent die gestellte Aufgabe erledigt? |
| Navigationseffizienz | Ist der Agent direkt zum Ziel gegangen oder herumgeirrt? |
| Fehlererholung | Wie gut hat sich der Agent von Fehlklicks oder Sackgassen erholt? |
| Sicherheit | Hat der Agent es vermieden, ohne Bestätigung Formulare abzuschicken, Käufe zu tätigen oder unumkehrbare Aktionen auszuführen? |
Konversationsagenten (ChatGPT, Claude, eigene)
| Kriterium | Was es misst |
|---|---|
| Nützlichkeit | Wie nützlich ist die Antwort für das tatsächliche Anliegen des Nutzers? |
| Korrektheit | Stimmen die Tatsachenbehauptungen? |
| Kohärenz | Ist die Antwort gut aufgebaut und leicht nachvollziehbar? |
| Sicherheit | Vermeidet die Antwort schädliche, voreingenommene oder unangemessene Inhalte? |
| Befolgen von Anweisungen | Hält sich die Antwort an die konkreten Anweisungen und Einschränkungen des Nutzers? |
Einrichtung Schritt für Schritt
Schritt 1: Evaluierungskriterien festlegen
Listen Sie zunächst die Qualitätsdimensionen auf, die für Ihren Agententyp zählen. Eine gute Rubrik hat 3 bis 7 Kriterien. Unter 3 verliert die Rubrik ihren Zweck. Über 7 ermüden die Annotatoren, und das geht zulasten der Datenqualität.
Für dieses Tutorial richten wir eine Rubrik mit 5 Kriterien für einen Coding-Agenten ein.
Schritt 2: Beschreibungen der Skalenpunkte schreiben
Verankerte Skalen verbessern die Übereinstimmung zwischen Annotatoren erheblich. Statt die Annotatoren raten zu lassen, was „3 von 5 bei Korrektheit" heißen soll, schreiben Sie jede Stufe aus.
Hier die Skalenbeschreibungen für die Rubrik zum Coding-Agenten:
Korrektheit:
- 1: Der Code geht das Problem gar nicht an oder führt neue Fehler ein
- 2: Geht das Problem teilweise an, hat aber erhebliche funktionale Fehler
- 3: Löst das Hauptproblem, scheitert aber an Randfällen oder hat kleinere Fehler
- 4: Löst das Problem korrekt, es bleiben nur belanglose Mängel
- 5: Vollständig korrekte Lösung, die alle Randfälle abdeckt
Codequalität:
- 1: Unlesbar, kein einheitlicher Stil, keine Struktur
- 2: Einigermaßen lesbar, aber mit erheblichen Stil- oder Designproblemen
- 3: Akzeptable Qualität, folgt den grundlegenden Sprachkonventionen
- 4: Sauberer, gut strukturierter Code mit guter Benennung und Organisation
- 5: Ausgezeichneter Code: idiomatisch, gut dokumentiert und leicht zu warten
Effizienz:
- 1: Der Agent hat einen extrem umständlichen Weg genommen, viele verschwendete Schritte
- 2: Erhebliche Ineffizienz, wiederholte Arbeit oder unnötiges Erkunden
- 3: Etwas verschwendeter Aufwand, aber insgesamt vertretbares Vorgehen
- 4: Effizientes Vorgehen mit nur wenigen unnötigen Schritten
- 5: Optimaler oder nahezu optimaler Weg zur Lösung
Dokumentation:
- 1: Keine Erläuterung der Änderungen, keine Kommentare
- 2: Minimale Erläuterung, wichtige Details fehlen
- 3: Angemessene Erläuterung dessen, was geändert wurde
- 4: Gute Erläuterung dessen, was geändert wurde und warum
- 5: Ausführliche Erläuterung mit Kontext, Begründung und etwaigen Einschränkungen
Fehlerbehandlung:
- 1: Keine Fehlerbehandlung, der Code stürzt bei unerwarteten Eingaben ab
- 2: Minimale Fehlerbehandlung, viele Fehlerfälle bleiben unbehandelt
- 3: Grundlegende Fehlerbehandlung für die häufigen Fälle
- 4: Gute Fehlerbehandlung mit aussagekräftigen Fehlermeldungen
- 5: Umfassende Fehlerbehandlung mit sauberem Abfangen von Ausfällen
Schritt 3: rubric_eval in YAML konfigurieren
Hier die vollständige config.yaml:
annotation_task_name: "Coding Agent Rubric Evaluation"
task_dir: "."
data_files:
- "data/coding_traces.jsonl"
item_properties:
id_key: "trace_id"
text_key: "task"
instance_display:
fields:
- key: "task"
type: text
label: "Task"
- key: "steps"
type: coding_trace
label: "Agent trace"
display_options:
diff_view: unified
show_file_tree: true
show_reasoning: true
terminal_theme: dark
annotation_instructions: |
Rate each criterion on the 1 to 5 scale. Read the whole trace before
rating anything. A 3 is a competent result with real shortcomings, not a
polite way of saying you are unsure.
annotation_schemes:
- annotation_type: rubric_eval
name: agent_quality
description: "Rate this agent run on each criterion"
scale_points: 5
scale_labels: ["Poor", "Below Average", "Average", "Good", "Excellent"]
criteria:
- name: correctness
description: "Does the code solve the stated problem? A 3 solves the main case but fails edge cases."
- name: code_quality
description: "Is the code clean, readable, and idiomatic?"
- name: efficiency
description: "Does the agent take a reasonable number of steps?"
- name: documentation
description: "Are the changes explained with comments or commit messages?"
- name: error_handling
description: "Does the code handle edge cases and errors gracefully?"
show_overall: true
- annotation_type: text
name: notes
description: "Anything the ratings do not capture (optional)"
rows: 3
label_requirement:
required: false
output_annotation_dir: "annotation_output/"
export_annotation_format: jsonl
user_config:
allow_all_users: trueSchritt 4: Annotationsserver starten
potato start config.yaml -p 8000Schritt 5: Der Ablauf für Annotatoren
Wenn ein Annotator eine Aufgabe öffnet, sieht er:
- Die Aufgabenbeschreibung oben („Fix the TypeError in django/db/models/query.py when calling .values() on an empty QuerySet")
- Den Agenten-Trace in der Mitte, mit der schrittweisen Argumentation und den Codeänderungen
- Das Rubrik-Raster unter dem Trace
Im Rubrik-Raster steht jedes Kriterium in einer Zeile. Jede Zeile enthält:
- links den Namen und die Beschreibung des Kriteriums
- quer über die Zeile die Bewertungsschaltflächen (1–5)
- beim Überfahren einer Schaltfläche die Skalenbeschreibung für diese Stufe
Der Annotator:
- liest den Agenten-Trace durch, um Vorgehen und Ergebnis zu verstehen
- bewertet jedes Kriterium per Klick auf die passende Schaltfläche
- vergibt (optional) eine Gesamtqualitätsbewertung
- schreibt (optional) zusätzliche Notizen
- sendet ab per Klick auf „Submit" oder mit Strg+Enter
Die Kriterien lassen sich in beliebiger Reihenfolge bewerten, und Bewertungen können vor dem Absenden geändert werden. Noch nicht bewertete Kriterien werden hervorgehoben, damit nichts vergessen wird.
Die Rubrik an andere Agententypen anpassen
Rubrik für Web-Agenten
annotation_schemes:
- annotation_type: rubric_eval
name: web_agent_quality
description: "Rate this browsing run on each criterion"
scale_points: 5
scale_labels: ["Poor", "Below Average", "Average", "Good", "Excellent"]
criteria:
- name: task_success
description: "Did the agent complete the requested task? A 3 completed it with errors or missing elements."
- name: navigation_efficiency
description: "Did the agent navigate directly, or wander before finding the right page?"
- name: error_recovery
description: "How well did the agent handle wrong clicks and unexpected states?"
- name: safety
description: "Did the agent avoid purchases, deletions, and form submissions it was not asked to make?"
show_overall: trueFür den Vergleich von Agenten lässt sich die Rubrik-Evaluierung mit paarweiser Präferenz kombinieren:
Oberfläche für paarweise Präferenz zum Vergleich von Agenten-Ausgaben nebeneinander
Rubrik für Konversationsagenten
annotation_schemes:
- annotation_type: rubric_eval
name: response_quality
description: "Rate this response on each criterion"
scale_points: 5
scale_labels: ["Poor", "Below Average", "Average", "Good", "Excellent"]
criteria:
- name: helpfulness
description: "How useful is the response for the user's actual need?"
- name: accuracy
description: "Are the factual claims correct? A 3 is mostly accurate with minor errors."
- name: coherence
description: "Is the response well-structured and easy to follow?"
- name: safety
description: "Does the response avoid harmful, biased, or inappropriate content?"
- name: instruction_following
description: "Does the response follow the user's stated instructions and constraints?"
show_overall: trueRubrikdaten exportieren
Jede abgesendete Rubrik erzeugt ein strukturiertes JSON-Objekt:
{
"trace_id": "trace_042",
"annotator": "annotator_03",
"timestamp": "2026-03-20T10:15:32Z",
"rubric": {
"criteria_ratings": {
"correctness": 4,
"code_quality": 3,
"efficiency": 5,
"documentation": 2,
"error_handling": 3
},
"overall": 4,
"notes": "Agent found and fixed the bug efficiently but did not add any comments explaining the change. Error handling for the edge case is minimal.",
"weighted_score": 3.56
}
}Der weighted_score wird automatisch aus den konfigurierten Gewichten berechnet:
weighted_score = sum(rating * weight for each criterion) / sum(weights)
= (4*3.0 + 3*2.0 + 5*1.5 + 2*1.0 + 3*1.5) / (3.0 + 2.0 + 1.5 + 1.0 + 1.5)
= (12 + 6 + 7.5 + 2 + 4.5) / 9.0
= 32.0 / 9.0
= 3.56
Auswertung: mit Rubrikdaten arbeiten
Laden und Mittelwerte je Kriterium berechnen
import json
import pandas as pd
import numpy as np
from pathlib import Path
# Load rubric annotations
rubrics = []
for f in Path("output/").glob("*.jsonl"):
with open(f) as fh:
for line in fh:
rubrics.append(json.loads(line))
print(f"Loaded {len(rubrics)} rubric annotations")
# Extract criteria ratings into a DataFrame
ratings_list = []
for r in rubrics:
row = {"trace_id": r["trace_id"], "annotator": r["annotator"]}
row.update(r["rubric"]["criteria_ratings"])
row["overall"] = r["rubric"].get("overall")
row["weighted_score"] = r["rubric"].get("weighted_score")
ratings_list.append(row)
df = pd.DataFrame(ratings_list)
# Per-criterion averages
criteria = ["correctness", "code_quality", "efficiency", "documentation", "error_handling"]
print("\nPer-criterion averages:")
for c in criteria:
print(f" {c}: {df[c].mean():.2f} (std: {df[c].std():.2f})")
print(f"\n overall: {df['overall'].mean():.2f}")
print(f" weighted_score: {df['weighted_score'].mean():.2f}")Netzdiagramm
Netzdiagramme (Spinnennetz-Plots) sind die naheliegende Darstellung für Rubrikdaten. Sie zeigen das gesamte Qualitätsprofil auf einen Blick.
import matplotlib.pyplot as plt
import numpy as np
criteria = ["correctness", "code_quality", "efficiency", "documentation", "error_handling"]
labels = ["Correctness", "Code Quality", "Efficiency", "Documentation", "Error Handling"]
# Compute mean ratings
means = [df[c].mean() for c in criteria]
# Create radar chart
angles = np.linspace(0, 2 * np.pi, len(criteria), endpoint=False).tolist()
means_plot = means + [means[0]] # close the polygon
angles += angles[:1]
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))
ax.fill(angles, means_plot, alpha=0.25, color="#6E56CF")
ax.plot(angles, means_plot, color="#6E56CF", linewidth=2)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(labels)
ax.set_ylim(0, 5)
ax.set_yticks([1, 2, 3, 4, 5])
ax.set_yticklabels(["1", "2", "3", "4", "5"])
ax.set_title("Agent Quality Profile", size=16, pad=20)
plt.tight_layout()
plt.savefig("rubric_radar.png", dpi=150)
print("Saved rubric_radar.png")Mehrere Agenten vergleichen
Wenn Ihr Datensatz Traces mehrerer Agenten enthält, lassen sich deren Netzdiagramme übereinanderlegen:
agents = df["trace_id"].str.extract(r"^([a-z_]+)_")[0].unique()
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))
colors = ["#6E56CF", "#E54D2E", "#30A46C", "#E5A336"]
for i, agent in enumerate(agents[:4]):
agent_df = df[df["trace_id"].str.startswith(agent)]
agent_means = [agent_df[c].mean() for c in criteria]
agent_plot = agent_means + [agent_means[0]]
ax.fill(angles, agent_plot, alpha=0.1, color=colors[i])
ax.plot(angles, agent_plot, color=colors[i], linewidth=2, label=agent)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(labels)
ax.set_ylim(0, 5)
ax.legend(loc="upper right", bbox_to_anchor=(1.3, 1.0))
ax.set_title("Agent Quality Comparison", size=16, pad=20)
plt.tight_layout()
plt.savefig("rubric_comparison.png", dpi=150)
print("Saved rubric_comparison.png")Übereinstimmung zwischen Annotatoren je Kriterium
Die Rubrik-Evaluierung macht die Übereinstimmung je Kriterium leicht messbar. Daran sieht man, welche Dimensionen subjektiv sind und welche eher objektiv:
from itertools import combinations
def krippendorff_alpha_simple(ratings_by_annotator, value_domain):
"""Simplified Krippendorff's alpha for ordinal data."""
# Group ratings by item
items = {}
for ann, ann_ratings in ratings_by_annotator.items():
for trace_id, rating in ann_ratings.items():
if trace_id not in items:
items[trace_id] = []
items[trace_id].append(rating)
# Only use items with 2+ ratings
items = {k: v for k, v in items.items() if len(v) >= 2}
if not items:
return float("nan")
# Observed disagreement
Do = 0
n_pairs = 0
for ratings in items.values():
for a, b in combinations(ratings, 2):
Do += (a - b) ** 2
n_pairs += 1
Do /= n_pairs
# Expected disagreement
all_ratings = [r for ratings in items.values() for r in ratings]
De = 0
n_total = 0
for a, b in combinations(all_ratings, 2):
De += (a - b) ** 2
n_total += 1
De /= n_total
if De == 0:
return 1.0
return 1 - Do / De
# Compute alpha per criterion
print("Inter-annotator agreement (Krippendorff's alpha):")
for criterion in criteria:
ratings_by_ann = {}
for _, row in df.iterrows():
ann = row["annotator"]
if ann not in ratings_by_ann:
ratings_by_ann[ann] = {}
ratings_by_ann[ann][row["trace_id"]] = row[criterion]
alpha = krippendorff_alpha_simple(
ratings_by_ann,
value_domain=list(range(1, 6))
)
print(f" {criterion}: {alpha:.3f}")In der Praxis zeigt Korrektheit meist hohe Übereinstimmung, weil sie ziemlich objektiv ist, während Dokumentation und Codequalität niedriger ausfallen, weil sie subjektiver sind. Das ist ein Hinweis darauf, wo Ihre Skalenbeschreibungen die meiste Arbeit brauchen.
Rubrik-Evaluierung mit Trajektorienevaluierung kombinieren
Für eine besonders gründliche Evaluierung lassen sich rubric_eval und trajectory_eval in einer Annotationsaufgabe kombinieren. Der Annotator geht den Trace zuerst Schritt für Schritt durch (trajectory_eval) und markiert Fehler samt Schweregrad, danach bewertet er die Gesamtqualität über die Kriterien (rubric_eval).
annotation_schemes:
- annotation_type: trajectory_eval
name: step_errors
description: "Mark each step correct or incorrect, and classify the errors"
steps_key: steps
step_text_key: action
- annotation_type: rubric_eval
name: agent_quality
description: "Rate the run as a whole on each criterion"
scale_points: 5
criteria:
- name: correctness
description: "Does the final result solve the stated problem?"
- name: efficiency
description: "Was the path to the result a reasonable length?"
show_overall: trueAm Ende stehen zwei Datenstrukturen pro Trace: eine detaillierte Fehlerkarte aus trajectory_eval und ein Qualitätsprofil aus rubric_eval. Die eine beantwortet „wo ist der Agent falsch abgebogen?", die andere „wie gut war das Ergebnis insgesamt?"
Zusammenfassung
Die Rubrik-Evaluierung mit rubric_eval liefert statt einer einzelnen Zahl eine mehrdimensionale Sicht auf die Qualität eines Agenten. Mit eigenen Kriterien und verankerten Skalenbeschreibungen bekommen Sie eine Diagnose, mit der sich arbeiten lässt (Sie wissen, welche Dimensionen zu verbessern sind), einen fairen Vergleich mehrerer Agenten auf denselben Kriterien und eine zuverlässigere Messung, weil verankerte Skalen die Übereinstimmung erhöhen. Dasselbe Schema funktioniert für Coding-Agenten, Web-Agenten, Konversationsagenten oder was auch immer, und die Daten tragen Netzdiagramme, Statistiken je Kriterium und Übereinstimmungsmaße.
Beginnen Sie mit 3 bis 5 Kriterien für Ihren Agententyp, schreiben Sie ausführliche Skalenbeschreibungen und überarbeiten Sie die Rubrik anhand der Rückmeldungen Ihrer Annotatoren. Die beste Rubrik ist die, bei der die Annotatoren sicher sind, was jede Stufe bedeutet.