문서 기반 질의응답에서 LLM의 hallucination을 탐지하고, 여러 모델의 응답 신뢰성을 정량적으로 비교 평가하는 파이프라인
LLM에 문서 기반 질문을 하면 hallucination(근거 없는 답변)을 생성하는 문제가 있다. 이 프로젝트는 RAG로 관련 문서를 검색하여 LLM에 제공하고, 3단계 평가 파이프라인으로 응답의 신뢰성을 자동 평가한다.
- Hybrid RAG: Vector Search + BM25 + Cross-Encoder Reranking
- 멀티 LLM 비교: GPT-4o, Claude, Llama3 동일 조건 테스트
- 3단계 신뢰성 평가: RAGAS (정량) + LLM-as-a-Judge (정성) + DeepEval (안전성)
[Documents] [User Query]
│ │
▼ ▼
┌──────────┐ ┌─────────────┐
│ Document │ │ Query │
│ Loader │ │ Engine │
│ (PDF/TXT)│ └──────┬──────┘
└────┬─────┘ │
▼ │
┌──────────┐ │
│ Semantic │ │
│ Chunker │ │
└────┬─────┘ │
▼ ▼
┌──────────┐ ┌─────────────┐
│Embedding │───────────▶│ Hybrid │
│ Model │ │ Retriever │
└────┬─────┘ │ Vector+BM25│
▼ │ +Reranker │
┌──────────┐ └──────┬──────┘
│ ChromaDB │ │
│ (Vector │ ▼
│ Store) │ ┌─────────────┐
└──────────┘ │ LLM Layer │
│ (LiteLLM) │
│ GPT/Claude │
│ /Ollama │
└──────┬──────┘
│
▼
┌─────────────┐
│ Response │
│ + Citation │
└──────┬──────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ RAGAS │ │ LLM │ │ DeepEval │
│ 정량평가 │ │ Judge │ │ 안전성 │
│ │ │ 정성평가 │ │ │
│ Faith. │ │ G-Eval │ │ Halluc. │
│ Relevancy│ │ 인용정확성│ │ Toxicity │
│ Ctx P/R │ │ 완결성 │ │ │
└────┬─────┘ └────┬─────┘ └────┬─────┘
└────────────┼────────────┘
▼
┌─────────────┐
│ Dashboard │
│ (Streamlit) │
└─────────────┘
| 구분 | 기술 | 선택 이유 |
|---|---|---|
| 언어 | Python 3.11+ | RAG 생태계 중심 |
| LLM 통합 | LiteLLM | 1줄로 GPT/Claude/Ollama 전환 |
| 임베딩 | OpenAI text-embedding-3-small | 비용 대비 성능 최적 |
| 벡터 DB | ChromaDB | pip install만으로 로컬 실행 |
| BM25 | rank_bm25 | 키워드 검색 보완 |
| 리랭커 | sentence-transformers (Cross-Encoder) | 검색 정밀도 향상 |
| PDF 파싱 | PyMuPDF | 빠르고 정확한 텍스트 추출 |
| 평가 | RAGAS + DeepEval | 학술적으로 검증된 RAG 메트릭 |
| UI | Streamlit | 빠른 데모 구축 |
PDF/TXT ──▶ 텍스트 추출 ──▶ 시맨틱 청킹 ──▶ 임베딩 ──▶ ChromaDB 저장
(PyMuPDF) (문장 경계 (OpenAI (벡터 + 메타데이터)
기반 분할) API)
- 시맨틱 청킹: 고정 크기가 아닌 문장 경계 기반 분할 (의미 단위 보존)
- 청크 크기: 512 토큰 (256/1024와 비교 실험 예정)
- 오버랩: 50 토큰 (컨텍스트 연결 유지)
Query ──┬──▶ Vector Search (ChromaDB, 코사인 유사도)
│ ──▶ RRF 병합 ──▶ Reranking ──▶ Top-5
└──▶ BM25 Search (키워드 매칭)
Hybrid Search가 필요한 이유:
| 검색 방식 | 강점 | 약점 |
|---|---|---|
| Vector Search | "졸업 요건" ≈ "학위 취득 조건" (의미 유사) | 정확한 고유명사/숫자 검색 약함 |
| BM25 | "제30조" 정확히 매칭 | 유의어/패러프레이즈 못 찾음 |
| Hybrid (RRF) | 두 방식의 장점 결합 |
Reciprocal Rank Fusion (RRF):
Score(doc) = Σ 1/(k + rank_i) (k=60)
각 검색 시스템의 순위를 역수로 합산하여 최종 순위 결정.
Cross-Encoder Reranking: 1차 검색에서 20개 후보 → Cross-Encoder로 정밀 재평가 → 상위 5개 선별.
# LiteLLM으로 모델 교체는 1줄
from litellm import completion
# GPT-4o
response = completion(model="openai/gpt-4o", messages=[...])
# Claude Sonnet
response = completion(model="anthropic/claude-sonnet-4-20250514", messages=[...])
# Llama3 (로컬, 무료)
response = completion(model="ollama/llama3.2", messages=[...])프롬프트에 출처 인용을 지시하여 답변에 [출처: 문서명, 페이지] 표시.
각 평가 방식이 잡는 문제가 다르다:
┌─ RAGAS ──────── "컨텍스트에 근거하는가?" (정량)
│
RAG 응답 ──▶ 평가 ───────┼─ LLM Judge ──── "답변이 완전하고 정확한가?" (정성)
│
└─ DeepEval ───── "명시적으로 틀린 내용이 있는가?" (안전성)
RAGAS는 RAG의 검색 품질과 생성 품질을 구분하여 평가한다.
| 메트릭 | 측정 대상 | 동작 방식 | Target |
|---|---|---|---|
| Faithfulness | 생성 | 답변→claim 분해→컨텍스트에서 NLI 검증 | ≥ 0.85 |
| Answer Relevancy | 생성 | 답변→역질문 생성→원래 질문과 유사도 비교 | ≥ 0.80 |
| Context Precision | 검색 | 검색 문서별 관련성 판정→Average Precision | ≥ 0.75 |
| Context Recall | 검색 | 정답→statement 분해→컨텍스트에서 확인 | ≥ 0.80 |
Faithfulness 동작 예시:
답변: "졸업에는 130학점이 필요하며, GPA 2.0 이상이어야 합니다."
↓ claim 분해
Claim 1: "졸업에는 130학점이 필요하다"
Claim 2: "GPA 2.0 이상이어야 한다"
↓ 컨텍스트 대조
Context: "학생은 최소 130학점을 이수해야 졸업할 수 있다."
↓
Claim 1: ✅ Supported Claim 2: ❌ Not Supported (hallucination)
↓
Faithfulness = 1/2 = 0.50
강력한 LLM(GPT-4o)을 **채점관(judge)**으로 사용하여 RAGAS가 잡지 못하는 정성적 품질을 평가한다.
G-Eval 방식:
- 평가 기준을 주면 LLM이 평가 절차(Chain-of-Thought)를 자동 생성
- 생성된 절차에 따라 답변을 평가
- 토큰 확률로 점수를 정규화 (정수가 아닌 연속 점수)
평가 항목: 인용 정확성, 답변 완결성, 가독성 (각 1-5점)
Judge 편향 완화:
| 편향 | 문제 | 완화 방법 |
|---|---|---|
| Position Bias | 순서에 따라 판정 뒤집힘 (10-30%) | 순서 바꿔 2회 평가 후 평균 |
| Verbosity Bias | 긴 답변 선호 (70%) | "길이가 아닌 정확성 기준" 명시 |
| Self-Enhancement | 자기 모델 답변에 +10-25% | 생성 모델과 다른 모델을 judge로 사용 |
RAGAS Faithfulness와 다른 관점에서 hallucination을 탐지한다.
RAGAS Faithfulness: "증거 없음" = 불충실 (엄격)
DeepEval Hallucination: "명시적 모순" = hallucination (모순만 탐지)
예시:
Context: "졸업 학점은 130이다"
답변: "졸업 학점은 130이며, 인턴십도 필수이다"
Faithfulness: 0.50 ("인턴십" 증거 없음 → 불충실)
Hallucination: 0.00 ("인턴십" 모순은 아님 → 미탐지)
→ 둘 다 사용해야 정확한 신뢰성 평가 가능
실험 1: 모델 비교 (검색 고정: Hybrid+Rerank)
GPT-4o-mini / GPT-4o / Claude Sonnet / Llama 3.2
× 100 QA 쌍 = 400 평가
실험 2: 검색 전략 비교 (모델 고정: GPT-4o-mini)
Vector Only / BM25 Only / Hybrid / Hybrid+Rerank
× 100 QA 쌍 = 400 평가
실험 3: RAG vs No-RAG
컨텍스트 제공 vs LLM 단독
× 100 QA 쌍 = 200 평가
Model Faith. Relev. Halluc. Latency
──────────────────────────────────────────────────
GPT-4o 0.92 0.94 0.05 3.2s
Claude Sonnet 0.90 0.91 0.07 4.1s
GPT-4o-mini 0.87 0.89 0.10 1.8s
Llama 3.2 0.78 0.82 0.18 2.5s
Strategy C.Prec C.Rec Faith.
────────────────────────────────────────
Vector Only 0.72 0.75 0.85
BM25 Only 0.68 0.70 0.83
Hybrid (RRF) 0.82 0.84 0.87
Hybrid+Rerank 0.89 0.88 0.87 ← Best
Faithfulness Hallucination
With RAG 0.87 0.10
Without RAG 0.45 0.52 ← 52% hallucination!
| Phase | 기간 | 내용 | 핵심 산출물 |
|---|---|---|---|
| Phase 1 | Week 1 | 문서 수집 파이프라인 | PDF → Chunks → Embeddings → ChromaDB |
| Phase 2 | Week 2 | 검색 시스템 | Hybrid Search + Reranker |
| Phase 3 | Week 3 | 답변 생성 | 멀티 LLM 파이프라인 + 출처 인용 |
| Phase 4 | Week 4 | 평가 파이프라인 | RAGAS + LLM Judge + DeepEval |
| Phase 5 | Week 5-6 | UI + 통합 | Streamlit 데모 + 최종 리포트 |
| 항목 | AWS | GCP | 추천 |
|---|---|---|---|
| 앱 호스팅 | App Runner ~$18/월 | Cloud Run ~$0/월 | GCP |
| 무료 크레딧 | $200 (숨은 비용 주의) | $300 (안전) | GCP |
| LLM 무료 | 없음 | Gemini 1M tokens/월 | GCP |
| 월 총 비용 | ~$24-28 | ~$6-10 | GCP |
개발은 로컬에서 진행 (비용 $0), 데모 배포만 GCP Cloud Run 사용 추천. 빠른 데모만 필요하면 Hugging Face Spaces (무료)도 좋은 대안.
Research_test/
├── config/ # 설정
│ ├── settings.py # 전역 설정 (청크 크기, 모델 등)
│ └── models.py # LLM 모델 설정
├── src/
│ ├── ingestion/ # 문서 수집
│ │ ├── loader.py # PDF/TXT 로더
│ │ ├── chunker.py # 시맨틱 청킹
│ │ └── embedder.py # 임베딩 생성
│ ├── retrieval/ # 검색
│ │ ├── vector_store.py # ChromaDB 래퍼
│ │ ├── bm25_store.py # BM25 키워드 검색
│ │ ├── hybrid.py # 하이브리드 검색 (RRF)
│ │ └── reranker.py # Cross-encoder 리랭킹
│ ├── generation/ # 답변 생성
│ │ ├── llm_client.py # LiteLLM 멀티 모델 래퍼
│ │ ├── prompt.py # 프롬프트 템플릿
│ │ └── pipeline.py # RAG 오케스트레이션
│ ├── evaluation/ # 평가 (3단계)
│ │ ├── ragas_metrics.py # RAGAS 정량 평가
│ │ ├── llm_judge.py # LLM-as-a-Judge 정성 평가
│ │ ├── safety_metrics.py # DeepEval 안전성 평가
│ │ ├── dataset.py # 평가 데이터셋 관리
│ │ └── report.py # 종합 비교 리포트
│ └── ui/
│ └── app.py # Streamlit 데모 앱
├── data/
│ ├── documents/ # 원본 문서
│ ├── eval/ # 평가 QA 데이터셋
│ └── results/ # 평가 결과
├── tests/ # 테스트
└── docs/ # 상세 문서
# 1. 클론 및 설치
git clone <repo-url>
cd Research_test
pip install -e ".[dev]"
# 2. 환경변수 설정
cp .env.example .env
# .env에 OPENAI_API_KEY, ANTHROPIC_API_KEY 입력
# 3. 문서 준비
# data/documents/에 PDF/TXT 파일 배치
# 4. 테스트
pytest tests/ -v
# 5. 파이프라인 실행
python -m src.generation.pipeline --query "질문" --model "openai/gpt-4o-mini"
# 6. 평가 실행
python -m src.evaluation.metrics --dataset data/eval/qa_pairs.json --models all
# 7. UI 실행
streamlit run src/ui/app.py| 문서 | 내용 |
|---|---|
| 01-project-overview.md | 프로젝트 개요, 아키텍처, 범위 |
| 02-development-plan.md | 단계별 개발 기획, 세부 태스크, 실험 설계 |
| 03-requirements.md | 기술 스택, 의존성, API 키, 비용 추정 |
| 04-research.md | 기술 비교 분석 (프레임워크, 벡터DB, 임베딩 등) |
| 05-cloud-deployment.md | 클라우드 배포 비교 (AWS vs GCP) |
| 06-evaluation-methods.md | RAG 평가 방법론 심층 분석 (RAGAS, LLM-as-a-Judge) |