LLM-as-a-Judge у 2026: автоматична оцінка виводу LLM з Python-прикладами

Практичний гайд з LLM-as-a-Judge у 2026: як побудувати автоматичного суддю відповідей LLM на Python з Claude API, які упередження очікувати, як зробити meta-evaluation і які фреймворки (DeepEval, Ragas, promptfoo) обрати для продакшену.

LLM-as-a-Judge 2026: Python-гайд

Оновлено: 30 липня 2026

LLM-as-a-Judge — це патерн автоматичної оцінки, коли одна велика мовна модель оцінює вивід іншої за заздалегідь сформульованою рубрикою, замінюючи (або доповнюючи) ручну розмітку. У 2026 році це фактично стандартний спосіб оцінювати відкриті відповіді LLM у продакшені: він масштабується, коштує в десятки разів дешевше за людську оцінку і при правильному дизайні досягає узгодженості з експертами на рівні 0,7–0,85 за коефіцієнтом Коена. Нижче розберемо, як побудувати такого суддю, які помилки він робить типово, і як мати з ним справу без самообману.

  • LLM-as-a-Judge масштабує оцінку відкритих відповідей, де класичні метрики (BLEU, ROUGE) провалюються.
  • Три робочі схеми: pointwise (одна відповідь + шкала), pairwise (A vs B) і reference-based (порівняння з еталоном). Pairwise стабільніша, але дорожча.
  • Судді страждають від position bias, verbosity bias і self-preference bias, і все це виправляється рандомізацією порядку, обмеженням довжини та вибором нейтральної моделі.
  • Без meta-evaluation (порівняння суддя ↔ людина на 100–300 прикладах) ви не знаєте, чи оцінка взагалі корелює з реальністю.
  • Продакшн-архітектура складається з двох контурів: офлайн-evals у CI на регресії і онлайн-sampling 1–5% трафіку для дрейфу.
  • DeepEval, Ragas, promptfoo і LangSmith покривають 90% типових задач, тож писати власний фреймворк майже ніколи не потрібно.

Що таке LLM-as-a-Judge і коли він потрібен

LLM-as-a-Judge, це підхід, у якому окрема LLM-модель (найчастіше сильніша або принаймні незалежна від тестованої) виступає у ролі автоматичного оцінювача. Ви даєте їй вхід користувача, згенеровану відповідь і рубрику, а вона повертає структуровану оцінку: бал, категорію та (у гарному дизайні) обґрунтування. Ідея не нова: Zheng et al. у роботі Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena формально показали, що GPT-4 як суддя досягає узгодженості з людьми на рівні узгодженості людей між собою (~80%). Відтоді патерн став дефолтом для оцінки чат-ботів, RAG-систем та агентів.

Питання «навіщо він потрібен» найкраще формулюється від зворотного. Класичні метрики (BLEU, ROUGE, exact match) працюють лише коли є один правильний рядок для порівняння. У 90% реальних LLM-задач правильних відповідей кілька: «пояснити концепцію», «переписати політично коректно», «згенерувати SQL за описом», «підсумувати документ». Тут потрібен саме семантичний суддя, і в 2026 таким суддею стало нормально робити ще одну LLM. Ручна розмітка не масштабується: 500 прикладів на реліз, це кілька людино-днів анотаторів, а команди хочуть прогонити тисячі evals у кожному PR. Отже, LLM-as-a-Judge закриває цю яму. Але, як побачимо далі, лише якщо ви його калібруєте.

Три схеми оцінки: pointwise, pairwise, reference-based

На верхньому рівні всі LLM-судді розкладаються на три схеми. Вибір між ними, це компроміс між вартістю, стабільністю оцінки і тим, що саме ви вимірюєте.

КритерійPointwise (абсолютна шкала)Pairwise (A vs B)Reference-based
Вхід1 відповідь + рубрика2 відповіді + рубрикаВідповідь + еталон
ВивідБал (1–5 / 0–10)Переможець або нічияБал схожості з еталоном
Вартість (токенів)Низька~2× pointwiseСередня
Стабільність між прогонамиПомірна (шкала «пливе»)ВисокаВисока
Основне упередженняScore inflationPosition biasRigid matching
Коли обиратиРегресії окремих критеріївПорівняння моделей або prompt-варіантівТестування з ground truth

Pointwise, це найпростіший варіант: даємо одну відповідь і просимо оцінити її за шкалою. Гарно підходить для окремих критеріїв («toxicity 0–5», «faithfulness 0–1»), але шкала «пливе» між днями і моделями: суддя, що вчора ставив 4, сьогодні поставить 3 за ідентичну відповідь. Тому pointwise завжди треба сполучати з бінарною версією «pass/fail за threshold».

Pairwise: суддя порівнює дві відповіді і обирає кращу. Це найстабільніша схема, бо усуває проблему шкали. Мінус у тому, що треба виконати рандомізацію порядку (див. розділ про упередження) і платити за два виклики генерації. Використовуйте pairwise, коли обираєте між моделями, prompt-варіантами або новим/старим релізом.

Reference-based потрібен, якщо у вас є «золоті» відповіді від експертів. Суддя оцінює семантичну близькість відповіді до еталону. Це компроміс між семантикою і структурою: ви отримуєте детермінованість, але втрачаєте здатність оцінити альтернативні валідні відповіді. Практично корисно у RAG (там еталон часто є) і в narrow-задачах на кшталт SQL-генерації.

Мінімальна імплементація на Python з Claude API

Отже, до коду. Нижче наводжу мінімальну робочу імплементацію pairwise-судді на Anthropic Claude API. Код повністю робочий (протестовано на anthropic==0.42.0, Claude Opus 5) і містить дві ключові речі, які пропускають у 90% туторіалів: рандомізацію порядку відповідей і structured output через tool use. Я сам цей патерн доводив до пуття в кількох проєктах, тож ці два кроки не косметичні, а рятувальні.

import os
import json
import random
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

JUDGE_TOOL = {
    "name": "record_verdict",
    "description": "Record the pairwise judgment.",
    "input_schema": {
        "type": "object",
        "properties": {
            "winner": {
                "type": "string",
                "enum": ["A", "B", "tie"],
                "description": "Which response better satisfies the rubric."
            },
            "reasoning": {
                "type": "string",
                "description": "1-3 sentence justification, grounded in the rubric."
            },
            "confidence": {
                "type": "number",
                "minimum": 0.0,
                "maximum": 1.0
            }
        },
        "required": ["winner", "reasoning", "confidence"]
    }
}

JUDGE_SYSTEM = """You are an impartial evaluator. Judge responses ONLY against
the provided rubric. Ignore response length, formatting flair, and self-praise.
If both responses are equivalent within the rubric, return 'tie'."""

def judge_pair(question: str, resp_a: str, resp_b: str, rubric: str) -> dict:
    # Randomize order to defeat position bias.
    swap = random.random() < 0.5
    left, right = (resp_b, resp_a) if swap else (resp_a, resp_b)

    user_msg = (
        f"QUESTION:\n{question}\n\n"
        f"RUBRIC:\n{rubric}\n\n"
        f"RESPONSE A:\n{left}\n\n"
        f"RESPONSE B:\n{right}\n\n"
        "Think step by step, then call record_verdict."
    )

    msg = client.messages.create(
        model="claude-opus-5",
        max_tokens=1024,
        system=JUDGE_SYSTEM,
        tools=[JUDGE_TOOL],
        tool_choice={"type": "tool", "name": "record_verdict"},
        messages=[{"role": "user", "content": user_msg}],
    )

    tool_use = next(b for b in msg.content if b.type == "tool_use")
    verdict = tool_use.input

    # Unswap so the caller always sees the original labels.
    if swap and verdict["winner"] in ("A", "B"):
        verdict["winner"] = "B" if verdict["winner"] == "A" else "A"
    return verdict


if __name__ == "__main__":
    result = judge_pair(
        question="Explain what a database index is to a junior developer.",
        resp_a="An index is like a book index - it lets the DB find rows without scanning the whole table.",
        resp_b="B-trees are the fundamental data structure...",
        rubric="Score highest the response that is accurate, uses a concrete analogy, and stays under 80 words.",
    )
    print(json.dumps(result, indent=2))

Той самий підхід (structured output через tool use + рандомізація) працює для pointwise: просто замініть схему на {"score": int, "reasoning": str}. Якщо ви робите багато оцінок на однакову рубрику, зверніть увагу на prompt caching у Claude API: рубрика і system prompt стають cache-hit і зменшують вартість судді у 8–10 разів.

Типові упередження LLM-суддів і як їх зменшити

Судді системно помиляються, і ці помилки не випадкові. Вони мають назви й документовані ефекти. Ігнорувати їх означає отримати evals, які показують «все чудово», поки продукт деградує.

Position bias

У pairwise LLM непропорційно часто обирає першу (або останню, залежить від моделі) відповідь. У згаданій вище роботі Zheng et al. GPT-4 демонстрував ~65% преференції першої позиції в неоднозначних випадках. Лікується рандомізацією порядку на кожен виклик (як у коді вище). Додатковий крок: виконувати кожне порівняння двічі з обома порядками і рахувати «tie», якщо результати не збігаються.

Verbosity bias

Довші відповіді автоматично отримують вищі бали, навіть коли рубрика цього не вимагає. Це особливо гостро для GPT-моделей у ролі суддів. Мітигації: явно обмежте довжину в рубриці («відповіді, довші за X слів, штрафуються за нерелевантні токени»), або нормалізуйте, розділивши бал на log(довжину).

Self-preference bias

Модель, оцінюючи власні відповіді, ставить їм у середньому на 10–20% вищий бал. Тому ніколи не використовуйте ту саму модель, що генерує, у ролі судді для порівняння з іншими моделями. Мінімальне правило: якщо тестуєте GPT-5, беріть Claude Opus 5 як суддю, і навпаки.

Chain-of-thought як засіб проти упереджень

Емпірично, судді, які спочатку пишуть 2–4 речення обґрунтування, а потім видають бал, менш схильні до position bias і verbosity bias. У коді вище я примусово прошу reasoning у tool schema до того, як виводиться winner. Це коштує ~200 додаткових токенів на виклик, але дає стабільніший результат.

Дизайн рубрики: критерії, які реально працюють

Погана рубрика знецінює будь-якого суддю. Я бачив команди, які ставили рубрику «оцініть якість відповіді від 1 до 10» і потім здивовано дивились, чому оцінки шумлять. Робоча рубрика має три властивості: атомарність, операціональність і приклади.

Атомарність. Один суддя = один критерій. Замість «оцініть якість» розкладіть на: faithfulness (чи не галюцинує), relevance (чи відповідає на питання), style (тон), safety (токсичність). Кожен з них, окремий виклик судді. Це дорожче, але результати інтерпретовані: ви бачите, який саме критерій просів.

Операціональність. Опишіть, що робить оцінку «4» відмінною від «3». Приклад для faithfulness у RAG:

  • 5: усі твердження прямо підтверджені контекстом.
  • 3: одне твердження частково не підтверджене, але немає прямих суперечностей.
  • 1: є хоча б одне пряме твердження, що суперечить контексту (галюцинація).

Це драматично зменшує розкид оцінок між прогонами.

Приклади (few-shot). Дайте у рубриці 2–3 повних приклади з поясненням, чому саме такий бал. Це найдешевша інвестиція в стабільність оцінки. Особливо критично для edge-cases: суддя повинен побачити, як ви класифікуєте «майже правильну» відповідь, інакше він видасть свою інтерпретацію.

Meta-evaluation: як переконатися, що суддя надійний

Найпоширеніша помилка команд, які починають з LLM-as-a-Judge, це «прикрутили і поїхали». Без meta-evaluation ви не знаєте, чи оцінка вашого судді взагалі корелює з реальністю. Meta-eval, це разова, але обов'язкова інвестиція: беремо 100–300 прикладів, розмічаємо їх експертами, і рахуємо узгодженість судді з людьми.

Робочий процес:

  1. Зберіть 150–300 репрезентативних прикладів (важливо: не лише easy cases; шукайте контрверсійні).
  2. Дайте розмітити двом-трьом експертам незалежно. Порахуйте inter-annotator agreement (Cohen's kappa або Krippendorff's alpha). Якщо люди між собою не узгоджуються (κ < 0.4), проблема в задачі, а не в судді.
  3. Прогоніть суддю по тому ж набору.
  4. Порахуйте узгодженість суддя ↔ людина за тим самим κ. Ціль: κ ≥ 0.6, ідеально 0.7+.
  5. Якщо не досягли, ітеруйте рубрику, додайте few-shot, спробуйте іншу модель. Повторіть.

Meta-evaluation, це те, що відділяє «ми маємо evals» від «ми маємо evals, яким довіряємо». Пропущений крок обходиться дорожче будь-якої іншої економії часу в цьому пайплайні. Чесно кажучи, я хіба раз бачив, щоб команда пошкодувала про час, витрачений на meta-eval.

Фреймворки 2026: DeepEval, Ragas, promptfoo, LangSmith

Писати LLM-as-a-Judge з нуля має сенс лише якщо у вас нестандартні критерії. Для 90% задач достатньо готових фреймворків. Ось короткий орієнтир, що коли обирати у 2026.

DeepEval

Open-source Python-фреймворк від Confident AI, побудований у стилі pytest. Найкраще для одиничних тестів LLM-відповідей у CI. Має вбудовані метрики G-Eval (LLM-as-a-Judge з ланцюжком думки), hallucination, toxicity, bias. Інтегрується з pytest, тож ваш GitHub Actions прогоняє evals як звичайні тести. Мій вибір, коли треба «швидко прикрутити evals до існуючого CI».

Ragas

Спеціалізований на RAG-системах. Реалізує метрики faithfulness, context precision, context recall, answer relevance, тобто рівно те, що вам потрібно для оцінки retrieval-augmented пайплайну. Якщо ви будуєте agentic RAG з LangGraph, ставте Ragas у CI одразу. Документація й приклади доступні на офіційному сайті Ragas.

promptfoo

YAML-декларативний фреймворк для порівняння prompt-варіантів або моделей. Ідеальний для локальної ітерації над промптами: пишете YAML з тестами, запускаєте promptfoo eval, отримуєте матрицю. Має вбудовані LLM-as-a-Judge assertions і red-teaming-модуль. Оберіть його, якщо основна задача полягає в тому, щоб optimize a prompt, а не тестувати систему цілком.

LangSmith

Комерційний продукт від LangChain для трейсингу і оцінки. Дає найкращу візуалізацію продакшн-трасів і human-in-the-loop розмітку. Обов'язковий, якщо ви вже на LangChain/LangGraph та хочете centralised evals. Дорожче за open-source, але зберігає час на інфраструктуру. Офіційна документація доступна на docs.smith.langchain.com.

Мій особистий стек у 2026: promptfoo для prompt-ітерації локально, DeepEval у CI, Ragas окремо для RAG-метрик, і власна тонка інтеграція для онлайн-sampling у продакшені. Це надлишок для маленьких проєктів (там достатньо одного promptfoo).

Продакшн-паттерн: офлайн- vs онлайн-оцінка

Робочий продакшн-паттерн для LLM-as-a-Judge складається з двох незалежних контурів.

Офлайн-контур живе в CI. У вас є фіксований eval-набір (~300–1000 прикладів), який покриває критичні сценарії і регресії. На кожен PR прогоняються всі судді по всьому набору, порівнюються з baseline попередньої версії. Якщо агрегатна оцінка просіла більш ніж на, скажімо, 3%, CI фейлиться. Цей паттерн ловить регресії від змін промптів або моделей.

Онлайн-контур живе у продакшені. Ви семплюєте 1–5% реального трафіку і асинхронно (щоб не збільшувати p95 latency) проганяєте його через тих самих суддів. Результати пишете у BigQuery / Snowflake / Prometheus і моніторите dashboard дрейфу. Цей контур ловить речі, які офлайн-набір не побачить: зміну розподілу запитів користувачів, регресії від оновлень базової моделі провайдером, seasonal effects.

Якщо ви будуєте мультиагентну систему і думаєте, як оцінювати кроки агента окремо від фінальної відповіді, раджу подивитися огляд LangGraph vs CrewAI vs AutoGen: кожен з них по-різному експонує проміжні кроки для оцінки, і це критично для agent evals.

Технічну глибину теми і посилання на актуальні дослідження щодо надійності LLM-суддів можна знайти в офіційній документації Anthropic з оцінки промптів.

Часті запитання

Наскільки надійний LLM-as-a-Judge порівняно з людською оцінкою?

За правильної рубрики і калібрування узгодженість судді з експертом досягає κ = 0.7–0.85, тобто рівень узгодженості людей між собою. Але без meta-evaluation ви цієї цифри просто не знаєте. Правило: жодного продакшн-контуру без разової валідації суддя ↔ людина на 100–300 прикладах.

Чи можна використовувати ту саму модель для генерації і оцінки?

Ні, якщо ви порівнюєте різні моделі: через self-preference bias суддя завищить оцінку «своїм» відповідям на 10–20%. Для оцінки регресій в одній моделі це прийнятно, для порівняння моделей беріть нейтрального суддю.

Що дешевше: DeepEval чи Ragas?

Обидва open-source, тому вартість це лише токени LLM-провайдера. Ragas зазвичай дорожчий на прогон, бо його метрики (context precision/recall) роблять більше викликів на кожен приклад. DeepEval простіший і легший, але вужчий у RAG-специфіці.

Як зменшити position bias у pairwise-судді?

Рандомізуйте порядок A/B на кожному виклику, а в критичних evals запускайте кожне порівняння двічі з обома порядками. Якщо результати не збігаються, рахуйте це як «tie». Це подвоює вартість, але дає стабільний ground truth для baseline'ів.

Скільки прикладів потрібно в eval-наборі?

Для стабільної CI-регресії мінімум 200 прикладів; практично краще 500–1000. Менше 100, і одна флюктуація судді дає значущий зсув агрегату. Головне не число, а покриття: категорії задач, edge-cases, adversarial-приклади мають бути представлені пропорційно.

Чи потрібен LLM-as-a-Judge, якщо є класичні метрики?

BLEU, ROUGE та exact match працюють лише для задач з єдиною правильною відповіддю (переклад, SQL-генерація за жорсткою специфікацією). Для будь-якої відкритої генерації (чат, підсумки, пояснення) вони корелюють з людською оцінкою слабо (r < 0.3). Там LLM-as-a-Judge, єдина масштабована опція.

Nikhil Verma
Про Автора Nikhil Verma

AI automation engineer chaining LLMs into workflows that actually work. Bullish on tool use; bearish on prompt theatre.