AI Prompt Engineering · 강의

LLM을 사용해 LLM 출력 평가하기

LLM 심사자가 작동하는 이유와 사람의 평가에 비해 부족한 부분을 알아봅니다.

레슨 1/413개 단계

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

LLM을 심사자로 사용하는 이유

전통적인 평가 지표인 BLEU, ROUGE, 정확 일치 여부는 구조화된 출력에는 유용하지만, 유용성, 정확성, 어조, 창의성처럼 미묘한 특성을 평가하는 데는 부족합니다.

사람의 평가는 미묘한 차이를 포착하지만 느리고 비용이 많이 듭니다. LLM 심사는 중간 지점을 제공합니다. 의미, 맥락, 주관적인 품질을 이해하는 자동 평가를 대규모로 낮은 비용에 수행할 수 있습니다.

LLM 심사가 작동하는 이유

LLM 심사가 성공하는 이유는 평가 대상 모델과 동일한 언어 이해 능력을 공유하기 때문입니다. 다음을 평가할 수 있습니다:

  • 응답이 참고 답변과 어휘적으로 유사한 것에 그치지 않고 사실적으로 정확한지
  • 응답이 명시된 목적에 도움이 되는지
  • 어조가 요구 사항에 맞는지
  • 요약이 핵심 points를 담는지

이러한 특성은 단순한 문자열 일치 지표로는 측정할 수 없습니다.

간단한 LLM 심사

가장 기본적인 LLM 심사 방식은 모델에 응답을 수치 척도로 평가하고 짧은 근거를 제시하도록 요청하는 것입니다. 이것이 더 발전된 모든 심사 방식의 토대가 됩니다.

import anthropic
import json

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

def simple_llm_judge(question, response, criterion):
    judge_prompt = (
        f'Rate the following response on {criterion} from 1 to 5.\n\n'
        f'Question: {question}\n'
        f'Response: {response}\n\n'
        f'Return JSON: {{"score": <1-5>, "reason": "<one sentence>"}}'
    )
    r = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=100,
        messages=[{'role': 'user', 'content': judge_prompt}]
    )
    try:
        result = json.loads(r.content[0].text)
        return result['score'], result['reason']
    except Exception:
        return None, r.content[0].text

score, reason = simple_llm_judge(
    question='What is recursion in programming?',
    response='Recursion is when a function calls itself.',
    criterion='clarity and completeness'
)
print(f'Score: {score}/5 — {reason}')

LLM 심사가 실패하는 지점: 위치 편향

위치 편향: 두 응답(A와 B)을 제시하면 LLM 심사자는 품질과 관계없이 먼저 나온 응답을 선호합니다. 단순한 심사 프롬프트를 사용할 때 쌍별 비교의 60~70%에 이러한 편향이 영향을 미친다는 연구 결과가 있습니다.

즉, 선택지를 제시하는 순서가 심사 결과를 바꿉니다.

import anthropic

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

def demonstrate_position_bias(question, response_a, response_b):
    def ask_judge(first, second, order):
        prompt = (
            f'Question: {question}\n\n'
            f'Response 1: {first}\n\n'
            f'Response 2: {second}\n\n'
            f'Which response is better? Reply with 1 or 2.'
        )
        r = client.messages.create(
            model='claude-opus-4-5',
            max_tokens=10,
            messages=[{'role': 'user', 'content': prompt}]
        )
        choice = r.content[0].text.strip()
        # Map back to original labels
        if order == 'AB':
            return 'A' if choice == '1' else 'B'
        else:  # BA
            return 'B' if choice == '1' else 'A'

    result_ab = ask_judge(response_a, response_b, 'AB')
    result_ba = ask_judge(response_b, response_a, 'BA')

    print(f'Order A-B: Judge picked {result_ab}')
    print(f'Order B-A: Judge picked {result_ba}')
    if result_ab != result_ba:
        print('Position bias detected: different results!')

    return result_ab, result_ba

LLM 심사가 실패하는 지점: 장황함 편향

장황함 편향: LLM 심사자는 간결한 응답이 객관적으로 더 나은 경우에도 더 길고 자세한 응답을 더 높게 평가하는 경향이 있습니다. 50단어로 말할 수 있는 내용을 400단어로 표현한 응답이 간결한 버전보다 더 높은 점수를 받는 경우가 많습니다.

심사자에게 불필요한(unnecessary) 길이를 감점하도록 명시적으로 지시하여 완화하세요.

import anthropic

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

def length_aware_judge(question, response):
    judge_prompt = (
        f'Evaluate this response for quality. Be aware of verbosity bias: '
        f'do NOT score longer responses higher just because they are longer.\n\n'
        f'Question: {question}\n'
        f'Response: {response}\n\n'
        f'Evaluate on:\n'
        f'1. Accuracy (does it correctly answer the question?)\n'
        f'2. Conciseness (does it avoid unnecessary filler?)\n'
        f'3. Helpfulness (does it serve the user well?)\n\n'
        f'Penalize responses that add filler, repetition, or irrelevant information.\n'
        f'Score each 1-5 and provide an overall score. Return JSON.'
    )
    r = client.messages.create(
        model='claude-opus-4-5',
        max_tokens=200,
        messages=[{'role': 'user', 'content': judge_prompt}]
    )
    print(r.content[0].text)

LLM 심사가 실패하는 지점: 자기 선호

자기 선호 편향: 클로드가 두 응답을 심사하면 클로드와 비슷한 응답을 선호하는 경향이 있습니다. GPT-4가 심사하면 GPT-4와 비슷한 응답을 선호합니다. 이는 모든 LLM 심사자에 영향을 미치는 체계적인 편향입니다.

완화 방법: 서로 다른 여러 모델을 심사자로 사용하고 점수를 종합하세요. 의견 불일치는 사람이 검토해야 하는 경계 사례임을 나타냅니다.

import anthropic
import openai

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

def multi_model_judge(question, response):
    judge_prompt = (
        f'Rate this response 1-10 for overall quality.\n'
        f'Q: {question}\nA: {response}\n'
        f'Reply with only a number.'
    )

    # Judge 1: Claude
    r_claude = anthropic_client.messages.create(
        model='claude-opus-4-5',
        max_tokens=10,
        messages=[{'role': 'user', 'content': judge_prompt}]
    )
    score_claude = float(r_claude.content[0].text.strip())

    # Judge 2: GPT-4o
    r_gpt = openai_client.chat.completions.create(
        model='gpt-4o',
        max_tokens=10,
        messages=[{'role': 'user', 'content': judge_prompt}]
    )
    score_gpt = float(r_gpt.choices[0].message.content.strip())

    avg = (score_claude + score_gpt) / 2
    print(f'Claude judge: {score_claude}, GPT judge: {score_gpt}, Average: {avg}')
    if abs(score_claude - score_gpt) > 2:
        print('WARNING: High disagreement — consider human review')
    return avg

점수 부풀리기

점수 부풀리기: LLM 심사자는 대부분의 응답에 5점 만점에 4~5점처럼 높은 점수를 주는 경향이 있습니다. 이로 인해 분포가 좁아지고 좋은 응답과 훌륭한 응답을 구분하기 어려워집니다. 3/5점일 응답이 4~4.5/5점을 받는 경우도 많습니다.

보정을 강제하는 평가 기준표를 사용하거나, 절대 점수 대신 상대적(쌍별) 점수를 사용하세요.

# Anti-inflation judge prompt with explicit score anchors
CALIBRATED_JUDGE_PROMPT = (
    'Rate this response 1-5 using these STRICT score definitions:\n'
    '1 = Completely wrong, harmful, or completely off-topic\n'
    '2 = Partially relevant but contains significant errors or omissions\n'
    '3 = Correct and addresses the question but lacks depth or precision\n'
    '4 = Correct, reasonably complete, and clearly expressed\n'
    '5 = Exceptional: correct, complete, insightful, and concise\n\n'
    'Only give 5 if the response is genuinely outstanding.\n'
    'Give 3 for any adequate-but-not-impressive response.\n\n'
    'Question: {question}\n'
    'Response: {response}\n\n'
    'Score (1-5) and one-sentence reason:'
)

# Compare to non-anchored prompt which tends to cluster at 4-5
print('Anchored rubrics force the judge to use the full scale')

LLM 심사가 가장 잘 작동하는 경우

LLM 심사는 다음과 같은 경우에 가장 신뢰할 수 있습니다:

  • 기준이 명확하고 잘 정의되어 있을 때
  • 응답 품질의 차이가 클 때(분명히 좋은 응답과 분명히 나쁜 응답)
  • 분야가 심사 모델의 지식 범위에 속할 때
  • 사람 평가자도 의견이 갈리는 주관적 특성(어조, 유용성)을 평가할 때

반대로 최신 지식, 고도로 기술적인 분야, 전문가 지식이 있어야 감지할 수 있는 미묘한 사실 오류를 평가할 때는 신뢰하기 어렵습니다.

사람 평가가 필요한 경우

다음과 같은 경우에는 사람의 검토를 계속 포함하세요:

  • 전문 분야(의료, 법률, 보안)의 응답을 평가할 때
  • LLM 심사를 보정하기 위한 기준 정답을 확립할 때
  • LLM 심사의 오류가 실제 결과를 초래할 수 있는 중대한 결정을 내릴 때
  • 심사 모델이 학습 신호를 거의 받지 못한 새로운 작업을 다룰 때
  • 전문 분야의 지식이 있어야 발견할 수 있는 미묘한 사실 오류를 감지할 때
def triage_for_human_review(question, response, llm_score, confidence_threshold=0.7):
    """
    Route low-confidence or high-stakes evaluations to human review.
    """
    # Route to human if judge is uncertain
    if llm_score is None:
        return 'human_review', 'LLM judge failed to produce a score'

    # Route to human for borderline scores (near decision boundaries)
    if 2.5 <= llm_score <= 3.5:
        return 'human_review', f'Borderline score {llm_score} — needs human judgment'

    # Route to human for domain-specific high-risk content
    HIGH_RISK_KEYWORDS = ['medication', 'legal advice', 'financial advice', 'security']
    if any(kw in question.lower() for kw in HIGH_RISK_KEYWORDS):
        return 'human_review', 'High-risk domain — human verification required'

    # Else: LLM score is sufficient
    return 'auto_accept', f'Score {llm_score} — LLM judgment sufficient'

routing, reason = triage_for_human_review('What medication should I take?', 'Take aspirin.', 4.5)
print(f'{routing}: {reason}')

평가 절차 구축하기

실용적인 LLM 심사 절차는 다음과 같습니다. 응답 생성 → LLM 심사 실행 → 경계 사례를 사람에게 넘겨 검토하게 하기 → 점수 종합 → 품질 지표 보고. 감사 추적을 위해 모든 것을 기록하세요.

import anthropic
import json

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

def evaluate_batch(examples, product_under_test, criteria):
    results = []
    for ex in examples:
        response = product_under_test(ex['question'])
        score, reason = simple_llm_judge(ex['question'], response, criteria)

        results.append({
            'question': ex['question'],
            'response': response,
            'score': score,
            'reason': reason,
            'needs_review': score is None or 2.5 <= (score or 0) <= 3.5
        })

    # Summarize
    valid_scores = [r['score'] for r in results if r['score'] is not None]
    avg_score = sum(valid_scores) / len(valid_scores) if valid_scores else 0
    review_count = sum(1 for r in results if r['needs_review'])

    print(f'Average score: {avg_score:.2f}/5')
    print(f'Cases needing review: {review_count}/{len(results)}')
    return results, avg_score

# results, avg = evaluate_batch(test_cases, my_product, 'helpfulness')

참조 없는 평가와 참조 기반 평가

LLM 심사는 두 가지 모드로 작동할 수 있습니다:

  • 참조 기반: 심사자가 응답을 알려진 정답과 비교합니다. 정확도가 높지만 라벨이 지정된 데이터가 필요합니다.
  • 참조 없이: 심사자가 응답 자체의 품질을 평가합니다(일관적인가? 도움이 되는가? 잘 작성되었는가?). 더 유연하지만 사실적 정확도는 떨어집니다.

표준 정답이 있다면 참조 기반 평가를 사용하세요. 요약, 어조 평가, 창의적 글쓰기 품질처럼 개방형 작업에는 참조 없는 평가를 사용하세요.

지식 확인: 위치 편향

LLM을 심사자로 사용하는 평가에서 위치 편향이란 무엇이며, 어떤 문제를 일으킵니까?

복습: LLM 심사자 평가

LLM 심사자는 뉘앙스, 의미적 정확성, 주관적 품질을 이해할 수 있지만, 기존 지표로는 이를 측정할 수 없습니다. 다음과 같은 경우에는 실패합니다: 위치 편향(첫 번째 선택지 선호), 장황함 편향(더 긴 응답 선호), 자기 선호(자신의 문체 선호), 점수 부풀림(4~5/5에 집중). 완화 방법으로는 응답 순서 무작위화, 장황함을 방지하는 명시적 지침, 각 점수 수준을 정의하는 기준점이 있는 평가 기준표, 서로 다른 여러 모델을 심사자로 사용하는 방법이 있습니다. 경계선 점수와 위험도가 높은 분야는 사람 평가자에게 전달하십시오. 규모 확장에는 LLM 심사자를 사용하고, 보정과 중대한 의사 결정에는 사람을 사용하십시오.

무료로 시작

AI 튜터와 함께 AI Prompt Engineering을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
53
레슨
199

자주 묻는 질문

“LLM을 사용해 LLM 출력 평가하기” 강의는 무료인가요?

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

“LLM을 사용해 LLM 출력 평가하기”에서 뭘 배우나요?

LLM 심사자가 작동하는 이유와 사람의 평가에 비해 부족한 부분을 알아봅니다. 브라우저에서 직접 실행하는 실습 코드로 AI Prompt Engineering을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

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

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

“LLM을 사용해 LLM 출력 평가하기” 강의는 얼마나 걸리나요?

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

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

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

이 강의의 모든 강의

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