LLM 답변 평가 — 환각과 편향을 숫자로 만드는 법

Published:

LLM 출력은 assert response == expected 로 검증할 수 없다. 같은 질문에도 매번 다른 문장이 나오고, 그 다른 문장들이 전부 정답일 수 있기 때문이다. 이 글은 그 정답이 없는 출력을 숫자로 채점하는 법이다 — 환각을 비율로 만들고, 편향을 쌍(pair)으로 드러내고, 채점자(LLM judge)의 편향까지 통제해서, 최종적으로 “이 모델, 배포해도 되나?” 에 예/아니오로 답할 수 있게 만든다.

관통하는 한 문장을 먼저 두면:

자유형 출력을 그대로 채점하지 마라. 검증 가능한 단위(claim, 쌍, rubric 항목)로 쪼갠 다음, 그 단위를 채점하라.

1. 왜 기존 테스트가 안 통하는가

전통적인 소프트웨어 테스트는 두 가지를 전제한다 — 결정성(같은 입력이면 같은 출력)과 유일한 정답(expected 값이 하나로 정의됨). LLM 은 둘 다 깬다.

전제일반 코드LLM
결정성같은 입력 → 같은 출력temperature 0 이어도 버전·인프라에 따라 출력 변동
정답expected 값 하나“맞는 답변” 이 무한히 많음 (표현만 다른)
실패 정의diff 가 있으면 실패표현이 달라도 의미가 맞으면 통과여야 함

그래서 LLM 평가는 “출력이 기대값과 같은가” 가 아니라 “출력이 어떤 성질을 만족하는가” 를 묻는다. 성질(property) 기반으로 바뀌는 순간, 평가의 문제는 두 개로 쪼개진다 — ① 어떤 성질을 잴 것인가, ② 그 성질을 누가/어떻게 채점할 것인가.

2. 무엇을 재는가 — 세 가지 성질

품질·안전성 평가에서 실무적으로 가장 자주 재는 성질은 세 개다. 용어를 먼저 고정한다.

  • 충실성 (faithfulness) — 답변이 주어진 근거(context) 에서 벗어나지 않는가. RAG 파이프라인에서 검색된 문서에 없는 말을 지어내면 충실성 위반이다.
  • 사실성 (factual accuracy) — 답변이 세상의 사실 과 맞는가. 근거 문서 없이 모델 자체 지식으로 답할 때 재는 성질이다.
  • 편향 (bias) — 입력의 보호 속성(성별·연령·지역 등)만 바꿨을 때 답변의 품질이나 결론이 달라지는가.

흔히 뭉뚱그려 “환각(hallucination)” 이라 부르는 것은 앞의 두 개다. 근거가 있는데 근거 밖의 말을 하면 충실성 문제, 근거가 없는데 틀린 사실을 지어내면 사실성 문제 — 원인이 다르므로 처방도 다르다. 충실성 위반은 프롬프트·검색 개선으로, 사실성 위반은 근거 주입(RAG)이나 거부 학습으로 고친다. 평가 지표를 분리해 두지 않으면 “환각률 5%” 라는 숫자만 남고 어디를 고쳐야 하는지 모르게 된다.

3. 환각을 숫자로 — claim 분해

환각 측정의 핵심 기법은 답변을 원자적 주장(atomic claim)으로 쪼갠 뒤, 주장 단위로 근거 대조하는 것이다. Ragas 의 faithfulness, FactScore 가 전부 이 구조다.

답변: "카프카는 2011년 링크드인에서 공개됐고, 스칼라로 작성됐으며,
       기본 포트는 9093이다."

① claim 분해
   c1. 카프카는 2011년 링크드인에서 공개됐다
   c2. 카프카는 스칼라로 작성됐다
   c3. 카프카의 기본 포트는 9093이다

② 근거 대조 (근거 문서 또는 사실 DB 와 entailment 판정)
   c1 → 지지됨
   c2 → 지지됨
   c3 → 반박됨 (기본 포트는 9092)

③ faithfulness = 지지된 claim / 전체 claim = 2/3 ≈ 0.67

답변 전체에 1~5점을 매기는 방식과 비교하면 장점이 뚜렷하다 — 어느 문장이 왜 틀렸는지가 그대로 남는다. 점수가 낮게 나온 케이스를 열면 “c3 이 반박됨” 이 보이므로, 원인 분석(검색이 포트 정보를 못 가져왔나? 모델이 지어냈나?)으로 바로 이어진다.

Ragas 로는 이렇게 잰다:

from ragas import evaluate
from ragas.metrics import faithfulness

result = evaluate(
    dataset,          # question, answer, contexts 컬럼을 가진 데이터셋
    metrics=[faithfulness],
)
# faithfulness: 0.0 ~ 1.0, claim 분해와 대조를 내부에서 LLM 이 수행

주의할 점 하나 — claim 분해와 entailment 판정 자체를 LLM 이 수행하므로, 측정기에도 오차가 있다. 그래서 4절의 judge 통제 기법이 여기에도 그대로 적용된다.

4. 누가 채점하는가 — LLM-as-a-Judge 와 그 편향

claim 분해든 rubric 채점이든, 사람이 전부 할 수는 없다. 실무 표준은 강한 LLM 에게 채점을 시키는 것(LLM-as-a-Judge) 이다. 채점 방식은 세 가지다.

방식하는 일적합한 경우
pointwise답변 하나에 rubric 기준 점수절대 기준이 명확할 때 (환각 유무 등)
pairwise답변 A vs B 중 승자 선택모델·프롬프트 비교, 점수 척도가 애매할 때
reference-guided정답 예시를 주고 비교 채점정답셋이 있을 때 — 가장 안정적

문제는 judge 자신이 편향돼 있다는 것이다. 알려진 편향과 통제법:

  • 위치 편향 (position bias) — pairwise 에서 먼저 제시된 답을 선호한다. → A/B 순서를 뒤집어 두 번 채점하고, 두 번 모두 이긴 쪽만 승자로 인정한다. 결과가 갈리면 무승부 처리.
  • 장황함 편향 (verbosity bias) — 긴 답변에 높은 점수를 준다. → rubric 에 “길이는 채점 기준이 아니다” 를 명시하고, 길이가 크게 다른 쌍은 따로 표집해 검증한다.
  • 자기 선호 (self-preference) — 자기 계열 모델의 답변을 선호한다. → 평가 대상과 다른 계열의 judge 를 쓰거나, 여러 judge 의 앙상블로 채점한다.

그리고 가장 중요한 통제 — judge 를 인간 라벨로 보정(calibration)한다. 표본 케이스에 인간 라벨을 만들고, judge 점수와의 일치율을 잰다. 일치율이 낮으면 judge 프롬프트(rubric, few-shot 예시)를 고치고 다시 잰다. 이 보정 없이 judge 점수를 그대로 믿는 것은 검증 안 된 자로 길이를 재는 것과 같다.

인간 라벨 쪽에도 품질 기준이 필요하다. 평가자 간 일치도(Inter-Annotator Agreement)를 Cohen’s kappa 로 재서, 통상 κ ≥ 0.6 을 넘지 못하면 라벨이 아니라 rubric 이 문제라는 신호로 본다 — 사람끼리도 합의 못 하는 기준으로 LLM 을 채점할 수는 없다.

5. 편향을 드러내는 법 — counterfactual 쌍

편향 측정의 기본 도구는 보호 속성 하나만 바꾼 입력 쌍(counterfactual pair) 이다.

입력 A: "30대 남성 직장인인데, 대출 한도가 궁금합니다."
입력 B: "30대 여성 직장인인데, 대출 한도가 궁금합니다."

→ 두 답변의 결론·정보량·톤이 다르면 편향 신호

한 쌍으로는 우연일 수 있으므로, 속성(성별·연령·지역·직업)마다 수십~수백 쌍의 템플릿을 만들어 집단 단위 통계로 본다 — 답변 길이 분포, 거부율, 결론(승인/거절 뉘앙스)의 차이를 속성별로 비교한다. 개별 케이스의 “이 답변이 편향됐다” 는 판정은 흔들리지만, “여성 표현 입력에서 거부율이 12%p 높다” 는 집단 통계는 흔들리지 않는다.

이 방식의 한계도 알아두자 — counterfactual 쌍은 명시적 속성 언급에 의한 편향만 잡는다. 이름·어투 같은 간접 신호로 새는 편향은 별도 템플릿(이름 치환 등)이 필요하다.

6. 점수에서 게이트로 — 평가를 프로세스로 만들기

여기까지가 “어떻게 재는가” 였다면, 마지막 문제는 잰 숫자를 어디에 쓰는가 다. 일회성 리포트로 끝나는 평가는 다음 모델 업데이트 때 무효가 된다. 평가는 게이트가 되어야 한다.

① eval set 구축     실사용 로그 표집 + 엣지케이스 + 적대적 케이스
② rubric 문서화     성질별 통과/실패 기준을 명시적으로
③ 회귀 게이트       모델·프롬프트가 바뀔 때마다 자동 재평가 (CI)
④ 온라인 모니터링   배포 후 실트래픽 표집 → 오프라인 지표로 재채점
⑤ 실패 분석 루프    실패 케이스 → 원인 분류 → eval set 에 편입

두 가지가 특히 자주 빠진다.

eval set 의 대표성. 팀이 상상해서 만든 질문만으로 구성하면, 실사용자가 던지는 이상한 질문(오타, 다중 의도, 도메인 밖 질문)이 통째로 빠진다. 실로그 표집을 기본으로 두고, 상상 케이스는 보강으로만 쓴다.

실패 케이스의 환류. ⑤ 가 없으면 eval set 이 낡는다. 온라인에서 발견된 새 실패 유형은 반드시 eval set 에 들어가야, 같은 실패가 다음 배포에서 게이트에 걸린다 — 일반 개발에서 버그마다 회귀 테스트를 추가하는 것과 정확히 같은 원리다.

정리

처음 문장으로 돌아가면 —

자유형 출력을 그대로 채점하지 마라. 검증 가능한 단위로 쪼갠 다음, 그 단위를 채점하라.

  • 환각은 claim 분해 → 근거 대조 → 지지 비율 로 숫자가 된다. 충실성과 사실성은 원인이 다르므로 지표를 분리한다.
  • 채점자(LLM judge)도 편향된다 — 순서 뒤집기, 길이 통제, 앙상블로 통제하고, 인간 라벨(κ ≥ 0.6)로 보정한다.
  • 편향은 counterfactual 쌍의 집단 통계로 드러낸다. 개별 판정이 아니라 분포 차이를 본다.
  • 점수는 게이트가 될 때만 의미가 있다 — eval set 은 실로그에서 표집하고, 실패 케이스는 eval set 으로 환류시킨다.

도구는 그 다음이다. claim 기반 RAG 평가는 Ragas, 범용 지표·CI 통합은 DeepEval, 프롬프트 회귀 테스트는 promptfoo, 자동 레드팀은 garak 부터 보면 된다 — 전부 위의 구조(성질 정의 → 단위 분해 → judge 채점)를 구현한 것들이라, 구조를 먼저 이해하고 열면 문서가 훨씬 빨리 읽힌다.