2024-11-20 TIL
TIL: LLM과 RAG를 활용한 AI 챗봇 만들기
1. 사용환경 준비
- OpenAI API 키를 환경 변수에서 가져오고, 필요한 라이브러리를 임포트한다.
ChatOpenAI
모델을 초기화하여 사용할 준비를 한다.
import os
from getpass import getpass
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
from langchain_openai import ChatOpenAI
# 모델 초기화
model = ChatOpenAI(model="gpt-4o-mini")
2. 모델 로드
- PDF 파일을 로드하기 위해
PyPDFLoader
를 사용한다. - 지정한 경로의 PDF 파일을 읽어 문서로 변환한다.
from langchain.document_loaders import PyPDFLoader
# PDF 파일 로드. 파일의 경로 입력
loader = PyPDFLoader("[2024 한권으로 OK 주식과 세금].pdf")
docs = loader.load()
3. 문서 청킹
CharacterTextSplitter
를 사용하여 문서를 작은 청크로 나눈다.- 청크의 크기와 중복되는 부분을 설정하여 문맥을 유지한다.
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
separator="\n\n",
chunk_size=100,
chunk_overlap=10,
length_function=len,
is_separator_regex=False,
)
splits = text_splitter.split_documents(docs)
# 청킹된 내용을 상위 10개까지 출력
for i, split in enumerate(splits[:10]):
print(f"Chunk {i+1}:\n{split.page_content}\n")
4. RecursiveCharacterTextSplitter 사용
RecursiveCharacterTextSplitter
를 사용하여 더 자연스러운 텍스트 분할을 시도한다.- 여러 구분자를 순차적으로 사용하여 문맥을 보존한다.
from langchain.text_splitter import RecursiveCharacterTextSplitter
recursive_text_splitter = RecursiveCharacterTextSplitter(
chunk_size=100,
chunk_overlap=10,
length_function=len,
is_separator_regex=False,
)
splits = recursive_text_splitter.split_documents(docs)
# 청킹된 내용을 상위 10개까지 출력
for i, split in enumerate(splits[:10]):
print(f"Chunk {i+1}:\n{split.page_content}\n")
5. 벡터 임베딩 생성
- OpenAI의 임베딩 모델을 초기화하여 문서의 벡터 표현을 생성한다.
from langchain_openai import OpenAIEmbeddings
# OpenAI 임베딩 모델 초기화
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
6. 벡터 스토어 생성
FAISS
를 사용하여 문서의 벡터 스토어를 생성한다.
import faiss
from langchain_community.vectorstores import FAISS
vectorstore = FAISS.from_documents(documents=splits, embedding=embeddings)
7. RAG 체인 설정
- 질문을 기반으로 관련 문서를 검색하고, 답변을 생성하는 RAG 체인을 설정한다.
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 1})
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# 프롬프트 템플릿 정의
contextual_prompt = ChatPromptTemplate.from_messages([
("system", "Answer the question using only the following context."),
("user", "Context: {context}\\n\\nQuestion: {question}")
])
8. 디버깅을 위한 클래스 추가
- 디버깅을 위한
DebugPassThrough
클래스를 정의하여 각 단계의 출력을 확인한다.
class DebugPassThrough(RunnablePassthrough):
def invoke(self, *args, **kwargs):
output = super().invoke(*args, **kwargs)
print("Debug Output:", output)
return output
9. 사용자 질문 처리
- 사용자로부터 질문을 입력받고, RAG 체인을 통해 답변을 생성한다.
while True:
print("========================")
query = input("질문을 입력하세요 (종료하려면 'q' 또는 'quit' 입력): ")
if query.lower() in ['q', 'quit']:
print("프로그램을 종료합니다.")
break
response = rag_chain_debug.invoke(query)
print("Final Response:")
print(response.content)
10. RAG vs 기존 챗봇 비교
- RAG의 장점과 기존 챗봇의 한계를 비교하여 설명한다.
- RAG는 실시간 정보 활용, 정확성 향상, 맞춤형 지식베이스 등의 장점을 가진다.
댓글남기기