포스트

RAG 연습 (4) — 혼동행렬을 알면 Ragas는 거의 다 읽힌다

RAG 연습 (4) — 혼동행렬을 알면 Ragas는 거의 다 읽힌다

RAG 연습 (3)에서 Ragas(Retrieval Augmented Generation Assessment)로 점수를 뽑았습니다. 그런데 점수가 0.847이든 0.473이든, 이 숫자가 무엇을 의미하는지를 알아야 어디를 고쳐야 할지가 보입니다.

다행히 Ragas의 메트릭 이름은 우연이 아닙니다. context_precision·context_recall·faithfulness는 클래식 머신러닝 분류 모델(스팸 분류, 이미지 분류, 암 진단 같은 “관련/무관” 이진 판별기)에서 쓰던 Precision·Recall과 같은 수식, 다른 대상입니다. 혼동행렬(Confusion Matrix)을 한 번이라도 본 적 있다면, 그 직관 그대로 RAG 점수를 읽을 수 있습니다.

혼동행렬 복습 — 두 가지 실수

분류기는 “관련 있다/없다”를 예측합니다. 실제 정답과 비교하면 4가지 경우가 나옵니다.

 예측: 관련예측: 무관
실제: 관련TP (맞게 잡음)FN (놓침)
실제: 무관FP (잘못 잡음)TN (맞게 무시)

각 칸의 약자는 이렇게 읽습니다.

  • TP (True Positive, 진양성): 관련 있다고 잡았고 실제로 관련 있음. 맞춘 것.
  • FN (False Negative, 거짓 음성): 무관하다고 본 것이 실제로는 관련 있었음. 놓친 것.
  • FP (False Positive, 거짓 양성): 관련 있다고 잡았으나 실제로는 무관. 노이즈.
  • TN (True Negative, 진음성): 무관하다고 본 것이 실제로도 무관. 맞춘 것.

TP와 TN은 잘 맞춘 경우라 따로 신경 쓸 일이 없습니다. 손볼 곳을 가리키는 건 FP와 FN, 두 가지 실수입니다. 이 4칸을 여러 방식으로 조합해서 평가 메트릭을 뽑는데, 분류 모델에서 흔히 쓰는 건 다섯 개입니다.

  • Precision = TP / (TP + FP). 내가 잡은 것 중 진짜 맞는 비율.
  • Recall = TP / (TP + FN). 실제 정답 중 내가 잡은 비율.
  • F1-score: Precision과 Recall의 조화평균. 둘 중 한쪽이 떨어지면 같이 떨어지는 합산 점수.
  • Accuracy = (TP + TN) / 전체. 전체 중 맞춘 비율.
  • FPR (False Positive Rate) = FP / (FP + TN). 무관한 것 중 잘못 잡은 비율. 분류 임계값을 움직이며 (FPR, Recall) 쌍을 그리면 ROC curve가 되고, 그 아래 면적이 AUC입니다.

어느 쪽이 더 중요한지는 상황에 따라 다릅니다. 스팸 필터는 정상 메일을 스팸으로 보내면(FP) 큰일이라 Precision 중심으로 평가하고, 암 진단은 암을 정상이라 하면(FN) 큰일이라 Recall 중심으로 평가합니다.

이 다섯 중 RAG 평가에 옮겨오는 건 사실상 Precision과 Recall 둘뿐입니다. 나머지 셋은 RAG에 대응되는 메트릭이 없습니다.

  • F1은 Ragas가 안 만듭니다. 검색과 생성을 분리해 4개 점수를 따로 보여주는 쪽을 택했고, 그걸 한 숫자로 뭉개는 합산은 제공하지 않습니다. 단계별로 어디가 약한지 보려면 합산보다 분리가 낫다는 판단입니다.
  • Accuracy는 RAG 검색에서 의미가 없습니다. 코퍼스(corpus, RAG가 검색 대상으로 삼는 인제스트된 문서 묶음) 수십만 청크 중 한 질문에 관련 있는 건 보통 몇 개뿐이라, “무관”으로 맞춘 TN이 분모를 압도해 점수가 항상 0.99대로 찍힙니다.
  • FPR·ROC·AUC는 분류 임계값을 움직이며 보는 곡선인데, RAG에선 임계값 대신 top_k(몇 개 가져올지)나 RRF 가중치를 손으로 움직이며 비슷한 트레이드오프를 봅니다 — top_k를 늘리면 Recall이 오르고 Precision이 내려가는 식입니다. Ragas에 자동화돼 있진 않습니다.

그래서 이 글은 Precision·Recall 두 개로 좁혀 풀어갑니다.

RAG에는 두 단계가 있다

RAG 파이프라인은 검색과 생성, 두 단계로 나뉩니다.

1
질문 → [검색] → 컨텍스트 청크 → [생성] → 최종 답변

각 단계마다 FP·FN 실수가 따로 생깁니다.

단계FP 실수FN 실수
검색무관한 청크를 가져옴관련 청크를 놓침
생성컨텍스트에 없는 내용을 답변에 추가 (환각)컨텍스트의 핵심 사실을 답변에 미포함

Ragas의 4메트릭은 이 두 단계의 네 가지 오류를 각각 잰 것입니다.

context_precision — 검색 단계의 Precision

“내가 가져온 청크들 중 실제로 쓸모 있는 것의 비율”입니다.

질문 “납부지연 가산세율은?”에 대해 검색이 5개 청크를 가져왔다고 해 봅시다.

가져온 청크실제 관련?
국세기본법 제47조의3 내용TP
부가가치세 영세율 조항FP
가산세 계산 유권해석TP
소득세 원천징수 조항FP
연체이자율 시행규칙TP

context_precision = 3 / 5 = 0.60. 노이즈가 40%란 뜻입니다. 이 숫자가 낮으면 LLM 컨텍스트 창이 무관한 내용에 점유당해 답변 품질이 떨어집니다. reranker 품질을 올리거나, top_k를 줄이거나, 검색 가중치를 조정해야 합니다.

엄밀히는 Ragas 구현이 단순 Precision보다 조금 정교합니다. 순위(rank)까지 고려하는 Mean Average Precision(MAP)에 가깝습니다.

1
2
3
4
context_precision@K =
  Σ (k번째까지의 precision × k번째 청크의 관련성)
  ─────────────────────────────────────────
            전체 관련 청크 수

같은 3개가 관련 있어도 1·2·3등이 관련 있는 경우와 3·4·5등이 관련 있는 경우 점수가 다릅니다. 앞에 올수록 점수가 높습니다. “관련 문서를 앞으로 보냈는가”까지 평가하는 셈입니다. 직관 단계에선 Precision으로 이해하고, 튜닝할 때 이 차이를 기억해 두면 됩니다.

context_recall — 검색 단계의 Recall

“정답에 필요한 사실 중 실제로 컨텍스트에 들어 있는 비율”입니다.

Ragas는 ground_truth를 LLM으로 분해해 사실 단위로 쪼갭니다.

1
2
3
ground_truth: "국세기본법 제47조의3에 따라 미납세액 × 경과일수 × 0.022%"
   ↓ LLM 분해
['0.022%이다', '국세기본법 제47조의3이다', '경과일수 기준이다']

이 사실들이 가져온 컨텍스트에 있는지 하나씩 확인하고, 있는 사실 / 전체 사실로 점수를 냅니다.

이 숫자가 낮으면 검색이 정답 청크를 놓쳤다는 뜻입니다. 코퍼스에 그 조문이 아예 없거나, 있는데 검색이 못 찾았거나입니다. 코퍼스 확장(인제스트 추가), 청크 분할 전략 재검토, dense·sparse 가중치 조정으로 대응합니다.

faithfulness — 생성 단계의 Precision

“답변의 각 문장이 컨텍스트에 근거하는 비율”입니다. 이름은 다르지만 본질은 Precision입니다 — 단, 청크가 아니라 답변 문장에 적용한 Precision입니다.

답변을 문장 단위로 쪼개고, 각 문장이 컨텍스트에서 지지되는지 LLM이 판단합니다.

답변 문장컨텍스트에 근거?
“가산세율은 0.022%이다”TP
“한도는 미납세액의 75%이다”TP
“2023년부터 적용된다”FP (환각)

faithfulness = 2/3 ≈ 0.667. 낮으면 LLM이 컨텍스트 밖 지식(훈련 데이터에서 본 것)을 가져다 쓰는 환각입니다. 시스템 프롬프트에서 “컨텍스트에 없는 내용은 말하지 말 것”을 강하게 지시하거나, temperature가 0인지 확인하거나, 청크 길이를 조절합니다.

answer_relevancy — 생성 단계의 또 다른 관점

이건 혼동행렬 구조를 직접 따르지 않습니다. 대신 역방향 추론을 씁니다.

답변을 LLM에게 주고 “이 답변을 만들었을 법한 질문 3개를 생성해 보라”고 시킵니다. 그 생성된 질문들과 원래 질문의 임베딩 유사도를 평균 냅니다.

직관은 이렇습니다. 답변이 질문의 핵심에 집중돼 있다면, 그 답변으로 역으로 만든 질문도 원래 질문과 비슷해야 합니다. 만약 답변이 엉뚱한 얘기를 하고 있다면, 역생성 질문이 원래 질문과 멀어집니다.

왜 굳이 역방향이냐는 의문이 생길 만합니다. 정방향, 즉 질문과 답변을 직접 임베딩해 유사도를 재면 안 되냐는 것입니다. 그렇게 하면 답변이 길수록 유사도가 떨어지는 길이 편향이 생깁니다. 짧고 정확한 답변과 길고 정확한 답변이 같은 점수를 받지 못합니다. 답변에서 거꾸로 질문을 뽑으면 비교 대상이 둘 다 “질문” 길이가 되니 그 편향이 줄어듭니다.

faithfulness와 짝지어 보면 진단이 더 또렷해집니다. 둘 다 낮으면 답변이 컨텍스트도 못 따르고 질문도 비껴가는 환각, faithfulness만 높고 answer_relevancy가 낮으면 사실은 맞는데 묻는 것에 직접 답하지 않는 경우입니다. 후자는 프롬프트에 “질문에 직접 답하라”는 지시를 강화하거나 답변 형식 템플릿을 두면 잡힙니다.

다만 한계도 있습니다. 역방향 추론도 임베딩도 LLM과 임베딩 모델 품질에 의존합니다. 한국어 임베딩이 약하면 정상 답변도 점수가 낮게 찍힐 수 있어, 절대 점수보다 같은 모델 안에서의 회귀 흐름을 보는 게 안전합니다.

네 메트릭 한눈에

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
RAG 파이프라인

  질문 ───────────────────────────── 답변
         ↓                              ↑
      [검색]                         [생성]

  context_precision           faithfulness
  ─────────────────           ─────────────
  선택된 청크 중              생성된 문장 중
  관련 청크 비율              컨텍스트 근거 비율
  = Precision(검색)           = Precision(생성)

  context_recall              answer_relevancy
  ──────────────              ────────────────
  정답 사실 중                답변이 질문에
  컨텍스트에 있는 비율         얼마나 집중되나
  = Recall(검색)              (역방향 질문 유사도)
메트릭본질FP 잡기FN 잡기
context_precision검색 PrecisionO
context_recall검색 RecallO
faithfulness생성 PrecisionO
answer_relevancy역방향 유사도

실제 점수 읽어보기

지금 프로젝트에서 나온 점수입니다.

1
2
3
faithfulness       : 0.473   ← 생성 단계 환각 비율 높음
context_precision  : 0.599   ← 검색 노이즈 40% 수준
context_recall     : 0.553   ← 정답 사실의 절반 미검색

도메인별 키워드 매칭률을 같이 보면 진단이 더 또렷합니다.

1
2
3
4
세무 리스크  : 72%  ← 세법 코퍼스 있음 → 검색 가능
수익인식     : 29%  ← K-IFRS 기준서 없음 → 코퍼스 갭
부정 탐지    : 23%  ← 내부감사 룰북 없음 → 코퍼스 갭
계약/판례    : 46%  ← 하도급법·민법 일부 커버

수익인식·부정탐지의 낮은 context_recall은 Recall 문제, 즉 FN이 많다는 뜻입니다. 관련 청크가 코퍼스 자체에 없으니 아무리 검색해도 못 찾습니다. 검색 알고리즘을 만져서 풀 일이 아니라, 데이터를 더 넣어야 풀립니다.

faithfulness 0.473은 Precision 문제, FP입니다. LLM이 컨텍스트 밖에서 K-IFRS 지식을 끌어와 답을 채우고 있습니다. 코퍼스를 넣어 주거나, 프롬프트로 컨텍스트 밖 발화를 막아야 합니다.

개선 우선순위가 자연스럽게 정해집니다. K-IFRS 1115호를 인제스트하면 context_recallfaithfulness가 같이 오릅니다(있는 걸 LLM이 끌어다 쓰면 그게 더 이상 환각이 아니니까). 내부감사 표준을 추가하면 부정탐지 Recall이 오릅니다. 그 다음에 프롬프트를 다듬어 잔여 환각을 낮춥니다.

정리

개념분류 모델RAG (Ragas)
Precision내가 양성이라 한 것 중 진짜 양성검색한 청크 중 관련된 것 / 답변 문장 중 근거 있는 것
Recall실제 양성 중 내가 잡은 것정답 사실 중 컨텍스트에 있는 것
FP잘못 잡은 양성 (노이즈)무관한 청크 / 환각 문장
FN놓친 양성코퍼스 갭 / 검색 누락

낮은 점수가 어느 쪽 실수인지를 알면 손볼 곳이 정해집니다. context_recall이 낮으면 코퍼스, faithfulness가 낮으면 프롬프트, context_precision이 낮으면 검색 전략. 메트릭 이름이 어렵게 느껴졌다면 사실은 분류 모델에서 쓰던 그 Precision·Recall이 단계별로 따로 적용된 것뿐입니다.

(클로드 코드의 도움을 받았습니다.)

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.