Évaluation comparative : A ou B
Prompts de comparaison par paires pour classer les sorties sans notation absolue.
Évaluation comparative : A ou B est une leçon AI Prompt Engineering gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Prompt Engineering, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Prompt Engineering comprend 4 leçons au total.
Qu’est-ce que l’évaluation par paires (A contre B) ?
L’évaluation par paires (également appelée évaluation comparative) présente à l’évaluateur deux réponses à la même question et lui demande laquelle est la meilleure. Au lieu de noter une seule réponse de 1 à 5, l’évaluateur porte un jugement relatif : A est meilleure, B est meilleure ou elles sont à égalité.
Cette approche contourne certains biais liés à la notation absolue et produit souvent des classements plus fiables que les notes absolues attribuées à chaque réponse.
Invite de base pour l’évaluation par paires
L’évaluation par paires la plus simple demande quelle réponse est la meilleure et pourquoi. L’essentiel est d’imposer un choix : ne laissez pas l’évaluateur éviter la comparaison avec un vague « les deux sont bonnes ».
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)Randomiser l’ordre pour réduire le biais de position
Le biais de position pousse les évaluateurs à préférer la première option. Pour le neutraliser, effectuez chaque comparaison deux fois : une fois avec A en premier, puis une fois avec B en premier. Ne retenez un gagnant que si les deux ordres aboutissent au même résultat. En cas de désaccord, déclarez une égalité ou soumettez le cas à une évaluation humaine.
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}')Évaluation par paires selon plusieurs critères
Demandez à l’évaluateur de comparer les réponses selon des dimensions précises, plutôt que de lui demander simplement « laquelle est globalement meilleure ? ». La comparaison par paires selon des dimensions précises fournit des informations exploitables sur la raison pour laquelle une réponse est préférée à l’autre.
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)Construire un tournoi : toutes rondes
Lorsque vous comparez plus de deux réponses, utilisez un tournoi toutes rondes : chaque réponse est comparée à toutes les autres. La réponse qui remporte le plus de victoires arrive en tête du classement.
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 rankingClassement Elo pour un classement continu
Pour une évaluation à grande échelle, utilisez les classements Elo plutôt qu’un tournoi toutes rondes. Chaque réponse commence avec 1 000 points. Après chaque comparaison, le gagnant gagne des points et le perdant en perd, en fonction du caractère surprenant du résultat. Après de nombreuses comparaisons, les scores Elo produisent un classement global fiable.
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}')Quand utiliser l’évaluation par paires ou la notation absolue
Utilisez l’évaluation par paires lorsque :
- vous souhaitez classer plusieurs modèles ou variantes d’invites ;
- les seuils de notation absolue sont difficiles à définir ;
- vous comparez des résultats qui sont tous deux « bons », mais de façons différentes.
Utilisez la notation absolue fondée sur une grille lorsque :
- vous avez besoin d’un seuil de réussite ou d’échec (« cette réponse est-elle suffisamment bonne ? ») ;
- vous n’avez qu’une seule réponse à évaluer pour chaque requête ;
- vous avez besoin de notes par critère pour effectuer un diagnostic.
Évaluation par paires échantillonnée à grande échelle
Comparer toutes les paires de N réponses nécessite N*(N-1)/2 comparaisons — O(N^2). Pour une grande valeur de N, utilisez un échantillonnage aléatoire : comparez chaque réponse à K adversaires choisis aléatoirement plutôt qu’à toutes les autres. Cette méthode approxime le classement réel à un coût bien inférieur.
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 rankingInterpréter les désaccords
Lorsque deux ordres aboutissent à des résultats différents (A gagne dans l’ordre A-B, B gagne dans l’ordre B-A), cela signale une comparaison véritablement limite, et pas seulement un biais de position. Ces cas limites méritent une analyse plus approfondie.
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])Journaliser les résultats des évaluations par paires
Journalisez tous les résultats des comparaisons par paires afin de constituer un historique consultable indiquant quelles réponses l’emportent sur lesquelles et dans quelles conditions. Ces données sont précieuses pour les vérifications de régression et pour comprendre l’évolution des modèles au fil du temps.
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'
)Évaluation par paires ou notation absolue : compromis
L’évaluation par paires et la notation absolue fondée sur une grille sont complémentaires, et non concurrentes. Utilisez-les ensemble : la notation absolue permet d’établir un seuil minimal de qualité, tandis que la comparaison par paires permet de classer les candidats qui dépassent ce seuil.
Le principal compromis est le suivant : l’évaluation par paires nécessite O(N^2) comparaisons pour N réponses, tandis que la notation absolue en nécessite O(N). À grande échelle, l’évaluation par paires échantillonnée ou les classements Elo deviennent nécessaires.
Vérification des connaissances : réduire les biais de l’évaluation par paires
Quel est le moyen le plus efficace de réduire le biais de position dans l’évaluation par paires avec un LLM ?
Récapitulatif : évaluation comparative A contre B
L’évaluation par paires demande laquelle de deux réponses est la meilleure, plutôt que de noter chacune selon une échelle absolue. Pour contrôler le biais de position, effectuez chaque comparaison deux fois en inversant l’ordre et n’acceptez que les résultats cohérents. Pour N réponses, utilisez un tournoi toutes rondes (toutes les paires) lorsque N est petit, ou des tournois échantillonnés lorsque N est grand. Les classements Elo produisent des classements continus à partir de nombreuses comparaisons par paires. Utilisez l’évaluation par paires selon les dimensions (exactitude, exhaustivité et clarté séparément) pour obtenir des informations diagnostiques exploitables. Journalisez tous les résultats pour effectuer des vérifications de régression et analyser les tendances entre les versions des modèles.
Apprends AI Prompt Engineering avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 53
- Leçons
- 199
Questions Fréquemment Posées
La leçon « Évaluation comparative : A ou B » est-elle gratuite ?
Oui — le texte complet de « Évaluation comparative : A ou B » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Prompt Engineering, passe à CoddyKit PRO. Le cours AI Prompt Engineering comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Évaluation comparative : A ou B » ?
Prompts de comparaison par paires pour classer les sorties sans notation absolue. Tu pratiques AI Prompt Engineering avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Prompt Engineering ?
Aucune expérience préalable n'est requise. AI Prompt Engineering sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Évaluation comparative : A ou B » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Prompt Engineering ?
Oui. Chaque leçon AI Prompt Engineering inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Utiliser un LLM pour évaluer les sorties d’un LLM
- Prompts d’évaluation fondés sur une grille
- Évaluation comparative : A ou B
- Étalonnage et biais des évaluateurs LLM