Skip to main content

A pairwise evaluator puts the model output head-to-head against a reference answer and returns a winner (or a tie). Use it to benchmark a new prompt or model against a known-good baseline that’s already in the dataset row.

The example below asks an LLM judge to pick the better candidate — but blinds the judge so it never sees which side is the model output and which is the reference. The presentation order is randomized per example using a seed derived from the inputs (so runs stay reproducible), and the judge’s positional choice is decoded back to the original labels after the call. This mitigates LLM position bias — the tendency of judges to systematically prefer whichever response they see first.

The judge never sees which side is the model output and which is the reference — only “Candidate 1” and “Candidate 2”. The seeded shuffle is deterministic per example, so the same inputs always produce the same presentation order.

Code#

Sandbox dependencies — paste into the sandbox configuration’s Dependencies field, one package per line:

The flip decision is recorded in the explanation so you can audit the decoding from the trace.

Input mapping#

ParameterBind to
outputThe model output you want to evaluate, usually output.
referenceThe competing answer to compare against — typically the baseline or known-good response stored on the example, usually reference.

Output configuration#

Categorical. The function returns its own numeric score along with the label, so configure these label-to-score mappings to match what it produces:

LabelScoreMeaning
output1.0The model output beats the reference.
reference-1.0The reference beats the model output.
tie0.0Judge could not separate them.
missing0.0One of the inputs was empty.
invalid0.0Judge returned malformed output.

Optimization direction: maximize — you want output to win against the reference baseline.

Runtime requirements#

SettingValue
SandboxA hosted backend that matches your language. Python: E2B, Daytona — Python, Vercel Sandbox — Python, or Modal. TypeScript: Daytona — TypeScript or Vercel Sandbox — TypeScript (the local Deno sandbox is started with --no-npm and cannot install the openai package).
DependenciesPython: openai. TypeScript: openai (npm).
Internet accessRequired — toggle Allow Internet Access on. The sandbox must reach api.openai.com.
Environment variablesOPENAI_API_KEY — preferably set as a secret reference to a key in Settings → Secrets.
Warning

Each evaluate(...) call makes one chat-completion request against gpt-4o-mini. At scale:

  • Raise the sandbox configuration’s Timeout to comfortably cover the LLM round-trip plus a cold-start package install.
  • Watch the judge’s per-token cost — every pairwise prompt includes both the output and the reference, so token counts grow with output length.
  • For high-stakes evaluations, see the Swap-and-confirm variant below. It doubles the cost but removes position bias on every example, instead of relying on randomized order to cancel it out in aggregate.

Variants#

Swap-and-confirm (position-bias-free)#

The blinding above randomizes order per example, so position bias cancels out in expectation — but any single example can still be biased. To remove it per-example, call the judge twice (once in each order) and only return a winner when both calls agree:

Costs 2× the API calls, but each example’s verdict is independent of the underlying model’s position bias.

Other directions#

  • Multi-criterion judging — ask the judge to score on several axes (correctness, conciseness, format) and combine the per-axis verdicts. Return a structured explanation so the trace shows the breakdown.
  • Embedding-based pairwise — replace the LLM call with cosine similarity between output and reference using OpenAI embeddings or scikit-learn. Cheaper and deterministic, but it won’t catch semantic equivalence the way an LLM judge can on free-text answers.