기술 포스트 · ai
RAG 시스템을 정량 평가하는 4가지 지표 — 마케팅 챗봇을 만든다면
마케팅 FAQ 챗봇·내부 위키 검색을 RAG로 만들 때, "답변이 맞다"를 어떻게 숫자로 증명할까. context relevance부터 faithfulness까지 4가지 지표를 케이스로 풀어봅니다.
마케팅팀에서 사내 FAQ 챗봇을 만들었는데, 답변이 그럴듯해 보이긴 합니다. 그런데 “이게 정말 맞는 답이야?”라고 물으면 답을 못 합니다. 이 글은 그 질문을 숫자로 바꾸는 4가지 지표 이야기예요.
1. RAG가 뭔지 한 단락으로
RAG는 Retrieval-Augmented Generation의 약자입니다. 풀어쓰면 “답변하기 전에 자료를 검색하는 LLM”이에요. 마케팅 도메인에 적용하면:
- 사내 위키의 광고 정책을 검색 → 마케터 질문에 답하는 챗봇
- 과거 캠페인 리포트를 검색 → “비슷한 KPI의 캠페인 결과 보여줘”
- 경쟁사 분석 문서를 검색 → “X 브랜드 최근 CPM 트렌드 알려줘”
문제는 답변이 그럴듯해 보일 뿐 진짜 맞는지를 어떻게 검증하느냐입니다.
2. RAG 평가는 두 축이다
흔한 오해는 “답변이 정확한가만 보면 된다”입니다. 실제로는 두 단계가 있어요.
flowchart LR Q[사용자 질문] --> R[검색 단계] R --> C[관련 문서들] C --> G[생성 단계] G --> A[최종 답변]
R -.평가1.-> M1[검색이 맞나?] G -.평가2.-> M2[답변이 맞나?]따라서 평가 지표는 검색 품질과 답변 품질 두 축에서 각각 측정됩니다.
3. 4가지 지표 — 한 표로
| 지표 | 무엇을 보는가 | 일상어로 |
|---|---|---|
| Context Relevance | 검색된 문서가 질문과 얼마나 관련 있나 | ”검색이 진짜 답에 가까운 자료를 가져왔어?” |
| Context Recall | 정답에 필요한 자료를 빠뜨리지 않았나 | ”필요한 문서가 다 들어왔어?” |
| Faithfulness | 답변이 검색된 문서 안에서만 말하는가 | ”지어내지 않고 자료를 진짜로 봤어?” |
| Answer Relevance | 답변이 질문에 정확히 답했나 | ”동문서답 아니야?” |
이 4가지를 한 번씩 계산하면 RAG 시스템의 건강 상태가 입체적으로 보입니다.
4. 각 지표를 코드 한 묶음으로
Ragas 라이브러리가 이 4가지를 모두 LLM-as-judge 방식으로 계산해줍니다. 한 번 돌려보면 이렇게 나와요.
from datasets import Datasetfrom ragas import evaluatefrom ragas.metrics import ( context_relevancy, context_recall, faithfulness, answer_relevancy)
# 마케팅 FAQ 챗봇 테스트 케이스data = { "question": ["우리 회사 광고 채널 중 ROAS 가장 높은 채널은?"], "answer": ["지난 분기 기준 Meta 광고 ROAS가 4.2로 가장 높았습니다."], "contexts": [["분기 보고서: Meta ROAS 4.2, Google 3.5, Naver 2.8..."]], "ground_truth": ["Meta 광고가 ROAS 4.2로 가장 높음"],}
result = evaluate( Dataset.from_dict(data), metrics=[context_relevancy, context_recall, faithfulness, answer_relevancy],)print(result){'context_relevancy': 0.91, 'context_recall': 1.00, 'faithfulness': 0.95, 'answer_relevancy': 0.88}Context Relevance 0.91
검색된 문서의 91%가 질문과 관련 있다는 뜻. 90% 이상이면 좋고, 70% 아래로 떨어지면 검색기를 손봐야 합니다.
Context Recall 1.00
정답 생성에 필요한 자료를 모두 가져왔습니다. 0.7 이하면 정답 정보가 빠졌다는 뜻이에요. 인덱싱 누락·청크 크기 문제를 의심합니다.
Faithfulness 0.95
답변의 95%가 검색 문서에서 직접 지지됩니다. 0.8 이하면 LLM이 자기 지식으로 빈 칸을 채우고 있다는 신호 — 환각 위험입니다.
수식으로 보면 단순합니다.
답변 안의 명제(claim)를 LLM이 쪼갠 뒤, 각 명제가 검색 문서에 의해 지지되는지 검사합니다. 분모가 작아지면 점수가 흔들리니, 답변을 너무 짧게 만들어 점수만 올리는 함정도 조심해야 해요.
Answer Relevance 0.88
질문 자체에 88% 직접적으로 답했습니다. 0.7 이하면 동문서답이 섞이고 있어요.
직관적으로 말하면, 답변에서 거꾸로 질문을 생성해보고 원 질문과 얼마나 가까운지를 봅니다. 임베딩 코사인 유사도로 환산하면 다음과 같아요.
- — 임베딩 함수
- — 원 질문, — 답변에서 역생성된 질문 후보
- — 후보 개수 (보통 3~5개)
5. 골든셋 — 어디서부터 시작하나
마케터 입장에서 가장 큰 장벽은 “정답이 적힌 데이터(ground truth)를 어디서 구하나”입니다. 답: 30~50개로 충분합니다.
만드는 절차
- 실제 마케터·운영팀이 챗봇에 자주 물을 만한 질문 50개를 적습니다.
- 각 질문에 사람이 직접 정답을 작성합니다 (15분짜리 문서 1쪽).
- 챗봇을 돌려서 4가지 지표를 매주 계산합니다.
이게 회귀 테스트가 됩니다. 챗봇 모델·프롬프트를 바꿨을 때 4가지 지표가 어떻게 움직이는지 한눈에 보여요.
골든셋의 다양성을 챙기는 방법
50개를 무작위로 뽑으면 비슷한 질문 패턴에 쏠립니다. 다음 4분면을 고르게 채우면 됩니다.
| 축 \ 축 | 사실형 (정답 1개) | 해석형 (정답 다수) |
|---|---|---|
| 단순 (한 문장) | “Meta CPM 기준값은?" | "최근 ROAS 좋은 캠페인은?” |
| 복합 (여러 단계) | “Q3 Naver 클릭 대비 전환은?" | "지난 분기 캠페인 중 다음에도 쓸 만한 건?” |
각 셀에 12~13개씩, 총 50개. 이렇게 다양성을 강제하면 4가지 지표가 어느 종류 질문에서 약해지는지 한눈에 드러납니다.
골든셋이 진화하는 단계
- 0주차: 50개 직접 작성, 정답을 사람이 작성
- 2~4주차: 챗봇 답변 중 좋은 케이스를 골라 골든셋에 편입 (사람 검수 후)
- 2~3개월차: 사용자 로그에서 자주 나오는 질문을 추가, 100~200개로 확장
- 반기: 더 이상 통과 못 하는 도메인 영역 발견, 도메인별 별도 골든셋
골든셋은 살아 있는 데이터셋입니다. 한 번 만들고 끝이 아니에요.
6. 검색기를 어떻게 고르고 튜닝하나
지표가 나빠졌을 때, 어디를 손대야 할지 모르면 무용지물입니다. 4지표가 가리키는 손볼 위치는 다음과 같아요.
| 나빠진 지표 | 의심 위치 | 첫 조치 |
|---|---|---|
| Context Relevance | 검색기(retriever) | 임베딩 모델 교체, 또는 hybrid (BM25 + dense) |
| Context Recall | 청크 분할 / 인덱싱 | 청크 크기 줄이기, 메타데이터 필터 보강 |
| Faithfulness | 생성기(LLM) 프롬프트 | ”검색 문서에 없는 내용 금지” 명시, temperature 낮추기 |
| Answer Relevance | 생성기 추론 단계 | rerank 추가, few-shot 예시로 답변 형식 고정 |
지표를 보고 어디를 조이는지가 정해진 매핑이 있으니, 회의에서 모호하지 않습니다.
Hybrid 검색 — BM25 + Dense
마케팅 도메인은 고유명사(브랜드명·캠페인 ID)가 많아서, dense embedding만으로는 정확 매칭이 약할 수 있어요. BM25 같은 키워드 검색을 함께 쓰는 hybrid 방식이 자주 효과적입니다.
from rank_bm25 import BM25Okapiimport numpy as np
def hybrid_search(query, docs, embeddings, k=5, alpha=0.5): # dense 점수 (코사인 유사도) q_emb = embed(query) dense_scores = np.dot(embeddings, q_emb)
# sparse 점수 (BM25) bm25 = BM25Okapi([d.split() for d in docs]) sparse_scores = bm25.get_scores(query.split())
# 정규화 후 가중 합산 dense = dense_scores / dense_scores.max() sparse = sparse_scores / sparse_scores.max() final = alpha * dense + (1 - alpha) * sparse
top_idx = np.argsort(final)[-k:][::-1] return [docs[i] for i in top_idx]alpha는 0.5에서 시작해 골든셋에서 튜닝합니다. 마케팅 데이터는 보통 0.3~0.4 (sparse 비중 더 큼)이 더 잘 동작해요.
7. LLM-as-judge의 한계
한 가지 솔직하게 짚을 점. Ragas가 쓰는 방식은 LLM이 LLM을 평가하는 것입니다. 비용이 들고, 평가자 LLM의 편향이 들어갈 수 있어요.
실무 권고
- 평가자는 답변 생성 모델보다 더 강한 모델을 씀 (GPT-4o로 답변, GPT-5로 평가 식)
- 같은 입력으로 3번 평가해서 분산 확인 (LLM 출력은 stochastic)
- 정량 지표 + 분기에 1번 사람의 정성 검수 병행
평가자의 편향 종류
LLM-as-judge가 자주 빠지는 편향이 알려져 있습니다.
- Position bias — 두 답변 중 앞에 나온 걸 더 후하게 평가. 평가 시 순서를 무작위로 섞기.
- Verbosity bias — 긴 답변을 더 똑똑해 보인다고 판단. 답변 길이를 정규화하거나 짧은 답이 좋은 케이스를 골든셋에 추가.
- Self-preference — 같은 가족의 LLM(예: GPT가 GPT 답변)을 더 후하게. 가능하면 평가자와 답변 생성기를 다른 가족으로.
LLM-as-judge vs 사람 평가의 일치도
연구에서는 강한 LLM 평가자(GPT-4 클래스)와 사람의 일치도가 0.8 안팎으로 보고됩니다. 사람끼리도 0.85~0.9이니, “LLM이 사람만큼은 아니지만 거의 그 수준”이라고 보면 적당합니다. 분기마다 50개 케이스를 사람 검수해서 LLM 점수와의 일치도를 추적하면 신뢰도를 객관적으로 관리할 수 있어요.
8. 마케팅 도메인에서 자주 빠지는 함정 (확장판)
- “답변이 맞다”의 정의가 안 잡힘. 마케팅 용어는 회사마다 의미가 달라요. 정답을 적기 전에 용어집부터.
- 컨텍스트 청크가 너무 큼. 보고서 한 장 통째로 넣으면 검색기는 좋은 자료라고 판단하지만, LLM이 핵심을 못 찾습니다. 300~500자가 적정.
- 메타데이터 필터를 빠뜨림. “지난 분기” 질문에 1년치 자료가 다 검색되면 답변 흐려져요. 날짜·카테고리 필터 필수.
- 평가 자동화가 비싸다고 미루는 것. 50개 골든셋이면 GPT 비용 1주에 몇 천 원 수준. 안 하면 챗봇이 점점 나빠지는 걸 모릅니다.
- 고유명사 정규화 빠뜨리기. “메타”, “Meta”, “facebook ads”가 같은 채널이라는 걸 검색기가 모르면 recall이 무너집니다. 동의어 사전을 별도로 관리.
- 최신 데이터 업데이트 누락. 어제 만들어진 캠페인 보고서가 인덱스에 없으면 “최근 어땠어?” 질문에서 환각이 나옵니다. 인덱스 동기화 SLA를 명시.
- 실패 케이스를 보고서에 안 넣기. “실패율 12%“를 정직하게 보고하지 않으면 점진적 개선의 동기가 사라집니다.
9. 자주 받는 질문
Q. 골든셋 50개로 정말 충분한가요?
회귀 테스트 목적이면 충분합니다. 다만 커버리지 측정이 따로 필요해요. 실제 사용자 질문 로그에서 무작위로 100개를 뽑아 어느 정도가 골든셋 패턴 안에 들어오는지 봅니다. 80% 이상이면 OK, 그보다 낮으면 골든셋을 확장해야 합니다.
Q. 임베딩 모델은 뭐 쓰나요?
한국어 도메인이라면 OpenAI text-embedding-3-large나 Cohere embed-multilingual-v3.0이 첫 시도로 무난합니다. 비용을 더 줄이고 싶으면 BGE-m3, KoSimCSE 같은 오픈소스를 자체 호스팅. 고유명사 비중이 높은 마케팅 데이터는 hybrid 검색이 거의 항상 더 낫습니다.
Q. RAG 대신 fine-tuning을 하면 안 되나요?
마케팅 데이터는 자주 바뀌어서(매일 새 캠페인) fine-tuning이 적합하지 않아요. 한 번 학습한 모델이 어제 만들어진 캠페인을 모릅니다. 지식이 자주 바뀌면 RAG, 형식·톤이 일정해야 하면 fine-tuning, 둘 다 필요하면 RAG + 가벼운 fine-tuning 조합이 일반 원칙입니다.
Q. 4지표 외에 무엇을 더 봐야 하나요?
운영 단계에서는 정성 지표를 추가합니다. 응답 시간(p95), 사용자 만족도(👍/👎), “답을 못 찾겠다” 비율, 비용/요청. 4지표가 좋아도 응답 시간이 느려서 사용자가 떠나는 케이스가 있어요.
10. 마치며
RAG 평가는 어렵지 않습니다. “검색”과 “생성” 두 단계 각각에 2개 지표씩. 그리고 골든셋 50개. 이게 시작이에요.
마케팅 챗봇을 만들고 있거나 만들 계획이 있다면, 이 4개 숫자를 매주 한 번 보는 것만으로 시스템이 살아 움직입니다. 한 분기가 지나면, 어느 지표가 어떤 변화에 민감한지 팀이 직관적으로 알게 돼요. 그게 RAG를 운영하는 진짜 능력입니다.