본문 바로가기

SK네트웍스 Family AI캠프 10기/Daily 회고

62일차. Advanced RAG - Retriever & Reranker

더보기

 

62일 차 회고.

 

 이번 단위 프로젝트에서 일단 유튜브에서 자막 데이터를 가져와서 정제하게 되었다. 영상 개수도 많고, 유튜브는 중간에 인증? 에러도 뜨는 경우가 있어서 조금 문제가 생길 수도 있을 것 같지만 일단 해보기로 했다.

 

 

 

 

1. Advanced RAG

 

 

1-1. Retriever

 

Loader

from langchain_community.document_loaders import TextLoader

loader = TextLoader(DATA_PATH+".txt")
docs = loader.load()

 

Splitter

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=600,
    chunk_overlap=60
)
splitted_docs = splitter.split_documents(docs)

 

Embedding Model

from langchain_openai import OpenAIEmbeddings

embedding = OpenAIEmbeddings(
    model="text-embedding-3-small"
)

 

Vector DB

import faiss
from langchain_community.vectorstores import FAISS

db = FAISS.from_documents(
    documents=splitted_docs,
    embedding=embedding
)

 

Retriever

retriever = db.as_retriever()
  • ContextualCompressionRetriever
# LLM
from langchain_openai import OpenAI

llm = OpenAI()
# Compressor
from langchain.retrievers.document_compressors import LLMChainExtractor

compressor = LLMChainExtractor.from_llm(llm)
# Retriever
from langchain.retrievers import ContextualCompressionRetriever

compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=retriever
)
# LLMChainFilter
from langchain.retrievers.document_compressors import LLMChainFilter

filter = LLMChainFilter.from_llm(llm)
filter_retriever = ContextualCompressionRetriever(
    base_compressor=filter,
    base_retriever=retriever
)
# EmbeddingsFilter
from langchain.retrievers.document_compressors import EmbeddingsFilter
from langchain_openai import OpenAIEmbeddings

embeddings_filter = EmbeddingsFilter(
    embeddings=OpenAIEmbeddings(),
    similarity_threshold=0.75
)
embeddings_retriever = ContextualCompressionRetriever(
    base_compressor=embeddings_filter,
    base_retriever=retriever
)
# DocumentCompressorPipeline
from langchain_text_splitters import CharacterTextSplitter
from langchain_community.document_transformers import EmbeddingsRedundantFilter
from langchain.retrievers.document_compressors import EmbeddingsFilter
from langchain.retrievers.document_compressors import DocumentCompressorPipeline

text_splitter = CharacterTextSplitter(
    chunk_size=300,
    chunk_overlap=30,
    separator=". "
)
redundant_filter = EmbeddingsRedundantFilter(
    embeddings=OpenAIEmbeddings()
)
relevant_filter = EmbeddingsFilter(
    embeddings=OpenAIEmbeddings(),
    similarity_threshold=0.75
)

pipeline_compressor = DocumentCompressorPipeline(
    transformers=[
        text_splitter,
        redundant_filter,
        relevant_filter
    ]
)

pipeline_retriever = ContextualCompressionRetriever(
    base_compressor=pipeline_compressor,
    base_retriever=retriever
)
  • MultiQueryRetriever
# LLM
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0
)
# Retriever
from langchain.retrievers.multi_query import MultiQueryRetriever

multiquery_retriever = MultiQueryRetriever.from_llm(
    retriever=retriever,
    llm=llm
)
# LCEL
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

prompt = PromptTemplate.from_template(
    """You are an AI language model assistant.
    Your task is to generate five different versions of the given user question to retrieve relevant documents from a vector database.
    By generating multiple perspectives on the user question, your goal is to help the user overcome some of the limitations of the distance-based similarity search.
    Your response should be a list of values separated by new lines, eg: `foo\nbar\nbaz\n`

    #ORIGINAL QUESTION:
    {question}

    #Answer in Korean:"""
)

multiquery_chain = (
    {"question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

multiquery_retriever = MultiQueryRetriever.from_llm(
    llm=multiquery_chain,
    retriever=retriever
)
  • EnsembleRetriever
doc_list = [
    "I like apples",
    "I like apple company",
    "I like apple's iphone",
    "Apple is my favorite company",
    "I like apple's ipad",
    "I like apple's macbook",
]

query = "My favorite fruit is apple."
# BM25Retriever
from langchain.retrievers import BM25Retriever

bm_retriever = BM25Retriever.from_texts(
    doc_list
)
bm_retriever.k = 1
# FAISS
db = FAISS.from_texts(
    texts=doc_list,
    embedding=embedding
)

faiss_retriever = db.as_retriever(
    search_kwargs={"k": 1}
)
# MMR
mmr_retriever = db.as_retriever(
    search_type="mmr",
    search_kwargs={"k": 1}
)
# EnsembleRetriever
ensemble_retriever = EnsembleRetriever(
    retrievers=[
        bm_retriever,
        faiss_retriever,
        mmr_retriever
    ],
    weights=[0.2, 0.5, 0.3]
)
  • LongContextReorder
texts = [
    "이건 그냥 내가 아무렇게나 적어본 글입니다.",
    "사용자와 대화하는 것처럼 설계된 AI인 ChatGPT는 다양한 질문에 답할 수 있습니다.",
    "아이폰, 아이패드, 맥북 등은 애플이 출시한 대표적인 제품들입니다.",
    "챗GPT는 OpenAI에 의해 개발되었으며, 지속적으로 개선되고 있습니다.",
    "챗지피티는 사용자의 질문을 이해하고 적절한 답변을 생성하기 위해 대량의 데이터를 학습했습니다.",
    "애플 워치와 에어팟 같은 웨어러블 기기도 애플의 인기 제품군에 속합니다.",
    "ChatGPT는 복잡한 문제를 해결하거나 창의적인 아이디어를 제안하는 데에도 사용될 수 있습니다.",
    "비트코인은 디지털 금이라고도 불리며, 가치 저장 수단으로서 인기를 얻고 있습니다.",
    "ChatGPT의 기능은 지속적인 학습과 업데이트를 통해 더욱 발전하고 있습니다.",
    "FIFA 월드컵은 네 번째 해마다 열리며, 국제 축구에서 가장 큰 행사입니다.",
]
# Retriever
retriever = FAISS.from_texts(
    texts=texts,
    embedding=embedding
).as_retriever(
    search_kwargs={"k": 5}
)
# LongContextReorder
from langchain_core.prompts import PromptTemplate
from langchain_community.document_transformers import LongContextReorder

reorder = LongContextReorder()
reorder_results = reorder.transform_documents(results)

 

 

1-2. Reranker

 

Reranker

  • RAG의 문제점
    • 문서 임베딩 과정에서의 정보 손실
      • 문서를 고정된 차원의 벡터로 변환하는 과정에서, 특히 긴 문서의 경우 핵심 정보가 누락될 수 있다.
    • 검색 과정의 정확도 문제
      • ANNs 기반 검색 속도는 빠르지만, 정밀한 관련성 판단에는 한계가 있다.
      • 초기 검색 결과에 중요한 문서가 누락될 수 있다.
  • Reranker
    • 장점
      • 검색 정확도 향상
      • 복잡한 의미적 관계 반영
      • 1차 검색의 한계 보완
    • 단점
      • 계산 비용 증가
      • 처리 시간 증가
      • 대규모 데이터셋 적용의 어려움

 

예시 코드

  • Vector DB
# Loader
from langchain_community.document_loaders import TextLoader

loader = TextLoader(DATA_PATH+".txt")
docs = loader.load()
# Splitter
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50
)
splitted_docs = splitter.split_documents(docs)
# Embedding Model
from langchain_huggingface import HuggingFaceEmbeddings

embedding = HuggingFaceEmbeddings(
    model_name="sentence-transformers/msmarco-distilbert-dot-v5"
)
# Vector DB
from langchain_community.vectorstores import FAISS

vector_db = FAISS.from_documents(
    documents=splitted_docs,
    embedding=embedding
)
  • CrossEncoder
retriever = vector_db.as_retriever(
    search_kwargs={"k": 10}
)
results = retriever.invoke(query)
# Reranker
from sentence_transformers import CrossEncoder

cross_encoder = CrossEncoder(
    model_name="Dongjin-kr/ko-reranker",
    max_length=512,
    device="cpu"
)
rerank_results = cross_encoder.rank(
    query=query,
    documents=[result.page_content for result in results],
    top_k=3,
    return_documents=True
)
  • CrossEncoderReranker
# CrossEncoder
from langchain_community.cross_encoders import HuggingFaceCrossEncoder

model = HuggingFaceCrossEncoder(
    model_name="BAAI/bge-reranker-v2-m3"
)
# CrossEncoderReranker
from langchain.retrievers.document_compressors import CrossEncoderReranker

compressor = CrossEncoderReranker(
    model=model,
    top_n=3
)
# LLM
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini"
)
# MultiQueryRetriever
from langchain.retrievers.multi_query import MultiQueryRetriever

multi_query_retriever = MultiQueryRetriever.from_llm(
    retriever=retriever,
    llm=llm
)
# ContextualCompressionRetriever
from langchain.retrievers import ContextualCompressionRetriever

reranker_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=multi_query_retriever
)