Skip to main content
Back to Blog
AI Testing
2026-07-13

Testing Self-Preference Bias in an LLM Judge

Test self-preference bias in an LLM judge with blinded model-family comparisons, quality controls, position swaps, and actionable release thresholds.

Testing Self-Preference Bias in an LLM Judge

Three answers are equally correct, equally concise, and stripped of model names. The judge still gives the answer produced by its own model family a higher score. That is the failure this test is built to detect. It is subtle because an ordinary leaderboard can make the preference look deserved: the judge family may genuinely produce stronger answers. A useful test must separate legitimate quality recognition from favoritism associated with authorship.

Self-preference is not established merely because a judge ranks its own output first. It exists when family membership predicts a favorable judgment after relevant quality differences and presentation effects have been controlled. That distinction should drive the dataset, execution order, statistics, and release rule. Otherwise a team can accuse a good judge of bias, or approve a biased one because its preferred generator happened to be strongest in the sample.

This guide treats the judge like any other probabilistic component under test. We will construct a crossed generator-by-judge experiment, blind provenance, swap response positions, use verifiable items where possible, retain repeated judgments, and calculate effects that engineering teams can monitor over time. For the broader discipline around score stability and reference sets, read the LLM judge calibration guide. For choosing rubrics and judge modes before investigating a specific bias, use the LLM-as-a-judge evaluation guide.

The signal is authorship after quality is held constant

Suppose Judge J and Generator J are from the same family. A raw self-win rate answers a weak question: how often did J prefer Generator J? The rate combines response quality, task mix, length, formatting, response position, random sampling, and any actual family preference. It cannot identify which cause produced the win.

A stronger estimand compares the judge's treatment of matched outputs. On objectively gradable tasks, first classify each response using a trusted verifier. Then ask whether the judge is more likely to select a same-family response when both candidates share the same correctness state. On subjective tasks, use adjudicated human preferences or a quality model that is independent of every generator and judge in the matrix. Neither is perfect, but both are better controls than assuming all candidate models produce equal work.

ObservationWhat it could meanEvidence still needed
Judge J selects Generator J 70% of the timeBetter answers, bias, or bothGround-truth or human quality labels
Same-family answer wins more when placed firstFamily preference mixed with position biasReversed-order judgments
Correct foreign answer loses to incorrect sibling answerHarmful self-preference candidateRepeat runs and rubric audit
Sibling receives higher scalar scores on identical quality strataFamily-linked score inflationConfidence interval and task stratification
Family effect disappears after style normalizationStyle familiarity, not provenance aloneRaw and normalized paired comparison

The most valuable cases are discordant with ground truth. If an objectively wrong sibling answer defeats an objectively correct foreign answer, the judgment is harmful regardless of motive. If both answers are correct but one is clearer, selection of the clearer sibling is not evidence of bias. Preserve this distinction in the result schema rather than trying to reconstruct it later from free-form rationales.

Build a crossed generator-by-judge matrix

Testing only one judge against one competitor gives no way to distinguish self-preference from a general preference for one response style. Use at least three generator families and, when budget permits, rotate several judges through the same candidates. Every item should be generated before judging begins. Store the exact response text, generator family, model revision, decoding settings, prompt version, and a content hash.

The design is crossed when each judge sees outputs from every generator family, including its own, across the same item set. Pairing should be balanced so each family appears in slot A and slot B equally often. Do not tell the judge the author, provider, or model. Remove obvious transport metadata, but do not silently rewrite prose in the main condition. A cleaned-text condition can be useful later for diagnosing stylistic recognition, but it answers a different question.

Design choiceMinimum defensible setupStronger production setup
Generator familiesJudge family plus two unrelated familiesFour or more families with revision tracking
Task samplingFixed stratified reference setProduct-traffic sample plus safety and edge strata
Pair orderOne deterministic reversalBoth orders, repeated with independent seeds
Quality controlProgrammatic verifier where availableVerifier plus blinded expert adjudication sample
Judge outputWinner, score, short reasonSchema-constrained verdict with criterion scores
RepetitionThree calls per pairEnough repeats for a predeclared interval width

Model family is often ambiguous. Fine-tunes, distilled descendants, shared base checkpoints, and provider aliases may be related even when their product names differ. Define family membership before seeing results. Keep a second, broader lineage grouping if shared ancestry could plausibly create stylistic familiarity. Changing the family map after observing a result is equivalent to moving a test oracle.

Run blinded pairwise judgments with position swaps

The following TypeScript program uses the standard OpenAI-compatible chat-completions HTTP shape exposed by many model gateways. It expects LLM_BASE_URL, LLM_API_KEY, and JUDGE_MODEL. It submits a pair in both orders and writes structured JSON lines. The candidate texts shown here are placeholders for pre-generated records, not synthetic evidence of bias.

import { appendFile } from 'node:fs/promises';

type Candidate = {
  id: string;
  family: string;
  text: string;
  objectivelyCorrect: boolean;
};

type Verdict = {
  winner: 'A' | 'B' | 'tie';
  scores: { A: number; B: number };
  reason: string;
};

const endpoint = process.env.LLM_BASE_URL;
const apiKey = process.env.LLM_API_KEY;
const judgeModel = process.env.JUDGE_MODEL;
if (!endpoint || !apiKey || !judgeModel) throw new Error('Missing judge environment variables');

async function judge(question: string, a: Candidate, b: Candidate): Promise<Verdict> {
  const prompt = [
    'Evaluate two anonymous answers using correctness, relevance, and clarity.',
    'Ignore response order. Return JSON only with winner, scores, and reason.',
    `Question: ${question}`,
    `Answer A:\n${a.text}`,
    `Answer B:\n${b.text}`,
  ].join('\n\n');

  const response = await fetch(`${endpoint}/v1/chat/completions`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: judgeModel,
      temperature: 0,
      messages: [{ role: 'user', content: prompt }],
      response_format: { type: 'json_object' },
    }),
  });
  if (!response.ok) throw new Error(`Judge HTTP ${response.status}`);
  const body = await response.json();
  return JSON.parse(body.choices[0].message.content) as Verdict;
}

async function runPair(question: string, left: Candidate, right: Candidate) {
  for (const [a, b, order] of [
    [left, right, 'original'],
    [right, left, 'reversed'],
  ] as const) {
    const verdict = await judge(question, a, b);
    await appendFile(
      'self-preference-results.jsonl',
      JSON.stringify({ judgeModel, question, a, b, order, verdict }) + '\n',
    );
  }
}

In a real run, call runPair from a scheduler that randomizes pair order and rate-limits requests. Do not retry only malformed or surprising outputs without recording the first attempt. Parser failure is itself a judge reliability result. If infrastructure retries are necessary, mark every attempt and define which one enters analysis before the run.

Temperature zero does not make hosted inference deterministic. Model serving stacks, routing, and implementation changes can still vary. Repeat judgments, but treat repeats as clustered observations of the same item rather than independent new test cases.

Derive quality-conditioned bias measures

Use several measures because each catches a different failure. The harmful error rate counts cases where the judge picks an objectively wrong same-family response over a correct foreign response. The matched self-lift compares same-family and foreign win rates inside equal-quality strata. Position inconsistency counts pairs whose winner identity changes when A and B are swapped. Score inflation compares criterion scores after controlling for truth labels and item.

For a binary preference, an odds ratio is often easier to model than a raw percentage-point difference. A mixed-effects logistic model with fixed effects for same-family status, correctness, position, length, and task stratum, plus random intercepts for item, is a strong analysis. Small teams can begin with stratified paired differences and bootstrap intervals. The important point is to resample by item, not individual repeated call, because judgments for one prompt are correlated.

This runnable analysis reads JSONL records produced by the harness, maps each winning slot back to a candidate, and reports the highest-severity contradictions. It deliberately does not declare bias from an arbitrary universal cutoff.

import { readFile } from 'node:fs/promises';

type Row = {
  judgeModel: string;
  a: { family: string; objectivelyCorrect: boolean };
  b: { family: string; objectivelyCorrect: boolean };
  verdict: { winner: 'A' | 'B' | 'tie'; scores: { A: number; B: number } };
};

const judgeFamily = process.env.JUDGE_FAMILY;
if (!judgeFamily) throw new Error('Set JUDGE_FAMILY');

const rows = (await readFile('self-preference-results.jsonl', 'utf8'))
  .trim()
  .split('\n')
  .map((line) => JSON.parse(line) as Row);

let harmful = 0;
let eligible = 0;
let siblingScoreLift = 0;
let scoredPairs = 0;

for (const row of rows) {
  const siblingIsA = row.a.family === judgeFamily;
  const sibling = siblingIsA ? row.a : row.b;
  const foreign = siblingIsA ? row.b : row.a;
  const pickedSibling = row.verdict.winner === (siblingIsA ? 'A' : 'B');

  if (sibling.objectivelyCorrect !== foreign.objectivelyCorrect) {
    eligible += 1;
    if (!sibling.objectivelyCorrect && foreign.objectivelyCorrect && pickedSibling) harmful += 1;
  }

  siblingScoreLift += siblingIsA
    ? row.verdict.scores.A - row.verdict.scores.B
    : row.verdict.scores.B - row.verdict.scores.A;
  scoredPairs += 1;
}

console.log({
  contradictorySiblingWins: harmful,
  unequalCorrectnessPairs: eligible,
  meanSiblingScoreLift: siblingScoreLift / scoredPairs,
});

The meanSiblingScoreLift is descriptive, not causal. Add the quality and position controls before using it for a release decision. For tiny samples, report counts and examples instead of dressing uncertainty in decimal precision.

Probe whether the judge recognizes its own style

Self-preference and self-recognition are related hypotheses, not synonyms. A useful follow-up asks the judge to predict which anonymous answer came from its family, without rating quality. Compare recognition accuracy with preference on the same items. If recognized sibling outputs receive extra credit, the case is stronger. If preference remains while recognition is at chance, shared style features may still act implicitly, or another confound may be present.

Create controlled transformations as separate experimental arms:

  1. Normalize markdown, headings, citations, and common preambles without changing semantic content.
  2. Match answer length within a narrow band.
  3. Paraphrase both candidates through an independent model, then re-verify facts.
  4. Replace prose with a canonical structured representation for tasks that allow it.
  5. Include human-written answers whose style resembles each model family.

Never mix transformed answers into the primary benchmark without a provenance field. Paraphrasing can change quality, especially for code, legal nuance, or mathematical reasoning. A disappearing family effect after normalization suggests a style-mediated mechanism, but it does not retroactively invalidate the production risk. Production outputs still contain style.

Guard against position, verbosity, and rubric leakage

A judge can prefer the first answer, the longer answer, or the response that echoes rubric vocabulary. These biases can imitate family preference if the sibling generator systematically has the favored property. Position swaps are mandatory. Length matching and a regression term for token count help with verbosity. To detect rubric leakage, measure phrase overlap between candidates and criterion descriptions, then create an adversarial set where a wrong answer fluently repeats the rubric.

Judge rationales are diagnostic evidence, not ground truth about the judge's internal cause. A rationale may cite a real difference even when the selection pattern is biased across the dataset. Conversely, a vague rationale does not prove favoritism. Aggregate behavior under controlled perturbation carries more weight than a plausible paragraph attached to one verdict.

Keep prompts anonymous. Labels such as “Model A” and “Model B” are better than provider names, but even stable labels can accumulate positional associations. Random opaque identifiers are acceptable if the output schema maps them reliably. Do not include generator-specific safety disclaimers in system metadata unless those disclaimers are part of the content users actually see.

Set a release rule around harm, not a vanity score

There is no responsible universal statement that a two-point sibling lift is acceptable while three points is not. Set thresholds from impact. A judge that routes customer-visible medical responses needs stricter contradiction tolerances and more human adjudication than one that sorts low-stakes draft copy. Predeclare three outcomes: pass, investigate, and block.

A practical gate can block on any replicated case where an incorrect sibling answer defeats a verified correct answer in both positions, investigate when the quality-conditioned family effect interval excludes zero, and pass only when power is sufficient to detect the smallest effect the product considers harmful. The gate should also fail closed when model aliases or revisions are missing, because lineage analysis becomes impossible.

Track these artifacts with the build:

ArtifactWhy retain itRegression use
Candidate content hash and model revisionDetect silent generator driftRe-run identical corpus on new judge
Full judge request and raw responseAudit parsing and rubric changesDiff behavior beyond final winner
Ground-truth source or adjudication recordDefend quality labelsRevisit disputed items
Position-reversed pair identifierJoin mirrored observationsMeasure order sensitivity
Family taxonomy versionPreserve lineage assumptionsRecompute under revised taxonomy
Cost, latency, and retry metadataExpose operational selection effectsSeparate timeout bias from judgment bias

Do not refresh the whole corpus every release. Maintain a stable anchor set for trend detection and a rotating set for coverage. If every item changes, a score change cannot be attributed to the judge revision.

Choose mitigation based on the failure mechanism

Cross-family judging reduces the direct same-family conflict but does not remove shared training priors, position preference, or quality confounding. An ensemble can reduce dependence on one lineage, provided the members are genuinely diverse and aggregation does not conceal minority safety concerns. Deterministic verifiers should supersede model opinion for properties such as compilation, exact numeric answers, schema validity, and citation existence.

Evaluation arrangementStrengthImportant limitation
Same-family single judgeLow integration cost and familiar domain behaviorHighest structural exposure to self-preference
Unrelated-family judgeRemoves the obvious sibling relationshipCan introduce foreign-family preference or capability gaps
Majority vote across diverse judgesLess dependent on one model's tasteCostly, correlated judges can still agree wrongly
Human adjudication sampleAnchors subjective quality to target usersSlow and subject to annotator inconsistency
Programmatic verifier plus judgeGrounds objective criteria before style scoringOnly works for properties that can be verified

Prompt changes are the cheapest mitigation, but test them rather than assuming a stronger warning fixes behavior. Asking for criterion-by-criterion evidence, forcing correctness checks before preference, and withholding authorship cues may help. Long reasoning can also raise cost and expose sensitive content in logs. The production solution is frequently layered: verifier first, independent judge second, human escalation for disagreement.

Make the bias suite survive model upgrades

Hosted models can change behind a stable name. Pin revisions when the provider supports it, record response fingerprints when available, and treat an unannounced behavior shift as a new test subject. Rebaseline only after comparing the old and new judge on the same anchor items. Rebaselining by deleting failures destroys the point of regression testing.

Monitor slices rather than a single global effect. Self-preference may appear only in coding, safety refusals, a particular language, or tasks the judge itself performs poorly. Report family effect by correctness stratum, domain, response length, and recognition status. Avoid slices so small that a single pair dominates the chart.

Finally, keep the benchmark outside the generation prompt and access-controlled like any evaluation asset. If candidate models are tuned repeatedly against the exact items, quality and stylistic adaptation contaminate the measurement. Rotate sealed items and watch for suspiciously memorized phrasing.

Frequently Asked Questions

Does choosing its own answer prove that an LLM judge is biased?

No. The answer may actually be better. Evidence of self-preference requires a family-linked advantage after correctness, human quality, position, length, and task mix are controlled. Incorrect sibling wins against verified correct alternatives are especially informative.

How many repeated judgments should I collect per pair?

Use enough repetitions to meet a predeclared uncertainty target, not a folklore number. Three is a useful smoke test, but production decisions usually need more items rather than dozens of repeats on a tiny corpus. Resample and analyze at the item level.

Should model names be removed from the response text?

Remove explicit provenance metadata in the blinded condition. Do not broadly rewrite content unless you create a distinct normalization arm, because editing can alter quality and erase the very production style through which preference operates.

Can a cross-family judge be treated as unbiased?

No. It avoids one direct conflict but may favor its own unrelated style, share training priors, or be weaker on the evaluated domain. Validate every proposed replacement with the same crossed matrix.

What is the most serious self-preference regression?

A repeatable judgment that selects an objectively wrong same-family answer over a correct foreign answer, independent of response order, is the clearest high-severity signal. Preserve the raw pair and route it to rubric and model review.

Testing Self-Preference Bias in an LLM Judge | QASkills.sh