0Pricing
AI Prompt Engineering · 강의

LLM 심사자의 보정과 편향

위치 편향과 장황함 편향을 알아보고 심사 프롬프트에서 이를 완화하는 방법을 배웁니다.

LLM 심사자의 보정과 편향은(는) CoddyKit의 무료 AI Prompt Engineering 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Prompt Engineering 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Prompt Engineering 강의에는 총 4개의 강의가 포함되어 있습니다.

평가자 보정이 중요한 이유

특정 유형의 응답을 실제 가치보다 체계적으로 높게 평가하는 LLM 심사자는 오해를 불러일으키는 평가 결과를 만듭니다. 평가자가 실제 품질이 아니라 장황한 문체를 선호했기 때문에 더 나쁜 모델을 출시할 수도 있습니다.

보정이란 평가자의 점수가 실제 품질을 정확하게 반영하는 것을 의미합니다. 보정된 평가자는 측정 가능한 비율로 사람 평가자와 일치하며, 품질과 무관한 특정 속성을 체계적으로 선호하지 않습니다.

위치 편향: 심층 분석

위치 편향은 LLM 평가자 편향 중 가장 강력하고 가장 많이 연구된 편향입니다. 쌍별 비교에서 평가자는 품질과 관계없이 60~65%의 경우 첫 번째 선택지를 선호합니다. 이는 앞면이 60%의 확률로 나오는 동전과 같으며, 규모가 커지면 유의미한 차이가 됩니다.

이 편향이 존재하는 이유는 LLM이 이어지는 내용을 생성하도록 학습되었기 때문입니다. ‘응답 A:’를 먼저 보면 B를 읽기 전에 A를 향하도록 미리 유도됩니다.

import anthropic

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

def measure_position_bias(question, n_pairs=20):
    """
    Measure position bias by comparing IDENTICAL responses.
    If both responses are the same, wins should be 50/50.
    Any deviation from 50/50 is pure position bias.
    """
    response = 'Machine learning is a subset of AI that learns from data.'
    first_wins = 0

    for _ in range(n_pairs):
        prompt = (
            f'Which response is better?\nQ: {question}\n'
            f'Response A: {response}\n'
            f'Response B: {response}\n'
            f'Reply with A or B.'
        )
        r = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=5,
            messages=[{'role': 'user', 'content': prompt}]
        )
        if 'A' in r.content[0].text:
            first_wins += 1

    bias = first_wins / n_pairs
    print(f'First-position win rate with IDENTICAL responses: {bias:.0%}')
    print(f'Expected (no bias): 50%')
    print(f'Measured bias: {(bias - 0.5) * 100:+.0f}%')
    return bias

장황함 편향: 심층 분석

장황함 편향은 더 짧은 응답이 더 정확하고 완전한 경우에도 평가자가 더 긴 응답을 선호하게 만듭니다. 연구에 따르면 내용 품질을 통제했을 때 LLM 평가자는 쌍별 비교에서 긴 응답을 ‘더 낫다’고 평가할 가능성이 1.5~2배 높습니다.

이 편향은 인간 평가자 역시 길이와 품질을 혼동하는 학습 데이터에서 비롯되었을 가능성이 큽니다.

import anthropic

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

def measure_verbosity_bias(question, correct_answer):
    """
    Compare a concise correct answer against a verbose one with filler.
    A good judge should prefer the concise version or call it a tie.
    """
    concise = correct_answer
    verbose = (
        f'That is a great question! I am happy to help. '
        f'{correct_answer} '
        f'I hope this comprehensive explanation addresses all your needs. '
        f'Please feel free to ask if you need any further clarification!'
    )

    for label, resp in [('Concise', concise), ('Verbose', verbose)]:
        prompt = (
            f'Rate this response 1-5 for quality.\n'
            f'Q: {question}\nA: {resp}\n'
            f'Return only a number 1-5.'
        )
        r = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=5,
            messages=[{'role': 'user', 'content': prompt}]
        )
        score = r.content[0].text.strip()
        print(f'{label} response score: {score}')
        print(f'  ({len(resp.split())} words)')

자기 선호 편향: 심층 분석

클로드 평가자는 평균적으로 클로드가 생성한 응답에 더 높은 점수를 줍니다. GPT-4 평가자는 GPT-4가 생성한 응답에 더 높은 점수를 줍니다. 이는 여러 독립적인 연구에서 입증되었습니다.

그 원리는 다음과 같습니다. 각 모델은 문장 구조, 완곡 표현 패턴, 어휘 선택에서 독특한 문체를 지닙니다. 같은 모델은 자신의 문체를 알아보고 선호합니다.

import anthropic
import openai

anthropic_client = anthropic.Anthropic(api_key='sk-ant-...')
openai_client = openai.OpenAI(api_key='sk-...')

def test_self_preference(question):
    # Generate one response per model
    claude_answer = anthropic_client.messages.create(
        model='claude-opus-4-5', max_tokens=100,
        messages=[{'role': 'user', 'content': question}]
    ).content[0].text

    gpt_answer = openai_client.chat.completions.create(
        model='gpt-4o', max_tokens=100,
        messages=[{'role': 'user', 'content': question}]
    ).choices[0].message.content

    judge_prompt = (
        f'Which response is better?\nQ: {question}\n'
        f'Response A: {claude_answer}\n'
        f'Response B: {gpt_answer}\n'
        f'Reply: A or B'
    )

    # Claude judges the comparison
    claude_verdict = anthropic_client.messages.create(
        model='claude-opus-4-5', max_tokens=5,
        messages=[{'role': 'user', 'content': judge_prompt}]
    ).content[0].text.strip()

    print(f'Claude judge verdict: {claude_verdict}')
    print('(A=Claude response, B=GPT response)')
    print('Self-preference: did Claude prefer its own response?')

완화 방법 1: 순서 바꾸기

위치 편향을 완화하는 가장 효과적인 단일 방법은 모든 쌍별 비교를 순서를 바꿔 두 번 실행하고 일관된 결과만 사용하는 것입니다. 모든 평가가 이 함수를 거치도록 표준 함수로 구현하십시오.

import anthropic
import json

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

def debiased_compare(question, response_a, response_b, label_a='A', label_b='B'):
    def single_pass(first, second, first_label, second_label):
        prompt = (
            f'Q: {question}\n\n'
            f'{first_label}: {first}\n\n'
            f'{second_label}: {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()

    # Pass 1: A first
    p1 = single_pass(response_a, response_b, label_a, label_b)
    # Pass 2: B first — but labels stay the same (we just swap presentation order)
    p2 = single_pass(response_b, response_a, label_b, label_a)

    # Normalize p2: if judge said label_b in pass 2, that means they preferred first-shown
    # Need to map back: if p2 = label_b, the 'first' won; if p2 = label_a, the 'second' won
    if p1 == p2 and p1 != 'TIE':
        return p1, 'Consistent result'
    else:
        return 'TIE', f'Inconsistent: pass1={p1}, pass2={p2}'

winner, reason = debiased_compare(
    'What is Docker?',
    'Docker is a containerization platform.',
    'Docker allows you to package applications into containers for consistent deployment.'
)
print(f'{winner}: {reason}')

완화 방법 2: 다양성을 갖춘 여러 평가자

서로 다른 여러 모델을 평가자로 사용하고 판정을 종합하면 자기 선호 편향이 줄어듭니다. 클로드, GPT-4, 제미나이가 모두 동의한다면 어느 한 모델만의 판정보다 결과를 훨씬 더 신뢰할 수 있습니다.

import anthropic
import openai

anthropic_client = anthropic.Anthropic(api_key='sk-ant-...')
openai_client = openai.OpenAI(api_key='sk-...')

def multi_model_pairwise(question, response_a, response_b):
    results = {}

    # Judge 1: Claude
    r1 = anthropic_client.messages.create(
        model='claude-opus-4-5', max_tokens=5,
        messages=[{'role': 'user', 'content':
            f'Q: {question}\nA: {response_a}\nB: {response_b}\n'
            f'Which is better? Reply A, B, or TIE.'
        }]
    )
    results['Claude'] = r1.content[0].text.strip()

    # Judge 2: GPT-4o
    r2 = openai_client.chat.completions.create(
        model='gpt-4o', max_tokens=5,
        messages=[{'role': 'user', 'content':
            f'Q: {question}\nA: {response_a}\nB: {response_b}\n'
            f'Which is better? Reply A, B, or TIE.'
        }]
    )
    results['GPT4o'] = r2.choices[0].message.content.strip()

    print(f'Claude judge: {results["Claude"]}')
    print(f'GPT-4o judge: {results["GPT4o"]}')

    # Aggregate: majority vote
    votes = list(results.values())
    if votes.count('A') >= 2: return 'A'
    if votes.count('B') >= 2: return 'B'
    return 'TIE'

final = multi_model_pairwise(
    'Explain recursion.',
    'A function that calls itself.',
    'Recursion is when a function solves a problem by solving a smaller version of the same problem.'
)
print(f'Final verdict: {final}')

완화 방법 3: 장황함 방지 지침

평가자에게 장황함에는 감점을 주고 간결함에는 가점을 주도록 직접 지시하십시오. 이렇게 하면 긴 응답이 더 좋아 보이게 만드는 장황함 편향에 대응할 수 있습니다.

ANTI_VERBOSITY_JUDGE = (
    'Evaluate this response. Apply these corrections for known judge biases:\n\n'
    'VERBOSITY CORRECTION: Do NOT rate a response higher simply because it is longer. '
    'A concise, accurate 20-word answer is better than a 200-word answer that says the same thing. '
    'Actively penalize unnecessary padding, filler phrases like "Great question!", '
    'and repetition.\n\n'
    'LENGTH PENALTY: If the response contains introductory filler, closing remarks, '
    'or restates the question, subtract 1 point from your score.\n\n'
    'Question: {question}\n'
    'Response: {response}\n\n'
    'Score 1-5 (apply verbosity correction above):'
)

# This instruction significantly reduces verbosity inflation in practice
print('Anti-verbosity instructions reduce the length-quality conflation')

사람 평가자를 기준으로 보정하기

평가자 보정의 표준적인 방법은 보정용 데이터 집합에서 LLM 평가자의 점수를 사람 평가자의 점수와 비교하는 것입니다. 일치도를 측정하고 체계적인 차이를 찾아내십시오.

import anthropic
import json
from scipy import stats  # pip install scipy

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

def calibrate_judge(calibration_set):
    """
    calibration_set: list of dicts with:
    {'question': str, 'response': str, 'human_score': float}
    """
    llm_scores = []
    human_scores = []

    for item in calibration_set:
        prompt = (
            f'Rate this response 1-5.\n'
            f'Q: {item["question"]}\nA: {item["response"]}\n'
            f'Return only a number.'
        )
        r = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=5,
            messages=[{'role': 'user', 'content': prompt}]
        )
        try:
            llm_score = float(r.content[0].text.strip())
        except ValueError:
            llm_score = 3.0  # Default on parse error

        llm_scores.append(llm_score)
        human_scores.append(item['human_score'])

    correlation, p_value = stats.pearsonr(llm_scores, human_scores)
    print(f'LLM-Human correlation: {correlation:.3f} (p={p_value:.4f})')
    print(f'LLM mean score: {sum(llm_scores)/len(llm_scores):.2f}')
    print(f'Human mean score: {sum(human_scores)/len(human_scores):.2f}')
    return correlation

체계적 편향 패턴 탐지

체계적인 편향을 탐지하려면 다양한 응답 범주에 대한 평가자의 출력을 분석하십시오. 평가자가 특정 모델의 응답을 일관되게 더 높게 평가합니까? 특정 주제의 응답에 감점을 줍니까?

import json
from collections import defaultdict

def analyze_judge_bias(log_file='pairwise_log.jsonl'):
    """
    Analyze pairwise logs to detect systematic bias.
    """
    wins_by_label = defaultdict(int)
    total_by_label = defaultdict(int)

    with open(log_file) as f:
        for line in f:
            entry = json.loads(line)
            winner = entry['winner']
            label_a = entry['label_a']
            label_b = entry['label_b']

            if winner == 'A':
                wins_by_label[label_a] += 1
            elif winner == 'B':
                wins_by_label[label_b] += 1

            total_by_label[label_a] += 1
            total_by_label[label_b] += 1

    print('Win rate by model:')
    for label in sorted(total_by_label):
        total = total_by_label[label]
        wins = wins_by_label[label]
        print(f'  {label}: {wins}/{total} = {wins/total:.0%}')

    # Flag if any model wins >60% — likely systematic bias
    for label in total_by_label:
        rate = wins_by_label[label] / total_by_label[label]
        if rate > 0.65 or rate < 0.35:
            print(f'WARNING: {label} win rate {rate:.0%} suggests systematic bias')

편향 완화 점검 목록

운영 환경에 LLM 평가자를 배포하기 전에 적용할 점검 목록입니다:

  • 모든 쌍별 비교를 순서를 바꿔 두 번 실행
  • 평가 기준표에 장황함 방지 지침을 명시적으로 포함
  • 중대한 평가에는 서로 다른 모델을 평가자로 최소 2개 사용
  • 점수 부풀림을 방지하도록 점수 수준을 명시적으로 설정
  • 대표 표본에 대해 사람 평가자를 기준으로 보정
  • 모델 이름별 승률을 기록하고 모니터링하여 변화를 탐지
  • 자유 형식 서술 속에 점수를 숨기지 못하게 구조화된 JSON 출력 추가

감사 추적과 설명 가능성

조정된 평가자는 설명 가능해야 합니다. 평가자가 응답에 5점 만점에 4점을 부여했다면 그 이유, 즉 어떤 기준을 충족했고 어떤 기준이 미흡했는지를 추적할 수 있어야 합니다.

평가자에게 기준별 점수와 간단한 이유를 포함한 JSON을 반환하도록 요구하면 자연스럽게 감사 추적이 생성됩니다. 이해관계자는 특정 응답이 해당 점수를 받은 이유를 검토할 수 있고, 낮은 점수에서 반복적으로 나타나는 패턴도 발견할 수 있습니다.

지식 확인: 자기 선호 완화

LLM 평가자의 자기 선호 편향을 가장 직접적으로 해결하는 완화 전략은 무엇입니까?

복습: LLM 평가자의 조정과 편향

LLM 평가자에게는 네 가지 주요 체계적 편향이 있습니다. 위치 편향(첫 번째 선택지를 선호함), 장황함 편향(더 긴 응답을 선호함), 자기 선호(자신의 스타일을 선호함), 점수 부풀림(5점 만점에 4~5점으로 몰림)입니다. 각 편향에 맞는 방법으로 완화해야 합니다. 위치 편향에는 순서를 바꾸고, 장황함 편향에는 장황함을 억제하는 지침을 추가하며, 자기 선호에는 다양한 모델 평가자를 사용하고, 점수 부풀림에는 기준점이 있는 평가 기준표를 사용합니다. 레이블이 지정된 데이터 세트에서 사람 평가자와 비교하여 평가자를 조정하고 피어슨 상관계수를 측정하십시오. 시간에 따른 레이블별 승률을 모니터링하여 평가 처리 흐름을 왜곡하기 전에 새롭게 나타나는 편향 패턴을 포착하십시오.

자주 묻는 질문

“LLM 심사자의 보정과 편향” 강의는 무료인가요?

네 — “LLM 심사자의 보정과 편향” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Prompt Engineering 강의 전체를 잠금 해제할 수 있습니다. AI Prompt Engineering 강의에는 총 4개의 강의가 포함되어 있습니다.

“LLM 심사자의 보정과 편향”에서 뭘 배우나요?

위치 편향과 장황함 편향을 알아보고 심사 프롬프트에서 이를 완화하는 방법을 배웁니다. 브라우저에서 직접 실행하는 실습 코드로 AI Prompt Engineering을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Prompt Engineering을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Prompt Engineering은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“LLM 심사자의 보정과 편향” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Prompt Engineering 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Prompt Engineering 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. LLM을 사용해 LLM 출력 평가하기
  2. 평가 기준표 기반 점수 매기기 프롬프트
  3. 비교 심사: A와 B
  4. LLM 심사자의 보정과 편향
← AI Prompt Engineering(으)로 돌아가기