RAG 기반 테스트 시리즈 — 파트 2: 검색 품질 테스트 — 올바른 데이터를 가져오고 있습니까?
요약
RAG 시스템의 성능을 결정짓는 핵심 요소인 검색(Retrieval) 품질 테스트 방법을 다룹니다. 정밀도(Precision)와 재현율(Recall)의 개념을 통해 검색 품질을 정의하고, 이를 측정하기 위한 지표의 중요성을 설명합니다.
핵심 포인트
- RAG 성능은 검색 품질에 전적으로 의존함
- 정밀도(Precision)는 검색된 문서의 관련성을 측정
- 재현율(Recall)은 필요한 문서를 얼마나 찾아냈는지 측정
- 정밀도와 재현율 사이의 균형을 맞추는 것이 핵심 목표
RAG 기반 테스트 시리즈 — 파트 2: 검색 품질 테스트 — 올바른 데이터를 가져오고 있습니까?
"RAG 시스템의 성능은 검색(Retrieval)하는 내용의 품질에 달려 있습니다. 검색이 잘못되면 그 이후의 모든 과정은 모래 위에 쌓은 성과 같습니다."
파트 1에서는 전체적인 그림을 그렸습니다.
우리는 RAG가 무엇인지, 왜 전통적인 테스트 방식이 AI 시스템에서는 제대로 작동하지 않는지, 그리고 주요 실패 모드(Failure modes)가 어떤 모습인지 배웠습니다.
아직 파트 1을 읽지 않으셨다면 — 먼저 읽어보시기 바랍니다. 이 시리즈는 앞의 내용을 바탕으로 진행됩니다. 🔗
이제 파트 2에서는 — 본격적으로 실무에 뛰어들어 보겠습니다. 🛠️
우리는 모든 RAG 시스템의 첫 번째이자 가장 중요한 계층인 **검색 품질 (Retrieval quality)**에 대해 이야기할 것입니다.
대부분의 사람들이 놓치는 사실이 여기 있기 때문입니다 👇
🎯 왜 검색이 전부인가
파트 1에서 다룬 RAG 파이프라인(Pipeline)을 다시 떠올려 보세요:
사용자 질의 (User Query)
│
▼
...
검색이 어디에 위치하는지 주목하세요 — 체인의 바로 최상단에 있습니다.
만약 검색기(Retriever)가 잘못된 문서를 가져온다면, LLM(대규모 언어 모델)에게는 기회가 없습니다. LLM은 환각(Hallucination)을 일으키거나, 불완전한 답변을 내놓거나, 더 최악의 경우 — 관련 없는 문맥(Context)을 바탕으로 자신 있게 틀린 답을 내놓을 것입니다.
쓰레기가 들어가면 쓰레기가 나옵니다 (Garbage in. Garbage out).
아무리 뛰어난 LLM이라도 잘못된 검색을 구원할 수는 없습니다. 🗑️
이것이 바로 검색 테스트가 선택 사항이 아니라, 여러분의 전체 RAG 테스트 전략의 **기초 (Foundation)**인 이유입니다.
🧠 "좋은 검색"이란 도대체 무엇을 의미하는가?
무언가를 테스트하기 전에, 우리는 성공이 어떤 모습인지 정의해야 합니다.
검색의 경우, 성공은 두 가지 차원을 가집니다:
정밀도 (Precision) — 내가 검색한 문서들 중 실제로 관련이 있는 문서는 몇 개인가?
재현율 (Recall) — 존재하는 모든 관련 문서들 중 내가 실제로 검색해낸 문서는 몇 개인가?
예시를 통해 구체적으로 설명해 보겠습니다. 👇
여러분의 지식 베이스(Knowledge base)에 _"취소 정책은 무엇인가요?"_라는 질문과 관련된 5개의 문서가 있다고 가정해 봅시다.
여러분의 검색기가 4개의 문서를 반환했습니다.
- 그 4개 중 3개는 실제로 취소 정책에 관한 것입니다 ✅
- 그 4개 중 1개는 배송 정책에 관한 것입니다 ❌
- 관련 있는 문서 2개는 전혀 검색되지 않았습니다 ❌
따라서:
- 정밀도 (Precision) = 관련 검색된 문서 3개 / 총 검색된 문서 4개 = 75%
- 재현율 (Recall) = 관련 검색된 문서 3개 / 총 관련 문서 5개 = 60%
두 지표 모두 중요합니다. 하지만 두 지표는 서로 상충하는 방향으로 움직입니다.
높은 정밀도 (High precision)는 불필요한 정보(junk)로 LLM의 컨텍스트 (context)를 오염시키지 않는다는 것을 의미합니다.
높은 재현율 (High recall)은 LLM이 필요로 하는 중요한 정보를 놓치지 않는다는 것을 의미합니다.
목표는 두 지표의 균형을 맞추는 것입니다. ⚖️
📐 반드시 알아야 할 검색 지표 (Retrieval Metrics)
이제 더 깊이 들어가 보겠습니다. 실제 운영되는 RAG 시스템에서는 네 가지 핵심 지표로 검색 품질을 측정합니다.
1. Precision@K
"내가 검색한 상위 K개의 문서 중 — 몇 개가 관련이 있는가?"
Precision@K = (상위 K개 내의 관련 문서 수) / K
예시:
검색기 (retriever)에게 상위 5개의 문서를 요청했습니다 (K=5).
그중 3개가 관련이 있습니다.
Precision@5 = 3/5 = 0.6
이 지표는 검색된 컨텍스트 (context)에 노이즈 (noise)가 얼마나 포함되어 있는지를 알려줍니다. 노이즈가 높으면 = LLM이 혼란을 겪습니다.
2. Recall@K
"지식 베이스 (knowledge base)에 있는 모든 관련 문서 중 — 상위 K개 내에서 몇 개를 찾아냈는가?"
Recall@K = (상위 K개 내의 관련 문서 수) / (전체 관련 문서 수)
예시:
전체 관련 문서가 8개 있습니다.
상위 5개 검색 결과 중 4개를 찾아냈습니다.
Recall@5 = 4/8 = 0.5
이 지표는 검색이 얼마나 완전한지를 알려줍니다. 재현율 (recall)이 낮으면 = 답변이 불완전해집니다.
3. MRR — 평균 역순위 (Mean Reciprocal Rank)
"첫 번째 관련 문서가 리스트의 얼마나 높은 위치에 있는가?"
RR = 1 / (첫 번째 관련 문서의 순위)
MRR = 모든 쿼리 (query)에 대한 RR의 평균
예시:
- 쿼리 1: 첫 번째 관련 문서가 순위 1에 나타남 → RR = 1/1 = 1.0
- 쿼리 2: 첫 번째 관련 문서가 순위 3에 나타남 → RR = 1/3 = 0.33
- 쿼리 3: 첫 번째 관련 문서가 순위 2에 나타남 → RR = 1/2 = 0.5
MRR = (1.0 + 0.33 + 0.5) / 3 = 0.61
이것이 왜 중요할까요? LLM은 프롬프트 (prompt)의 앞부분에 나타나는 컨텍스트 (context)에 더 많은 가중치를 두기 때문입니다. 가장 관련성이 높은 문서가 순위 5에 묻혀 있다면, LLM은 이를 제대로 "보지" 못할 수도 있습니다.
4. NDCG — 정규화된 할인 누적 이득 (Normalized Discounted Cumulative Gain)
"가장 관련성이 높은 문서가 목록의 상단에 나타나고 있습니까?"
이것은 가장 정교한 지표입니다. 단순히 "올바른 문서를 검색했는가?"를 묻는 것이 아니라, "올바른 순서로 검색했는가?"를 묻습니다.
NDCG는 가장 관련성이 높은 문서를 맨 앞에 배치하는 시스템에는 보상을 주고, 중요한 문서를 목록 하단에 묻어버리는 시스템에는 페널티를 부여합니다.
점수는 0에서 1 사이의 범위를 가집니다. 높을수록 좋습니다. NDCG가 1.0이면 완벽한 순위(Ranking)를 의미합니다.
이 지표는 연구 논문과 실제 운영 중인 RAG 평가에서 가장 자주 접하게 될 지표입니다.
빠른 참조 표 (Quick Reference Table)
| 지표 | 측정 대상 | 최적의 용도 |
|---|---|---|
| Precision@K | 검색된 문서의 관련성 | 노이즈 제어 |
| ... |
🛠️ 실제 검색 테스트 작성해보기
이론은 이 정도면 충분합니다. 이제 직접 만들어 봅시다.
이 시리즈에서는 Python과 RAG 평가를 위한 선도적인 오픈 소스 프레임워크인 RAGAS를 사용합니다.
아직 Python 환경이 구축되지 않았다면, 다음 명령어가 필요합니다:
pip install ragas
pip install openai
pip install chromadb
1단계 — 간단한 지식 베이스(Knowledge Base) 설정하기
먼저, 검색할 대상이 필요합니다. ChromaDB(경량 벡터 데이터베이스)를 사용하여 최소한의 지식 베이스를 만들어 보겠습니다:
import chromadb
from chromadb.utils import embedding_functions
...
2단계 — 테스트 케이스 정의하기
이것이 가장 중요한 단계입니다. 질문과 그에 따라 검색되어야 하는 문서가 쌍으로 구성된 **정답 데이터셋 (Ground Truth Dataset)**이 필요합니다.
이것이 무작위 테스트와 제대로 된 평가를 구분 짓는 지점입니다. 👇
# 정답(Ground truth): 쿼리(query) → 실제로 관련 있는 문서 ID들
test_cases = [
{
...
참고: 이 정답 데이터셋을 구축하는 것은 실제적인 작업이며, 제대로 수행할 가치가 있는 작업입니다. 테스트 스위트(Test suite)의 품질은 정답 데이터셋의 품질에 달려 있습니다. 대규모로 이를 구축하는 방법에 대해서는 파트 5에서 더 자세히 다루겠습니다.
3단계 — 검색 실행 및 Precision@K 계산하기
def calculate_precision_at_k(retrieved_ids, relevant_ids, k):
"""
상위 K개의 검색된 문서 중 — 얼마나 많은 문서가 관련이 있었습니까?
...```
### 4단계 — 테스트 스위트 전체에 대한 MRR 계산하기
```python
def calculate_mrr(collection, test_cases, k=5):
"""
평균 역순위 (Mean Reciprocal Rank) — 첫 번째 관련 문서가 얼마나 높은 순위에 있습니까?
...```
### 5단계 — 단언문(Assertions)을 추가하여 실제 테스트로 만들기
이제 이를 테스트 스위트나 CI/CD 파이프라인에서 실행할 수 있도록 적절한 테스트 단언문(Assertions)으로 감싸보겠습니다:
```python
import pytest
K = 3
...```
다음 명령어로 실행하세요:
```bash
pytest test_retrieval.py -v
📊 점수가 실제로 의미하는 것은 무엇인가요?
이 테스트를 실행하고 나면, 나타나는 결과들을 다음과 같이 해석할 수 있습니다:
| 점수 범위 | 의미 | 조치 사항 |
|---|---|---|
| Precision@K > 0.8 | 깨끗한 검색, 낮은 노이즈 | ✅ 좋음 — 이 상태를 유지하세요 |
| ... |
🔴 실제로 마주하게 될 실제 실패 시나리오
제가 실제 RAG 시스템에서 목격했던 검색 실패 사례들과, 그러한 상황이 발생했을 때 지표가 어떻게 나타나는지 설명해 드리겠습니다.
실패 1 — 의미론적 불일치 (Semantic Mismatch)
발생 상황: 문서는 격식 있는 언어를 사용합니다. 반면 사용자는 일상적인 언어를 사용합니다. 임베딩 모델 (Embedding model)이 이 둘을 연결하는 데 어려움을 겪습니다.
문서 내용: "기업 계정의 구독 해지 절차"
사용자 질문: "플랜 어떻게 취소해요?"
...
해결책: 쿼리 (Query)를 의역한 버전들로 테스트하세요. 파이프라인에 쿼리 재작성 (Query rewriting) 단계를 추가하세요.
실패 2 — 청크 크기 문제 (Chunk Size Problems)
발생 상황: 문서가 너무 작게 청킹 (Chunked)되어 관련 정보가 여러 청크에 걸쳐 분산됩니다. 또는 너무 크게 청킹되어 관련 문장이 노이즈에 파묻힙니다.
정책 문서는 2,000단어입니다.
50단어 단위로 청킹되었습니다.
정답은 청크 4와 5에 걸쳐 있지만 — 청크 4만 검색되었습니다.
...
해결책: 다양한 청크 크기 (256, 512, 1024 토큰)를 실험해 보고, 테스트 스위트를 통해 재현율 (Recall)에 미치는 영향을 측정하세요.
실패 3 — 지식 베이스의 노후화 (Knowledge Base Staleness)
발생 상황: 정책이 변경되었습니다. 지식 베이스 (Knowledge Base)가 업데이트되지 않았습니다. 오래된 문서가 여전히 가장 높은 순위로 검색됩니다.
이전 문서: "환불은 14일 이내에 가능합니다" ← 검색됨 ✅ (하지만 틀림)
새 문서: "환불은 30일 이내에 가능합니다" ← 검색되지 않음 ❌
...
해결책: 테스트 케이스에 문서 버전 관리 (Document Versioning)를 추가하세요. 관련 쿼리에 대해 문서의 가장 최근에 업데이트된 버전이 검색되는지 확인(Assert)해야 합니다. 이것이 지식 베이스를 위한 **회귀 테스트 (Regression Test)**입니다.
🧩 종합하기
전체적인 검색 테스트 실행의 엔드 투 엔드 (End-to-End) 과정은 다음과 같습니다:
1. 정답 데이터셋 (Ground Truth Dataset) 정의 (쿼리 + 관련 문서 ID)
2. 각 쿼리에 대해 검색 실행
3. Precision@K, Recall@K, MRR, NDCG 계산
...
파트 5의 6단계에 도달하면 이 과정은 완전히 자동화될 것입니다. 지금 단계에서는 — 지표 (Metrics)를 정확하게 산출하는 것이 기초입니다. 🏗️
🔖 파트 2의 핵심 요약
실제로 중요한 사항들을 정리해 드립니다 👇
- 검색 (Retrieval)은 기초입니다 — 다른 모든 RAG 테스트는 검색이 올바르게 작동하는지에 달려 있습니다.
- 정답 데이터셋 (Ground Truth Datasets)은 선택이 아닌 필수입니다 — 측정하기 전에 무엇이 "올바른 검색"인지 정의해야 합니다.
- 다양한 지표를 사용하세요 — 정밀도 (Precision)는 노이즈에 대해 알려주고, 재현율 (Recall)은 완전성에 대해 알려주며, MRR은 순위 (Ranking)에 대해 알려줍니다.
- 임계값 (Thresholds)은 직접 설정해야 합니다 — 보편적인 "합격 점수"는 없습니다. 시스템의 위험 수준에 따라 임계값을 설정하고 반복 개선하세요.
- 검색 테스트는 지식 베이스가 변경될 때마다 실행되어야 합니다 — 이것이 여러분의 회귀 테스트 안전망입니다.
🚀 다음 단계
파트 3에서는 한 단계 더 깊이 들어갑니다.
우리는 이제 올바른 문서가 검색되고 있음을 확인했습니다.
하지만 검색된 컨텍스트 (Context)가 존재한다고 해서 LLM이 그것을 사용한다는 뜻은 아닙니다.
만약 LLM이 컨텍스트를 무시하고 마음대로 내용을 지어낸다면 어떻게 될까요?
그것이 바로 **환각 (Hallucination)**이며, 파트 3에서 다룰 핵심 내용입니다.
다음 내용을 다룰 예정입니다:
- RAG 문맥에서 충실도 (Faithfulness)가 실제로 의미하는 것
- 이를 프로그래밍 방식으로 측정하는 방법
- RAGAS를 사용하여 환각 (Hallucination)을 자동으로 탐지하는 방법
- 그리고 프로덕션 (Production)에 도달하기 전에 이를 잡아내는 테스트를 작성하는 방법
Part 1 — RAG란 무엇이며 왜 다른 테스트 방식이 필요한가 ✅ 완료
Part 2 — 검색 품질 테스트: 올바른 데이터를 가져오고 있습니까? ← 현재 위치
Part 3 — 충실도 및 환각 탐지 ← 다음 예정
...
파트 3를 놓치지 않도록 저를 팔로우 (Follow) 하세요 — 정말 흥미로운 내용이 기다리고 있습니다. 환각 탐지는 AI 테스트에서 가장 어려운 문제 중 하나이며, 우리는 이를 접근하기 쉽게 만들어 볼 것입니다. 🧠
아래에 댓글을 남겨주세요 👇
- 이전에 검색 품질을 측정해 본 적이 있나요, 아니면 이번이 처음인가요?
- RAG 시스템에서 어떤 청크 크기 (Chunk size)를 사용하고 계신가요? 서로의 노하우를 공유하고 싶습니다.
- 파트 3로 넘어가기 전에 파트 2 내용 중 더 깊이 다루었으면 하는 부분이 있나요?
모든 질문을 환영합니다. 함께 배워봅시다. 🙌
Faizal Shaikh | 시니어 자동화 엔지니어 (Senior Automation Engineer) | AI & RAG 기반 테스트
저와 LinkedIn에서 연결하세요
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기