LLM-Judge Position-Bias Check by Swapping Order
A pairwise judge `judge(first, second) -> "first" | "second" | "tie"` compares two answers. For each pair `(a, b)`, call it in both orders, map both verdicts back to `A`/`B`/`tie`, and record the final verdict only when the two orders agree (otherwise `tie`). Return the consistency rate, the rate at which decisive verdicts favour the first slot, a two-sided exact sign-test p-value for that first-slot rate against 0.5, and the per-pair verdicts.
LLM judges prefer whichever answer appears first (or second, depending on the model), and also longer answers and their own outputs. Running both orders turns that bias into something you measure instead of something that silently inflates one system's win rate. Inconsistent pairs are not noise to discard; collapsing them to ties is the conservative choice, and the consistency rate itself is the judge's quality metric. The exact binomial test tells you whether the first-slot preference is real or chance on this sample size.
Try it first.
tests.py · 8 passing
pairs = [("x" * i, "y" * (i + 3)) for i in range(20)]
def by_length(f, s):
return "tie" if len(f) == len(s) else ("first" if len(f) > len(s) else "second")
r = position_bias_report(pairs, by_length)
assert r["consistency"] == 1.0 and r["first_position_rate"] == 0.5 and r["p_value"] == 1.0
assert r["verdicts"] == ["B"] * 20
r = position_bias_report(pairs, lambda f, s: "first")
assert r["consistency"] == 0.0 and r["verdicts"] == ["tie"] * 20
assert r["first_position_rate"] == 1.0 and r["p_value"] == 2 / 2 ** 40
def leaning(f, s):
return "first" if abs(len(f) - len(s)) < 3 else by_length(f, s)
mixed = [("aa", "bbb"), ("a", "bbbbbb"), ("aaaa", "b")]
r = position_bias_report(mixed, leaning)
assert r["verdicts"] == ["tie", "B", "A"]
assert abs(r["consistency"] - 2 / 3) < 1e-12
assert abs(r["first_position_rate"] - 4 / 6) < 1e-12
assert sign_test_p(5, 10) == 1.0 and abs(sign_test_p(0, 5) - 2 / 32) < 1e-15Swapping fixes position bias but not length or self-preference bias; control length by comparing answers of similar length or adding a length-penalty rubric, and use a judge from a different model family than the systems under test. Calibrate the judge against a few hundred human labels and report agreement (Cohen's kappa), not just accuracy. For large evals, randomise order once per pair and check bias on a sample to halve judge cost.