RAG를 실제로 구축하려고 하면 어디서 부터 시작해야 할 지 막막할 수 있다. 막상 실제로 시작해보면 단순히 “검색 → 생성”이 아니라 그 이전 단계의 데이터 준비 과정이 훨씬 더 중요하다는 걸 깨닫게 된다. 이번 글에서는 RAG 시스템을 만들 때 꼭 거치게 되는 기본 단계를 하나씩 짚어보며, 전체적인 흐름을 머릿속에 정리해보려고 한다.

1. Documents Load (문서 로드)
가장 첫 단계는 데이터를 불러오는 것.
RAG의 성능은 어떤 데이터를 넣느냐에 따라 달라지므로 다양한 형식의 문서를 불러오는 과정이 필요하다.
- PDF, Word, PPT, 텍스트 파일, HTML 등 다양한 포맷을 지원
- 보통 LangChain이나 LlamaIndex 같은 라이브러리에서는 DocumentLoader를 제공해 쉽게 가져올 수 있음
- 예시: 사내 보고서를 PDF로 로드하거나, 웹페이지를 크롤링해 텍스트를 추출
from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("report.pdf")
documents = loader.load()
2. Parsing (구문 분석)
로드된 문서는 대부분 그대로 쓰기 어렵다.
예를 들어 PDF는 단순히 텍스트 블록 단위로 잘리거나, HTML은 태그가 뒤섞여 있어서 그대로 임베딩하기 힘들다.
- 이 단계에서 불필요한 메타데이터 제거, 본문 정리, 표/이미지 텍스트화(OCR) 같은 작업 수행
- 목표는 모델이 이해하기 좋은 순수 텍스트 구조로 변환하는 것
3. Chunking (청크 분할)
LLM은 긴 문서를 한 번에 다루지 못한다.
따라서 문서를 적절한 크기(chunk)로 잘라야 한다.
- 보통 500~1024 토큰 단위로 잘라내며, 겹치는 부분(overlap)을 조금 두어 문맥이 끊기지 않게 처리
- Chunking은 단순 분할이 아니라, 검색 정확도를 높이기 위한 핵심 전처리
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(documents)
4. Contextualize (문맥 보강)
Chunking만 하면 “이 문장이 어디에 속하는지” 정보가 사라지기 쉽다.
그래서 문맥을 보강하는 단계가 필요하다.
- 제목, 섹션 레벨, 페이지 번호 같은 메타데이터를 함께 저장
- 예: “이 문단은 3장 · 데이터 분석 파트에 속함” 같은 정보
- 이를 통해 검색 시 더 풍부한 결과 제공 가능
즉, 단순한 문단이 아니라 문서 내 위치를 아는 청크로 만들어주는 작업이다.
5. Embedding (벡터화)
이제 각 청크를 임베딩 모델로 변환한다.
텍스트 → 고차원 벡터로 바꿔서 나중에 벡터 검색이 가능해진다.
- OpenAI의 text-embedding-3-small, text-embedding-3-large 같은 모델 자주 사용
- HuggingFace의 BERT 계열, Korean-SBERT 같은 로컬 모델도 가능
- 벡터화된 결과는 보통 수백~수천 차원의 float 벡터
from openai import OpenAI
client = OpenAI()
emb = client.embeddings.create(
model="text-embedding-3-small",
input="이 문단은 AI 기반 RAG 구축에 대한 설명입니다."
)
vector = emb.data[0].embedding
6. Upsert (DB 저장)
마지막은 벡터 DB에 저장하는 단계이다.
검색할 때마다 모든 문서를 다시 임베딩하는 건 비효율적이므로, 한 번 임베딩한 벡터는 DB에 올려놓고 재활용한다.
- 대표적인 벡터DB: FAISS, Milvus, Pinecone, Weaviate 등
- Upsert라는 표현을 쓰는 이유: 새로운 데이터는 추가(insert)하고, 기존 데이터는 갱신(update)하기 때문
- DB에는 벡터뿐 아니라 원문, 메타데이터, 문서ID 등을 같이 저장
Load → Parsing → Chunking → Contextualize → Embedding → Upsert
이 일련의 과정을 보통 RAG 데이터 파이프라인(Data Pipeline) 혹은 전처리 파이프라인(Preprocessing Pipeline)이라고 부른다.
좀 더 구체적으로 나누면
- Data Ingestion 단계: Load + Parsing
→ 외부 문서나 데이터 소스를 불러오고, 모델이 활용할 수 있도록 기본 텍스트 형태로 정리하는 과정 - Preprocessing 단계: Chunking + Contextualize
→ 문서를 적절한 크기로 쪼개고, 섹션·제목·페이지 같은 문맥 정보를 보강하여 검색 품질을 높이는 단계 - Vectorization 단계: Embedding
→ 각 청크를 임베딩 모델을 통해 벡터로 변환하여 의미적 검색이 가능하게 만드는 과정 - Indexing 단계: Upsert
→ 변환된 벡터와 원문, 메타데이터를 벡터DB에 저장하여 빠르고 효율적인 검색을 준비하는 단계
즉, 문서를 단순히 읽고 넘기는 것이 아니라, 검색 가능한 지식 베이스로 바꿔주는 전처리 파이프라인이라고 할 수 있다.
실제 RAG 성능의 절반 이상은 이 준비 과정에서 결정되며, 제대로 된 파이프라인을 갖추지 못하면 아무리 좋은 LLM을 붙여도 원하는 답변을 얻기 어렵다.
결국 RAG를 구축한다는 건, 단순히 LLM을 불러오는 것이 아니라 문서를 구조화하고, 검색 친화적인 형태로 바꿔주는 데이터 엔지니어링 과정을 설계하는 일이다. 이 과정을 거친 후에야 비로소 LLM이 검색된 문맥을 받아 답변을 생성하는 본래의 “RAG” 프로세스가 제대로 작동하게 된다.
정리하면, Load → Parsing → Chunking → Contextualize → Embedding → Upsert 단계를 거치며,
“문서 → 의미 있는 벡터 DB”라는 구조를 만든다.
실제 RAG 구축에서 가장 많은 시간을 잡아먹는 건 모델 튜닝이 아니라, 이 데이터 준비 과정이다.
데이터가 잘 구조화될수록 검색 정확도가 올라가고, 결과적으로 LLM의 답변 품질도 크게 향상된다.
다음 글에서는 이 데이터 파이프라인 위에 Retrieval과 Generation 단계를 올려, 실제로 질문에 대한 답변이 어떻게 생성되는지까지 설명 할 예정이다.
'AI > Natural language processing' 카테고리의 다른 글
| RAG 구축하기 - 3.1 성능 최적화 : Chunking 전략 제대로 파헤치기 (0) | 2025.08.19 |
|---|---|
| RAG 구축하기 - 2. Retrieval과 Generation (1) | 2025.08.19 |
| RAG- LangGraph 시작하기 (state+ node + edge = graph) (2) | 2025.08.18 |
| 텍스트 분류를 위한 NLP 모델 학습 (0) | 2024.11.22 |
| 트랜스포머 모델의 구조: 쉽게 이해하는 NLP 기초 (0) | 2024.11.20 |