12.3 RAG (Retrieval-Augmented Generation) 구현
Chapter 12.3 RAG (Retrieval-Augmented Generation) 구현
이번 절에서는 생성형 AI의 핵심 활용 기법 중 하나인 RAG(Retrieval-Augmented Generation)의 구조와 활용법을 깊이 있게 다루고, LangChain 및 LlamaIndex 라이브러리와 연계한 실전 구현 방법까지 단계적으로 설명합니다. RAG는 외부 문서를 통해 지식을 보완하는 생성 방식으로, 정확성과 신뢰성을 요구하는 비즈니스 응용에 특히 강력한 도구입니다.
🙋 기본 개념: RAG란 무엇인가?
RAG(Retrieval-Augmented Generation)는 외부 지식베이스나 문서에서 정보를 가져오는 검색(Retrieval) 단계와, 해당 정보를 바탕으로 자연스러운 문장을 생성하는 생성(Generation)을 결합한 하이브리드 방법론입니다. 이는 단순히 LLM(Large Language Model)에 프롬프트를 주는 수준을 넘어서, 정보를 동적으로 불러와 문맥 속에 반영함으로써 다음과 같은 이점을 제공합니다.
최신 정보 반영: 훈련 시점 이후 생긴 정보를 다룰 수 있음
정확도 향상: 기억 기반이 아닌 외부 지식 기반 생성
비용 효율성: 사소한 질문에 대량 토큰을 소진하지 않음
프롬프트 족쇄 해방: 모델에 모든 정보를 고정하지 않아도 됨
🧱 RAG의 아키텍처 구성도
아래는 RAG의 전형적인 아키텍처입니다.
Query Input (사용자의 질문 입력)
Query Embedding (LLM 또는 Embedding 모델로 입력을 벡터화)
Vector Database Search (FAISS, Pinecone, Weaviate 등에서 유사한 문서 검색)
Context Injection (검색된 문서 + 질문 → 프롬프트로 구성)
Generation (OpenAI GPT 또는 다른 LLM으로 답변 생성)
📦 주요 구성 요소 설명
Embedding Model
텍스트를 벡터화. OpenAI의 text-embedding-3-small 등
Vector Database
벡터로 저장된 문서의 검색. FAISS, Chroma, Pinecone
Retriever
사용자 질문과 유사한 문서를 찾는 로직
Prompt Template
검색된 문서를 문맥에 삽입하는 템플릿
LLM
OpenAI ChatGPT 모델 등으로 최종 출력 생성
🧪 실습: LangChain을 이용한 RAG 구현
이제 LangChain을 활용한 RAG 시스템을 단계별로 개발해보겠습니다.
🔧 Step 1: 필요한 패키지 설치
pip install openai langchain faiss-cpu tiktoken
🔧 Step 2: 환경 설정
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
import os
os.environ["OPENAI_API_KEY"] = "your-api-key"
🔧 Step 3: 문서 임베딩 및 벡터 스토어 구성
docs = [
"LangChain is a scaffold for building LLM-powered applications.",
"Retrieval-Augmented Generation uses an external knowledge base to supplement the generation.",
"OpenAI provides powerful Embedding models for vectorization.",
]
# 텍스트 임베딩
embeddings_model = OpenAIEmbeddings(model="text-embedding-3-small") # 최신 embedding 모델 사용
# FAISS 벡터 스토어 생성
vectorstore = FAISS.from_texts(docs, embedding=embeddings_model)
🔧 Step 4: Retriever + LLM 구성 및 QA 체인 생성
# 검색기 구성
retriever = vectorstore.as_retriever()
# 언어모델 설정
llm = ChatOpenAI(model_name="gpt-4", temperature=0)
# RAG 체인 구성
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 검색 문서들을 "stuffing"하여 프롬프트에 넣는 간단한 방식
retriever=retriever,
return_source_documents=True
)
🔧 Step 5: 질문 입력 및 실행
result = qa_chain("What is Retrieval-Augmented Generation?")
print("Answer:", result["result"])
print("\n🔗 Source Document(s):")
for doc in result["source_documents"]:
print("-", doc.page_content)
🧠 Prompt 내부 구성 예시
LangChain 내부적으로 아래와 같은 형식으로 프롬프트를 구성합니다.
You are a helpful assistant.
Use the following pieces of context to answer the user's question.
Context:
[문서1]
[문서2]
Question: What is Retrieval-Augmented Generation?
Answer:
이처럼 검색된 문서를 최대 입력 토큰 범위 내에서 LLM 프롬프트에 직접 삽입하는 방식은 “stuffing 방식”이라 하며, 다양한 구성 전략 중 하나입니다.
📈 RAG 구성 전략 비교
Stuffing
검색된 문서를 그대로 프롬프트에 붙임
단순, 빠름
토큰 초과 시 유실
Map-Reduce
각 문서에 대해 개별 응답 → 집계
대규모 문서에서 안정적
비용 ↑, 속도 ↓
Refine
초기 문서로 응답 생성 후 점진적 개선
고품질 생성
설계 복잡, 비용 ↑
LangChain은 위 전략 모두를 chain_type 인자로 지원합니다.
RetrievalQA.from_chain_type(
llm=llm,
chain_type="map_reduce", # 또는 "refine"
retriever=retriever,
)
📙 LlamaIndex를 활용한 대안 구현
LlamaIndex는 문서 구조화에 더 중점을 둔 프레임워크입니다. 문서 → 인덱스 → 쿼리 흐름으로 구성되며, 구조적 메타데이터나 긴 문서 처리에 더 유리합니다.
🔧 핵심 코드 구조 예시
from llama_index import VectorStoreIndex, SimpleDirectoryReader, ServiceContext
from llama_index.llms import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# 문서 로딩
documents = SimpleDirectoryReader("./docs").load_data()
# 서비스 컨텍스트 설정
service_context = ServiceContext.from_defaults(
llm=OpenAI(model="gpt-4"),
embed_model=OpenAIEmbedding(model="text-embedding-3-small")
)
# 인덱스 빌드
index = VectorStoreIndex.from_documents(documents, service_context=service_context)
# 질의 및 답변 생성
query_engine = index.as_query_engine()
response = query_engine.query("RAG의 장점은 무엇인가요?")
print(response)
📌 LlamaIndex vs LangChain 비교
설계 중심
체인, 프롬프트 구성 중심
문서 인덱싱 중심
유연성
다양한 전략 구성 가능
문서 기반 워크플로에 적합
튜닝 난이도
중
낮음
문서 길이 처리
stuffing 한계
chunking 내장 더 강력
📎 Best Practices: 실전 RAG 적용 시 주의할 점
Embedding 모델 선택
클라이언트 요청이 다양할 경우 다국어 지원되는 모델 사용
OpenAI text-embedding-3-small은 비용 효율적 사용 가능
Chunk size 조절
검색 단위가 너무 크면 관련성 ↓, 너무 작으면 문맥성 ↓
일반적으로 300~500 token이 추천됨
Chunk overlap 설정
단락 간 문맥 끊김을 방지하기 위해 20~50 토큰 정도 겹치게 처리
메타데이터 포함
문서의 출처(URL, 제목) 등도 벡터화에 반영하면 신뢰도 ↑
Token 예산에 따른 출력 전략 조정
검색된 문서가 많을수록 답변의 Token 예산은 줄어듦 → 답변 최대 길이 설정 필요
📍 마무리 요약
RAG는 단순 생성형 AI의 한계를 넘어, 사실 기반 검색을 결합한 고품질 응용을 가능하게 하는 핵심 기술입니다. LangChain과 LlamaIndex는 각기 다른 접근 방식으로 구현을 도와주며, 실제 서비스에서는 구성 요소(임베딩 모델, vector DB, 검색 전략 등)를 상황에 맞게 조합하는 것이 매우 중요합니다.
다음 절에서는 이런 RAG 구성을 실제 웹/모바일 애플리케이션과 통합하는 프론트엔드 연결 방식(Chapter 13)으로 이어집니다.
Last updated