본문 바로가기
C.W.K.
Stream
Lesson 03 of 09 · published

평가와 테스트

~22 min · evals, testing, ci

Level 0추측자
0 XP0/55 lessons0/10 achievements
0/150 XP to next level150 XP to go0% complete

익숙한 소프트웨어 테스트 방식은 LLM에 그대로 적용되지 않아

20년 동안 쌓인 소프트웨어 개발의 지혜는 명확해. 단위 테스트를 작성하고, 결과를 정확히 비교하고, 커밋할 때마다 실행하고, 회귀가 생기면 빌드를 막아. 하지만 함수가 확률적 모델을 호출하는 순간부터 이 익숙한 방식만으로는 부족해져.

  • 같은 입력도 호출할 때마다 다른 출력이 나올 수 있어. 샘플링 온도, top-p, 확률적 디코딩이 결과에 영향을 주기 때문이야.
  • temperature=0이어도 모델 제공업체가 예고 없이 가중치를 갱신할 수 있어. 지난주에 고정해 둔 결과가 이번 주에는 조금 달라질 수 있지.
  • 허용 가능한 출력이 문자열 하나뿐인 경우는 드물어. "Paris is the capital of France."와 "The capital of France is Paris."는 표현이 달라도 둘 다 맞아.
  • 품질은 통과와 실패로만 나뉘지 않고 정도의 차이가 있어. 90% 유용한 답과 60% 유용한 답은 분명히 다르지만, 둘 다 assert is_string(output) 검증은 통과해.

테스트에서 평가로 옮겨 가면 무엇이 달라질까?

측면테스트평가
출력결정론적확률적
통과 기준완전 일치등급형 점수와 임곗값
실패의 의미버그출력 분포의 회귀
재시도 정책불안정한 테스트로 취급통계적 분산으로 다루고 N회 실행 결과의 평균을 사용
검사 범위코드 줄과 분기행동, 경계 사례, 사용자 유형
실행 비용CPU 비용LLM API 호출 × N개 표본 × 채점기 비용
원칙: 평가는 예산, 허용 범위, 표본 추출 전략을 갖춘 테스트야. 불리언 검증문보다는 통계적 가설 검정에 가깝게 동작해.

겹치는 부분과 겹치지 않는 부분

결정론적 테스트는 여전히 필요해. 검색 함수가 알려진 질의에 올바른 문서 ID를 반환하는지, 도구 호출 파서가 잘못된 JSON에서 예외를 내는지, 프롬프트 템플릿이 변수를 정확히 치환하는지는 소프트웨어 테스트로 확인해야 해. 평가는 그보다 위 계층에서, 시스템이 올바르게 연결된 상태의 모델 행동을 측정해. 둘을 혼동해서 단위 테스트 안에서 LLM 호출을 직접 실행하면 CI가 불안정해지고 동료들만 힘들어져.

Code

잘못된 방식 — 확률적 시스템에 결정론적 테스트 적용하기·python
# This will pass on Tuesday, fail on Wednesday, and you will blame CI.
def test_summarizer():
    output = summarize_article("...long text...")
    assert output == "This article is about climate change."  # ❌ brittle
올바른 방식 — 임곗값 + N개 표본·python
from statistics import mean

def eval_summarizer(article, expected_topics, n_samples=5):
    """Run the summarizer N times, score each, return distribution."""
    scores = []
    for _ in range(n_samples):
        output = summarize_article(article)
        coverage = topic_coverage_grader(output, expected_topics)  # 0..1
        scores.append(coverage)
    return {
        "mean": mean(scores),
        "min": min(scores),  # worst-case is what production users feel
        "n": n_samples,
        "pass": min(scores) >= 0.7,  # threshold, not equality
    }
pytest 혼합 구성 — 결정론적 연결부 + 평가 관문·python
import pytest

# Deterministic — runs on every commit, fast, free.
def test_prompt_template_substitution():
    rendered = render_prompt("hello {name}", name="world")
    assert rendered == "hello world"

# Eval — runs on a schedule or before release, slower, costs money.
@pytest.mark.eval
def test_summarizer_quality():
    result = eval_summarizer(SAMPLE_ARTICLE, EXPECTED_TOPICS, n_samples=10)
    assert result["pass"], f"summarizer regression: {result}"

External links

Exercise

프로젝트에서 LLM을 호출하는 테스트 파일 하나를 골라. 어떤 검증문이 결정론적인 소프트웨어 테스트이고, 어떤 검증문이 확률적인 모델 행동 평가인지 구분해. 그런 다음 두 파일로 나눠서 하나는 CI에서, 다른 하나는 야간에 정기적으로 실행해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.