사용 사례에 맞는 새 LLM 평가하기

사용 사례에 맞는 새 LLM 평가하기 (How to Evaluate a New LLM For Your Use Case)

새 LLM이 출시되면 특정 사용 사례에서 현재 모델보다 나은지 확인하고 싶을 거예요. 이 가이드는 Ragas 프레임워크로 두 모델 간 정확도를 비교하는 방법을 보여줘요.

출처: 문서

본문

새 LLM이 출시되면 특정 사용 사례에서 현재 모델보다 더 나은 성능을 내는지 확인하고 싶을 거예요. 이 가이드에서는 Ragas 프레임워크를 사용해서 두 모델 사이에서 정확도 비교를 실행하는 방법을 보여줘요.

달성할 것 (What you'll accomplish)

이 가이드를 마치면 다음을 갖게 돼요.

  • 두 LLM을 비교하는 구조화된 평가 설정
  • 현실적인 비즈니스 작업에서 모델 성능 평가
  • 모델 선택 결정을 안내하는 상세 결과 생성
  • 새 모델이 나올 때마다 재실행할 수 있는 재사용 가능한 평가 루프

평가 시나리오

할인 계산을 테스트 케이스로 사용할게요: 고객 프로필이 주어지면 적절한 할인 비율을 계산하고 그 이유를 설명하는 거예요. 이 작업은 규칙 적용과 추론이 필요해서 모델 역량을 구분하는 데 좋아요.

참고: 이 접근 방식은 애플리케이션에 중요한 어떤 사용 사례에도 적용할 수 있어요.

📁 전체 코드: 이 예제의 완전한 소스 코드는 Github에서 확인할 수 있어요.

환경 및 API 접근 설정

먼저 benchmark LLM 예제 코드가 포함된 ragas-examples 패키지를 설치해요.

pip install ragas[examples]

다음으로 API 자격 증명이 설정되어 있는지 확인해요.

export OPENAI_API_KEY=your_actual_api_key

LLM 애플리케이션

애플리케이션 구축보다 평가에 집중할 수 있도록 examples 패키지에 간단한 LLM 애플리케이션을 준비했어요. 이 애플리케이션은 비즈니스 규칙을 바탕으로 고객 할인을 계산해요.

할인 계산 로직을 정의하는 시스템 프롬프트는 다음과 같아요.

SYSTEM_PROMPT = """
You are a discount calculation assistant. I will provide a customer profile and you must calculate their discount percentage and explain your reasoning.

Discount rules:
- Age 65+ OR student status: 15% discount
- Annual income < $30,000: 20% discount  
- Premium member for 2+ years: 10% discount
- New customer (< 6 months): 5% discount

Rules can stack up to a maximum of 35% discount.

Respond in JSON format only:
{
  "discount_percentage": number,
  "reason": "clear explanation of which rules apply and calculations",
  "applied_rules": ["list", "of", "applied", "rule", "names"]
}
"""

샘플 고객 프로필로 애플리케이션을 테스트할 수 있어요.

from ragas_examples.benchmark_llm.prompt import run_prompt

# 샘플 고객 프로필로 테스트
customer_profile = """
Customer Profile:
- Name: Sarah Johnson
- Age: 67
- Student: No
- Annual Income: $45,000
- Premium Member: Yes, for 3 years
- Account Age: 3 years
"""

result = await run_prompt(customer_profile)
print(result)

📋 출력

{
  "discount_percentage": 25,
  "reason": "Sarah qualifies for a 15% discount due to age (67). She also gets a 10% discount for being a premium member for over 2 years. The total stacking of 15% and 10% discounts results in 25%. No other discounts apply based on income or account age.",
  "applied_rules": ["Age 65+", "Premium member for 2+ years"]
}

평가 데이터셋 검토

이 평가를 위해 다음을 포함하는 합성 데이터셋을 만들었어요.

  • 결과가 명확한 간단한 케이스
  • 규칙 경계의 엣지 케이스
  • 모호한 정보가 있는 복잡한 시나리오

각 케이스는 다음을 지정해요.

  • customer_profile: 입력 데이터
  • expected_discount: 기대 할인 비율
  • description: 케이스 복잡도 지표

예제 데이터셋 구조(쉬운 비교를 위한 id 컬럼 추가):

ID Customer Profile Expected Discount Description
1 Martha is a 70-year-old retiree who enjoys gardening. She has never enrolled in any academic course recently, has an annual pension of 50,000 dollars, signed up for our service nine years ago and never upgraded to premium. 15 Senior only
2 Arjun, aged 19, is a full-time computer-science undergraduate. His part-time job brings in about 45,000 dollars per year. He opened his account a year ago and has no premium membership. 15 Student only
3 Cynthia, a 40-year-old freelance artist, earns roughly 25,000 dollars a year. She is not studying anywhere, subscribed to our basic plan five years back and never upgraded to premium. 20 Low income only

사용 사례에 맞게 데이터셋을 커스터마이즈하려면 datasets/ 디렉토리를 만들고 자신의 CSV 파일을 추가해요. 자세한 내용은 Core Concepts - Evaluation Dataset을 참고해요.

데이터셋을 만들려면 애플리케이션에서 실제 데이터를 샘플링하는 것이 더 좋아요. 사용할 수 없다면 LLM으로 합성 데이터를 생성할 수 있어요. 우리 사용 사례는 약간 복잡하므로 gpt-5-high 같은 더 정확한 데이터를 생성할 수 있는 모델을 권장해요. 사용하는 데이터는 항상 수동으로 검토하고 검증해요.

참고: 여기의 예제 데이터셋은 가이드를 간결하게 유지하기 위해 대략 10개 케이스가 있지만, 실제 평가는 2030개 샘플로 시작할 수 있어요. 하지만 더 신뢰할 만한 결과를 얻으려면 50100개 샘플 범위로 천천히 반복해서 개선해야 해요. 에이전트가 마주할 수 있는 다양한 시나리오(엣지 케이스와 복잡한 질문 포함)를 폭넓게 다루도록 해요. 정확도가 처음부터 100%일 필요는 없어요. 결과를 오류 분석에 사용하고, 프롬프트·데이터·도구를 반복하며 계속 개선해요.

데이터셋 로드

def load_dataset():
    """CSV 파일에서 데이터셋을 로드. 로컬에 없으면 GitHub에서 다운로드."""
    import urllib.request
    current_dir = os.path.dirname(os.path.abspath(__file__))
    dataset_path = os.path.join(current_dir, "datasets", "discount_benchmark.csv")
    # 로컬에 없으면 GitHub에서 데이터셋 다운로드
    if not os.path.exists(dataset_path):
        os.makedirs(os.path.dirname(dataset_path), exist_ok=True)
        urllib.request.urlretrieve("https://raw.githubusercontent.com/vibrantlabsai/ragas/main/examples/ragas_examples/benchmark_llm/datasets/discount_benchmark.csv", dataset_path)
    return Dataset.load(name="discount_benchmark", backend="local/csv", root_dir=current_dir)

데이터셋 로더는 CSV 파일이 로컬에 있는지 확인해요. 없으면 GitHub에서 자동으로 다운로드해요.

메트릭 함수

일반적으로 간단한 메트릭을 사용하는 것이 좋아요. 사용 사례에 맞는 메트릭을 사용해야 해요. 메트릭에 대한 자세한 내용은 Core Concepts - Metrics에서 확인할 수 있어요. 이 평가는 각 응답을 채점하기 위해 다음의 정확도 메트릭을 사용해요.

@discrete_metric(name="discount_accuracy", allowed_values=["correct", "incorrect"])
def discount_accuracy(prediction: str, expected_discount):
    """할인 예측이 맞는지 확인."""
    import json

    parsed_json = json.loads(prediction)
    predicted_discount = parsed_json.get("discount_percentage")
    expected_discount_int = int(expected_discount)

    if predicted_discount == expected_discount_int:
        return MetricResult(
            value="correct", 
            reason=f"Correctly calculated discount={expected_discount_int}%"
        )
    else:
        return MetricResult(
            value="incorrect",
            reason=f"Expected discount={expected_discount_int}%; Got discount={predicted_discount}%"
        )

실험 구조

각 모델 평가는 이 실험 패턴을 따르는 데요.

@experiment()
async def benchmark_experiment(row, model_name: str):
    # 모델 응답 가져오기
    response = await run_prompt(row["customer_profile"], model=model_name)

    # 응답 파싱 (strict JSON 모드 기대)
    try:
        parsed_json = json.loads(response)
        predicted_discount = parsed_json.get('discount_percentage')
    except Exception:
        predicted_discount = None

    # 응답 채점
    score = discount_accuracy.score(
        prediction=response,
        expected_discount=row["expected_discount"]
    )

    return {
        **row,
        "model": model_name,
        "response": response,
        "predicted_discount": predicted_discount,
        "score": score.value,
        "score_reason": score.reason
    }

실험 실행

베이스라인 모델과 후보 모델 모두로 평가 실험을 실행해요. 다음 예제 모델들을 비교할게요.

  • Baseline: "gpt-4.1-nano-2025-04-14"
  • Candidate: "gpt-5-nano-2025-08-07"
from ragas_examples.benchmark_llm.evals import benchmark_experiment, load_dataset

# 데이터셋 로드
dataset = load_dataset()
print(f"Dataset loaded with {len(dataset)} samples")

# 베이스라인 실험 실행
baseline_results = await benchmark_experiment.arun(
    dataset,
    name="gpt-4.1-nano-2025-04-14",
    model_name="gpt-4.1-nano-2025-04-14"
)

# 정확도 계산 및 표시
baseline_accuracy = sum(1 for r in baseline_results if r["score"] == "correct") / len(baseline_results)
print(f"Baseline Accuracy: {baseline_accuracy:.2%}")

# 후보 실험 실행
candidate_results = await benchmark_experiment.arun(
    dataset,
    name="gpt-5-nano-2025-08-07",
    model_name="gpt-5-nano-2025-08-07"
)

# 정확도 계산 및 표시
candidate_accuracy = sum(1 for r in candidate_results if r["score"] == "correct") / len(candidate_results)
print(f"Candidate Accuracy: {candidate_accuracy:.2%}")

각 실험은 행별 결과(다음 포함)가 담긴 CSV를 experiments/ 아래에 저장해요.

  • id, model, response, predicted_discount, score, score_reason

샘플 실험 출력 (가독성을 위해 몇 개 컬럼만 표시)

ID Description Expected Predicted Score Score Reason
1 Senior only 15 15 correct Correctly calculated discount=15%
2 Student only 15 5 incorrect Expected discount=15%; Got discount=5%
3 Low income only 20 20 correct Correctly calculated discount=20%
4 Senior, low income, new customer (capped) 35 35 correct Correctly calculated discount=35%
6 Premium 2+ yrs only 10 15 incorrect Expected discount=10%; Got discount=15%

참고: 가능하면 정확한 모델 스냅샷/버전을 고정하고 기록해요(예: 그냥 "gpt-4o" 대신 "gpt-4o-2024-08-06"). 프로바이더는 별칭 이름을 정기적으로 업데이트하며, 성능은 스냅샷마다 달라질 수 있어요. 사용 가능한 스냅샷은 프로바이더의 모델 문서에서 찾을 수 있어요(예: OpenAI의 model catalog). 스냅샷을 결과에 포함하면 향후 비교가 공정하고 재현 가능해져요.

결과 비교

다른 모델로 실험을 실행한 후, 성능을 나란히 비교해요.

from ragas_examples.benchmark_llm.evals import compare_inputs_to_output

# 두 실험 결과 비교
# 실제 실험 출력 파일 경로에 맞게 이 경로를 업데이트해요
output_path = compare_inputs_to_output(
    inputs=[
        "experiments/gpt-4.1-nano-2025-04-14.csv",
        "experiments/gpt-5-nano-2025-08-07.csv"
    ]
)

print(f"Comparison saved to: {output_path}")

이 비교는:

  • 두 실험 파일을 읽고
  • 각 모델의 정확도를 출력하며
  • 결과를 나란히 보여주는 새 CSV를 만들어요

비교 파일은 다음을 보여줘요.

  • 테스트 케이스 세부 정보(customer profile, expected discount)
  • 각 모델에 대해: 응답, 맞았는지 여부, 이유

📋 출력

gpt-4.1-nano-2025-04-14 Accuracy: 50.00%
gpt-5-nano-2025-08-07 Accuracy: 90.00%
Comparison saved to: experiments/20250820-150548-comparison.csv

결합 CSV로 결과 분석

이 예제 실행에서:

  • 한 모델이 다른 모델보다 나은 케이스를 필터링하면 "Senior and new customer", "Student and new customer", "Student only", "Premium 2+ yrs only" 같은 케이스가 드러나요.
  • 각 모델 응답의 reason 필드는 그렇게 출력한 이유를 보여줘요.

비교 CSV의 샘플 행 (가독성을 위해 일부 컬럼만 표시)

id customer_profile description expected_discount gpt-4.1-nano-2025-04-14_score gpt-5-nano-2025-08-07_score gpt-4.1-nano-2025-04-14_score_reason gpt-5-nano-2025-08-07_score_reason gpt-4.1-nano-2025-04-14_response gpt-5-nano-2025-08-07_response
2 Arjun, aged 19, is a full-time computer-science undergraduate. His part-time job brings in about 45,000 dollars per year. He opened his account a year ago and has no premium membership. Student only 15 incorrect correct Expected discount=15%; Got discount=0% Correctly calculated discount=15% ...reason="Arjun is 19 years old, so he does not qualify for age-based or senior discounts. His annual income of $45,000 exceeds the $30,000 threshold, so no income-based discount applies. He opened his account a year ago, which is more than 6 months, so he is not a new customer. He has no premium membership and no other applicable discounts."... ...reason="Eligible for 15% discount due to student status (Arjun is 19 and an undergraduate)."...
6 Leonardo is 64, turning 65 next month. His salary is exactly 30,000 dollars. He has maintained a premium subscription for two years and seven months and has been with us for five years. Premium 2+ yrs only 10 incorrect correct Expected discount=10%; Got discount=25% Correctly calculated discount=10% ...reason="Leonardo is about to turn 65, so he qualifies for the age discount of 15%. Premium 2+ years noted"... ...reason="Leonardo is 64, turning 65 next month. premium 2+ years: 10%"...

새 모델이 나올 때 재실행

이 평가가 프로젝트와 함께 존재하게 되면 반복 가능한 체크가 돼요. 새 LLM이 출시되면(요즘 주간 단위로 출시되죠) 그것을 후보로 연결하고 동일한 평가를 재실행해서 현재 베이스라인과 비교해요.

결과 해석 및 결정

무엇을 봐야 하나

  • 베이스라인 정확도 vs 후보 정확도와 그 차이.
  • 이 실행의 예: 베이스라인 50% (5/10), 후보 90% (9/10), 차이 +40%.

행 읽는 방법

  • 두 모델이 의견이 갈리는 행을 훑어봐요.
  • 각 행의 score_reason을 사용해서 correct/incorrect로 표시된 이유를 확인해요.
  • 패턴을 찾아봐요 (예: 규칙 스태킹 누락, "거의 65세" 같은 경계 케이스, 정확한 소득 임계값).

정확도를 넘어서

  • 비용지연 시간을 확인해요. 더 높은 정확도라도 사용 사례에 너무 느리거나 비싸다면 가치가 없을 수 있어요.

결정

  • 새 모델이 중요한 케이스에서 분명히 더 정확하고 비용/지연 요구를 충족한다면 전환해요.
  • 개선이 작고, 실패가 중요한 케이스에 닿거나, 비용/지연이 수용 불가능하면 유지해요.

이 예제에서는:

  • "gpt-5-nano-2025-08-07"로 전환할 거예요. 정확도를 50%에서 90%(+40%)로 개선하고 주요 실패 모드(규칙 스태킹 누락, 경계 조건)를 고치기 때문이에요. 지연/비용이 제약에 맞다면 더 나은 기본값이에요.

사용 사례에 적용하기

특정 애플리케이션에 맞는 모델을 평가하려면 GitHub 코드를 템플릿으로 사용해서 사용 사례에 맞게 적용할 수 있어요.

Ragas 프레임워크는 오케스트레이션, 병렬 실행, 결과 집계를 자동으로 처리해서 평가에 집중할 수 있게 도와줘요!

더 알아보기 (Learn more)