0Pricing
AI Prompt Engineering · Lezione

Valutazione comparativa: A contro B

Prompt per il confronto a coppie, per classificare gli output senza un punteggio assoluto

Valutazione comparativa: A contro B è una lezione AI Prompt Engineering gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Prompt Engineering, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Prompt Engineering include 4 lezioni in totale.

Che cos'è la valutazione a coppie (A vs B)

La valutazione a coppie (detta anche valutazione comparativa) presenta al giudice due risposte alla stessa domanda e chiede quale sia migliore. Invece di assegnare a una singola risposta un punteggio da 1 a 5, il giudice formula un giudizio relativo: A è migliore, B è migliore oppure le due risposte sono a pari merito.

Questo approccio evita alcuni bias della valutazione assoluta e spesso produce classifiche più affidabili rispetto ai punteggi assoluti assegnati a ogni risposta.

Prompt di base per il giudice a coppie

Il prompt più semplice per un giudice a coppie chiede quale risposta sia migliore e perché. La chiave consiste nell'imporre una scelta: non permetta al giudice di evitare il confronto con un vago «sono entrambe buone».

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)

Randomizzare l'ordine per ridurre il bias di posizione

Il bias di posizione porta i giudici a preferire la prima opzione. Per neutralizzarlo, esegua ogni confronto due volte: una con A al primo posto e una con B al primo posto. Consideri una risposta vincente solo se i due ordini concordano. In caso contrario, dichiari un pareggio oppure sottoponga il caso alla revisione umana.

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}')

Valutazione a coppie con più criteri

Chieda al giudice di confrontare le risposte in base a dimensioni specifiche, invece di limitarsi a chiedere «quale sia migliore nel complesso». Il confronto a coppie per singola dimensione fornisce indicazioni utili sul perché una risposta sia preferita all'altra.

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)

Costruire un torneo: round-robin

Quando confronta più di due risposte, utilizzi un torneo round-robin: ogni risposta viene confrontata con tutte le altre. La risposta con il maggior numero di vittorie si classifica al primo posto.

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 continua con i punteggi Elo

Per valutazioni su larga scala, utilizzi i punteggi Elo invece del round-robin. Ogni risposta parte da 1000 punti. Dopo ogni confronto, il vincitore guadagna punti e il perdente ne perde, in proporzione a quanto fosse sorprendente il risultato. Dopo molti confronti, i punteggi Elo producono una classifica globale affidabile.

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 utilizzare la valutazione a coppie o quella assoluta

Utilizzi la valutazione a coppie quando:

  • Desidera classificare più modelli o varianti di prompt
  • È difficile definire soglie di punteggio assoluto
  • Sta confrontando risultati entrambi «buoni», ma in modi diversi

Utilizzi la valutazione assoluta (basata su rubriche) quando:

  • Ha bisogno di una soglia di superamento o fallimento («questa risposta è abbastanza buona?»)
  • Ha una sola risposta da valutare per ogni query
  • Ha bisogno di punteggi a livello di criterio per il debugging

Valutazione a coppie basata su campionamento su larga scala

Eseguire tutti i confronti a coppie per N risposte richiede N*(N-1)/2 confronti, ovvero O(N^2). Per valori elevati di N, utilizzi un campionamento casuale: confronti ogni risposta con K avversari scelti casualmente invece che con tutte le altre. In questo modo può approssimare la classifica reale a un costo molto inferiore.

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

Interpretare i disaccordi

Quando i due ordini producono risultati discordanti (A vince nell'ordine A-B, B vince nell'ordine B-A), ciò segnala un confronto realmente borderline, non soltanto un bias di posizione. Questi casi al limite meritano un'analisi più approfondita.

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])

Registrare i risultati dei confronti a coppie

Registri tutti i risultati dei confronti a coppie per creare uno storico consultabile delle risposte che prevalgono sulle altre e delle condizioni in cui ciò avviene. Questi dati sono preziosi per i test di regressione e per comprendere i miglioramenti del modello nel 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'
)

Valutazione a coppie e valutazione assoluta: compromessi

La valutazione a coppie e la valutazione assoluta basata su rubriche sono approcci complementari, non alternativi. Li utilizzi insieme: la valutazione assoluta per stabilire una soglia minima di qualità, il confronto a coppie per classificare i candidati che superano tale soglia.

Il compromesso principale è il seguente: il confronto a coppie richiede O(N^2) confronti per N risposte, mentre la valutazione assoluta richiede O(N). Su larga scala, diventano necessari il confronto a coppie basato su campionamento o i punteggi Elo.

Verifica delle conoscenze: eliminare il bias nella valutazione a coppie

Qual è il modo più efficace per ridurre il bias di posizione nella valutazione a coppie con LLM?

Riepilogo: valutazione comparativa A vs B

La valutazione a coppie chiede quale delle due risposte sia migliore, invece di assegnare a ciascuna un punteggio su una scala assoluta. Per controllare il bias di posizione, esegua ogni confronto due volte scambiando l'ordine e accetti solo i risultati coerenti. Per N risposte, utilizzi il round-robin (tutte le coppie) per valori piccoli di N oppure tornei basati su campionamento per valori elevati. I punteggi Elo producono classifiche continue a partire da molti confronti a coppie. Utilizzi la valutazione a coppie per dimensione (accuratezza, completezza e chiarezza separatamente) per ottenere indicazioni diagnostiche utili. Registri tutti i risultati per i test di regressione e l'analisi dell'andamento tra le versioni del modello.

Domande Frequenti

La lezione «Valutazione comparativa: A contro B» è gratuita?

Sì — il testo completo di «Valutazione comparativa: A contro B» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Prompt Engineering, passa a CoddyKit PRO. Il corso AI Prompt Engineering include 4 lezioni in totale.

Cosa imparerò in «Valutazione comparativa: A contro B»?

Prompt per il confronto a coppie, per classificare gli output senza un punteggio assoluto Eserciti AI Prompt Engineering con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare AI Prompt Engineering?

Non è richiesta alcuna esperienza precedente. AI Prompt Engineering su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Valutazione comparativa: A contro B»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione AI Prompt Engineering?

Sì. Ogni lezione AI Prompt Engineering include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Uso degli LLM per valutare gli output degli LLM
  2. Prompt di valutazione basati su rubriche
  3. Valutazione comparativa: A contro B
  4. Calibrazione e bias nei giudici LLM
← Torna a AI Prompt Engineering