인공지능 개발자 수다(유튜브 바로가기) 자세히보기

자연어처리/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)

     

     

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

    반응형