홈으로
🔍

RAG 검색 증강 생성

문서 기반 AI 시스템 구축의 모든 것

12시간
intermediate
6개 챕터
초급 과정으로 돌아가기

Chapter 4: 첫 RAG 시스템 구축하기

30분 만에 작동하는 RAG 시스템을 만들어봅시다!

4.1 시스템 구성 요소

최소한의 RAG 시스템에 필요한 것들

📦 필수 패키지

pip install langchain

pip install openai

pip install chromadb

pip install pypdf

🔧 핵심 컴포넌트

  • 문서 로더 (Document Loader)
  • 텍스트 분할기 (Text Splitter)
  • 임베딩 모델 (Embeddings)
  • 벡터 저장소 (Vector Store)
  • LLM (Language Model)

RAG 파이프라인 아키텍처

📄 문서
✂️ 청킹
🔢 임베딩
💾 저장
🔍 검색
💬 생성

4.2 단계별 구현

실제 코드로 RAG 시스템 구축하기

Step 1: 환경 설정

import os
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# API 키 설정
os.environ["OPENAI_API_KEY"] = "your-api-key"

Step 2: 문서 로딩 및 처리

# PDF 문서 로드
loader = PyPDFLoader("example.pdf")
documents = loader.load()

# 텍스트 분할
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
    length_function=len,
)
chunks = text_splitter.split_documents(documents)

print(f"총 {len(chunks)}개의 청크가 생성되었습니다.")

Step 3: 임베딩 및 벡터 저장

# 임베딩 모델 초기화
embeddings = OpenAIEmbeddings()

# 벡터 데이터베이스 생성 및 저장
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

print("벡터 데이터베이스가 생성되었습니다!")

Step 4: 질의응답 체인 생성

# LLM 초기화
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# 검색기 생성
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

# QA 체인 생성
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True,
)

Step 5: 시스템 사용하기

# 질문하기
question = "이 문서의 핵심 내용은 무엇인가요?"
result = qa_chain({"query": question})

# 결과 출력
print("답변:", result["result"])
print("\n참고한 문서:")
for doc in result["source_documents"]:
    print(f"- {doc.page_content[:100]}...")

4.3 전체 코드 예제

simple_rag.py - 복사해서 바로 실행 가능!

#!/usr/bin/env python3
"""
Simple RAG System - 첫 번째 RAG 시스템
30분 만에 작동하는 RAG를 만들어보세요!
"""

import os
from typing import List
from langchain.document_loaders import TextLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

class SimpleRAG:
    def __init__(self, persist_directory="./rag_db"):
        """RAG 시스템 초기화"""
        self.persist_directory = persist_directory
        self.embeddings = OpenAIEmbeddings()
        self.llm = ChatOpenAI(
            model_name="gpt-3.5-turbo",
            temperature=0,
            max_tokens=500
        )
        self.vectorstore = None
        self.qa_chain = None
        
    def load_documents(self, file_paths: List[str]):
        """다양한 문서 형식 로드"""
        documents = []
        
        for file_path in file_paths:
            if file_path.endswith('.pdf'):
                loader = PyPDFLoader(file_path)
            elif file_path.endswith('.txt'):
                loader = TextLoader(file_path)
            else:
                print(f"지원하지 않는 파일 형식: {file_path}")
                continue
            
            documents.extend(loader.load())
            print(f"✓ {file_path} 로드 완료")
        
        return documents
    
    def process_documents(self, documents):
        """문서를 청크로 분할"""
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=1000,
            chunk_overlap=200,
            length_function=len,
            separators=["\n\n", "\n", " ", ""]
        )
        
        chunks = text_splitter.split_documents(documents)
        print(f"\n📊 총 {len(chunks)}개의 청크가 생성되었습니다.")
        return chunks
    
    def create_vectorstore(self, chunks):
        """벡터 데이터베이스 생성"""
        print("\n🔄 벡터 데이터베이스 생성 중...")
        
        self.vectorstore = Chroma.from_documents(
            documents=chunks,
            embedding=self.embeddings,
            persist_directory=self.persist_directory
        )
        
        self.vectorstore.persist()
        print("✓ 벡터 데이터베이스 생성 완료!")
    
    def setup_qa_chain(self):
        """질의응답 체인 설정"""
        # 커스텀 프롬프트 템플릿
        template = """아래의 문맥을 사용하여 질문에 답변해주세요.
        
문맥: {context}

질문: {question}

답변할 때 다음 사항을 지켜주세요:
1. 문맥에 있는 정보만을 사용하여 답변하세요.
2. 문맥에 없는 내용은 추측하지 마세요.
3. 답변을 찾을 수 없다면 "제공된 문서에서 해당 정보를 찾을 수 없습니다"라고 답하세요.

답변:"""
        
        PROMPT = PromptTemplate(
            template=template,
            input_variables=["context", "question"]
        )
        
        # QA 체인 생성
        self.qa_chain = RetrievalQA.from_chain_type(
            llm=self.llm,
            chain_type="stuff",
            retriever=self.vectorstore.as_retriever(
                search_kwargs={"k": 3}
            ),
            return_source_documents=True,
            chain_type_kwargs={"prompt": PROMPT}
        )
        
        print("✓ QA 체인 설정 완료!")
    
    def build(self, file_paths: List[str]):
        """전체 RAG 시스템 구축"""
        print("🚀 RAG 시스템 구축을 시작합니다...\n")
        
        # 1. 문서 로드
        documents = self.load_documents(file_paths)
        
        # 2. 문서 처리
        chunks = self.process_documents(documents)
        
        # 3. 벡터 DB 생성
        self.create_vectorstore(chunks)
        
        # 4. QA 체인 설정
        self.setup_qa_chain()
        
        print("\n✅ RAG 시스템이 준비되었습니다!")
    
    def query(self, question: str):
        """질문에 대한 답변 생성"""
        if not self.qa_chain:
            print("❌ 먼저 build() 메서드를 실행하세요.")
            return None
        
        result = self.qa_chain({"query": question})
        
        return {
            "answer": result["result"],
            "sources": result["source_documents"]
        }

def main():
    # 1. RAG 시스템 초기화
    rag = SimpleRAG()
    
    # 2. 문서 준비 (예시)
    file_paths = [
        "document1.pdf",
        "document2.txt",
    ]
    
    # 3. RAG 시스템 구축
    rag.build(file_paths)
    
    # 4. 대화형 질의응답
    print("\n💬 질문을 입력하세요 (종료: 'quit')\n")
    
    while True:
        question = input("질문> ")
        
        if question.lower() == 'quit':
            print("RAG 시스템을 종료합니다. 안녕히 가세요! 👋")
            break
        
        # 답변 생성
        result = rag.query(question)
        
        if result:
            print(f"\n답변: {result['answer']}")
            print(f"\n참고한 문서 ({len(result['sources'])}개):")
            for i, doc in enumerate(result['sources'], 1):
                print(f"{i}. {doc.page_content[:100]}...")
            print("-" * 50 + "\n")

if __name__ == "__main__":
    # OpenAI API 키 확인
    if not os.getenv("OPENAI_API_KEY"):
        print("⚠️  OPENAI_API_KEY 환경변수를 설정해주세요!")
        print("export OPENAI_API_KEY='your-api-key'")
    else:
        main()

🚀 실행 방법

  1. 1.API 키 설정: export OPENAI_API_KEY='sk-...'
  2. 2.문서 준비: PDF 또는 TXT 파일
  3. 3.코드에서 파일 경로 수정
  4. 4.실행: python simple_rag.py

💡 확장 아이디어

  • 웹 UI 추가 (Streamlit, Gradio)
  • 다양한 파일 형식 지원 (Word, HTML)
  • 대화 히스토리 관리
  • 멀티모달 지원 (이미지, 표)

🔧 자주 발생하는 문제 해결

1. ImportError: langchain 모듈을 찾을 수 없음

해결: pip install langchain openai chromadb pypdf

2. OpenAI API 키 오류

해결: 환경변수 확인 echo $OPENAI_API_KEY

3. 메모리 부족 오류

해결: chunk_size를 500으로 줄이고, 문서를 작은 단위로 처리

🎉 축하합니다!

✅ 완료한 내용

  • • PDF/텍스트 문서 처리
  • • 청킹 및 임베딩 생성
  • • 벡터 데이터베이스 구축
  • • 질의응답 시스템 구현
  • • 대화형 인터페이스 제작

🚀 다음 단계

  • • 중급 과정에서 성능 최적화 배우기
  • • 하이브리드 검색 구현하기
  • • 프롬프트 엔지니어링 적용
  • • 프로덕션 배포 준비
  • • 평가 메트릭 구현