들어가며
LLM의 할루시네이션을 극복하기 위한 대안으로 RAG(Retrieval-Augmented Generation)가 나왔지만, RAG에서도 어떻게 설정하는가에 따라 품질이 극명하게 갈립니다.
결국 RAG(Retrieval-Augmented Generation)를 구축해서 벡터 DB 검색과 LLM 답변 생성이 정상적으로 동작하는 걸 확인했다고 해서 끝이 아니란 이야기 입니다. “답이 그럴듯하게 나온다”와 “답이 실제로 정확하고 근거가 있다”는 전혀 다른 이야기이기 때문입니다.
RAG는 두 단계로 구성됩니다.
- 검색(Retrieval) 단계: 질문과 관련된 문서(청크)를 벡터 DB에서 찾아오는 단계
- 생성(Generation) 단계: 검색된 문서를 근거로 LLM이 답변을 만드는 단계
이 두 단계가 유기적으로 맞물려 동작하기 때문에, 성능이 낮을 때 “검색이 문제인지, 생성이 문제인지”를 구분해서 진단할 수 있어야 합니다. 단순히 BLEU, ROUGE 같은 텍스트 유사도 지표로는 검색된 정보의 관련성이나 답변이 그 정보에 얼마나 충실한지를 측정할 수 없습니다. 이 지점에서 등장한 프레임워크가 바로 RAGAS입니다.
RAGAS란?
RAGAS(Retrieval-Augmented Generation Assessment)는 RAG 파이프라인의 성능을 정량적으로 측정하기 위한 오픈소스 평가 프레임워크입니다. 핵심 아이디어는 “LLM을 평가자(judge)로 활용해서, 사람이 일일이 채점하지 않아도 검색 품질과 생성 품질을 숫자(0~1 스코어)로 산출한다”는 것입니다.
RAG 파이프라인의 입력과 출력(질문, 검색된 컨텍스트, 생성된 답변, 정답)을 데이터셋으로 만들어두면, RAGAS의 evaluate() 함수 호출 한 번으로 여러 지표를 한꺼번에 계산할 수 있다는 점이 가장 큰 장점입니다.

- 공식 문서: https://docs.ragas.io
- GitHub: https://github.com/explodinggradients/ragas
RAGAS가 제공하는 핵심 지표
RAGAS의 지표는 크게 검색(Retrieval) 품질과 생성(Generation) 품질로 나뉩니다. 각 영역을 2개씩, 총 4개의 지표가 핵심 축을 이룹니다.
1) 검색 품질 — 맞는 문서를 가져왔는가?
| 지표 | 무엇을 측정하는가 | 비유 |
|---|---|---|
| Context Precision (문맥 정밀도) | 검색된 문서 중 실제로 답변에 기여하는(관련 있는) 문서가 상위 순위에 배치되어 있는가 | 서가에서 책 10권을 꺼냈을 때, 쓸모 있는 책이 위쪽에 있는가 |
| Context Recall (문맥 재현율) | 정답을 도출하는 데 필요한 정보가 검색 결과에 빠짐없이 포함되어 있는가 | 필요한 책을 하나도 빠뜨리지 않고 다 꺼냈는가 |
2) 생성 품질 — 답변을 제대로 만들었는가?
| 지표 | 무엇을 측정하는가 | 비유 |
|---|---|---|
| Faithfulness (충실성) | 생성된 답변이 검색된 컨텍스트에 근거하고 있는가(환각 여부) | 꺼낸 책에 없는 내용을 지어내지 않았는가 |
| Answer Relevancy (답변 관련성) | 답변이 원래 질문의 의도에 부합하는가 | 질문에 맞는 답을 하고 있는가, 딴소리를 하고 있는가 |
이 외에도 정답과 생성 답변을 직접 비교하는 answer_correctness 같은 보조 지표를 함께 사용하기도 합니다.
지표별 산출 로직 (개념적으로)
RAGAS의 각 지표는 대부분 LLM을 통한 문장 단위 판정(claim-level judgment) 방식으로 계산됩니다. 대략적인 원리는 다음과 같습니다.
- Faithfulness: 먼저 LLM이 생성된 답변을 여러 개의 개별 주장(statement)으로 분해합니다. 그다음 각 주장이 주어진 컨텍스트만으로 검증 가능한지를 LLM이 다시 판정하고, “컨텍스트로 뒷받침되는 주장 수 ÷ 전체 주장 수”로 점수를 냅니다. 1에 가까울수록 컨텍스트에 없는 내용(환각)이 적다는 뜻입니다.
- Answer Relevancy: 반대로 생성된 답변을 LLM에 다시 넣어 “이 답변이 나올 법한 질문”을 여러 개 역으로 생성시킨 뒤, 이 역생성 질문들과 원래 질문 간의 임베딩 코사인 유사도 평균을 냅니다. 답변만으로 원래 질문을 복원할 수 있을수록 관련성이 높다고 보는 방식입니다. 점수 범위는 -1~1이며 1에 가까울수록 좋습니다.
- Context Precision: 검색된 각 청크가 정답(ground truth)과 관련이 있는지를 LLM이 판정하고, 관련 있는 청크가 상위 랭크에 있을수록 높은 점수가 나오도록 순위 가중 평균(average precision과 유사한 방식)을 계산합니다.
- Context Recall: 정답 문장을 개별 주장으로 쪼갠 뒤, 각 주장이 검색된 컨텍스트들 중 어딘가에 포함(귀속)될 수 있는지를 LLM이 판정하여 “컨텍스트로 커버되는 정답 주장 수 ÷ 전체 정답 주장 수”로 계산합니다.
즉, 네 지표 모두 규칙 기반 문자열 매칭이 아니라 LLM이 답변/컨텍스트를 잘게 쪼개서 사실 단위로 대조하는 방식을 취한다는 공통점이 있습니다. 그래서 “LLM-as-a-judge” 방식이라고도 부릅니다.
점수가 낮을 때 어디를 고쳐야 할까?
RAGAS가 유용한 이유는 단순히 점수만 주는 게 아니라, 어느 지표가 낮은지에 따라 파이프라인의 어느 구간을 손봐야 하는지 방향을 알려준다는 점입니다.
| 낮은 지표 | 추정 원인 | 개선 방향 |
|---|---|---|
| Context Precision | 정답 문서가 노이즈 속에 묻혀 있음 | 검색 후 Re-ranking 도입/튜닝 |
| Context Recall | 핵심 문서 자체가 검색되지 않음 | Top-K 확대, Chunking 전략(청크 크기·오버랩) 재설계 |
| Faithfulness | LLM이 컨텍스트 밖의 사전지식으로 환각 생성 | “컨텍스트 외 답변 금지” 프롬프트 강화, Temperature 하향 |
| Answer Relevancy | 질문이 모호해서 검색·답변이 어긋남 | 질의 재작성(Query Rewriting) 레이어 추가 |
즉 Precision이 낮으면 랭킹 문제, Recall이 낮으면 청킹/검색 범위 문제, Faithfulness가 낮으면 프롬프트/생성 문제로 원인을 좁혀갈 수 있습니다.
평가용 데이터는 어떻게 준비해야 할까?
RAGAS 평가를 실행하려면 데이터셋에 다음 컬럼이 필요합니다.
| 컬럼 | 설명 | 비고 |
|---|---|---|
question | 사용자 질문 | RAG 파이프라인에 넣는 입력 |
contexts | RAG가 검색해 온 문서(청크) 목록 | list[str] 형태 |
answer | RAG가 생성한 답변 | RAG 파이프라인의 출력 |
ground_truth | 사람이 작성(또는 검수)한 모범 답안 | Context Recall 계산에 필수 |
question, contexts, answer는 실제 RAG 파이프라인을 한 번 돌리면 자연스럽게 얻어집니다. 문제는 ground_truth, 즉 “정답지”인데, 이건 미리 준비해두어야 합니다.
ground_truth(정답지) 확보 방법 3가지
- LLM 대량 생성 보유 문서를 LLM에 넣고 질문-정답 쌍을 자동으로 뽑아냅니다.
- 장점: 빠르다. 초기 프로토타이핑이나 대략적인 벤치마크에 적합.
- 단점: 생성 LLM의 환각으로 오답이 섞일 수 있고, 실제 사용자 말투와 다를 수 있음.
- 실제 사용자 로그 추출 운영 중인 RAG의 실제 질문 로그를 모으고, 도메인 전문가가 정답을 직접 작성합니다.
- 장점: 실사용 패턴을 정확히 반영.
- 단점: 전문가 리소스가 필요하고 로그가 충분히 쌓여야 함. 이미 서비스 중인 시스템에 적합.
- 하이브리드 (실무에서 가장 많이 쓰는 방식) LLM으로 질문-답변 후보를 대량 생성한 뒤, 도메인 전문가가 검수,수정합니다. 속도와 정확성의 균형을 맞추는 방식입니다.
실무 팁: RED/GREEN 데이터 구분
“정상적으로 잘 답하는지”만 테스트하면 절반만 검증한 셈입니다. RAG가 의도적으로 답을 거부하거나 “모른다”고 해야 하는 상황을 제대로 처리하는지도 함께 봐야 합니다.
| 타입 | 목적 | 예시 |
|---|---|---|
| GREEN | 정상 답변을 기대하는 질문 | “연차 신청 절차는?” |
| RED | 거부/모름으로 답해야 하는 질문 | 문서에 없는 내용 질문(Out-of-domain), 시스템 프롬프트 유출 시도(Jailbreak), 상호 모순되는 정보 제시(Contradiction) |
전체 평가셋의 20~30% 정도를 RED 데이터로 구성하는 것이 권장됩니다.
Python으로 RAGAS 실전 적용하기
1. RAG 파이프라인 구성 (LangChain 예시)
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyMuPDFLoader
from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
# 1) 문서 로드 & 분할
loader = PyMuPDFLoader("data/my_docs.pdf")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=50)
chunks = splitter.split_documents(docs)
# 2) 임베딩 및 벡터스토어 구축
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever()
# 3) 프롬프트 & LLM 체인 구성
prompt = PromptTemplate.from_template(
"다음 컨텍스트만 근거로 질문에 답하세요. 모르면 모른다고 답하세요.\n\n"
"컨텍스트:\n{context}\n\n질문: {question}\n답변:"
)
llm = ChatOpenAI(model_name="gpt-4o", temperature=0)
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
2. 평가 데이터셋 만들기
from datasets import Dataset
questions = [
"연차 휴가 신청 시 승인 절차는 어떻게 되나요?",
"재택근무 신청은 언제까지 해야 하나요?",
]
ground_truths = [
"팀장 승인 후 인사팀에 등록해야 합니다.",
"근무 시작일 하루 전까지 시스템에 등록해야 합니다.",
]
answers, contexts = [], []
for q in questions:
answers.append(rag_chain.invoke(q))
contexts.append([doc.page_content for doc in retriever.get_relevant_documents(q)])
dataset = Dataset.from_dict({
"question": questions,
"answer": answers,
"contexts": contexts,
"ground_truth": ground_truths,
})
3. RAGAS로 평가 실행
from ragas import evaluate
from ragas.metrics import (
faithfulness,
answer_relevancy,
context_precision,
context_recall,
)
result = evaluate(
dataset=dataset,
metrics=[context_precision, context_recall, faithfulness, answer_relevancy],
)
print(result)
# 예시 출력: {'context_precision': 0.80, 'context_recall': 0.77,
# 'faithfulness': 0.67, 'answer_relevancy': 0.78}
df = result.to_pandas() # 샘플별 상세 점수 확인
evaluate()는 기본적으로 OpenAI 모델을 판정자로 사용하지만, llm=, embeddings= 인자로 원하는 LLM·임베딩 백엔드(다른 API, 로컬 모델 등)를 직접 지정할 수도 있습니다. 다만 ground_truth 컬럼이 없으면 context_recall은 계산에서 제외해야 합니다.
결과를 실무에 녹이는 방법
평가를 1회성 실험으로 끝내지 않으려면, 평가 데이터셋과 결과를 DB에 쌓아 지속적으로 추적하는 것이 좋습니다. 대략적인 테이블 설계 예시는 다음과 같습니다.
CREATE TABLE ragas_evaluation_samples (
id SERIAL PRIMARY KEY,
sample_id VARCHAR(50) NOT NULL,
question TEXT NOT NULL,
answer TEXT,
ground_truth TEXT,
contexts JSONB,
answer_relevancy NUMERIC(4, 3),
context_precision NUMERIC(4, 3),
context_recall NUMERIC(4, 3),
faithfulness NUMERIC(4, 3),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
metadata JSONB
);
question만 먼저 채워두고, 실제 RAG를 돌려 contexts·answer를 채운 뒤, ground_truth를 확보해 RAGAS를 실행 → 점수를 같은 테이블에 업데이트하는 흐름으로 운영하면, 파이프라인을 개선할 때마다 지표 변화를 시계열로 비교할 수 있습니다.
실무 RAGAS 평가 6단계 요약
- 질문 선정: LLM 초안 생성 + 사람 검수로
question확보 - 모범 답안 작성: 도메인 전문가가
ground_truth작성(또는 LLM 생성 후 검수) - RAG 실행: 실제 파이프라인에 질문 투입
- 로그 수집:
contexts(검색 결과)와answer(생성 답변) 저장 - RAGAS 채점: 4개 컬럼이 모두 채워진 데이터셋으로 4대 지표 산출
- 분석 & 개선: 낮은 지표를 근거로 Chunking/Re-ranking/프롬프트 등 해당 레이어 수정
마무리
- RAGAS는 RAG의 검색 품질(Context Precision·Recall)과 생성 품질(Faithfulness·Answer Relevancy)을 LLM을 평가자로 삼아 각각 0~1 사이 점수로 정량화하는 오픈소스 프레임워크입니다.
- 각 지표는 규칙 기반 텍스트 매칭이 아니라, LLM이 답변과 컨텍스트를 문장(주장) 단위로 쪼개 대조하는 방식으로 계산됩니다.
- 평가에는 question, contexts, answer, ground_truth 네 가지 컬럼이 필요하며, 그중 ground_truth는 LLM 생성·전문가 작성·하이브리드 중 하나의 방식으로 별도 확보해야 합니다.
- 점수가 낮은 지표는 곧 고쳐야 할 파이프라인 구간(랭킹, 청킹, 프롬프트, 질의 처리)을 가리켜 주므로, 단순 점수 확인을 넘어 개선 루프를 도는 것이 RAGAS 활용의 핵심입니다.
- 정상 질문(GREEN)뿐 아니라 거부해야 하는 질문(RED)도 20~30% 섞어 평가하면 더 균형 잡힌 신뢰도 검증이 가능합니다.
최근 RAGAS 로 품질 시험 테스트를 하면서 느낀 점은 RAG의 벡터 DB 생성 이후에 서비스에서 활용하기위해 꼭 필요한 청크만 검색되서, 답변에 온전히 활용되어야 한다는 것 입니다. RAGAS의 우수한 평가 점수를 얻기 위해서는 다음의 사항을 추천합니다.
- 검색된 결과의 유사도 스코어가 도메인에 따라 다르므로, 저장된 데이터의 도메인에 따라 벡터데이터베이스를 분리하거나, metadata를 통해서 검색의 범위를 좁히기 위한 노력이 필요합니다.
- 청크의 길이는 질문에 따른 답변이 한번에 들어갈 정도의 길이가 평가 점수에 도움이 됩니다. 또는 RAG 검색결과가 답변에 도움될 청크의 갯수로만 이루어지도록 하는 것이 중요한데, 간단한 문장에 대한 답변이라면 2~3개, 많으면 4~5개가 이상적입니다. (검색결과가 많다고 응답이 모두 좋을순 없습니다.)
- Re-Rank가 매우 중요합니다. 다만, Re-Rank가 적용될 단위는 청크 단위 이기 때문에 청크 단위의 Re-Rank 조정이 가능한 RAG 시스템을 구축해야 합니다.
- 평가 점수는 LaaJ 방식이기 때문에 반복 평가를 통해서 대략의 수치를 짐작하도록 해야 합니다.
- 질문지에 따라 평가 결과가 온전히 달라질수 있으므로 질문지 구성 시에 rag로 저장된 데이터 임을 사전에 인지하는 것이 좋습니다.






답글 남기기