Human-in-the-Loop 평가

평가자 간 일치도, 평가 루브릭 설계, 자동-인간 평가 상관 검증

LLM-as-Judge와 자동 지표만으로는 Agent 응답 품질을 완전히 포착할 수 없다. 인간 평가의 설계(루브릭, 평가자 훈련), 신뢰도 측정(Cohen’s κ, ICC), 자동 평가와의 상관 검증 방법을 다룬다.

Experimentation
Agent
저자

Kwangmin Kim

공개

2026년 03월 21일

1 정의

정의: Human-in-the-Loop 평가

Human evaluation이란, 도메인 전문가 또는 훈련된 평가자가 Agent의 응답을 직접 읽고 사전 정의된 루브릭(rubric)에 따라 점수를 부여하는 평가 방식이다.

  • 자동 평가의 보완: LLM-as-Judge가 포착하지 못하는 뉘앙스, 도메인 정확성, 실용성을 평가한다

  • 비용이 높고 느리지만, 평가의 최종 기준(gold standard)이다

  • 자동 평가의 타당성(validity)을 검증하는 기준점 역할을 한다

  • 역학: Expert panel review, Endpoint adjudication committee

  • IT: Human evaluation, Human-in-the-Loop (HITL) assessment


2 왜 인간 평가가 필요한가

2.1 자동 평가의 한계

한계 예시
표면적 유사성 편향 ROUGE/BERTScore가 높지만, 핵심 개념이 틀린 응답
LLM-as-Judge 편향 자기가 생성한 스타일의 응답에 높은 점수를 주는 경향
도메인 특수성 “표준 용어”와 “표준 단어”의 차이를 일반 LLM이 평가하기 어려움
실용성 판단 불가 정확하지만 실무에서 쓸 수 없는 형식의 응답

구체적 실패 사례: MINERVA Data Standardization Helper에서 LLM-as-Judge가 Relevance 5점을 준 응답이 실제로는 사용 불가능한 경우가 있다. “컬럼명 cust_nm의 표준 용어를 추천하라”에 대해 “고객명(customer name)입니다”라고 답하면 LLM은 의미적으로 정확하다고 판단하지만, 실무에서는 표준 도메인 코드, 데이터 타입, 길이 제약까지 포함해야 실제로 채택할 수 있다. 이 괴리를 자동 지표만으로는 감지할 수 없다.

2.2 인간 평가가 필수인 상황

  • 초기 시스템 검증: 자동 평가 파이프라인을 구축하기 전
  • 자동 평가 보정: LLM-as-Judge의 점수가 인간 판단과 일치하는지 검증
  • High-stakes 의사결정: 프로덕션 전환, 모델 교체 등 중대한 결정
  • 새로운 태스크 도입: 기존 자동 지표가 적용되지 않는 새 Agent 기능

3 평가 루브릭 설계

3.1 루브릭이란

루브릭은 평가 기준과 점수 할당 규칙을 명시한 문서이다. 평가자 간 일치도를 높이는 핵심 도구이다.

3.2 설계 원칙

  • 구체적 행동 기술: “좋은 응답”이 아니라 “정답 키워드 3개 중 2개 이상 포함”
  • 등간 척도: 각 점수 간 차이가 균등하게 느껴지도록 설계
  • 경계 사례 명시: 3점과 4점의 경계에 해당하는 구체적 예시를 포함
  • 도메인 용어 정의: 평가에 필요한 도메인 지식을 루브릭에 포함

3.3 MINERVA QnA Chatbot 루브릭 예시

## Relevance (질의-응답 적합도)

| 점수 | 기준 | 구체적 예시 |
|------|------|------------|
| 5 | 질의의 모든 측면에 직접 답하며, 추가 정보도 유용하다 | Q: "표준 용어와 표준 단어의 차이?" → 정의 비교 + 관계 설명 + 예시 |
| 4 | 핵심 질문에 답하며, 부가적 측면 1~2개 누락 | 정의 비교는 정확하나 예시 없음 |
| 3 | 관련 내용이나, 질의의 핵심을 부분적으로만 다룸 | 표준 용어만 설명하고 비교 없음 |
| 2 | 주제는 관련되나, 질문에 대한 실질적 답변이 아님 | 데이터 표준화 일반론만 서술 |
| 1 | 질의와 무관한 응답 | 완전히 다른 주제 |

## Faithfulness (문서 근거성)

| 점수 | 기준 |
|------|------|
| 5 | 모든 주장이 검색 문서에서 직접 확인 가능 |
| 4 | 대부분 문서에 근거, 합리적 추론 1~2개 포함 |
| 3 | 핵심은 문서 근거, 일부 근거 없는 서술 존재 |
| 2 | 부분적으로만 문서와 일치, 상당 부분 근거 없음 |
| 1 | 문서와 거의 무관하거나 명백히 모순 |

## Completeness (답변 완전성)

| 점수 | 기준 |
|------|------|
| 5 | 기대 답변의 핵심 요소를 모두 포함하고 추가 가치도 제공 |
| 4 | 핵심 요소 대부분 포함 (80% 이상) |
| 3 | 핵심 요소의 절반 정도 포함 |
| 2 | 핵심 요소 일부만 포함 (30% 미만) |
| 1 | 핵심 요소가 거의 없음 |

4 평가자 간 일치도 (Inter-Rater Reliability)

4.1 왜 일치도가 중요한가

평가자 A는 4점, 평가자 B는 2점을 주면 이 평가 결과를 신뢰할 수 없다. 평가자 간 일치도가 충분히 높아야 인간 평가가 의미 있다.

4.2 Cohen’s Kappa (κ)

2명의 평가자 간 일치도를 측정한다. 우연에 의한 일치를 보정한다.

\[ \kappa = \frac{p_o - p_e}{1 - p_e} \]

  • \(p_o\): 관찰된 일치율
  • \(p_e\): 우연에 의한 기대 일치율

직관적으로, κ는 “두 평가자가 진짜 합의한 정도”를 측정한다. 5점 척도에서 두 사람이 아무 생각 없이 랜덤으로 점수를 매겨도 20% 정도는 우연히 일치한다. κ는 이 우연 일치를 빼고 남는 “진짜 합의”만 계산한다. κ=0.60이면 “우연을 뺀 후에도 60%의 합의가 있다”는 뜻이고, κ=0이면 “평가자 간 합의가 동전 던지기 수준”이라는 뜻이다. Quadratic weighting은 4점 vs 5점(1점 차이)보다 1점 vs 5점(4점 차이)에 훨씬 큰 페널티를 주어, 극단적 불일치를 더 심각하게 반영한다.

from sklearn.metrics import cohen_kappa_score

def evaluate_inter_rater(rater1_scores, rater2_scores):
    """2명의 평가자 간 일치도 측정"""
    kappa = cohen_kappa_score(rater1_scores, rater2_scores, weights="quadratic")

    # 해석 기준 (Landis & Koch, 1977)
    interpretation = {
        (0.81, 1.00): "거의 완전 일치 (Almost Perfect)",
        (0.61, 0.80): "상당한 일치 (Substantial)",
        (0.41, 0.60): "보통 일치 (Moderate)",
        (0.21, 0.40): "약한 일치 (Fair)",
        (0.00, 0.20): "미약한 일치 (Slight)",
        (-1.00, 0.00): "일치하지 않음 (Poor)",
    }

    label = "Unknown"
    for (lo, hi), desc in interpretation.items():
        if lo <= kappa <= hi:
            label = desc
            break

    return {
        "kappa": round(kappa, 3),
        "interpretation": label,
        "acceptable": kappa >= 0.60,
        "action": (
            "평가 진행 가능" if kappa >= 0.60
            else "루브릭 재교육 또는 개선 필요"
        )
    }

4.3 ICC (Intraclass Correlation Coefficient)

3명 이상의 평가자 간 일치도, 또는 연속형 점수의 일치도를 측정한다.

Cohen’s κ가 2명 전용이라면, ICC는 3명 이상으로 확장한 것이다. 비유하면, κ는 두 명의 심사위원이 일치하는지 보는 것이고, ICC는 심사위원단 전체의 채점 패턴이 일관되는지 보는 것이다. ICC(2,1)은 “무작위로 뽑은 평가자 한 명의 점수가 다른 평가자의 점수를 얼마나 예측하는가”를 측정한다.

import pingouin as pg
import pandas as pd

def compute_icc(ratings_df, rater_col="rater", item_col="item", score_col="score"):
    """ICC(2,1): 무작위 효과 모델 기반 일치도

    Args:
        ratings_df: columns=[rater, item, score]
    """
    icc_results = pg.intraclass_corr(
        data=ratings_df,
        targets=item_col,
        raters=rater_col,
        ratings=score_col
    )
    # ICC(2,1): two-way random, single measures
    icc_2_1 = icc_results[icc_results["Type"] == "ICC2"].iloc[0]

    return {
        "icc": round(icc_2_1["ICC"], 3),
        "ci_95": (round(icc_2_1["CI95%"][0], 3), round(icc_2_1["CI95%"][1], 3)),
        "interpretation": (
            "우수" if icc_2_1["ICC"] >= 0.75
            else "양호" if icc_2_1["ICC"] >= 0.60
            else "불충분 — 루브릭 개선 필요"
        )
    }

4.4 일치도가 낮을 때의 대응

κ / ICC 판정 조치
≥ 0.80 우수 평가 진행
0.60 ~ 0.79 양호 불일치 사례 토론 후 진행
0.40 ~ 0.59 보통 루브릭 개정 + 재교육 + pilot 재실시
< 0.40 불충분 루브릭 전면 재설계

왜 κ ≥ 0.60을 최소 기준으로 삼는가: κ < 0.60이면 두 평가자의 점수 차이가 평균 1~2점에 달한다. 5점 척도에서 1.5점 차이는 “3점(부분적 답변)” vs “4.5점(거의 완벽)”을 구분하지 못한다는 뜻이다. 이런 평가로 구성 A(평균 3.8점)와 구성 B(평균 4.1점)의 차이를 판정하면, 0.3점 차이가 실제 품질 차이인지 평가자 간 변동인지 알 수 없다. 평가자 간 변동이 처치 효과보다 크면, 표본을 아무리 늘려도 올바른 결론에 도달할 수 없다.


5 자동 평가 vs 인간 평가 상관 검증

5.1 절차

Step 1: 인간 평가 셋 구축
  → 200~300개 질의-응답 쌍을 2명 이상의 평가자가 평가

Step 2: 동일 셋에 자동 평가 적용
  → LLM-as-Judge로 동일 기준으로 평가

Step 3: 상관 분석
  → Spearman ρ 또는 Pearson r 계산

Step 4: 판정
  → ρ ≥ 0.7: 자동 평가로 대체 가능
  → 0.5 ≤ ρ < 0.7: 자동 평가 사용 가능하나 주기적 인간 보정 필요
  → ρ < 0.5: 자동 평가 신뢰 불가, 인간 평가 비중 확대
from scipy.stats import spearmanr
import numpy as np

def validate_auto_evaluation(human_scores, auto_scores):
    """자동 평가와 인간 평가의 상관을 검증한다"""
    corr, p_value = spearmanr(human_scores, auto_scores)

    # 점수 차이 분포
    diffs = np.array(auto_scores) - np.array(human_scores)

    return {
        "spearman_rho": round(corr, 3),
        "p_value": p_value,
        "mean_diff": round(np.mean(diffs), 3),  # 양수 = 자동이 관대
        "std_diff": round(np.std(diffs), 3),
        "auto_bias": (
            "자동 평가가 관대" if np.mean(diffs) > 0.3
            else "자동 평가가 엄격" if np.mean(diffs) < -0.3
            else "편향 없음"
        ),
        "reliability": (
            "대체 가능" if corr >= 0.7
            else "보정 후 사용" if corr >= 0.5
            else "신뢰 불가"
        ),
    }

5.2 보정(Calibration) 방법

자동 평가가 체계적으로 편향되어 있으면 선형 보정을 적용한다:

from sklearn.linear_model import LinearRegression

def calibrate_auto_scores(human_scores, auto_scores, new_auto_scores):
    """인간 점수 기준으로 자동 점수를 보정한다"""
    model = LinearRegression()
    model.fit(np.array(auto_scores).reshape(-1, 1), human_scores)

    calibrated = model.predict(np.array(new_auto_scores).reshape(-1, 1))
    return {
        "calibrated_scores": calibrated,
        "slope": round(model.coef_[0], 3),
        "intercept": round(model.intercept_, 3),
        "interpretation": (
            f"보정 식: human_equiv = {model.coef_[0]:.2f} × auto + {model.intercept_:.2f}"
        )
    }

6 평가 프로세스 설계

6.1 실무 워크플로우

평가 대상 선정 (무작위 샘플링 또는 층화 샘플링)
    ↓
평가자 배정 (각 항목 최소 2명)
    ↓
독립 평가 (평가자 간 논의 금지)
    ↓
일치도 계산 (κ ≥ 0.60?)
    ↓
┌─ YES → 평가 결과 확정
└─ NO → 불일치 항목 토론 → 합의 또는 3번째 평가자

6.2 평가 항목 수 결정

def required_evaluation_items(
    expected_correlation: float = 0.7,
    ci_width: float = 0.15,
    confidence: float = 0.95
) -> int:
    """자동-인간 상관 검증에 필요한 평가 항목 수

    Fisher's z transformation 기반
    """
    from scipy.stats import norm
    z = norm.ppf((1 + confidence) / 2)
    # 상관계수의 표준오차: 1/√(n-3)
    n = (2 * z / ci_width) ** 2 + 3
    return int(np.ceil(n))

# 상관 0.7, 신뢰구간 폭 ±0.15 → 약 140개 항목 필요
n_items = required_evaluation_items()
print(f"필요 평가 항목 수: {n_items}")

6.3 MINERVA 적용

단계 활동 항목 수 평가자
Pilot 루브릭 검증 + 평가자 훈련 30 2명
일치도 확인 κ ≥ 0.60 확인 50 2명
본 평가 자동-인간 상관 검증 150 2명
정기 보정 자동 평가 드리프트 확인 50/월 1명

7 관련 주제

선행 지식

시리즈 다음 포스트

다른 카테고리 연결

  • 통계 기초 — 상관 분석, 분산 분석의 이론적 기반

Subscribe

Enjoy this blog? Get notified of new posts by email: