- Candidates: the model pool under test, any size from two upwards, called through the AI Gateway so one API key covers every provider
- Jury: a panel of judge models that compares the two answers, scoring each pair twice with the seats swapped
- Rating: a Bradley-Terry fit over every judged round, reported with bootstrapped 95% confidence intervals
A judge that votes differently when only the seat order changes abstains for that round, and the flip is recorded. A round needs at least two surviving votes, a configurable threshold, and those votes must reach a strict plurality. Rounds that fall short are recorded as inconclusive and never reach the rating, so a small run reports fewer rated rounds rather than a ranking built on coin flips.
orq_arena.yaml key, and the full scoring methodology, see the orq-arena documentation.
Prerequisites
Python 3.10 or later, uv, Git, and an Orq.ai workspace. Config validation requires at least two candidates and a non-empty judge panel, so enable the models for both before running; the shipped config expects its full eight-model pool and three judges. Arena is an open-source CLI installed from GitHub rather than a published package:.env, created per the API keys guide:
Although
uv tool install puts orq-arena on the PATH globally, it reads .env, the config, and the prompts file relative to the working directory. Run it from the cloned repository, or pass absolute paths to --config and --prompts.First benchmark run
run refuses to overwrite a non-empty log unless --overwrite is passed. At the end, the standings print and the HTML report is written next to the log.
Before any of that, the preflight prints the exact call counts and a RUN PLAN table, one row per candidate and judge with its call count, catalog price, and projected cost. It then stops on a confirmation carrying both figures:
-y, since a pipe cannot answer the confirmation.
No API key yet? A recorded run is committed in the repository.
orq-arena report examples/quickstart/battles.jsonl rebuilds its report with no key and no network calls.Choosing the model pool
The pool is thecandidates list in the config passed to --config, using AI Gateway model IDs. orq-arena refresh-catalog --show lists the models enabled in the workspace, grouped by provider.
orq_arena.yaml
reasoning fields are forwarded to the router verbatim, so each provider takes its own shape; the configuration reference lists the per-provider recipes. The repository also ships preset pools under configs/ for frontier, budget, and sixteen-model fields, plus configs/reasoning_arena.yaml, the thinking-on counterpart to the thinking-off default, for measuring whether reasoning earns its cost.
Supplying prompts
The shippedprompts/starter.jsonl is a 30-prompt smoke test sized to exercise every mechanism, not to defend a ranking. Swap it with --prompts.
- Local JSONL
- Orq.ai Dataset
One JSON object per line.
prompt is the only required field; category is optional and feeds per-category ratings. Any other keys ride along into the battle log, so results can be joined back to the source data.prompts.jsonl
match.max_rounds caps how many prompts each match judges. With the default of 5 against the 30-prompt starter bank, every match sees a seeded random slice of five. Pass --rounds 30 to use every prompt in every match.Where results land
Every run writes three files, named after the battle log and written beside it (the working directory by default, or wherever--output points): battles.jsonl (one line per judged round, with both responses, per-judge votes, and token accounting), battles.run.json (the manifest: config, content hashes, panel, seed, agreement stats, no credentials), and battles.report.html (a single-file report, no server or external assets, safe to share).
Everything downstream works from the battle log alone. orq-arena report rebuilds the page, annotate renders a blind version for human raters and anchor scores their votes against the panel, and rejudge re-scores the recorded responses with a different jury for judge tokens only, reporting the rank correlation against the original. That last one is the direct test of whether a ranking depends on who judged it.
Reading the report
The report opens on a verdict, then the Elo ladder with error bars, a quality-versus-cost value map, speed, and dollar spend.
- 95% CI comes from a seeded 1000-resample bootstrap, plotted on one shared scale. The intervals are marginal, so read them one at a time: two of them overlapping does not mean the two models are tied, or even that they are indistinguishable.
- Length-adj. prices out the jury’s preference for longer answers. A large gap between a model’s rating and its length-adjusted rating means verbosity, not quality, was doing the separating. The column appears only when that preference is identified: the fit converged, and a bootstrap interval over the same rounds excludes zero.
How far to trust a run
Every run publishes the numbers needed to challenge its own ranking: mean judge agreement, chance-corrected kappa, and each judge’s flip rate between seat orders. Three things are worth knowing before quoting a result:- A failed stream never becomes a verdict. One retry per side, then the round is voided: logged, but never judged or rated. Truncated answers are judged as-is and flagged, so the jury sees what a reader would see.
- Small runs produce wide intervals, and that is the honest output. The top spot counts as separated only when the bootstrapped interval on the difference between the top two excludes zero.
- The defaults are a smoke test. A ranking worth defending takes a real prompt set, hundreds of rounds, and judges from families outside the pool.
After the run
Arena keeps its results in the three local files rather than writing them back to Orq.ai. Candidates and judges share one router client, so every call a tournament makes is recorded in Traces alongside the workspace’s other AI Gateway traffic, with its own latency, token usage, and cost. Share the HTML report, then act on the ranking: pin the winner in a Deployment, or put the strongest and most economical models into a Smart Router pool and let it choose per request.Going further
Getting started
Install, credentials, first tournament, and troubleshooting.
CLI reference
Every command and flag with its expected output.
Configuration
Every
orq_arena.yaml key, its type and default, plus the prompts file format.Source on GitHub
Example runs, preset model pools, and the implementation. MIT licensed.