Reciprocal Rerank Fusion Retriever

Reciprocal Rerank Fusion Retriever

여러 쿼리와 여러 인덱스에서 가져온 검색 결과를 어떻게 결합하는지 살펴보는 예시예요. Reciprocal Rerank Fusion 알고리즘으로 노드를 재정렬하는 방법을 함께 배워볼게요.

출처: 문서

본문

이 예시에서는 여러 쿼리와 여러 인덱스에서 가져온 검색 결과를 결합하는 방법을 살펴봅니다.

검색된 노드는 이 논문에서 소개된 Reciprocal Rerank Fusion 알고리즘에 따라 재정렬됩니다. 이 알고리즘은 과도한 계산이나 외부 모델에 의존하지 않고도 검색 결과를 효율적으로 재정렬하는 방법을 제공합니다.

이 예시 구현은 github의 @Raduaschl이 만든 예시 구현에 크게 기여받았습니다.

%pip install llama-index-llms-openai
%pip install llama-index-retrievers-bm25
import os
import openai


os.environ["OPENAI_API_KEY"] = "sk-..."
openai.api_key = os.environ["OPENAI_API_KEY"]

Setup

이 노트북을 colab에서 여는 경우 LlamaIndex 🦙를 설치해야 할 수 있습니다.

데이터 다운로드

!mkdir -p 'data/paul_graham/'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'
from llama_index.core import SimpleDirectoryReader


documents = SimpleDirectoryReader("./data/paul_graham/").load_data()

다음으로 문서 위에 벡터 인덱스를 구성합니다.

from llama_index.core import VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter


splitter = SentenceSplitter(chunk_size=256)


index = VectorStoreIndex.from_documents(documents, transformations=[splitter])

Hybrid Fusion Retriever 생성

이 단계에서는 인덱스를 BM25 기반 리트리버와 융합합니다. 이렇게 하면 입력 쿼리에서 의미적 관계와 키워드를 모두 포착할 수 있습니다.

두 리트리버 모두 점수를 계산하므로, 추가 모델이나 과도한 계산 없이 reciprocal rerank 알고리즘을 사용해 노드를 재정렬할 수 있습니다.

이 설정은 또한 쿼리를 4번 수행하는데, 원래 쿼리로 한 번, 그리고 추가로 3개의 쿼리를 생성합니다.

기본적으로 추가 쿼리를 생성하는 데 다음 프롬프트를 사용합니다:

QUERY_GEN_PROMPT = (
    "You are a helpful assistant that generates multiple search queries based on a "
    "single input query. Generate {num_queries} search queries, one on each line, "
    "related to the following input query:\n"
    "Query: {query}\n"
    "Queries:\n"
)

먼저 리트리버를 생성합니다. 각 리트리버는 가장 유사한 상위 2개 노드를 가져옵니다:

from llama_index.retrievers.bm25 import BM25Retriever


vector_retriever = index.as_retriever(similarity_top_k=2)


bm25_retriever = BM25Retriever.from_defaults(
    docstore=index.docstore, similarity_top_k=2
)

다음으로 퓨전 리트리버를 만들 수 있는데, 이 리트리버는 리트리버들이 반환한 4개 노드 중 상위 2개를 반환합니다:

from llama_index.core.retrievers import QueryFusionRetriever


retriever = QueryFusionRetriever(
    [vector_retriever, bm25_retriever],
    similarity_top_k=2,
    num_queries=4,  # set this to 1 to disable query generation
    mode="reciprocal_rerank",
    use_async=True,
    verbose=True,
    # query_gen_prompt="...",  # we could override the query generation prompt here
)
# apply nested async to run in a notebook
import nest_asyncio


nest_asyncio.apply()
nodes_with_scores = retriever.retrieve(
    "What happened at Interleafe and Viaweb?"
)
for node in nodes_with_scores:
    print(f"Score: {node.score:.2f} - {node.text}...\n-----\n")

보시다시피 두 반환 노드 모두 Viaweb과 Interleaf를 정확히 언급합니다!

Query Engine에서 사용하기!

이제 리트리버를 쿼리 엔진에 연결해 자연어 응답을 합성할 수 있습니다.

from llama_index.core.query_engine import RetrieverQueryEngine


query_engine = RetrieverQueryEngine.from_args(retriever)
response = query_engine.query("What happened at Interleafe and Viaweb?")
from llama_index.core.response.notebook_utils import display_response


display_response(response)

더 알아보기 (Learn more)