AI-evals · LLM-as-Judge Position Bias
← Симуляторы

LLM-as-Judge: position bias и mirror-judging

Маркетплейс хочет автоматизировать сравнение двух LLM-моделей для саппорт-бота. Вместо тысяч человеческих оценок — сгенерировать N ответов от каждой модели на одни и те же запросы клиентов, отдать пары ответов LLM-судье (GPT-4 в роли оценщика), попросить выбрать лучший. Цель — win rate новой модели B против текущей A.

План выглядит идеально: дёшево, быстро, масштабируемо. На 1000 пар $20 в API-вызовах вместо $5000 в зарплате разметчикам. Команда уже планирует выкатить новую модель на основе результатов pairwise judgment.

Но в этой методологии есть систематическая ошибка, которую не видно при простом запуске. LLM-судьи имеют position bias — они склонны предпочитать ответ, показанный первым, независимо от качества. Это measured number из академической литературы: для GPT-4 как судьи bias составляет 15–25 п.п. Если всегда показывать ответы в порядке (A, B) — оценка win rate B будет смещена.

Эта страница про то, как position bias работает, как его обнаружить, и как методологически правильно с ним бороться (mirror-judging). Симулятор посередине показывает, как смещена оценка при naive подходе и насколько mirror-стратегия исправляет результат.

Position bias — что это и почему серьёзно

Главная тема этого кейса.

Что такое position bias

LLM-судья получает промпт вида: «Вот два ответа на запрос клиента. Какой лучше?». В промпте ответы идут друг за другом — один первый, второй второй. По данным академических работ (Zheng et al. 2023, MT-Bench; Li et al., AlpacaFarm), GPT-4-class судьи систематически предпочитают ответ показанный первым — даже когда явно сказано «не учитывайте порядок».

Численно: если истинная вероятность что A лучше — 50%, то при «A первый» judge выберет A примерно в 60–65% случаев. Это не случайный шум, это systematic shift. Bias меняется от 15 до 25 процентных пунктов в зависимости от модели-судьи, типа задачи и формулировки промпта.

Почему это серьёзно

В типичном A/B-pipeline команда генерирует пары и оценивает их в фиксированном порядке (обычно «текущая модель первая, новая вторая» или наоборот — кому как удобнее). Результат — win rate смещён в сторону той модели, которая всегда первая.

Конкретно: если в эксперименте всегда A первый, и judge имеет bias +20 п.п. в сторону первого:

Это не academic curiosity. Это реальные продакшен-ошибки, которые приводят к неправильным решениям о замене моделей. В одну сторону, если порядок (A, B) — недооцениваем B. В другую, если (B, A) — переоцениваем. Случайный порядок смещения не убирает, потому что bias всё равно работает в каждой паре — он просто маскируется в среднем.

Как обнаружить

Простой sanity check: рандомизировать порядок и сравнить с обратным. Если win rate B при «A первый» равен 30%, а при «B первый» равен 70% — есть position bias. Если bias есть, эти две оценки расходятся на 2× bias_strength. Если порядок был всегда фиксирован — расхождение не видно, и команда «не знает» что есть проблема.

Как лечить — mirror-judging

Стандартная методология устранения position bias — mirror-judging. Каждую пару судить дважды:

Дальше засчитываем «B выиграл» только если B победил в обоих ордерах. Если B победил в одном, а A в другом — это tie (значит судья выбирал по позиции, не по содержанию).

Стоимость: 2× больше API-вызовов. Точность: позиционное смещение полностью устраняется (если оно симметрично). Это стандарт в академической литературе и продакшен-RLHF pipelines больших AI-лабораторий.

Численно: при истинном win rate 55% и bias 20 п.п.:

Симулятор ниже показывает эту разницу на разных параметрах.

Симулятор: position bias и стратегии judgment

True win rate B
0.55
Estimated win rate B
Bias
Tie rate

Naive vs Mirror: оценка win rate

Зелёный — истинный win rate. Синий — оценка при текущей стратегии. Серый — tie rate (только для mirror). Красная линия — ±5 п.п. допустимое смещение.

Сравнение всех стратегий

Оценка win rate B при разных стратегиях при текущих параметрах. Горизонтальная линия — истинный win rate.

Что показывает симулятор

  1. Always A first / Always B first — naive. Систематически смещают оценку в сторону или против B на 2× bias_strength.
  2. Random order — снимает «направление» смещения, но добавляет шум. На большой выборке среднее правильное, но variance больше.
  3. Mirror (оба порядка) — единственная стратегия, которая действительно устраняет position bias. Стоимость — 2× API-вызовов на пару.

Главный takeaway: если ваш eval — naive (всегда один порядок), и bias 20 п.п., вы можете легко спутать «equivalent» с «50% хуже» или «50% лучше». Mirror — это не optional, это база.

Полный judgment pipeline

Практическое — как настроить LLM-as-judge pipeline без position bias.

Что генерировать

На N запросов клиентов получаем N пар (response_A, response_B). Это твой dataset для сравнения моделей. Запросы должны быть representative — взять реальные запросы из логов саппорта, не synthetic. Минимум 200–500 пар для статистически значимого вывода.

Что отправлять в judge

Каждую пару отправляем дважды в LLM-судью:

judgment_1 = judge(prompt, response_A, response_B)
judgment_2 = judge(prompt, response_B, response_A)

Логируем оба результата вместе с порядком:

pair_id          — ID пары
order            — "AB" или "BA"
judge_choice     — "first" или "second"
judge_confidence — если judge даёт rationale, тоже логируем

Псевдокод:

for pair in pairs:
    # Order 1: A first
    verdict_1 = call_judge(pair.prompt,
                           first=pair.response_A,
                           second=pair.response_B)
    log(pair_id=pair.id, order="AB", verdict=verdict_1)

    # Order 2: B first
    verdict_2 = call_judge(pair.prompt,
                           first=pair.response_B,
                           second=pair.response_A)
    log(pair_id=pair.id, order="BA", verdict=verdict_2)

Что считать на уровне эксперимента

SQL-агрегация по логам:

WITH paired AS (
  SELECT
    pair_id,
    MAX(CASE WHEN order = 'AB' THEN judge_choice END) AS verdict_AB,
    MAX(CASE WHEN order = 'BA' THEN judge_choice END) AS verdict_BA
  FROM judgments
  WHERE experiment_id = 'llm_judge_q2'
  GROUP BY pair_id
)
SELECT
  COUNT(*) AS total_pairs,
  -- B wins только если выиграл в обоих ордерах
  AVG(CASE
    WHEN verdict_AB = 'second' AND verdict_BA = 'first'
    THEN 1 ELSE 0
  END) AS mirror_winrate_B,
  -- A wins только если выиграл в обоих ордерах
  AVG(CASE
    WHEN verdict_AB = 'first' AND verdict_BA = 'second'
    THEN 1 ELSE 0
  END) AS mirror_winrate_A,
  -- Tie если расходятся
  AVG(CASE
    WHEN (verdict_AB = 'second' AND verdict_BA = 'second')
      OR (verdict_AB = 'first' AND verdict_BA = 'first')
    THEN 1 ELSE 0
  END) AS tie_rate
FROM paired;

Что писать в финальный отчёт

В отчёте для команды:

Не писать просто «win rate B = 55%». Правильная форма: «Mirror-corrected win rate B = 55% (CI 48–62%), tie rate = 18%. Naive win rate без mirror коррекции дал бы 38% из-за position bias. Решение: B equivalent или slightly better; рекомендуется второй раунд с увеличенной выборкой».

Что делать дальше

Минимальный checklist для аналитика, который собирается делать LLM-as-judge сравнение:

Связь с курсом и другими симуляторами

Этот кейс опирается на понятия из курса квазиэкспериментов и дополняет первый AI-evals симулятор: