RAG(Retrieval-Augmented Generation) 개념을 배우고 예시 코드를 처음 적용했을 때는 정말 쉬워 보였습니다. "이거면 금방 끝나겠네!" 싶었죠.
하지만 현실은 역시 만만치 않았습니다.
❌ 첫 번째 문제: 부정확한 컨텍스트와 잘린 답변
처음에는 간단한 설정으로 시작했습니다.
# 초기 설정
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=250, # 너무 작았음
chunk_overlap=100,
separators=["\n## ", "\n### ", "\n\n", "\n", ". ", " ", ""],
add_start_index=True,
)
def retrieve_context(query: str):
# k값도 너무 작았음
retrieved_docs = vector_store.similarity_search(query, k=2)
serialized = "\n\n".join(
(f"Source: {doc.metadata}\nContent: {doc.page_content}")
for doc in retrieved_docs
)
return serialized, retrieved_docs
테스트를 진행하자마자 문제점이 드러났습니다.
- k=2가 너무 적었습니다. 관련성 높은 청크 2개만 가져오니, 정책이나 절차처럼 더 많은 컨텍스트가 필요한 질문에 제대로 답하지 못했습니다.
- chunk_size=250이 너무 작았습니다. 중요한 정보가 여러 청크로 나뉘면서, AI의 답변에 "..."처럼 불완전한 내용이 포함되거나 문맥이 끊겨 정확한 답변 생성에 실패했습니다.
🔬 1차 해결 시도: 청크 크기 및 K값 증가
단순히 파라미터를 수정해 봤습니다.
- chunk_size: 250 → 500으로 증가
- chunk_overlap: 100 → 150으로 증가
- k (검색 개수): 2 → 5로 증가
결과: 조금 나아지긴 했지만, 여전히 답변 품질이 만족스럽지 않았습니다. 😔 근본적인 원인은 다른 곳에 있었습니다.
💡 근본 원인 분석 및 향후 개선 계획
단순한 파라미터 튜닝이 아니라, RAG 시스템의 구조 자체를 개선해야 한다는 결론에 도달했습니다.
1. 메타데이터 활용 (필터링)
첫 번째 해결책은 각 문서에 **구조화된 정보(메타데이터)**를 추가하는 것이었습니다. '업무 지식' 문서는 그 특성상 카테고리, 관련 모듈, 서비스 제공자 등이 명확합니다.
문서 상단에 YAML 헤더 추가:
---
doc_id: payment_module_setup
title: A-Pay 결제 모듈 연동 가이드
category: 연동설정
service_provider: A-Pay
payment_methods: bank_transfer, credit_card
keywords: API, 웹훅, notification, URL
---
(문서 본문...)
청킹 시 메타데이터 추출 및 포함: 문서를 청킹하기 전에, 이 YAML 헤더를 파싱하여 metadata 객체로 만들고, create_documents 시 함께 주입합니다.
import re
import yaml
import json
def extract_metadata_from_content(content):
"""YAML 헤더에서 메타데이터 추출"""
match = re.match(r"^---\n(.*?)\n---\n", content, re.DOTALL)
if match:
try:
metadata = yaml.safe_load(match.group(1))
clean_content = content[match.end():]
# ChromaDB 등 벡터 DB 호환 메타데이터로 변환 (리스트, 딕셔너리 처리)
cleaned_metadata = {}
for key, value in metadata.items():
if isinstance(value, (str, int, float, bool)) or value is None:
cleaned_metadata[key] = value
elif isinstance(value, list):
cleaned_metadata[key] = ', '.join(str(item) for item in value)
else:
cleaned_metadata[key] = str(value)
return cleaned_metadata, clean_content
except yaml.YAMLError as e:
print(f"YAML 파싱 오류: {e}")
return {}, content
return {}, content
# 사용 예시:
metadata, clean_content = extract_metadata_from_content(content)
metadata['source'] = os.path.basename(filepath)
doc_chunks = text_splitter.create_documents([clean_content], metadatas=[metadata])
메타데이터 활용 검색: 이제 similarity_search에서 filter 옵션을 사용하여, 특정 서비스 제공자(A-Pay)의 문서 내에서만 검색하도록 범위를 좁힐 수 있습니다.
def retrieve_context(query: str, provider_name: str = None):
"""메타데이터 필터로 검색 정확도 향상"""
if provider_name:
# 예: 'A-Pay' 관련 문서만 검색
retrieved_docs = vector_store.similarity_search(
query,
k=5,
filter={"service_provider": {"$eq": provider_name}}
)
else:
retrieved_docs = vector_store.similarity_search(query, k=5)
return retrieved_docs
2. 하이브리드 검색 (Hybrid Search)
의미 기반의 벡터 검색과 키워드 기반의 **BM25 (키워드 검색)**를 결합하여 정확도를 높이는 방식입니다. (이 부분은 향후 적용 예정입니다.)
3. 문서 재구조화 (⭐ 핵심)
이게 핵심이었습니다! 청킹과 메타데이터로도 해결이 어려운 근본 원인은 문서 구조 자체였습니다.
- 기존 문서: "사람이 읽기 좋은" 서술형 가이드
- 필요한 문서: "AI가 검색하고 답변하기 좋은" 구조
특히 업무 지식 관련 질문은 패턴이 명확하고 FAQ 작성이 용이하므로, 문서를 하이브리드(Hybrid) 형식으로 재정의하기로 결정했습니다.
🎯 핵심 해결 전략: 문서 재구조화 (계획)
AI가 빠르고 정확하게 답변을 찾을 수 있도록 문서 포맷 자체를 변경할 예정입니다.
새로운 문서 구조 (예시):
---
doc_id: apay_bank_transfer_setup
title: A-Pay 가상계좌 연동 및 알림 설정
type: hybrid
service_provider: A-Pay
payment_methods: bank_transfer
---
# A-Pay 가상계좌 연동 설정 가이드
## 🎯 핵심 요약 (Quick Answer)
**알림(웹훅) URL:** `https://api.your-service.com/webhook/payment-notification`
**설정 위치:** A-Pay 관리자 > 상점 관리 > 알림 설정 > URL 등록
**예상 소요 시간:** 약 5분
---
## 📋 자주 묻는 질문 (FAQ)
### Q1: 결제 알림(웹훅) URL이 무엇인가요?
고객이 결제를 완료하면 A-Pay가 상점 서버로 결제 정보를 전송(POST)하는 고유 주소입니다.
표준 URL: `https://api.your-service.com/webhook/payment-notification`
### Q2: 결제 알림이 오지 않아요.
1. URL이 정확히 등록되었는지 확인 (오타, http/https)
2. 서버 방화벽이 A-Pay IP 대역을 차단하는지 확인
3. HTTPS 인증서가 유효한지 확인
---
## 📚 상세 가이드
### 1. 웹훅 시스템 이해하기
[웹훅의 개념과 데이터 흐름 설명...]
### 2. 설정 방법 (Step-by-Step)
[관리자 페이지 로그인부터 설정 완료까지 상세 절차...]
---
## 🔧 기술 상세 (Advanced)
### API Spec
- Method: POST
- Content-Type: application/json
- Timeout: 5s
문서 구성 전략
문서 자체를 '하이브리드' 형식으로 만드는 것과 동시에, 자주 묻는 질문은 별도의 Q&A 파일로도 분리할 계획입니다.
📁 documents_optimized/
├── 📄 01_apay_연동_가이드.md (하이브리드 70%)
│ ├── Quick Answer (즉각적인 답변)
│ ├── FAQ (자주 묻는 질문)
│ ├── 상세 가이드 (절차)
│ └── 기술 상세 (개발자용)
│
├── 📄 02_qa_apay_알림_url.md (Q&A 30%)
│ └── Q: A-Pay 알림 URL은 무엇인가요? (특정 질문 최적화)
│
├── 📄 03_qa_apay_알림_누락.md (Q&A)
│ └── Q: A-Pay 알림이 누락돼요.
│
└── 📄 04_qa_apay_알림_테스트.md (Q&A)
└── Q: A-Pay 알림 테스트 방법은?
- 전략:
- 하이브리드 문서: 전체적이고 완전한 정보를 제공합니다.
- 단독 Q&A 문서: 자주 묻는 특정 질문에 대한 검색 정확도를 높입니다.
- 결론: 둘 다 벡터 DB에 임베딩하여 검색 커버리지를 최대화합니다.
하이브리드 형식의 장점
- 빠른 답변 (Quick Answer): "URL 알려줘" 같은 즉답이 필요한 질문에 즉시 대응합니다.
- 일반 질문 (FAQ): 가장 흔한 질문들을 미리 준비하여 정확도를 높입니다.
- 깊이 있는 정보 (상세 가이드): 복잡한 설정 절차나 개념 설명에 대응합니다.
- 검색 다양성 (별도 Q&A): 같은 내용이라도 다른 방식의 질문(Q&A)으로 검색될 확률을 높입니다.
🚀 다음 단계 및 💭 현재까지 배운 점
RAG 구축은 생각보다 험난한 여정이었습니다. 간단한 파라미터 튜닝으로 끝날 줄 알았지만, 결국 **'데이터'**가 가장 중요하다는 근본적인 문제에 도달했습니다.
현재까지 배운 점:
- RAG는 코드만의 문제가 아니다. 문서 구조(데이터)가 검색 품질에 가장 큰 영향을 미친다.
- 메타데이터는 선택이 아닌 필수다. (특히 여러 카테고리가 섞인 업무 지식에서는)
- 기술로 해결하려 하기 전에, 문서 구조부터 점검하는 것이 가장 효과적이다.
다음 단계:
- [진행 예정] 모든 문서를 하이브리드 형식으로 재작성
- [진행 예정] 메타데이터 필터링 기능 적용
- [검토 예정] 하이브리드 검색 도입
'사이드프로젝트' 카테고리의 다른 글
| [사이드 프로젝트] #2. RAG 챗봇 개발기 (5) - '메타데이터'를 활용한 필터링 (1) | 2025.11.13 |
|---|---|
| [사이드 프로젝트] #2 RAG 챗봇 개발기 (4) - 문서를 FAQ로 바꿨더니 답변 품질이 10배 향상됐다 (1) | 2025.11.08 |
| [사이드 프로젝트] #2. RAG 기반 '업무 지식' AI 챗봇 개발기 (2) - 챗봇 프로토타입 및 RAG 기본개념정리 (0) | 2025.10.24 |
| [사이드 프로젝트] #2. RAG 기반 '업무 지식' AI 챗봇 개발기 (1) (0) | 2025.10.22 |
| DevReview – 익명성을 보장하는 개발자 포트폴리오 리뷰 플랫폼 (1) | 2025.09.08 |