LLM-as-Judge
Human preference data is slow and expensive; a strong model agrees with human annotators about as often as they agree with each other. That agreement is real, and so is the list of things it systematically gets wrong.
Standing
Commonly usedEstablished and frequently the right choice, but competing with live alternatives rather than having settled the question.
Ubiquitous and known to be biased in documented ways. Used because the alternative is human annotation, not because it is trusted.
judged as of 2026-09 · what the labels mean
Theory
A judge is asked to compare two responses to the same prompt and pick one. The outputs feed a Bradley–Terry fit exactly as human votes would.
The three biases
Position. Judges prefer the first response, or in some models the second, at rates well above chance. Eq. 1 is the standard correction.
Verbosity. Longer answers win more often, beyond any quality difference. Length-controlled scoring fits a regression with length as a covariate and reports the length-adjusted effect.
Self-preference. A judge scores its own generations higher, and the effect tracks its ability to recognise them. Evaluating a model with a judge from the same family is a conflict of interest with a measured magnitude.
What it is bad at
Judging is bounded by the judge’s own competence. On a maths problem the judge must solve it to grade it; on domain expertise it does not have, it grades fluency. Where a programmatic check exists — tests pass, the answer matches, the JSON parses — use the check.
The 85% agreement figure is quoted far more often than its context. It is agreement on open-ended chat comparisons where humans themselves agree 81% of the time. It is not a claim about grading correctness.
Implementation
import itertools
TEMPLATE = """Compare the two responses to the question below.
Judge accuracy first, then helpfulness. Ignore length and ordering.
Question: {question}
[A] {a}
[B] {b}
Answer with exactly one of: A, B, TIE."""
def judge_pair(client, question: str, a: str, b: str) -> str:
"""Run both orders; a judgement that flips is a tie."""
def ask(first: str, second: str) -> str:
reply = client(TEMPLATE.format(question=question, a=first, b=second))
return reply.strip().upper()[:3].rstrip(".")
forward = ask(a, b)
reverse = ask(b, a)
flip = {"A": "B", "B": "A", "TIE": "TIE"}
return forward if forward == flip.get(reverse, "TIE") else "TIE"Asking for a single token rather than a rationale is a deliberate trade: chain of thought improves judge accuracy on reasoning-heavy comparisons and costs throughput, so it is worth measuring on your own data rather than assuming. Parse strictly and count unparseable replies — a judge that starts refusing to choose is telling you something about the comparison.