왜 AI 평가가 어려운가?
전통적인 소프트웨어는 입력-출력이 결정적입니다. 하지만 LLM은 같은 프롬프트에도 매번 다른 출력을 냅니다. "이 답변이 좋은가?"를 자동으로 측정하는 것 자체가 하나의 AI 문제입니다.
2025년 현재 세 가지 주요 접근법이 있습니다:
- 규칙 기반 평가: 정규식, 키워드 매칭, JSON 스키마 검증
- 참조 기반 평가: ROUGE, BLEU 등 참조 답변과 비교
- LLM-as-Judge: 더 강한 LLM이 다른 LLM 출력을 평가
평가 프레임워크 비교
| 항목 | RAGAS | LangSmith | Promptfoo |
|---|---|---|---|
| 특화 분야 | RAG 품질 평가 | LLM 앱 전반 | 프롬프트 테스트 |
| 오픈소스 | ✓ | 부분 | ✓ |
| 가격 | 무료 | 무료 티어 + 유료 | 무료 |
| 셀프호스팅 | ✓ | ✓ (Enterprise) | ✓ |
| CI/CD 통합 | ✓ | ✓ | ✓ |
| 한국어 지원 | △ | △ | △ |
RAGAS: RAG 시스템 전문 평가
RAGAS(Retrieval Augmented Generation Assessment)는 RAG 파이프라인의 각 단계를 독립적으로 평가합니다.
flowchart LR Query[사용자 질문] --> Retriever[검색기] Retriever --> Contexts[검색된 문서들] Contexts --> LLM[LLM] Query --> LLM LLM --> Answer[최종 답변] Answer --> F1[Faithfulness<br/>답변이 문서에 근거하는가] Contexts --> F2[Context Recall<br/>관련 문서를 잘 찾았는가] Answer --> F3[Answer Relevancy<br/>질문에 답하는가] Query --> F3 F1 --> Score[종합 점수] F2 --> Score F3 --> Score
핵심 지표
Faithfulness (충실도): 생성된 답변이 검색된 문서에 근거하는지 측정. 환각(hallucination) 탐지에 핵심.
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_recall
from datasets import Dataset
# 테스트 데이터셋
data = {
"question": ["RAG란 무엇인가?", "벡터 DB의 장점은?"],
"answer": ["RAG는 검색 증강 생성입니다...", "벡터 DB는 유사도 검색이 빠릅니다..."],
"contexts": [
[["RAG(Retrieval-Augmented Generation)는..."]],
[["벡터 데이터베이스는 고차원 벡터를..."]],
],
"ground_truth": ["RAG는 검색과 생성을 결합한 방법입니다", "빠른 유사도 검색이 가능합니다"],
}
dataset = Dataset.from_dict(data)
result = evaluate(dataset, metrics=[faithfulness, answer_relevancy, context_recall])
print(result)
# {'faithfulness': 0.92, 'answer_relevancy': 0.87, 'context_recall': 0.85}
RAG 품질 개선 사이클
flowchart TD A[RAG 시스템 실행] --> B[RAGAS 평가] B --> C{점수 분석} C --> D[Faithfulness 낮음] C --> E[Context Recall 낮음] C --> F[Answer Relevancy 낮음] D --> G[프롬프트 수정<br/>출처 강조 지시 추가] E --> H[청크 크기 조정<br/>임베딩 모델 교체] F --> I[시스템 프롬프트 수정<br/>관련성 강조] G --> A H --> A I --> A
Promptfoo:
CI/CD에 통합하는 프롬프트 테스트
Promptfoo는 프롬프트를 코드처럼 테스트합니다. YAML로 테스트 케이스를 정의하고 CLI로 실행합니다.
설정 예시
# promptfoo.yaml
providers:
- openai:gpt-4o
- anthropic:claude-sonnet-4-6
- openai:gpt-4o-mini # 비용 비교용
prompts:
- file://prompts/customer_support_v1.txt
- file://prompts/customer_support_v2.txt
tests:
- description: "환불 요청 처리"
vars:
customer_message: "3일 전 구매한 상품을 환불하고 싶습니다"
assert:
- type: contains
value: "환불"
- type: llm-rubric
value: "응답이 공감적이고 구체적인 처리 절차를 포함하는가"
- type: latency
threshold: 3000 # 3초 이내
- description: "욕설 포함 메시지 처리"
vars:
customer_message: "씨X 이게 뭐야 진짜"
assert:
- type: not-contains
value: "죄송합니다" # 과도한 사과 금지
- type: llm-rubric
value: "침착하게 문제 해결에 집중하는가"
# 실행
npx promptfoo eval
# CI/CD에서 실패 기준 설정
npx promptfoo eval --fail-threshold 0.8 # 80% 미만이면 빌드 실패
모델 비교 결과 예시
┌─────────────────────────┬──────────┬──────────┬──────────┐
│ Prompt / Model │ gpt-4o │ claude │ mini │
├─────────────────────────┼──────────┼──────────┼──────────┤
│ customer_support_v1 │ 85% │ 88% │ 71% │
│ customer_support_v2 │ 91% │ 93% │ 78% │
├─────────────────────────┼──────────┼──────────┼──────────┤
│ 평균 레이턴시 │ 1.2s │ 1.4s │ 0.6s │
│ 예상 월 비용 (10K 호출) │ $25 │ $30 │ $3 │
└─────────────────────────┴──────────┴──────────┴──────────┘
→ v2 프롬프트 + Claude가 가장 높은 점수. 비용이 중요하면 v2 + gpt-4o-mini도 78%로 준수.
LangSmith: 종합 관찰 플랫폼
LangSmith는 LangChain 팀이 만든 LLM 앱 관찰 플랫폼입니다. 추적, 평가, 데이터셋 관리를 통합합니다.
from langsmith import Client
from langsmith.evaluation import evaluate
client = Client()
# 데이터셋 생성
dataset = client.create_dataset("customer-support-qa")
client.create_examples(
inputs=[{"question": "환불 정책이 어떻게 되나요?"}],
outputs=[{"answer": "구매 후 7일 이내 환불 가능합니다"}],
dataset_id=dataset.id,
)
# 평가 실행
def my_app(inputs):
return {"output": llm.invoke(inputs["question"])}
def correctness_evaluator(run, example):
score = llm_judge(run.outputs["output"], example.outputs["answer"])
return {"key": "correctness", "score": score}
results = evaluate(
my_app,
data=dataset.name,
evaluators=[correctness_evaluator],
experiment_prefix="v2-prompt-test",
)
어떤 도구를 선택할까?
flowchart TD Start[평가 필요] --> Q1{RAG 시스템인가?} Q1 -- Yes --> RAGAS[RAGAS<br/>+ Langfuse 조합] Q1 -- No --> Q2{CI/CD 통합 필요?} Q2 -- Yes --> Promptfoo[Promptfoo<br/>+ GitHub Actions] Q2 -- No --> Q3{LangChain 사용 중?} Q3 -- Yes --> LangSmith[LangSmith] Q3 -- No --> Q4{예산?} Q4 -- 무료/오픈소스 --> Langfuse[Langfuse<br/>+ RAGAS] Q4 -- 유료 허용 --> LangSmith
최소한의 시작: 직접 구현
도구를 바로 도입하기 어렵다면 간단한 평가 루프부터 시작합니다:
import json
from openai import OpenAI
client = OpenAI()
TEST_CASES = [
{"input": "환불 정책?", "expected_keywords": ["7일", "환불", "영업일"]},
{"input": "배송 기간?", "expected_keywords": ["3~5일", "영업일", "배송"]},
]
def simple_eval(prompt_template: str) -> float:
scores = []
for case in TEST_CASES:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": prompt_template},
{"role": "user", "content": case["input"]},
]
).choices[0].message.content
# 키워드 포함 여부로 기본 점수
hit = sum(1 for kw in case["expected_keywords"] if kw in response)
scores.append(hit / len(case["expected_keywords"]))
return sum(scores) / len(scores)
v1_score = simple_eval(open("prompts/v1.txt").read())
v2_score = simple_eval(open("prompts/v2.txt").read())
print(f"v1: {v1_score:.2f}, v2: {v2_score:.2f}")
결론AI 평가는 "한 번 설정하고 끝"이 아니라
지속적인 파이프라인입니다.
- 시작: Promptfoo로 프롬프트 A/B 테스트
- RAG 시스템: RAGAS로 검색 품질 측정
- 프로덕션: Langfuse로 실시간 품질 모니터링
평가 없이 프롬프트를 수정하는 것은 눈 감고 운전하는 것과 같습니다. 테스트 케이스 10개라도 갖추고 시작하세요.





