지난 글에서 에이전트를 평가할 때 최종 정답률 하나로는 고칠 자리를 못 찾는다는 이야기를 했다. RAG도 같은 성질을 갖는다. 그리고 이유가 더 단순하다 — RAG는 서로 다른 두 부품이 직렬로 붙어 있고, 그중 하나만 고장 나도 답이 틀리기 때문이다.
앞 구간은 정보 검색의 문제이고 뒤 구간은 생성의 문제다. 쓰는 지표도 다르고, 필요한 라벨도 다르고, 나빠졌을 때 손대는 자리도 다르다. 한 점수로 합치는 순간 이 구별이 사라진다.
검색 구간 — 무엇을 세고 있는지 정확히 알기
검색 지표는 대부분 「@k」가 붙는다. 상위 개만 보고 잰다는 뜻이고, RAG에서 는 실제로 프롬프트에 넣는 문서 개수다.
Recall@k는 그 질문의 정답 문서 중 몇 개가 상위 안에 들어왔는지를 잰다.
RAG에서 가장 먼저 봐야 할 지표다. 이유는 단순하다 — 여기서 놓친 문서는 뒤 구간이 아무리 좋아도 되살릴 수 없다. Recall@k가 0.6이면 질문의 40%는 애초에 답할 근거가 프롬프트에 없는 상태이고, 그 40%에 대해 생성 모델이 할 수 있는 최선은 「모른다」고 답하는 것이다.
Precision@k는 반대쪽을 잰다.
를 키우면 Recall@k는 오르고 Precision@k는 떨어진다. 이 둘이 반대로 움직이므로 「 를 몇으로 할까」는 저울질이 된다. 다만 RAG에서 Precision@k가 낮다는 것은 검색 정확도만의 문제가 아니라 관련 없는 문서가 컨텍스트를 차지해 토큰을 쓰고 모델을 헷갈리게 한다는 뜻이라 무시할 수 없다.
MRR(Mean Reciprocal Rank)은 첫 정답이 몇 번째에 있었는지만 본다. 첫 정답의 순위를 이라 하면 그 질문의 점수는 이고, 전체 질문에 대해 평균한다.
1등이면 1점, 2등이면 0.5점, 5등이면 0.2점이다. 정답 문서가 사실상 하나뿐인 질문에 어울리고, 여러 근거를 모아야 답이 되는 질문에는 맞지 않는다.
nDCG@k는 순위와 관련도를 함께 반영한다. 문서마다 관련도 를 매기고 아래쪽에 있을수록 깎는다.
이것을 이상적인 순서로 정렬했을 때의 값으로 나눠 0~1로 만든 것이 nDCG@k다. 관련도를 0/1이 아니라 등급으로 매길 수 있을 때 쓴다. 「정확히 답이 적힌 문서」와 「관련은 있지만 답은 없는 문서」를 구별해 라벨링했다면 nDCG가 그 구별을 반영해 주고, 전부 0/1로 라벨링했다면 nDCG는 대체로 다른 지표와 같은 결론을 낸다.
| 지표 | 쓰기 좋은 자리 | 놓치는 것 |
|---|---|---|
| Recall@k | RAG의 상한을 확인할 때. 첫 번째로 본다 | 순위를 전혀 안 본다 |
| Precision@k | 컨텍스트 낭비를 볼 때 | 정답을 다 가져왔는지 모른다 |
| MRR | 정답 문서가 하나인 질문 | 두 번째 이후 정답을 안 본다 |
| nDCG@k | 관련도를 등급으로 매겼을 때 | 등급 라벨이 없으면 이점이 없다 |
정답 문서 라벨은 어떻게 만드나
위 넷은 전부 「이 질문의 정답 문서가 무엇인지」를 알아야 잰다. 이 라벨을 만드는 것이 RAG 평가에서 가장 비싼 작업이고, 그래서 가장 자주 대충 넘어가는 자리다.
문서가 수만 건일 때 질문 하나마다 전체를 훑을 수는 없다. 실무에서 쓰는 방법은 셋이다.
- 풀링. 여러 검색 방식으로 각각 상위 20개를 뽑아 합집합을 만들고 그것만 라벨링한다. 합집합 밖에 정답이 있으면 놓치지만, 검색 방식을 여럿 섞으면 놓치는 비율이 꽤 낮아진다
- 역방향 생성. 문서를 먼저 고르고 그 문서로만 답할 수 있는 질문을 모델에게 만들게 한다. 라벨이 저절로 붙는다는 것이 장점이고, 질문이 문서의 표현을 그대로 따라 해서 검색이 쉬워진다는 것이 함정이다. 만든 질문을 사람이 다시 쓰는 단계를 넣는다
- 운영 로그. 사용자가 실제로 물은 질문에 사람이 라벨을 붙인다. 가장 정확하지만 가장 느리다
셋을 섞어 쓰되 어느 방법으로 만든 라벨인지 질문마다 기록해 둔다. 역방향 생성으로 만든 질문의 Recall@k가 0.95이고 운영 로그 질문이 0.62라면, 그 차이가 곧 「우리 지표가 실제보다 얼마나 낙관적인가」의 크기다.
생성 구간 — 라벨 없이 잴 수 있는 것들
뒤 구간 지표는 정답 문서 라벨이 없어도 잰다. 질문·근거·답 셋만 있으면 되기 때문이고, 그래서 운영 트래픽에 그대로 붙일 수 있다.
Faithfulness(근거 충실도)는 답에 있는 주장이 근거에서 확인되는지를 본다. 재는 방법은 답을 주장 단위로 쪼개고, 주장마다 「이 근거로 뒷받침되는가」를 판정한 뒤 비율을 내는 것이다.
쪼개는 단계를 생략하고 답 전체를 한 번에 판정하면 값이 뭉개진다. 다섯 문장 중 한 문장만 지어낸 답이 「대체로 맞음」으로 넘어가기 때문이다. 주장 단위로 쪼개는 것이 이 지표의 핵심이고, 쪼개기를 모델에게 시키면 그 단계도 채점 대상이다.
Answer relevance는 답이 질문에 답했는지를 본다. 근거에 충실하기만 하고 질문과 상관없는 답이 실제로 나온다 — 근거를 요약해 버리는 경우가 대표적이다. 답에서 역으로 질문을 여러 개 생성해 원래 질문과의 유사도를 재는 방식이 흔히 쓰인다.
Context precision과 Context recall은 이름은 검색 지표를 닮았지만 정답 문서 라벨 없이 잰다. 앞의 것은 실제로 답에 쓰인 문서가 상위에 있었는지를, 뒤의 것은 정답을 만들려면 필요했던 근거가 컨텍스트에 다 있었는지를 본다. 정답 답변 문장이 있어야 뒤의 것을 잴 수 있다.
두 구간을 맞대면 원인이 나온다
지표를 나눠 재는 이유는 숫자를 많이 갖기 위해서가 아니다. 두 구간의 결과를 맞대면 틀린 답이 어느 칸에 있는지가 정해지기 때문이다.
오른쪽 위 칸이 특히 위험하다. 검색이 엉뚱한 문서를 가져왔는데 생성이 그것을 충실히 요약하면 Faithfulness가 높게 나온다. 근거와 답이 잘 맞으니까 그렇다. 근거 충실도만 보고 있으면 이 실패가 보이지 않고, Recall@k를 함께 봐야 잡힌다. 자동 채점을 붙일 때 두 구간 중 하나만 붙이면 안 되는 이유가 이것이다.
진단은 표로 정리해 두면 편하다.
| 검색 지표 | 생성 지표 | 먼저 볼 자리 |
|---|---|---|
| 낮음 | 높음 | 청킹 크기, 임베딩 모델, , 질의 재작성 |
| 높음 | 낮음 | 프롬프트, 생성 모델, 근거 인용 강제 |
| 낮음 | 낮음 | 데이터 자체. 문서에 답이 없을 수 있다 |
| 높음 | 높음 | 답의 형식·완성도. 루브릭 쪽 문제다 |
세 번째 줄이 가장 자주 잘못 읽힌다. 두 지표가 다 낮으면 시스템이 나쁘다고 결론 내리기 쉬운데, 문서 집합에 애초에 답이 없는 질문이 섞여 있는 경우가 흔하다. 평가 세트를 만들 때 「답할 수 없는 질문」을 일부러 넣고 그것들이 「모른다」로 답해지는지 따로 세는 편이 낫다.
재기 전에 정해야 하는 것
지표를 붙이기 전에 정해 두지 않으면 나중에 숫자를 못 이어 읽는 값들이 있다.
- 를 고정한다. Recall@5와 Recall@10을 섞어 보고하면 개선이 실제 개선인지 를 키운 것인지 알 수 없다. 하나를 기준으로 삼고 나머지는 참고로 둔다
- 관련도 라벨의 등급 수를 고정한다. 0/1로 하다가 0/1/2로 바꾸면 nDCG 값이 통째로 움직인다
- 재순위 전후를 구별해 잰다. 재순위 모델을 붙였다면 1차 검색의 Recall이 상한이므로 그것을 따로 기록한다. 재순위는 순서를 바꿀 뿐 없는 문서를 만들지 못한다
- 채점 모델에 버전을 붙인다. 지난 글에서 궤적 채점기에 붙인 것과 같은 이유다
정리
RAG 평가는 지표를 많이 붙이는 일이 아니라 구간을 나눠 붙이는 일이다. 앞 구간은 정답 문서 라벨을 만들어야 재고, 뒤 구간은 라벨 없이 운영 트래픽에서 잰다.
순서를 하나만 정한다면 Recall@k부터다. 그 값이 RAG 전체의 천장이고, 천장이 낮은 채로 프롬프트를 아무리 다듬어도 올라가지 않는다. 천장을 확인한 다음에 그 아래에서 생성이 얼마나 손해를 내고 있는지 재면 된다.
읽어주셔서 감사합니다. 😊

