RAG (Retrieval-Augmented Generation) 구축 가이드
Source: rag-langchain-implementation-datacamp Type: Article (DataCamp) Valid as of: 2026-04-26
핵심 Takeaway
- RAG의 필요성 — LLM의 “환각(hallucination)” 문제와 최신 정보 반영 불가를 LLM + 검색 엔진 + 벡터 DB 조합으로 해결 (출처: rag-langchain-implementation-datacamp > rag가-필요한-이유)
- 3단계 아키텍처 — 색인화(Indexing) → 검색(Retrieval) → 생성(Generation)으로 구성 (출처: rag-langchain-implementation-datacamp > rag의-3단계-아키텍처)
- 문서 청킹(Chunking) — 긴 문서를 1000-2000자 단위로 분할하고 200자 중복으로 맥락 보존 (출처: rag-langchain-implementation-datacamp > 1-2-문서-분할-chunking)
- 벡터 임베딩 — 텍스트를 고차원 벡터로 변환하여 의미론적(semantic) 유사도 검색 가능 (출처: rag-langchain-implementation-datacamp > 1-3-임베딩-생성-embedding)
- 고급 검색 기법 — MMR(Maximal Marginal Relevance)로 관련성과 다양성 동시 확보, 메타데이터 필터로 시간/출처 기준 검색 (출처: rag-langchain-implementation-datacamp > 고급-검색-기법)
상세 요약
RAG가 필요한 이유
문제 1: LLM의 Hallucination
Q: "Claude 3.5 Sonnet의 훈련 데이터는 언제까지인가?"
LLM: "2024년 4월까지의 데이터로 훈련되었습니다" ❌
(사실: 정확한 cutoff date는 다를 수 있음)
문제 2: 최신 정보 미반영
Q: "2026년 4월의 암호화폐 가격은?"
LLM: "죄송하지만, 2023년 이후의 정보는 없습니다" ❌
해결책: RAG
LLM + 검색 엔진 + 벡터 데이터베이스 = 정확하고 최신의 답변
사용자 질문
↓
[검색] 벡터 DB에서 유관 문서 검색 (상위 3개)
↓
[강화] 검색 결과 + 질문을 LLM에 전달
↓
[생성] LLM이 문맥을 기반으로 답변 생성
↓
정확하고 최신의 답변 ✓
RAG의 3단계 아키텍처
단계 1: Indexing (색인화)
1-1. 문서 로드
from langchain.document_loaders import PyPDFLoader
import pandas as pd
# PDF 로드
loader = PyPDFLoader("your_document.pdf")
documents = loader.load()
# CSV 로드
df = pd.read_csv("data.csv")
# → LangChain Document로 변환1-2. 문서 분할 (Chunking)
문제: 전체 문서를 벡터화하면 토큰 제한 초과
해결책: 문서를 작은 청크로 분할
from langchain.text_splitter import CharacterTextSplitter
splitter = CharacterTextSplitter(
chunk_size=1000, # 1,000자 청크
chunk_overlap=200 # 200자 중복 (맥락 보존)
)
chunks = splitter.split_documents(documents)
# 청크 크기 선택 기준
# - 500자 (너무 작음): 정보 손실
# - 1000-2000자 (적절): 문맥 보존 + 검색 정확도
# - 5000자 (너무 큼): 토큰 낭비1-3. 임베딩 생성 (Embedding)
각 청크를 벡터로 변환 → 의미론적 검색 가능
from langchain.embeddings import OpenAIEmbeddings
from langchain.embeddings import HuggingFaceEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# 각 청크 → 1,536차원 벡터로 변환
# "AI 기술은 혁명적입니다" → [0.023, -0.145, 0.078, ..., 0.456]임베딩의 의미:
의미론적으로 유사한 텍스트 → 유사한 벡터
"AI는 인공지능입니다" → [0.1, 0.2, 0.3, ...]
"AI는 자동화된 학습입니다" → [0.11, 0.19, 0.31, ...] ← 유사
의미론적으로 다른 텍스트 → 다른 벡터
"고양이는 동물입니다" → [0.8, 0.05, 0.9, ...] ← 거리 먼
1-4. 벡터 데이터베이스에 저장
from langchain.vectorstores import Chroma # 로컬
# 또는
from langchain.vectorstores import Pinecone, FAISS, Weaviate
vector_db = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
# 저장되는 데이터:
# Chunk 1: "AI는..." → [벡터]
# Chunk 2: "머신러닝은..." → [벡터]
# ...벡터 DB 선택 기준:
| DB | 특징 | 용도 |
|---|---|---|
| Chroma | 로컬, 경량 | 프로토타입, 소규모 |
| Pinecone | 클라우드, 관리형 | 프로덕션, 대규모 |
| FAISS | 로컬, 고속 | 오프라인, 배치 검색 |
| Weaviate | 분산, 스케일 가능 | 엔터프라이즈 |
단계 2: Retrieval (검색)
사용자 질문과 가장 유사한 청크 검색
2-1. 유사도 검색 (Similarity Search)
query = "AI의 장점은 무엇인가?"
# 쿼리도 임베딩으로 변환
query_embedding = embeddings.embed_query(query)
# 벡터 DB에서 가장 가까운 청크 검색 (Cosine Similarity)
similar_chunks = vector_db.similarity_search(query, k=3)
# 결과 (상위 3개):
# 1. "AI는 반복적인 작업을 자동화합니다..."
# 유사도: 0.92 ← 매우 높음
# 2. "AI는 인간 지능을 보강합니다..."
# 유사도: 0.87
# 3. "머신러닝 알고리즘은 데이터에서 패턴을 학습합니다..."
# 유사도: 0.81고급 검색 기법:
2-2. MMR (Maximal Marginal Relevance)
문제: 상위 3개 청크가 모두 비슷한 내용 → 정보 다양성 없음
해결책: 관련성 + 다양성을 모두 고려
similar_chunks = vector_db.max_marginal_relevance_search(
query,
k=3,
fetch_k=10 # 먼저 상위 10개를 가져온 후 다양성 고려
)
# 결과:
# 1. "AI의 정의와 역사..." (관련성: 0.92)
# 2. "AI의 윤리적 문제..." (관련성: 0.75, 다양성 보강)
# 3. "AI 산업의 미래..." (관련성: 0.78, 추가 다양성)2-3. 메타데이터 필터
# 저장 시 메타데이터 추가
chunks_with_meta = [
{
"content": "AI는...",
"metadata": {"source": "ai_overview.pdf", "page": 1, "date": "2024"}
},
]
# 검색 시 필터 적용
filtered_chunks = vector_db.similarity_search(
query,
k=3,
filter={"date": {"$gte": "2024-01-01"}} # 2024년 이후만
)단계 3: Generation (생성)
검색된 청크를 컨텍스트로 LLM에 전달 → 답변 생성
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
llm = ChatOpenAI(model="gpt-4", temperature=0)
# RAG 체인 구성
rag_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 검색 결과를 프롬프트에 직접 포함
retriever=vector_db.as_retriever(search_kwargs={"k": 3})
)
# 질문
query = "AI의 주요 응용 분야는 무엇인가?"
# RAG 실행
result = rag_chain.run(query)
# 결과:
# "AI의 주요 응용 분야는:
# 1. 헬스케어 - 질병 진단, 신약 개발
# 2. 금융 - 사기 탐지, 투자 자동화
# 3. 제조 - 품질 관리, 생산 최적화"내부 동작 (프롬프트 구조):
System: 당신은 전문가 AI 어시스턴트입니다.
User: 다음 문맥을 기반으로 질문에 답하세요:
[검색 결과 1]
"AI는 헬스케어 산업에서 질병 진단에 사용됩니다..."
[검색 결과 2]
"의료 AI는 영상 분석에 특히 효과적합니다..."
[검색 결과 3]
"AI 기술은 신약 개발 시간을 50% 단축했습니다..."
질문: AI의 주요 응용 분야는 무엇인가?
실제 사용 예시
기업 문서 Q&A 시스템
아키텍처:
사용자 쿼리 (UI)
↓
[Retriever] 벡터 DB에서 관련 PDF/CSV 검색
↓
[LLM with RetrievalQA] 검색 결과 + 쿼리 처리
↓
JSON 응답 (FastAPI)
RAG의 장점
- 정확성: 기존 지식 기반 + 검색된 최신 정보 합성
- 신뢰성: 출처 추적 가능 (메타데이터)
- 확장성: 새로운 문서 추가 = 자동 학습 (재학습 불필요)
- 비용 효율: 작은 모델 + RAG > 큰 모델만 사용
연결되는 위키 페이지
- rag-architecture — RAG 아키텍처 개념
- vector-embeddings — 벡터 임베딩
- langchain — LangChain 도구
- chroma-db — Chroma 벡터 DB
- llm-hallucination — LLM 환각 문제
- genai-design-patterns-devto-skala — 생성형 AI 패턴
- transformer-architecture-huggingface — Transformer 기초