[Python] RAG활용하여 문서기반 답변
Posted by Albert 15Day 7Hour 16Min 49Sec ago [2025-11-13]
문서: sample1.pdf, sample2.pdf 파일
해당 파일들을 활용하여
1. 텍스트 추출 -> 2.청크분할 처리 -> 3.벡터, 임베딩 처리 -> 4.처리된 벡터 Data를 크로마 DB에 등록 -> 5.GPT가 크로마 DB내용기반으로 사용자 질문에 답변하기
1~4 : pdf data를 벡터data로 가공하여 크로마 db에 등록
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from dotenv import load_dotenv
from langchain_chroma import Chroma
import os
load_dotenv()
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
' PDF 파일을 읽어서 텍스트 데이터를 추출합니다.
loader = PyPDFLoader('C:/Users/visio/Downloads/sample1.pdf')
data_nyc = loader.load()
' print(data_nyc)
' 텍스트 데이터를 1000자 단위로 나눕니다. overlap은 100자로 설정합니다.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
all_splits = text_splitter.split_documents(data_nyc)
for i, split in enumerate(all_splits):
print(f"Split {i+1}:------------------------------------\n")
print(split)
loader_seoul = PyPDFLoader('C:/Users/visio/Downloads/sample2.pdf')
data_seoul = loader_seoul.load()
seoul_splits = text_splitter.split_documents(data_seoul)
for i in range(len(seoul_splits) - 1):
seoul_splits[i].page_content += "\n"+ seoul_splits[i + 1].page_content[:100]
all_splits.extend(seoul_splits)
embedding = OpenAIEmbeddings(model='text-embedding-3-large', api_key=OPENAI_API_KEY)
v = embedding.embed_query("뉴욕의 온실가스 저감 정책은 뭐야?")
persist_directory = '../chroma_store'
' 저장된 크로마 DB가 없다면 새로 만들기
if not os.path.exists(persist_directory):
print("Creating new Chroma store")
vectorstore = Chroma.from_documents(
documents=all_splits,
embedding=embedding,
persist_directory=persist_directory
)
else:
print("Loading existing Chroma store")
vectorstore = Chroma(
persist_directory=persist_directory,
embedding_function=embedding
)
해당작업으로 sample1,sample2 pdf 파일내용이 벡터화되어 크로마디비 chroma.sqlite3 행태로 저장된걸 확인할 수 있다.
5. 크로마 db data를 활용하여 사용자 문의에 답변
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder ' ①
from langchain_classic.chains.combine_documents import create_stuff_documents_chain ' ②
from langchain_classic.memory import ChatMessageHistory
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI ' ③
import os
load_dotenv()
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
chat = ChatOpenAI(model="gpt-4o-mini") ' ③
persist_directory = '../chroma_store'
embedding = OpenAIEmbeddings(model='text-embedding-3-large', api_key=OPENAI_API_KEY)
vectorstore = Chroma(
persist_directory=persist_directory,
embedding_function=embedding
)
retriever = vectorstore.as_retriever(k=3)
docs = retriever.invoke("서울시의 환경 정책에 대해 궁금해")
' ④
question_answering_prompt = ChatPromptTemplate.from_messages(
[
( ' ⑤
"system",
"사용자의 질문에 대해 아래 context에 기반하여 답변하라.:\n\n{context}",
),
MessagesPlaceholder(variable_name="messages"), ' ⑥
]
)
document_chain = create_stuff_documents_chain(chat, question_answering_prompt) ' ⑦
' 채팅 메시지 저장할 메모리 객체 생성
chat_history = ChatMessageHistory()
' 사용자 질문을 메모리에 저장
chat_history.add_user_message("서울시의 온실가스 저감 정책에 대해 알려줘.")
' 문서 검색하고 답변 생성
answer = document_chain.invoke(
{
"messages": chat_history.messages,
"context": docs,
}
)
' 생성된 답변 메모리에 저장
chat_history.add_ai_message(answer)
print(answer)
실행시 GPT는 아래와 문서내용기반으로 정리하여 아래와 같은 내용을 출력한다.
서울시는 온실가스 저감을 위해 다양한 정책과 전략을 추진하고 있습니다. 다음은 주요 내용입니다:
1. **탄소중립 목표 설정**: 서울시는 탄소중립을 목표로 설정하고 이를 실현하기 위한 도시 인프라의 전환을 강조하고 있습니다.
2. **건물 부문 혁신**: 친환경 기술 개발 및 적극적인 적용을 통해 건물 부문의 탄소배출을 감축하려고 합니다. 예를 들어, 제로에너지 건물 확산과 같은 initiatives가 포함됩니다.
3. **교통 인프라 개선**: 미래 모빌리티 기술을 활용하고, 친환경 차량 및 관련 인프라를 확충하여 교통 부문에서의 온실가스 배출을 줄이는 방안을 모색하고 있습니다.
4. **청정에너지 기반 구축**: 에너지 전환을 위해 청정에너지를 기반으로 한 시스템을 구축하고 있습니다.
5. **자원순환 체계 강화**: 자립적인 자원순환 체계를 구축하여 폐기물의 발생을 줄이고 재활용을 최대화하려는 노력을 기울이고 있습니다. 이를 위해 분산형 폐기물 처리 시설을 확충하고 있습니다.
6. **시민 참여 활성화**: 시민의 기후 행동을 촉진하기 위한 포용적인 거버넌스를 구축하고, 다양한 교육 및 캠페인을 통해 기후 행동에 대한 인식을 제고하고 있습니다.
이러한 정책들은 서울시의 지속 가능한 발전과 시민 건강을 보장하는 동시에 미세먼지와 온실가스 배출을 획기적으로 감축하는 것을 목표로 하고 있습니다.