RAG 챗봇 구축 가이드

By | 2025년 6월 16일
Table of Contents

RAG 챗봇 구축 가이드

개요

RAG(Retrieval-Augmented Generation) 챗봇은 외부 지식베이스를 활용해 더 정확하고 최신 정보를 제공하는 AI 챗봇입니다. 이 가이드는 RAG 챗봇을 구축하는 과정을 단계별로 설명합니다.

RAG란 무엇인가?

RAG는 검색(Retrieval)생성(Generation)을 결합한 접근 방식입니다. 사용자 질문에 대해 관련 문서를 먼저 검색하고, 그 정보를 바탕으로 답변을 생성합니다.

RAG의 장점

  • 정확성: 실제 문서에 기반한 답변 제공
  • 최신성: 지식베이스 업데이트로 최신 정보 반영
  • 투명성: 답변의 출처를 명확히 제시
  • 비용 효율성: 모델 재학습 없이 지식 확장 가능

시스템 아키텍처

사용자 질문 → 임베딩 → 벡터 검색 → 문서 검색 → 컨텍스트 + 질문 → LLM → 답변

주요 구성 요소

  1. 문서 처리 파이프라인: 원본 문서를 청크 단위로 분할하고 벡터화
  2. 벡터 데이터베이스: 문서 임베딩을 저장하고 유사도 검색 수행
  3. 검색 엔진: 사용자 질문과 관련된 문서 청크를 찾아 반환
  4. 생성 모델: 검색된 컨텍스트를 활용해 최종 답변 생성

단계별 구축 가이드

1단계: 환경 설정

# 필요한 라이브러리 설치
pip install langchain chromadb openai sentence-transformers pypdf

pip install -U langchain-community
pip install -U langchain-openai

2단계: 문서 전처리

from langchain_community.document_loaders import PyPDFLoader
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

def load_documents(file_path):
    """문서 로드"""
    if file_path.endswith('.pdf'):
        loader = PyPDFLoader(file_path)
    else:
        loader = TextLoader(file_path)
    return loader.load()

def split_documents(documents):
    """문서를 청크로 분할"""
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    return text_splitter.split_documents(documents)

3단계: 벡터 데이터베이스 구축

from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OpenAIEmbeddings
# from langchain_openai import OpenAIEmbeddings

def create_vectorstore(documents):
    """벡터 저장소 생성"""
    embeddings = OpenAIEmbeddings()
    vectorstore = Chroma.from_documents(
        documents=documents,
        embedding=embeddings,
        persist_directory="./chroma_db"
    )
    return vectorstore

4단계: 검색 시스템 구현

def create_retriever(vectorstore, search_type="similarity", k=5):
    """검색기 생성"""
    retriever = vectorstore.as_retriever(
        search_type=search_type,
        search_kwargs={"k": k}
    )
    return retriever

5단계: RAG 체인 구성

from langchain.chains import RetrievalQA
from langchain_community.llms import OpenAI

def create_rag_chain(retriever):
    """RAG 체인 생성"""
    llm = OpenAI(temperature=0)
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=retriever,
        return_source_documents=True
    )
    return qa_chain

6단계: 챗봇 인터페이스 구현

OPENAI_API_KEY 발급받기

import os
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain.chains import RetrievalQA
from langchain_openai import OpenAI
from langchain_openai import ChatOpenAI

os.environ["OPENAI_API_KEY"] = "your-openai-api-key-here"

def load_documents(file_path):
    """문서 로드"""
    if file_path.endswith('.pdf'):
        loader = PyPDFLoader(file_path)
    else:
        loader = TextLoader(file_path)
    return loader.load()

def split_documents(documents):
    """문서를 청크로 분할"""
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    return text_splitter.split_documents(documents)

def create_vectorstore(documents):
    """벡터 저장소 생성"""
    embeddings = OpenAIEmbeddings()
    vectorstore = Chroma.from_documents(
        documents=documents,
        embedding=embeddings,
        persist_directory="./chroma_db"
    )
    return vectorstore

def create_retriever(vectorstore, search_type="similarity", k=5):
    """검색기 생성"""
    retriever = vectorstore.as_retriever(
        search_type=search_type,
        search_kwargs={"k": k}
    )
    return retriever

def create_rag_chain(retriever):
    """RAG 체인 생성"""
    # llm = OpenAI(temperature=0)
    llm = ChatOpenAI(
        model="gpt-4o-mini",
        temperature=0,
        max_tokens=200  # 응답 길이 제한
    )
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=retriever,
        return_source_documents=True
    )
    return qa_chain

class RAGChatbot:
    def __init__(self, documents_path):
        # 문서 로드 및 전처리
        documents = load_documents(documents_path)
        splits = split_documents(documents)

        # 벡터 저장소 생성
        self.vectorstore = create_vectorstore(splits)

        # 검색기 및 체인 생성
        retriever = create_retriever(self.vectorstore)
        self.qa_chain = create_rag_chain(retriever)

    def chat(self, question):
        """사용자 질문에 대한 답변 생성"""
        result = self.qa_chain.invoke({"query": question})
        return {
            "answer": result["result"],
            "sources": result["source_documents"]
        }

# 사용 예시
chatbot = RAGChatbot("./law.pdf")
response = chatbot.chat("성년의 기준이 되는 나이가 어떻게 되지?")
print(response["answer"])

성능 최적화

여기서부터 아래의 문서는 인공지능에 의해 작성되었으며, 테스트 되지 않은 코드입니다.

청크 크기 조정

# 다양한 청크 크기 실험
chunk_sizes = [500, 1000, 1500, 2000]
for size in chunk_sizes:
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=size,
        chunk_overlap=size//5
    )
    # 성능 평가

하이브리드 검색

from langchain.retrievers import EnsembleRetriever
from langchain.retrievers import BM25Retriever

def create_hybrid_retriever(documents, vectorstore):
    """하이브리드 검색기 생성"""
    # 키워드 기반 검색
    bm25_retriever = BM25Retriever.from_documents(documents)

    # 의미 기반 검색
    vector_retriever = vectorstore.as_retriever()

    # 앙상블 검색기
    ensemble_retriever = EnsembleRetriever(
        retrievers=[bm25_retriever, vector_retriever],
        weights=[0.5, 0.5]
    )
    return ensemble_retriever

재랭킹 시스템

from langchain.document_transformers import LongContextReorder

def rerank_documents(documents, query):
    """문서 재랭킹"""
    reordering = LongContextReorder()
    reordered_docs = reordering.transform_documents(documents)
    return reordered_docs

고급 기능

대화 메모리 추가

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain

def create_conversational_chain(retriever):
    """대화형 RAG 체인 생성"""
    memory = ConversationBufferMemory(
        memory_key="chat_history",
        return_messages=True
    )

    qa_chain = ConversationalRetrievalChain.from_llm(
        llm=OpenAI(temperature=0),
        retriever=retriever,
        memory=memory
    )
    return qa_chain

실시간 문서 업데이트

def update_vectorstore(vectorstore, new_documents):
    """벡터 저장소 업데이트"""
    splits = split_documents(new_documents)
    vectorstore.add_documents(splits)
    vectorstore.persist()

답변 품질 평가

from langchain.evaluation.qa import QAEvalChain

def evaluate_rag_system(qa_chain, test_questions):
    """RAG 시스템 평가"""
    eval_chain = QAEvalChain.from_llm(OpenAI(temperature=0))

    results = []
    for question in test_questions:
        result = qa_chain({"query": question})
        evaluation = eval_chain.evaluate(
            question,
            result["result"],
            result["source_documents"]
        )
        results.append(evaluation)

    return results

배포 및 모니터링

FastAPI를 이용한 API 서버

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()
chatbot = RAGChatbot("./documents/")

class ChatRequest(BaseModel):
    question: str

@app.post("/chat")
async def chat_endpoint(request: ChatRequest):
    response = chatbot.chat(request.question)
    return response

로깅 및 모니터링

import logging
from datetime import datetime

def setup_logging():
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler('rag_chatbot.log'),
            logging.StreamHandler()
        ]
    )

def log_interaction(question, answer, sources):
    """사용자 상호작용 로그"""
    logging.info(f"Question: {question}")
    logging.info(f"Answer: {answer}")
    logging.info(f"Sources: {len(sources)} documents")

주의사항 및 모범 사례

보안 고려사항

  • API 키 및 민감한 정보는 환경 변수로 관리
  • 사용자 입력 검증 및 sanitization 필수
  • 접근 권한 및 인증 시스템 구현

성능 최적화

  • 캐싱 시스템 도입으로 응답 시간 단축
  • 비동기 처리를 통한 동시 요청 처리
  • 벡터 데이터베이스 인덱싱 최적화

데이터 품질 관리

  • 정기적인 문서 업데이트 및 품질 검토
  • 중복 문서 제거 및 일관성 유지
  • 사용자 피드백을 통한 지속적인 개선

결론

RAG 챗봇은 기존 LLM의 한계를 극복하고 도메인 특화된 고품질 답변을 제공하는 강력한 솔루션입니다. 이 가이드를 통해 기본적인 RAG 시스템부터 고급 기능까지 단계별로 구축할 수 있습니다.

성공적인 RAG 챗봇 구축을 위해서는 지속적인 모니터링과 개선이 필요하며, 사용자 피드백을 적극적으로 반영해 시스템의 품질을 향상시켜야 합니다.

참고 자료

답글 남기기