AI 개발 공부 공간

AI, 머신러닝, 딥러닝, Python & PyTorch, 실전 프로젝트

딥러닝/딥러닝: 자연어

RAG 챗봇 시스템 구현

qordnswnd123 2025. 6. 8. 14:46

1. 프로젝트 소개 및 환경 설정

최근 서울시에서 실행하는 정책을 참고해, 유저의 질문에 대답을 할 수 있도록 챗봇을 만들어 봅니다.
이를 위해서, 서울시 정책 PDF 문서 중 청년 정책 관련 부분을 데이터로 사용하고, HuggingFace에 등록된 LLM을 이용해 프로젝트를 진행합니다.

 

1.1 환경 설정

1) 필수 라이브러리

  • langchain
  • langchain_community
  • langchain_huggingface
  • pypdf
  • faiss-cpu or faiss-gpu

2) Hugging Face 라이브러리를 사용하기 위한 토큰 발급 받기
이 프로젝트는 Hugging Face에서 제공하는 라이브 러리를 사용하여 임베딩 모델과 LLM 모델을 불러와서 사용합니다.
로컬 환경에서 프로젝트를 진행하시는 경우, 해당 라이브러리를 사용하기 위해 Hugging Face에서 토큰을 발급 받아야 합니다.

 

2. 문서 불러오기

from langchain_community.document_loaders import PyPDFLoader
# 단계 1: 문서 로드(Load Documents)
loader = PyPDFLoader("seoul_y.pdf")
docs = loader.load()

# 문서 요약 정보 출력
print(f"로드된 문서 수: {len(docs)}")
if docs:
    print("\n첫 번째 문서 요약:")
    print(f"내용 미리보기: {docs[0].page_content[:100]}...")  # 처음 100자만 출력
로드된 문서 수: 24

첫 번째 문서 요약:
내용 미리보기: 2024 달라지는 서울생활
48  
동행특별시
18
이제는 몰라서 지원받지 못하는 사례가 없도록!
서울시 가족돌봄청년 지원  
전담기구 운영
서울시는 가족돌봄이라는 막중한 책임을 ...

 

3. 문서 분할하기

from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=100,
)

splits = text_splitter.split_documents(docs)
len(splits)
26

 

4. 벡터 스토어에 문서 저장하기

embeddings는 아래와 같은 코드로 설정 되어있습니다.

from langchain_openai import OpenAIEmbeddings
import os

embeddings = OpenAIEmbeddings(
    model="text-embedding-3-small",
    openai_api_key= '발급 받은 API key'
)
# 초기 실행 시 1~2분 까지 시간이 소요될 수 있습니다.
# 벡터 스토어에 저장
from langchain_community.vectorstores import FAISS 

vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)

print(f"타입 확인: {type(vectorstore)}")
print(f"저장된 문서 수: {vectorstore.index.ntotal}")
print(f"벡터의 차원: {vectorstore.index.d}")
  • OpenAIEmbeddings 라이브리러리를 통해 "text-embedding-3-small" 임베딩 모델을 불러옵니다.
  • FAISS 벡터 스토어에 분할된 문서를 불러온 임베딩 모델을 통해 임베딩하여 저장합니다.
타입 확인: <class 'langchain_community.vectorstores.faiss.FAISS'>
저장된 문서 수: 26
벡터의 차원: 1536

 

5. Retrievers 생성하기

#벡터스토어를 retriever로 변환
retriever = vectorstore.as_retriever(search_type="similarity")

#Retriever 정보 확인
print(f"타입 확인: {type(retriever)}")
print(f"검색 유형: {retriever.search_type}")
타입 확인: <class 'langchain_core.vectorstores.base.VectorStoreRetriever'>
검색 유형: similarity

 

6. 프롬프트 탬플릿 정의

from langchain.prompts import PromptTemplate

prompt_template = """
당신은 서울시의 정책에 대해 상세히 알고 있는 친절한 상담사입니다. 
당신의 임무는 서울시의 다양한 정책을 쉽고 친절하게 설명하는 것입니다.

주어진 문맥(context)을 바탕으로 질문(question)에 답해주세요. 답변할 때는 다음 지침을 따라주세요:
1. 친절하고 이해하기 쉬운 말로 설명해주세요.
2. 가능한 한 구체적인 정보를 제공하되, 불필요한 세부사항은 생략하세요.
3. 정책의 목적과 시민들에게 어떤 혜택이 있는지 강조해주세요.
4. 만약 주어진 문맥에서 답을 찾을 수 없다면, "죄송합니다. 현재 가지고 있는 정보로는 이 질문에 답하기 어렵습니다." 라고 답하세요.
5. 기술적인 용어나 정책 이름은 그대로 사용하되, 필요하다면 간단한 설명을 덧붙여주세요.
6. 답변은 꼭 한국어를 사용해주세요.

질문에 대해 단계적으로 생각하고, 논리적으로 답변을 구성해주세요.

#질문: 
{question} 

#제공된 정보: 
{context} 

#답변:
"""

PROMPT = PromptTemplate(
    template=prompt_template,
    input_variables=["context", "question"]
)

 

7. LLM 모델 설정하기

HuggingFaceEndpoint 라이브러리를 사용하여 허깅페이스에 등록된 "mistralai/Mistral-7B-Instruct-v0.2" 모델을 불러옵니다.

from langchain_huggingface import HuggingFaceEndpoint

llm_mistralai = HuggingFaceEndpoint(
    endpoint_url="mistralai/Mistral-7B-Instruct-v0.3",
    max_new_tokens=1024,
    top_k=10,
    top_p=0.95,
    typical_p=0.95,
    temperature=0.01,
    repetition_penalty=1.03,
    huggingfacehub_api_token=os.environ["HUGGINGFACEHUB_API_TOKEN"]
)

 

8. RAG 체인 구성하기

앞 단계에서 정의한 검색기, 프롬프트 탬플릿, LLM을 이용해 RAG 체인을 생성합니다.

# 체인 생성하기
from langchain.chains import RetrievalQA

chain = RetrievalQA.from_chain_type(
    llm=llm_mistralai,
    chain_type="stuff",
    retriever=retriever,
    chain_type_kwargs={"prompt": PROMPT},
)
# 초기 실행 시 1~2분 까지 시간이 소요될 수 있습니다.
# 에러가 발생하면 새로고침을 시도해 보세요.

# 질문하고 답변 받기
result = chain.invoke("서울시에서 운영하는 청년 복지 정책은 어떤 것들이 있나요?")
print(result["result"])
서울시에서 운영하는 청년 복지 정책으로는 다음과 같습니다.

1. 영플러스서울: 자립준비 청년들을 위한 공간으로, 자조모임, 취미·동아리 활동공간, 교육장, 작품갤러리, 상담실 등이 있습니다. 사전예약 시 공간대관이 가능합니다. 위치는 서울시 용산구 백범로99길 40, 102동 2층(삼각지역 5, 8번 출구 도보 5분)입니다. 이용시간은 주간(월~금: 09~18시 / 토: 10~17시) / 야간(화·목: 18~21시)입니다. 사전예약 방법은 자립지원전담기관 누리집(www.sjarip.or.kr)에서 대관 신청하시면 됩니다.

2. 서울시 가족돌봄청년 지원: 돌봄 대상자가 없어지는 것을 방지하기 위한 정책으로, 상담 신청 시 별도의 구비서류는 없으며, 상담신청서를 작성하여 신청자 정보, 돌봄상황, 돌봄대상자 건강상태 등을 알려주시면 됩니다. 상담 종료 후 서비스 제공, 후원사업 연계를 위해 일부 자료를 요구할 수 있습니다.

3. 서울 청년 기업체험 프로젝트: 대학생들을 대상으로 적절한 직무체험과 적성탐색 기회를 제공하여 청년들의 일자리 정책서비스 수요를 충족하고, 고용 미스매칭 해소에 기여합니다. 새롭게 시작해요 시행일은 2024년 하반기입니다.

4. 청년취업사관학교: 각 캠퍼스별 교육과정 개설 시 청년취업사관학교 누리집(sesac.seoul.kr)에서 신청 가능하고, 레벨테스트와 면접을 통해 선발합니다.

 

 

추가로, 아래 코드를 통해 RAG가 없다면 LLM이 어떤 답변을 생성할지 확인해 봅니다.

# 초기 실행 시 1~2분 까지 시간이 소요될 수 있습니다.
from langchain_core.output_parsers import StrOutputParser

prompt_template_no_rag = """<|system|>
당신은 서울시의 정책에 대해 상세히 알고 있는 친절한 시민 상담사입니다. 당신의 임무는 서울 시민들에게 서울시의 다양한 정책을 쉽고 친절하게 설명하는 것입니다.

주어진 질문(question)에 답해주세요. 답변할 때는 다음 지침을 따라주세요:
1. 항상 친절하고 이해하기 쉬운 말로 설명해주세요.
2. 가능한 한 구체적인 정보를 제공하되, 불필요한 세부사항은 생략하세요.
3. 정책의 목적과 시민들에게 어떤 혜택이 있는지 강조해주세요.
4. 만약 주어진 문맥에서 답을 찾을 수 없다면, "죄송합니다. 현재 가지고 있는 정보로는 이 질문에 답하기 어렵습니다. 서울시 공식 홈페이지나 다산콜센터(120)에서 더 자세한 정보를 얻으실 수 있습니다."라고 답하세요.
5. 기술적인 용어나 정책 이름은 그대로 사용하되, 필요하다면 간단한 설명을 덧붙여주세요.
6. 답변은 꼭 한국어를 사용해주세요.

질문에 대해 단계적으로 생각하고, 논리적으로 답변을 구성해주세요.

<|user|>
{question}<|end|>
<|assistant|>
"""

prompt_no_rag = PromptTemplate.from_template(prompt_template_no_rag)

# RAG 없는 일반 답변 생성 체인 생성
chain_no_rag = prompt_no_rag | llm_mistralai | StrOutputParser()

# 결과 출력
response_no_rag = chain_no_rag.invoke({"question": "서울시에서 운영하는 청년 복지 정책은 어떤 것들이 있나요?"})
print(response_no_rag)
서울시에서는 청년 복지를 위해 다양한 정책을 운영하고 있습니다. 이 중 일부는 다음과 같습니다.

1. 청년 직업 지원 프로그램: 청년들이 직업을 찾고 취업하기 위한 지원을 제공합니다. 이 프로그램에는 취업 교육, 인턴십, 직업 경력 개발 프로그램 등이 포함됩니다.

2. 청년 생활 지원 프로그램: 청년들이 생활 지원을 받을 수 있도록 하는 프로그램입니다. 이 프로그램에는 공급품 지원, 임대 지원, 교육비 지원 등이 포함됩니다.

3. 청년 문화 및 예술 지원 프로그램: 청년들이 문화와 예술을 통해 자기실현을 위한 기회를 얻을 수 있도록 하는 프로그램입니다. 이 프로그램에는 예술 교육, 문화 행사 참여 등이 포함됩니다.

이러한 정책들은 청년들이 자신의 생활과 직업 발전에 도움을 받을 수 있도록 하며, 서울시의 청년 복지 정책 중 하나입니다. 더 자세한 정보는 서울시 공식 홈페이지나 다산콜센터(120)에서 확인하실 수 있습니다.