0Pricing
AI Prompt Engineering · Aula

Avaliação comparativa: A versus B

Prompts de comparação em pares para classificar saídas sem uma pontuação absoluta.

Avaliação comparativa: A versus B é uma aula grátis de AI Prompt Engineering no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Prompt Engineering, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Prompt Engineering inclui 4 aulas no total.

O que é avaliação aos pares (A versus B)?

Avaliação aos pares (também chamada de avaliação comparativa) apresenta ao avaliador duas respostas para a mesma pergunta e pergunta qual é melhor. Em vez de atribuir uma nota de 1 a 5 a uma única resposta, o avaliador faz um julgamento relativo: A é melhor, B é melhor ou há empate.

Essa abordagem contorna alguns vieses da pontuação absoluta e geralmente produz classificações mais confiáveis do que as pontuações absolutas por resposta.

Instrução básica para avaliação aos pares

A instrução mais simples para avaliação aos pares pergunta qual resposta é melhor e por quê. O essencial é exigir uma escolha — não permita que o avaliador evite a comparação com um vago «ambas são boas».

import anthropic
import json

client = anthropic.Anthropic(api_key='sk-ant-...')

PAIRWISE_PROMPT = (
    'Given the same question, compare these two responses and decide which is better.\n\n'
    'Question: {question}\n\n'
    'Response A:\n{response_a}\n\n'
    'Response B:\n{response_b}\n\n'
    'Which response is better? You must pick A, B, or TIE (use TIE only if '
    'they are truly equal in all meaningful ways).\n\n'
    'Return JSON: {{"winner": "A" or "B" or "TIE", '
    '"reason": "<one sentence explaining why the winner is better>"}}'
)

def pairwise_judge(question, response_a, response_b):
    prompt = PAIRWISE_PROMPT.format(
        question=question,
        response_a=response_a,
        response_b=response_b
    )
    r = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=150,
        messages=[{'role': 'user', 'content': prompt}]
    )
    return json.loads(r.content[0].text)

result = pairwise_judge(
    'What is machine learning?',
    'Machine learning is a subset of AI.',
    'Machine learning is a method of data analysis that automates model building.'
)
print(result)

Aleatorização da ordem para reduzir o viés de posição

O viés de posição faz com que os avaliadores prefiram a primeira opção. Para neutralizá-lo, execute cada comparação duas vezes: uma com A primeiro e outra com B primeiro. Só considere um vencedor quando as duas ordenações concordarem. Se houver discordância, declare empate ou encaminhe o caso para análise humana.

import anthropic
import json
import random

client = anthropic.Anthropic(api_key='sk-ant-...')

def debiased_pairwise_judge(question, response_a, response_b):
    def single_comparison(first, second, first_label, second_label):
        prompt = (
            f'Question: {question}\n\n'
            f'Response {first_label}:\n{first}\n\n'
            f'Response {second_label}:\n{second}\n\n'
            f'Which is better? Reply with {first_label}, {second_label}, or TIE.'
        )
        r = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=10,
            messages=[{'role': 'user', 'content': prompt}]
        )
        return r.content[0].text.strip()

    # Run A-first
    result_ab = single_comparison(response_a, response_b, 'A', 'B')
    # Run B-first
    result_ba = single_comparison(response_b, response_a, 'B', 'A')

    if result_ab == 'A' and result_ba == 'A':
        return 'A', 'Consistent: A wins in both orderings'
    elif result_ab == 'B' and result_ba == 'B':
        return 'B', 'Consistent: B wins in both orderings'
    else:
        return 'TIE', f'Inconsistent: {result_ab} then {result_ba} — position bias detected'

winner, reason = debiased_pairwise_judge(
    'Explain a hash table.',
    'A hash table maps keys to values.',
    'A hash table is a data structure using a hash function to store key-value pairs for O(1) lookup.'
)
print(f'Winner: {winner} — {reason}')

Avaliação aos pares com vários critérios

Peça ao avaliador que compare dimensões específicas, em vez de perguntar apenas «qual é melhor no geral?». A comparação aos pares por dimensão fornece um sinal acionável sobre por que uma resposta é preferida.

import anthropic
import json

client = anthropic.Anthropic(api_key='sk-ant-...')

DIMENSIONAL_PAIRWISE = (
    'Compare Response A and Response B on each dimension.\n\n'
    'Question: {question}\n\n'
    'Response A: {response_a}\n\n'
    'Response B: {response_b}\n\n'
    'For each dimension, say A, B, or TIE:\n'
    '1. ACCURACY: Which is more factually correct?\n'
    '2. COMPLETENESS: Which answers the question more fully?\n'
    '3. CLARITY: Which is easier to understand?\n'
    '4. CONCISENESS: Which avoids unnecessary length?\n\n'
    'Return JSON: {{"accuracy":"A/B/TIE", "completeness":"A/B/TIE", '
    '"clarity":"A/B/TIE", "conciseness":"A/B/TIE", "overall":"A/B/TIE"}}'
)

def dimensional_compare(question, a, b):
    r = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=200,
        messages=[{'role': 'user', 'content': DIMENSIONAL_PAIRWISE.format(
            question=question, response_a=a, response_b=b
        )}]
    )
    return json.loads(r.content[0].text)

result = dimensional_compare(
    'How does HTTPS work?',
    'HTTPS encrypts web traffic using SSL/TLS.',
    'HTTPS secures HTTP using TLS. The browser and server perform a handshake, exchange certificates, and establish an encrypted channel for all data transfer.'
)
print(result)

Construindo um torneio: todos contra todos

Ao comparar mais de duas respostas, use um torneio todos contra todos: cada resposta é comparada com todas as outras. A resposta com mais vitórias fica em primeiro lugar.

from itertools import combinations
from collections import defaultdict

def round_robin_tournament(question, responses):
    """
    responses: list of (label, text) tuples
    Returns ranking by win count.
    """
    wins = defaultdict(int)
    ties = defaultdict(int)

    # Every pair compared once
    for (label_a, text_a), (label_b, text_b) in combinations(responses, 2):
        winner, reason = debiased_pairwise_judge(question, text_a, text_b)

        if winner == 'A':
            wins[label_a] += 1
        elif winner == 'B':
            wins[label_b] += 1
        else:  # TIE
            ties[label_a] += 1
            ties[label_b] += 1

        print(f'{label_a} vs {label_b}: {winner}')

    # Rank by wins, then ties
    ranking = sorted(
        responses,
        key=lambda x: (wins[x[0]], ties[x[0]]),
        reverse=True
    )
    print('\nFinal ranking:')
    for i, (label, _) in enumerate(ranking, 1):
        print(f'{i}. {label}: {wins[label]} wins, {ties[label]} ties')
    return ranking

Classificação Elo para ranqueamento contínuo

Para avaliações em grande escala, use classificações Elo em vez de um torneio todos contra todos. Cada resposta começa com 1000 pontos. Após cada comparação, o vencedor ganha pontos e o perdedor perde pontos, proporcionalmente ao quão surpreendente foi o resultado. Depois de muitas comparações, as pontuações Elo produzem uma classificação global confiável.

import math

def elo_update(rating_a, rating_b, winner, k=32):
    """
    Update Elo ratings after a match.
    winner: 'A' (A won), 'B' (B won), 'TIE' (draw)
    Returns (new_rating_a, new_rating_b)
    """
    expected_a = 1 / (1 + 10 ** ((rating_b - rating_a) / 400))
    expected_b = 1 - expected_a

    if winner == 'A':
        score_a, score_b = 1, 0
    elif winner == 'B':
        score_a, score_b = 0, 1
    else:  # TIE
        score_a, score_b = 0.5, 0.5

    new_a = rating_a + k * (score_a - expected_a)
    new_b = rating_b + k * (score_b - expected_b)
    return new_a, new_b

# Simulate ratings for 4 model variants
ratings = {'ModelA': 1000, 'ModelB': 1000, 'ModelC': 1000, 'ModelD': 1000}

# After running many pairwise comparisons:
ratings['ModelA'], ratings['ModelB'] = elo_update(ratings['ModelA'], ratings['ModelB'], 'A')
ratings['ModelC'], ratings['ModelD'] = elo_update(ratings['ModelC'], ratings['ModelD'], 'TIE')

ranking = sorted(ratings.items(), key=lambda x: x[1], reverse=True)
for model, score in ranking:
    print(f'{model}: {score:.0f}')

Quando usar avaliação aos pares versus pontuação absoluta

Use a avaliação aos pares quando:

  • Desejar classificar vários modelos ou variantes de instrução
  • For difícil definir limites de pontuação absoluta
  • Estiver comparando resultados que são ambos «bons», mas de maneiras diferentes

Use a pontuação absoluta (por rubrica) quando:

  • Precisar de um limite de aprovação/reprovação («esta resposta é boa o suficiente?»)
  • Tiver apenas uma resposta para avaliar por consulta
  • Precisar de pontuações por critério para depuração

Avaliação aos pares por amostragem em escala

Executar todos os pares para N respostas exige N*(N-1)/2 comparações — O(N^2). Para valores grandes de N, use amostragem aleatória: compare cada resposta com K oponentes aleatórios, em vez de todas as outras. Isso aproxima a classificação verdadeira a um custo muito menor.

import random
from collections import defaultdict

def sampled_tournament(question, responses, k_opponents=5):
    """
    Compare each response against k random opponents.
    More efficient than full round-robin for large N.
    """
    wins = defaultdict(int)
    n = len(responses)

    for i, (label, text) in enumerate(responses):
        # Sample k random opponents (not self)
        opponent_indices = random.sample(
            [j for j in range(n) if j != i],
            min(k_opponents, n - 1)
        )
        for j in opponent_indices:
            opp_label, opp_text = responses[j]
            winner, _ = debiased_pairwise_judge(question, text, opp_text)
            if winner == 'A':
                wins[label] += 1
            elif winner == 'B':
                wins[opp_label] += 1

    ranking = sorted(responses, key=lambda x: wins[x[0]], reverse=True)
    for i, (label, _) in enumerate(ranking, 1):
        print(f'{i}. {label}: {wins[label]} wins')
    return ranking

Interpretando discordâncias

Quando as duas ordenações discordam (A vence na ordem A-B, B vence na ordem B-A), isso indica uma comparação genuinamente limítrofe — não apenas viés de posição. Esses casos limítrofes merecem uma análise mais profunda.

import anthropic
import json

client = anthropic.Anthropic(api_key='sk-ant-...')

def deep_analyze_tie(question, response_a, response_b):
    """When A vs B is a genuine tie, ask the judge to explain strengths of each."""
    analysis_prompt = (
        f'These two responses to the same question are closely matched in quality.\n\n'
        f'Question: {question}\n\n'
        f'Response A: {response_a}\n\n'
        f'Response B: {response_b}\n\n'
        f'Analyze both:\n'
        f'1. What does A do better than B?\n'
        f'2. What does B do better than A?\n'
        f'3. For what audience or context would you prefer A?\n'
        f'4. For what audience or context would you prefer B?'
    )
    r = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=400,
        messages=[{'role': 'user', 'content': analysis_prompt}]
    )
    return r.content[0].text

analysis = deep_analyze_tie(
    'Explain async/await in Python.',
    'Async/await allows non-blocking code execution.',
    'Async/await lets you write asynchronous code that looks synchronous, '
    'using the asyncio event loop to handle I/O without blocking.'
)
print(analysis[:300])

Registrando resultados da avaliação aos pares

Registre todos os resultados das comparações aos pares para construir um registro pesquisável de quais respostas superaram quais e em que condições. Esses dados são valiosos para testes de regressão e para compreender as melhorias do modelo ao longo do tempo.

import json
import datetime

def logged_pairwise(question, response_a, response_b,
                    label_a='A', label_b='B', log_file='pairwise_log.jsonl'):
    winner, reason = debiased_pairwise_judge(question, response_a, response_b)

    entry = {
        'timestamp': datetime.datetime.utcnow().isoformat(),
        'question': question[:100],  # Truncate for storage
        'label_a': label_a,
        'label_b': label_b,
        'winner': winner,
        'reason': reason,
        'response_a_length': len(response_a.split()),
        'response_b_length': len(response_b.split()),
    }

    with open(log_file, 'a') as f:
        f.write(json.dumps(entry) + '\n')

    print(f'{label_a} vs {label_b}: {winner} — {reason}')
    return winner

logged_pairwise(
    'What is SQL?',
    'SQL is a database query language.',
    'SQL (Structured Query Language) is used to query and manage relational databases.',
    label_a='ModelV1',
    label_b='ModelV2'
)

Avaliação aos pares versus pontuação absoluta: compensações

A avaliação aos pares e a pontuação absoluta por rubrica são abordagens complementares, não concorrentes. Use-as em conjunto: a pontuação absoluta para estabelecer um nível mínimo de qualidade, e a comparação aos pares para classificar os candidatos acima desse nível.

A principal compensação é: a avaliação aos pares exige O(N^2) comparações para N respostas, enquanto a pontuação absoluta exige O(N). Em grande escala, a avaliação aos pares por amostragem ou as classificações Elo tornam-se necessárias.

Verificação de conhecimento: Redução de viés na avaliação aos pares

Qual é a maneira mais eficaz de reduzir o viés de posição na avaliação aos pares com LLM?

Recapitulação: Avaliação comparativa A versus B

A avaliação aos pares pergunta qual de duas respostas é melhor, em vez de atribuir uma pontuação absoluta a cada uma. Para controlar o viés de posição, execute cada comparação duas vezes, invertendo a ordem, e aceite apenas resultados consistentes. Para N respostas, use um torneio todos contra todos (todos os pares) quando N for pequeno ou torneios por amostragem quando N for grande. As classificações Elo produzem classificações contínuas a partir de muitas comparações aos pares. Use o julgamento aos pares por dimensão (precisão, completude e clareza separadamente) para obter um sinal diagnóstico acionável. Registre todos os resultados para testes de regressão e análise de tendências entre versões do modelo.

Perguntas Frequentes

A aula “Avaliação comparativa: A versus B” é grátis?

Sim — o texto completo de “Avaliação comparativa: A versus B” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Prompt Engineering, atualize para CoddyKit PRO. O curso de AI Prompt Engineering inclui 4 aulas no total.

O que vou aprender em “Avaliação comparativa: A versus B”?

Prompts de comparação em pares para classificar saídas sem uma pontuação absoluta. Você pratica AI Prompt Engineering com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Prompt Engineering?

Nenhuma experiência prévia é necessária. AI Prompt Engineering no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Avaliação comparativa: A versus B”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Prompt Engineering?

Sim. Cada aula de AI Prompt Engineering inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Usando LLM para avaliar saídas de LLM
  2. Prompts de pontuação baseados em critérios
  3. Avaliação comparativa: A versus B
  4. Calibração e vieses em avaliadores LLM
← Voltar para AI Prompt Engineering