Agent Arena

Scorer reference

The ten eval types, their options and failure modes.

Ten builtin eval types. arena scorers lists them.

Options go under scorers.options.<type>; a case picks a type with eval_type: or inherits scorers.default.

classification

Finds which of labels the output selects, then compares to the reference.

scorers:
  default: classification
  options:
    classification:
      labels: [billing, technical, account, other]

Reference: the correct label. Tolerant of a model that answers "The category is billing." rather than "billing" — it looks for a label in the output.

Fails when two labels are substrings of each other (account and account_closure), or when the model names a label while rejecting it ("this is not billing"). Keep labels short and mutually exclusive.

exact_match

Normalised string equality — case, punctuation and whitespace insensitive by default.

Reference: the exact expected string. Use for deterministic short outputs. Fails when the model adds a preamble; use contains or a post_process hook to strip it.

contains

Substring containment. A list reference requires all or any depending on mode.

options:
  contains:
    mode: all      # or: any

Use for "the answer must mention X and Y". Fails when the substring appears inside a negation — it cannot tell "includes a refund" from "does not include a refund".

regex

Regex search over the output, with optional capture-group comparison.

Use for structured formats: an order id, a date, a code. Fails when the pattern is anchored too tightly; models vary their surrounding text far more than the value you want.

numeric

Extracts a number and compares with absolute or relative tolerance.

options:
  numeric:
    tolerance: 0.01
    relative: true

Fails when the output contains several numbers and the wanted one is not first. Narrow it with a post_process hook or use regex with a capture group.

json_match

JSON-parses the output and scores the fraction of reference keys that match.

Reference: the expected object. Partial credit is the point — an extraction that gets four of five fields right scores 0.8, which is far more useful for comparing models than a pass/fail.

Fails when the model wraps JSON in a markdown fence. Strip it in post_process; projects/doc_extraction does exactly this.

semantic

Token-set cosine similarity, or your own embedding function.

For free-text answers where wording varies but meaning should not. Weak by default — the builtin is lexical, so it rewards shared vocabulary rather than shared meaning. Supply an embedding function, or use llm_judge, when that distinction matters.

code_exec

Executes generated code plus reference assertions in a subprocess.

Reference: assertions to run against the generated code.

This is process isolation, not a sandbox. The subprocess runs as you, with your filesystem and your network. Use it on code from a model you control, on inputs you wrote. See ../security/hardening.md.

llm_judge

Grades with a judge model and returns its 0–1 score.

judge:
  model: claude-sonnet-5
  prompt: |
    Score 0-1 how well the answer addresses the question...

For qualitative criteria — tone, helpfulness, whether an explanation is correct — that no deterministic scorer can express.

Three costs, all real: it makes every evaluation call a second model, it costs money per case, and it makes your ranking depend on another model's judgement. Validate the judge against human labels on a sample before trusting a leaderboard built on it.

manual

Always returns 0.5, unscored. Collects outputs for human grading.

Use to run a sweep, export the results, grade by hand, and turn the graded set into references for a real scorer. That progression — manual first, automated once you know what "good" looks like — is usually the right order.

Choosing

Your output is Use
One of a fixed set classification
An exact short string exact_match
Free text that must mention things contains
A structured value in prose regex or numeric
A JSON object json_match
Free text where wording varies semantic, or llm_judge
Code code_exec
Qualitative llm_judge
Not yet known manual, then decide

Writing your own

# projects/my_project/scorers/tone.py
from agent_arena.scorers import Scorer, ScoreResult

class ToneScorer(Scorer):
    name = "tone"

    def score(self, output, reference, context):
        polite = "please" in output.lower()
        return ScoreResult(
            score=1.0 if polite else 0.0,
            passed=polite,
            reason="found 'please'" if polite else "no politeness marker",
            metrics={"politeness": 1.0 if polite else 0.0},
        )

Discovered automatically from the project's scorers/ folder. metrics entries become weightable leaderboard dimensions by name.

projects/doc_extraction/scorers/currency.py is a committed worked example.