본문 바로가기
AI2026년 7월 27일6분 읽기

RAG 검색 평가지표 — Recall@k·MRR·nDCG로 검색 품질 재기

YS
김영삼
조회 5
RAG 검색 평가지표 — Recall@k·MRR·nDCG로 검색 품질 재기

RAG 검색 평가지표는 "검색이 정답 문서를 잘 물어오는가"를 숫자로 재는 도구다. 크게 두 층이 있다. 하나는 검색 단계(retrieval)를 재는 Recall@k·MRR·nDCG 같은 순위 지표, 다른 하나는 생성 단계를 재는 faithfulness·answer relevancy 같은 지표다. 이 둘을 섞어 보면 "검색이 문제냐, 프롬프트가 문제냐"를 분리해서 진단할 수 있다.

RAG를 만들다 보면 "답이 이상한데 어디가 원인인지 모르겠다"는 벽에 부딪힌다. 검색이 엉뚱한 문서를 물어온 건지, 문서는 맞는데 모델이 못 읽은 건지, 감으로는 절대 안 갈린다. 그래서 지표가 필요하다. 나는 이 단계를 건너뛰고 프롬프트만 계속 만지다가 시간을 크게 날린 적이 있다.

검색 단계 지표

먼저 소규모라도 평가셋(golden set)이 있어야 한다. 질문과 "이 질문의 정답이 담긴 문서 id"를 짝지은 목록이다. 50~100개만 만들어도 방향을 잡기엔 충분하다. 이게 없으면 아래 지표를 아예 계산할 수 없다.

지표무엇을 보나순위 반영
Recall@ktop-k 안에 정답이 들어왔나안 함(있냐/없냐)
MRR첫 정답이 몇 등인가함(첫 정답)
nDCG@k관련 문서들이 위쪽에 잘 모였나함(전체)

Recall@k는 가장 직관적이다. "top-k 안에 정답이 하나라도 들어왔으면 1, 아니면 0". 순위는 안 본다. 그래서 "1차 검색이 정답을 최소한 후보에는 담아오는가"를 볼 때 쓴다. 리랭커를 붙이기 전이라면 이 지표를 먼저 봐야 한다 — Recall@50이 낮으면 리랭커를 아무리 좋게 만들어도 소용없다.

MRR(Mean Reciprocal Rank)은 첫 번째 정답의 순위를 본다. 정답이 1등이면 1, 2등이면 0.5, 3등이면 0.33… 이렇게 1/순위를 평균낸다. "정답이 얼마나 위쪽에 오는가"에 민감해서, 챗봇처럼 상위 몇 개만 쓰는 경우에 잘 맞는다.

nDCG@k는 관련 문서가 여러 개일 때, 그것들이 얼마나 위쪽에 잘 배치됐는지를 0~1로 잰다. 위쪽에 있을수록 로그로 가중치를 준다. 관련도가 이진(관련/무관)이 아니라 등급(매우 관련/약간 관련)일 때 특히 유용하다.

def recall_at_k(retrieved_ids, relevant_ids, k):
    top = set(retrieved_ids[:k])
    return 1.0 if top & set(relevant_ids) else 0.0
def reciprocal_rank(retrieved_ids, relevant_ids):
    for rank, doc_id in enumerate(retrieved_ids, start=1):
        if doc_id in relevant_ids:
            return 1.0 / rank
    return 0.0
# 평가셋 전체 평균이 곧 Recall@k, MRR
mrr = sum(reciprocal_rank(r, g) for r, g in eval_set) / len(eval_set)

생성 단계 지표

검색이 정답 문서를 잘 물어와도 최종 답이 틀릴 수 있다. 여기서 보는 게 faithfulness(충실성)answer relevancy(답변 관련성)다.

  • faithfulness: 답변의 각 주장이 검색된 문서로 뒷받침되는가. 즉 모델이 지어냈는지(환각) 여부. 이게 낮으면 검색은 됐는데 모델이 근거 없이 말을 보탠 것이다.
  • answer relevancy: 답변이 질문에 실제로 답하는가. 문서 내용을 충실히 옮겼어도 질문의 핵심을 비껴가면 이 값이 낮다.

이 둘은 사람이 일일이 채점하기 힘들어서, 요즘은 LLM을 채점자로 쓰는(LLM-as-judge) 방식이 흔하다. 답변과 근거 문서를 다른 모델에게 주고 "이 주장이 근거에 있나"를 판정시키는 식이다. RAGAS 같은 라이브러리가 이 계산을 자동화해준다. 다만 채점 모델도 완벽하진 않으니, 초반엔 사람 채점과 대조해 신뢰도를 확인하는 게 좋다.

지표로 원인 갈라내기

Recall은 높은데 답이 나쁘다 → 프롬프트/청킹/모델의 문제. Recall이 낮다 → 임베딩/검색 자체의 문제. faithfulness가 낮다 → 모델이 근거 없이 지어내는 중. 지표를 나눠 보면 손댈 곳이 보인다.

이렇게 층을 나눠 보는 게 핵심이다. 나는 한동안 "답이 이상하다 → 프롬프트를 고친다"만 반복했는데, 알고 보니 Recall@10이 0.5도 안 됐다. 검색이 절반은 정답을 놓치고 있었던 것이다. 프롬프트로는 절대 고칠 수 없는 문제였다. 숫자를 먼저 봤다면 며칠을 아꼈을 것이다.

자주 묻는 질문

평가셋은 몇 개나 만들어야 하나요?

완벽을 노리면 시작을 못 한다. 50~100개로 시작하는 걸 권한다. 실제 사용자 질문 로그에서 대표적인 걸 뽑고, 각 질문의 정답이 담긴 문서를 표시하면 된다. 적더라도 있는 것과 없는 것의 차이가 크다. 규모는 운영하면서 늘려가면 된다.

Recall@k에서 k는 몇으로 잡나요?

파이프라인 단계마다 다르게 본다. 1차 검색의 후보 크기(예: 50)로 Recall@50을 보면 "정답을 후보에 담아오는가"를, 최종적으로 모델에 넣는 개수(예: 5)로 Recall@5를 보면 "최종 컨텍스트에 정답이 있는가"를 잰다. 둘의 격차가 크다면 리랭킹/재정렬이 필요하다는 신호다.

MRR과 nDCG 중 뭘 봐야 하나요?

정답 문서가 보통 하나뿐이고 "그게 얼마나 위에 오는가"가 중요하면 MRR이 간단하고 충분하다. 관련 문서가 여러 개이고 등급(강한 관련/약한 관련)이 있으면 nDCG가 더 정밀하게 상황을 반영한다. 둘 다 계산 비용은 작으니 함께 봐도 부담 없다.

LLM-as-judge 점수를 그대로 믿어도 되나요?

맹신은 금물이다. 채점 모델도 편향이 있고 프롬프트에 따라 결과가 흔들린다. 초기에는 사람이 채점한 소규모 샘플과 상관관계를 확인해 캘리브레이션하고, 절댓값보다는 "버전 A vs B" 상대 비교로 쓰는 게 안전하다. 지표는 방향을 잡는 나침반이지 최종 판결문이 아니다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록