자연어처리/Langchain

[Langchain] Retriever 사용하기

Suda_777 2024. 9. 21. 16:15
반응형

1.  Retriever 는 무엇인가

Retriever는 주어진 질문에 대해 관련된 정보를 찾아오는 구성 요소입니다. 특히, 여러 개의 문서나 데이터베이스에서 필요한 정보를 검색하는 역할을 합니다. 검색은 챗봇이 챗 모델의 훈련 데이터 외부의 데이터로 응답을 증강하는 데 사용하는 일반적인 기술입니다. Retriever는 대용량의 비정형 데이터를 효율적으로 처리하여 사용자에게 필요한 정보를 빠르게 제공하는 핵심 요소입니다.


2. Retriever의 종류

  • Vectorstore Retriever
    • 이 방식은 가장 기본적이고 쉽게 시작할 수 있는 방법입니다.
    • 각 텍스트 조각마다 임베딩을 생성하여 검색을 수행하며, 빠르고 간단한 검색 시스템을 구축하고자 할 때 적합합니다.
    • 주로 유사도 검색을 위해 벡터 공간에 문서를 매핑하여 활용합니다.
  • ParentDocument Retriever
    • 여러 개의 청크로 문서를 나누고, 임베딩 공간에서 가장 유사한 청크를 찾은 후 해당 청크가 속한 전체 문서를 반환하는 방식입니다.
    • 문서에 많은 작은 정보들이 포함되어 있고, 전체 문서를 검색할 때 유용합니다.
  • Multi Vector Retriever
    • 문서마다 여러 개의 벡터를 생성하는 방식으로, 문서의 텍스트 자체보다는 더 중요한 정보를 추출하여 인덱싱할 수 있을 때 사용합니다.
    • 예를 들어, 텍스트 요약이나 가상 질문을 바탕으로 벡터를 생성할 수 있습니다.
  • Self Query Retriever
    • 이 방식은 LLM을 사용해 사용자의 질문을 처리합니다.
    • 주로 질문이 문서의 메타데이터와 관련된 경우, LLM이 질문을 검색할 문자열메타데이터 필터로 변환하여, 메타데이터 기반 검색을 수행합니다.
  • Contextual Compression Retriever
    • 검색된 문서에 불필요한 정보가 너무 많을 때 유용한 방식입니다.
    • 검색 후, 후처리 과정을 통해 LLM 또는 임베딩을 사용해 가장 중요한 정보만 추출하여 반환합니다.
  • Time-Weighted Vectorstore Retriever
    • 문서에 타임스탬프가 있을 경우, 이 방식은 유사성과 최신성 기준을 결합하여 검색합니다.
    • 최신 문서 검색이 중요한 경우에 유용합니다.
  • Multi-Query Retriever
    • 복잡한 질문이 여러 가지 서로 다른 정보 조각을 필요로 할 때 사용됩니다.
    • LLM을 사용해 원래 질문에서 여러 개의 쿼리를 생성하고, 각 쿼리에 대해 문서를 검색한 후 이를 조합하여 답변합니다.
  • Ensemble Retriever
    • 여러 가지 검색 방식을 결합하고자 할 때 사용되는 방법입니다.
    • 다양한 retriever를 사용해 각기 다른 방식으로 문서를 검색하고, 이를 합쳐서 최종적으로 문서를 반환합니다.
  • Long-Context Reorder Retriever
    • 긴 문맥을 처리하는 모델에서 중간 정보를 무시하는 경향이 있을 때 사용됩니다. 검색된 문서를 재배열하여 가장 유사한 정보를 처음과 끝에 배치하여, 긴 문맥에서 유용한 정보를 놓치지 않도록 합니다.

3. Retriever 예시 코드

3.1. Vectorstore Retriever 

작업 순서

1. TextLoader: 문서를 로드합니다.
2. CharacterTextSplitter: 문서를 청크로 분할합니다.
3. OpenAIEmbeddings: 텍스트 임베딩을 생성합니다.
4. FAISS: 벡터스토어를 구축합니다.
5. RetrievalQA: Retriever와 LLM을 결합하여 QA 시스템을 만듭니다.

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.text_splitter import CharacterTextSplitter
from langchain.document_loaders import TextLoader
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI

# 문서 로드
loader = TextLoader('your_document.txt')
documents = loader.load()

# 텍스트 분할
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

# 임베딩 및 벡터스토어 생성
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embeddings)

# Retriever 설정
retriever = vectorstore.as_retriever()

# QA 체인 생성
qa = RetrievalQA.from_chain_type(
    llm=OpenAI(),
    chain_type="stuff",
    retriever=retriever
)

# 질문에 답변
query = "여기에 질문을 입력하세요."
answer = qa.run(query)
print(answer)

 

3.2. Self Query Retriever

작업 순서

1. SelfQueryRetriever: LLM을 사용하여 쿼리를 변환하고, 메타데이터 필터링을 수행합니다.

2. metadata: 문서에 메타데이터를 추가하여 필터링에 사용합니다.

 

from langchain.retrievers import SelfQueryRetriever
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.schema import Document

# 문서 생성
documents = [
    Document(page_content="이 문서는 과학에 관한 내용입니다.", metadata={"주제": "과학"}),
    Document(page_content="이 문서는 예술에 관한 내용입니다.", metadata={"주제": "예술"}),
]

# 벡터스토어 생성
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)

# Self Query Retriever 설정
llm = OpenAI()
retriever = SelfQueryRetriever.from_llm(
    llm=llm,
    vectorstore=vectorstore,
    verbose=True
)

# 질문에 대한 검색
query = "예술에 대한 최신 연구 자료가 있나요?"
docs = retriever.get_relevant_documents(query)
for doc in docs:
    print(doc.page_content)

 

3.3. Contextual Compression Retriever

작업 순서

1. LLMChainExtractor: LLM을 사용하여 문서의 중요한 부분만 추출합니다.

2. ContextualCompressionRetriever: 압축기를 사용하여 검색 결과를 축소합니다.

 

from langchain.retrievers import TimeWeightedVectorStoreRetriever
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
import datetime

# 문서에 타임스탬프 추가
documents = [
    Document(page_content="2021년의 정보입니다.", metadata={"timestamp": datetime.datetime(2021, 1, 1)}),
    Document(page_content="현재의 정보입니다.", metadata={"timestamp": datetime.datetime.now()}),
]

# 벡터스토어 생성
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)

# Time-Weighted Retriever 설정
retriever = TimeWeightedVectorStoreRetriever(
    vectorstore=vectorstore,
    decay_rate=0.1,
    time_key='timestamp'
)

# 질문에 대한 검색
query = "최신 정보를 알려주세요."
docs = retriever.get_relevant_documents(query)
for doc in docs:
    print(doc.page_content)

 

3.4. Time-Weighted Vectorstore Retriever

실행 순서

1. TimeWeightedVectorStoreRetriever: 시간에 따른 가중치를 적용하여 최신 문서를 우선적으로 검색합니다.

2. decay_rate: 시간에 따른 중요도 감소율을 설정합니다.

from langchain.retrievers import TimeWeightedVectorStoreRetriever
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
import datetime

# 문서에 타임스탬프 추가
documents = [
    Document(page_content="2021년의 정보입니다.", metadata={"timestamp": datetime.datetime(2021, 1, 1)}),
    Document(page_content="현재의 정보입니다.", metadata={"timestamp": datetime.datetime.now()}),
]

# 벡터스토어 생성
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)

# Time-Weighted Retriever 설정
retriever = TimeWeightedVectorStoreRetriever(
    vectorstore=vectorstore,
    decay_rate=0.1,
    time_key='timestamp'
)

# 질문에 대한 검색
query = "최신 정보를 알려주세요."
docs = retriever.get_relevant_documents(query)
for doc in docs:
    print(doc.page_content)

 

3.5 Ensemble Retriever

실행 순서

1. EnsembleRetriever: 여러 Retriever의 결과를 결합하여 더 풍부한 검색 결과를 제공합니다.

2. retrievers: 결합하고자 하는 Retriever들의 리스트를 설정합니다.

from langchain.retrievers import EnsembleRetriever

# 여러 Retriever 설정
retriever1 = vectorstore1.as_retriever()
retriever2 = vectorstore2.as_retriever()

# Ensemble Retriever 설정
ensemble_retriever = EnsembleRetriever(retrievers=[retriever1, retriever2])

# 질문에 대한 검색
query = "통합된 검색 결과를 보여주세요."
docs = ensemble_retriever.get_relevant_documents(query)
for doc in docs:
    print(doc.page_content)

 

 

다음 시간에는 벡터 데이터베이스를 사용하는 것에 대해 알아보겠습니다.

반응형