이번 강의에서는 벡터 스토어 리트리버에 대해 쉽고 자세하게 설명해 드리겠습니다. 마지막에는 실제로 작동하는 전체 실습 코드를 제공하겠습니다. OPENAI_API_KEY
는 .env
파일에 저장하고 이를 불러오는 방식으로 진행하겠습니다.
벡터 스토어 리트리버(Vector Store Retriever)는 벡터 스토어에서 관련 있는 문서를 효율적으로 검색하기 위한 도구입니다. 벡터 스토어는 문서나 텍스트를 임베딩 벡터로 변환하여 저장한 데이터베이스로, 유사한 의미를 가진 문서를 빠르게 검색할 수 있습니다.
예를 들어, 방대한 양의 문서에서 특정 질문과 관련된 정보를 찾고 싶을 때 벡터 스토어 리트리버를 사용하면 매우 효율적으로 원하는 결과를 얻을 수 있습니다.
LangChain과 같은 언어 모델 체인을 구축할 때, 복잡한 작업을 수행하기 위해 여러 개체를 연결해야 할 때가 있습니다. 이때 벡터 스토어를 직접 넘겨주는 대신, 리트리버 객체를 사용하여 더 표준화되고 일관된 방식으로 관련 문서를 검색할 수 있습니다.
리트리버는 벡터 스토어 위에 추상화된 계층을 제공하여, 다양한 백엔드에서 동일한 인터페이스를 통해 문서를 검색할 수 있도록 합니다. 이는 다중 쿼리 검색이나 컨텍스트 압축과 같은 고급 기능을 구현할 때 특히 유용합니다.
이제 실제로 벡터 스토어 리트리버를 사용하는 방법을 단계별로 알아보겠습니다.
먼저 필요한 라이브러리를 설치하고 임포트합니다.
pip install langchain openai chromadb tiktoken dotenv langchain_community
pip install wikipedia
import os
from dotenv import load_dotenv
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
.env
파일에서 OPENAI_API_KEY
를 불러옵니다.
.env
파일 내용.env
파일은 프로젝트 루트 디렉토리에 위치하며, 다음과 같은 내용을 포함합니다:
OPENAI_API_KEY=your_openai_api_key_here
# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
# OpenAI API 키 설정
os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY
텍스트 문서를 로드하고 적절한 크기로 분할합니다.
# 문서 로드 (예: 연설문 텍스트 파일)
loader = TextLoader("data/FDR_State_of_Union_1944.txt")
documents = loader.load()
# 문서 분할
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=500, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
참고: data/FDR_State_of_Union_1944.txt
파일 경로는 실제로 존재하는 텍스트 파일로 변경해야 합니다.
OpenAI의 임베딩 함수를 초기화합니다.
embedding_function = OpenAIEmbeddings()
분할된 문서를 벡터 스토어에 저장합니다.
# 벡터 스토어에 문서와 벡터 저장
persist_directory = 'db/speech_embedding_db'
vectordb = Chroma.from_documents(docs, embedding_function, persist_directory=persist_directory)
# 데이터베이스 저장
vectordb.persist()
저장된 벡터 스토어를 로드하고 리트리버 객체를 생성합니다.
# 저장된 벡터 스토어 로드
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)
# 리트리버 생성
retriever = vectordb.as_retriever()
특정 쿼리에 대한 관련 문서를 검색합니다.
# 검색 파라미터 설정
search_kwargs = {"score_threshold": 0.8, "k": 4}
# 쿼리 입력
query = "루스벨트가 식품법의 비용에 대해 뭐라고 말했나요?"
# 관련 문서 검색
results = retriever.get_relevant_documents(query, search_kwargs=search_kwargs)
# 결과 출력
for idx, doc in enumerate(results):
print(f"결과 {idx+1}:\n{doc.page_content}\n")
새로운 문서를 추가하고 다시 검색해봅니다.
# 새로운 문서 로드 및 분할
loader_new = TextLoader("data/Lincoln_State_of_Union_1862.txt")
documents_new = loader_new.load()
docs_new = text_splitter.split_documents(documents_new)
# 기존 벡터 스토어에 새로운 문서 추가
vectordb.add_documents(docs_new)
vectordb.persist()
# 업데이트된 벡터 스토어 로드
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)
retriever = vectordb.as_retriever()
# 새로운 쿼리로 유사성 검색
query_new = "링컨이 노예제에 대해 뭐라고 말했나요?"
results_new = retriever.get_relevant_documents(query_new, search_kwargs=search_kwargs)
# 결과 출력
for idx, doc in enumerate(results_new):
print(f"결과 {idx+1}:\n{doc.page_content}\n")
아래는 위의 모든 단계를 포함한 전체 코드입니다.
import os
from dotenv import load_dotenv
# 필요한 라이브러리 임포트
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
# .env 파일에서 API 키 로드
load_dotenv()
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
# OpenAI API 키 설정
os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY
# 문서 로드
loader = TextLoader("data/FDR_State_of_Union_1944.txt")
documents = loader.load()
# 문서 분할
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=500, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
# 임베딩 함수 초기화
embedding_function = OpenAIEmbeddings()
# 벡터 스토어 생성 및 저장
persist_directory = 'db/speech_embedding_db'
vectordb = Chroma.from_documents(docs, embedding_function, persist_directory=persist_directory)
vectordb.persist()
# 벡터 스토어 로드 및 리트리버 생성
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)
retriever = vectordb.as_retriever()
# 검색 파라미터 설정
search_kwargs = {"score_threshold": 0.8, "k": 4}
# 쿼리 입력
query = "루스벨트가 식품법의 비용에 대해 뭐라고 말했나요?"
# 관련 문서 검색
results = retriever.get_relevant_documents(query, search_kwargs=search_kwargs)
# 결과 출력
for idx, doc in enumerate(results):
print(f"결과 {idx+1}:\n{doc.page_content}\n")
# 새로운 문서 로드 및 분할
loader_new = TextLoader("data/Lincoln_State_of_Union_1862.txt")
documents_new = loader_new.load()
docs_new = text_splitter.split_documents(documents_new)
# 기존 벡터 스토어에 새로운 문서 추가
vectordb.add_documents(docs_new)
vectordb.persist()
# 업데이트된 벡터 스토어 로드 및 리트리버 생성
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding_function)
retriever = vectordb.as_retriever()
# 새로운 쿼리로 유사성 검색
query_new = "링컨이 노예제에 대해 뭐라고 말했나요?"
results_new = retriever.get_relevant_documents(query_new, search_kwargs=search_kwargs)
# 결과 출력
for idx, doc in enumerate(results_new):
print(f"결과 {idx+1}:\n{doc.page_content}\n")
as_retriever()
메서드를 사용하여 벡터 스토어에서 리트리버 객체를 생성합니다.get_relevant_documents()
메서드를 사용하여 쿼리에 대한 관련 문서를 검색합니다.score_threshold
, k
등의 파라미터를 사용하여 결과를 필터링할 수 있습니다.이렇게 해서 벡터 스토어 리트리버의 개념과 사용 방법에 대해 알아보았습니다. 이 방법을 통해 대규모 문서 집합에서 효율적으로 관련 정보를 검색할 수 있습니다. 다음 강의에서는 이 개념을 기반으로 더 발전된 주제를 다루도록 하겠습니다.