Home 답변 품질을 극대화하는 RAG 시스템 설계의 기술
Post
Cancel

답변 품질을 극대화하는 RAG 시스템 설계의 기술

ChatGPT와 같은 거대 언어 모델(LLM)이 IT 생태계를 바꾸고 있지만, 실제 비즈니스에 적용하려 할 때 우리는 몇 가지 명확한 한계에 부딪힙니다. 모델이 학습하지 않은 최신 정보를 모르거나, 기업 내부 데이터에 접근할 수 없으며, 때로는 사실이 아닌 정보를 그럴듯하게 지어내는 ‘환각(Hallucination)’ 현상을 보이기 때문입니다.

이러한 문제를 해결하기 위해 등장한 가장 현실적이고 강력한 기술이 바로 RAG(Retrieval-Augmented Generation, 검색 증강 생성)입니다. RAG는 LLM이 답변을 생성할 때, 외부 또는 내부의 신뢰할 수 있는 데이터 소스를 실시간으로 ‘검색’하고, 그 결과를 ‘참고’하여 답변의 정확성과 신뢰도를 획기적으로 높이는 방식입니다.


왜 Custom RAG 인가?

“ChatGPT에 파일을 업로드하는 것도 RAG 아닌가요?”라고 생각할 수 있습니다. 맞습니다. 하지만 이 방식은 결정적인 한계를 가집니다. 바로 ‘블랙박스’라는 점입니다. 내부 동작을 알 수 없어 왜 특정 답변이 나왔는지, 혹은 왜 정보를 찾지 못했는지 파악하고 개선하기가 어렵습니다.

실제로 특정 문서의 상세 정보를 질문했을 때, 정보가 있음에도 “자료를 찾을 수 없다”고 답변하는 사례는 흔하게 발생합니다.

따라서 우리가 직접 RAG 파이프라인의 모든 구성 요소를 제어하고 최적화하는 Custom RAG가 중요합니다. Custom RAG는 다음과 같은 명확한 장점을 제공합니다.

  • 투명성과 제어: 데이터 처리부터 검색, 답변 생성까지 전 과정을 추적하고 디버깅할 수 있습니다.
  • 성능 최적화: 우리 데이터에 가장 적합한 임베딩 모델, 벡터 DB, 검색 전략을 선택해 성능을 극대화할 수 있습니다.
  • 안정적인 환각 억제: 답변의 근거를 명확히 하고, 검색된 내용에 기반해서만 답변하도록 강제하여 환각을 효과적으로 제어할 수 있습니다.

이제 RAG를 구성하는 핵심 요소들을 하나씩 살펴보겠습니다.

RAG(Retrieval-Augmented Generation)란?

RAG는 문서 기반 검색을 통해 관련 데이터를 추출하고, 이를 LLM이 활용하여 답변을 생성하는 기술입니다. 전체 파이프라인은 크게 데이터를 준비하는 전처리 단계와 질문에 답변하는 서비스 단계로 나뉩니다.

1
2
3
4
5
6
7
8
9
RAG 파이프라인 구조
─────────────────────────────────────────────────────────────────
전처리 단계:
  문서 → 문서 로더 → 텍스트 분할 → 임베딩 → 벡터 DB 저장
                 (Chunking)
─────────────────────────────────────────────────────────────────
서비스 단계:
  질문 → 임베딩 → 검색(Retrieve) → LLM 처리 → 답변 생성
─────────────────────────────────────────────────────────────────

주요 RAG 구성 요소 상세 분석

1. 문서 로더 (Document Loader)

RAG의 첫 단계는 다양한 포맷의 문서를 시스템으로 불러오는 것입니다. 어떤 로더를 사용하느냐에 따라 초기 데이터의 품질이 결정됩니다.

로더 종류장점단점추천 사용 사례
PyPDF매우 빠른 속도문장이 잘릴 수 있음실시간 요약 등 빠른 처리가 필요할 때
PyPDFLoader한글 처리 우수, 준수한 속도-가장 일반적인 PDF 처리
UnstructuredPDF테이블, 제목 등 요소별 정보 추출속도가 느림문서의 상세한 구조 정보가 필요할 때
PDFPlumber인코딩 우수, 풍부한 메타데이터 제공읽기 속도가 느림메타데이터 기반 작업이 중요할 때

2. 텍스트 분할기 (Text Splitter)

긴 문서는 LLM이 한 번에 처리하기 어렵기 때문에 의미 있는 작은 단위인 ‘청크(Chunk)’로 나누어야 합니다.

  • 강력 추천: RecursiveCharacterTextSplitter는 단락 → 문장 → 단어 순으로 계층적으로 분할을 시도하여 의미 단위의 손실을 최소화합니다.
  • 한국어 특화: KoNLPyTextSplitter는 한국어 형태소 분석기를 사용하여 더 정교한 분할이 가능하지만, 처리 속도가 느릴 수 있습니다.
  • 최신 기법: SemanticChunker는 문장의 의미적 유사성을 기반으로 자동으로 텍스트를 분할하는 새로운 접근법입니다.

3. 임베딩 (Embedding) 및 벡터 저장소 (Vector Store)

임베딩은 텍스트 청크를 검색 가능한 숫자 벡터로 변환하는 과정입니다.

  • 모델 선택: OpenAI의 임베딩 모델은 사용이 간편하고 성능이 우수하며, Hugging Face에서는 다양한 무료 오픈소스 모델을 선택할 수 있습니다. 한국어 처리 성능을 반드시 벤치마킹해야 합니다.
  • 비용 절약 팁: Cache-backed Embedding을 활용하면, 한 번 임베딩한 결과를 로컬에 저장해두고 재사용하여 중복 API 호출 비용을 줄일 수 있습니다.

변환된 벡터들은 벡터 저장소(Vector Store)에 저장됩니다. 클라우드 환경에서는 Pinecone, Milvus 등을, 로컬에서는 FAISS, Chroma DB 등을 주로 사용합니다.

4. 검색기 (Retriever)

사용자 질문에 가장 관련성 높은 문서를 벡터 DB에서 찾아내는 핵심 엔진입니다. 단순 검색을 넘어 다음과 같은 고급 전략을 사용할 수 있습니다.

  • Multi-Query Retriever: 하나의 질문을 LLM을 통해 여러 유사한 질문으로 변형시켜 검색함으로써, 사용자의 숨은 의도까지 파악하여 검색 범위를 넓힙니다.
  • Ensemble Retriever: 키워드 기반 검색(Sparse, 예: BM25)의 정확성과 의미 기반 벡터 검색(Dense)의 풍부함을 결합하여 검색 품질을 극대화합니다.
  • Long Context Reorder: LLM이 긴 문맥의 중간 부분을 놓치는 경향(‘Lost in the middle’)을 보완하기 위해, 검색된 문서 중 가장 중요한 것을 맨 앞과 맨 뒤로 재배치하는 전략입니다.

전문가를 위한 RAG 응용 전략

기본 파이프라인을 구축했다면, 다음 전략들로 RAG 시스템의 성능을 한 차원 더 높일 수 있습니다.

  1. 불필요한 영역 제거: 문서의 머리글, 바닥글, 페이지 번호 등 반복적이고 무의미한 부분은 전처리 단계에서 제거하여 검색 노이즈를 줄입니다.
  2. 테이블/이미지 추출: Camelot, PaddleOCR과 같은 라이브러리를 사용해 PDF 내의 표나 이미지 속 텍스트를 정확하게 추출하고 별도로 처리합니다.
  3. 메타데이터 필터링: 문서의 생성 날짜, 카테고리, 작성자 등의 메타데이터를 함께 저장하고, 검색 시 필터 조건으로 활용하여 검색 범위를 효과적으로 좁힐 수 있습니다.
  4. 고급 요약 (Chain of Density): 검색된 문서들을 단순히 LLM에 전달하는 대신, 여러 단계에 걸쳐 요약을 반복하며 핵심 정보를 누락 없이 압축하는 기법입니다.
  5. 프롬프트 관리: 시스템 프롬프트를 YAML 파일 등으로 버전 관리하고, LangChain Hub와 같은 도구를 활용하여 검증된 프롬프트 템플릿을 재사용합니다.

지금까지 RAG의 개념과 핵심 구성 요소, 그리고 실제 구현을 위한 여러 전략을 살펴보았습니다. 성공적인 RAG 시스템은 단순히 기술을 적용하는 것을 넘어, 데이터의 특성에 맞춰 각 구성 요소를 어떻게 선택하고 튜닝하느냐에 따라 그 성능이 결정됩니다.

안정적이고 신뢰도 높은 AI 서비스 구현에 있어 RAG는 매우 강력한 도구입니다. 이 글이 여러분의 프로젝트에 적합한 RAG 아키텍처를 설계하는 데 실질적인 도움이 되었기를 바랍니다.

This post is licensed under CC BY 4.0 by the author.

Java 개발자를 위한 SOLID 설계 원칙과 실제 예제

LangChain 학습 노트 #1: API 키 관리부터 LCEL 파이프라인까지