/AI & 자동화/[코드 예제 완벽 가이드] LangChain & LlamaIndex로 나만의 RAG 시스템 구축하기
AI & 자동화RAGLangChain

[코드 예제 완벽 가이드] LangChain & LlamaIndex로 나만의 RAG 시스템 구축하기

LLM의 한계를 극복하는 RAG(검색 증강 생성) 시스템 구축, 이론만으로는 부족합니다. 본 가이드는 LangChain과 LlamaIndex를 활용하여 실제 작동하는 Q&A 파이프라인을 단계별 코드 예제와 함께 제공합니다.

[코드 예제 완벽 가이드] LangChain & LlamaIndex로 나만의 RAG 시스템 구축하기

[코드 예제 완벽 가이드] LangChain & LlamaIndex로 나만의 RAG 시스템 구축하기

"LLM이 만능이라고요? 아닙니다. 하지만, LLM을 제대로 쓰려면 '지식 기반'이 필요합니다."

최근 몇 년간 LLM(대규모 언어 모델)의 발전 속도는 경이롭습니다. 마치 마법처럼 복잡한 질문에 답하고, 글을 쓰고, 코드를 짜는 것 같습니다. 하지만 개발자로서 이 강력한 도구를 실제 서비스에 적용하려 할 때, 우리는 종종 벽에 부딪힙니다.

"이 모델이 아는 정보가 최신 정보가 아닐 수도 있잖아?" "우리 회사 내부 매뉴얼에 있는 특정 규정을 모르면 어떻게 해?" "가끔 엉뚱한 소리(환각, Hallucination)를 지어내지 않을까?"

이러한 문제들이 바로 **RAG(Retrieval-Augmented Generation, 검색 증강 생성)**가 필요한 이유입니다. RAG는 LLM에게 '외부의 신뢰할 수 있는 지식 베이스'를 참고하여 답변하게 만드는 과정입니다.

이론만으로는 부족합니다. 오늘은 추상적인 'RAG' 개념을 실제로 작동하는 코드 블록과 단계별 워크플로우로 변환하여, 독자님이 오늘 당장 따라 치고 결과물을 만들어낼 수 있는 완벽한 청사진을 제시하겠습니다.


📚 1단계: 데이터 준비 및 임베딩 (Knowledge Base 구축)

RAG 시스템의 성패는 80%가 이 '지식 베이스(Knowledge Base)'를 얼마나 잘 구축하느냐에 달려있습니다. 마치 도서관의 책들을 분류하고 검색하기 좋게 정리하는 과정과 같습니다.

우리는 PDF, DOCX 등 비정형 문서(Unstructured Data)를 가지고 시작합니다. 이 문서들을 LLM이 이해할 수 있는 '숫자 벡터'로 변환하는 것이 첫 번째 목표입니다.

🧱 워크플로우 개요: 로드 $\rightarrow$ 분할 $\rightarrow$ 임베딩 $\rightarrow$ 저장

  1. Document Loader: 다양한 형식의 파일(PDF, TXT 등)을 불러옵니다.
  2. Text Splitter: 불러온 문서를 LLM의 컨텍스트 창 크기에 맞춰 적절한 크기(Chunk)로 잘게 나눕니다. 너무 크면 노이즈가 되고, 너무 작으면 문맥이 끊깁니다.
  3. Embedding: 각 청크(Chunk)를 임베딩 모델(예: OpenAI text-embedding-ada-002)을 이용해 고차원 벡터(숫자 배열)로 변환합니다.
  4. Vector Store: 이 벡터들을 검색하기 쉬운 특수 데이터베이스(Vector DB)에 저장합니다.

💻 실습 코드: 데이터 로드 및 벡터화 (LlamaIndex 예시)

실제 환경에서는 pip install llama-index pypdf chromadb openai 등의 라이브러리 설치가 선행되어야 합니다.

Python
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.chroma import ChromaVectorStore
import chromadb
import os

# 1. 가상 데이터 준비 (실제로는 PDF 폴더를 지정합니다)
# os.makedirs("data", exist_ok=True)
# print("💡 'data' 폴더에 테스트용 매뉴얼 PDF 파일을 넣어주세요.")

# 2. Document Loader: 로컬 폴더에서 문서 로드
print("✅ 1. 문서 로딩 시작...")
try:
    documents = SimpleDirectoryReader("data").load_data()
    print(f"✨ 총 {len(documents)}개의 문서를 성공적으로 로드했습니다.")
except FileNotFoundError:
    print("🚨 'data' 폴더를 찾을 수 없습니다. 테스트 파일을 넣어주세요.")
    exit()

# 3. Vector Store 및 Index 생성
# ChromaDB를 사용하며, 로컬에 벡터 DB를 구축합니다.
print("✅ 2. ChromaDB 연결 및 Index 구축 시작...")
db = chromadb.EphemeralClient() # 임시 클라이언트 사용
chroma_collection = db.get_or_create_collection("company_manual_index")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)

# 4. Index 생성 (자동으로 청킹, 임베딩, 저장까지 처리)
# LlamaIndex는 이 과정을 매우 간결하게 처리해줍니다.
index = VectorStoreIndex.from_documents(
    documents,
    vector_store=vector_store,
    show_progress=True
)

print("\n🎉 데이터베이스 구축 완료! 이제 검색 준비가 끝났습니다.")

💡 개발자 디버깅 팁: 만약 Embedding Model 관련 에러가 발생한다면, API 키(OPENAI_API_KEY 등)가 환경 변수에 제대로 설정되었는지, 그리고 해당 모델이 사용 가능한지(예: 유료 API 사용 여부)를 가장 먼저 확인해야 합니다.


🚀 2단계: 오케스트레이션 구축 (질의응답 파이프라인 완성)

지식 베이스가 준비되었다면, 이제 사용자의 질문을 받아 답변을 생성하는 '뇌'를 만들어야 합니다. 이 과정이 바로 **오케스트레이션(Orchestration)**입니다.

핵심 흐름: $$\text{User Query} \xrightarrow{\text{Embedding}} \text{Vector Search} \xrightarrow{\text{Retrieval}} \text{Context Documents} \xrightarrow{\text{Prompt Augmentation}} \text{LLM} \xrightarrow{\text{Answer}} \text{Final Answer}$$

📊 LangChain vs. LlamaIndex: 나에게 맞는 도구는?

두 프레임워크 모두 RAG 구현에 최적화되어 있지만, 철학적 차이가 있습니다.

특징LangChainLlamaIndex추천 상황
강점범용적인 워크플로우(Chain) 구성, 다양한 Tool 연동에 강함.**데이터 연결 및 검색(Retrieval)**에 특화되어 있음. 데이터 중심 설계.복잡한 Tool 조합 (예: 검색 $\rightarrow$ API 호출 $\rightarrow$ 요약)이 필요할 때.
구조체인(Chain) 기반의 모듈식 연결.인덱스(Index) 기반의 데이터 중심 접근.문서 기반의 Q&A가 주 목적이고, 데이터 관리가 중요할 때.
적합 대상엔지니어링 워크플로우 설계가 주 목표일 때.데이터 과학자, 도메인 지식 기반의 검색이 주 목표일 때.

결론: RAG 시스템 구축의 '뼈대'를 세우는 데는 두 가지 모두 훌륭하지만, 순수하게 '문서 기반의 지식 검색'에 집중한다면 LlamaIndex가 더 직관적일 수 있습니다.

💻 코드 예시 (LangChain 기반)

Python
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# 1. 임베딩 및 벡터 저장소 로드 (이전 단계에서 생성된 벡터 DB 사용 가정)
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
    documents=loaded_documents, # 미리 로드된 문서 객체
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# 2. 검색기(Retriever) 설정
retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 상위 3개 문서 검색

# 3. QA 체인 생성 (검색된 문서를 기반으로 답변 생성)
llm = ChatOpenAI(model_name="gpt-4o")
qa_chain = RetrievalQA.from_chain_type(
    llm=llm, 
    retriever=retriever, 
    return_source_documents=True # 출처 문서도 함께 반환받기
)

# 4. 질문 실행
query = "최근 시장 동향에 대한 핵심 요약은 무엇인가요?"
result = qa_chain({"query": query})

print(f"🤖 답변: {result['result']}")
print("\n📚 출처 문서:")
for doc in result['source_documents']:
    print(f"- {doc.metadata.get('source')}: {doc.page_content[:50]}...")

💡 심화 학습 포인트: RAG의 완성도를 높이는 방법

단순히 검색해서 답변을 받는 것(Basic RAG)을 넘어, 실제 서비스 수준으로 끌어올리려면 다음 단계를 고려해야 합니다.

  1. 프롬프트 엔지니어링 (Prompt Engineering):

    • 역할 부여: LLM에게 "당신은 전문적인 금융 분석가입니다."와 같이 명확한 페르소나를 부여합니다.
    • 출처 명시 요구: "답변할 때 반드시 출처 문서를 인용하고, 출처가 불분명한 정보는 추측하지 마십시오."와 같은 제약 조건을 명시합니다.
  2. 하이브리드 검색 (Hybrid Search):

    • 키워드 + 벡터: 순수 벡터 검색(의미 검색)만으로는 정확도가 떨어질 수 있습니다. BM25(키워드 기반) 검색벡터 검색(의미 기반) 검색을 결합하여 검색의 정확도를 극대화해야 합니다. (대부분의 고급 검색 엔진에서 지원)
  3. 리랭킹 (Re-ranking):

    • 검색된 상위 $K$개의 문서(예: 10개)를 무조건 사용하는 대신, 별도의 리랭커 모델을 사용하여 이 문서들의 순위를 재조정합니다. 가장 관련성이 높은 상위 3~5개만 최종 답변 생성에 사용하면 답변의 품질이 비약적으로 상승합니다.

이러한 단계를 거치면, 단순한 Q&A 챗봇을 넘어 기업의 지식 베이스를 활용하는 강력한 AI 검색 증강 생성(RAG) 시스템을 구축할 수 있습니다.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Reviewer·검토 · 사람 편집자·발행 · 2026년 5월 22일

댓글

불러오는 중...