EnsembleRetriever
는 retriever 리스트를 입력으로 받아 이들의 get_relevant_documents() 메서드 결과를 합치고, 상호 순위 융합(Reciprocal Rank Fusion) 알고리즘을 기반으로 결과를 재정렬한다.
다양한 알고리즘의 강점을 활용함으로써, EnsembleRetriever는 단일 알고리즘보다 더 나은 성능을 달성할 수 있다.
가장 일반적인 패턴은 희소형 검색기(BM25 같은)와 밀집형 검색기(임베딩 유사성 같은)를 결합하는 것이다. 이 두 가지의 강점이 상호 보완적이기 때문이다. 이는 "하이브리드 검색"으로도 알려져 있다. 희소형 검색기는 키워드를 기반으로 관련 문서를 찾는 데 뛰어난 반면, 밀집형 검색기는 의미적 유사성을 기반으로 관련 문서를 찾는 데 뛰어나다.
아래 예제에서는 BM25Retriever와 FAISS용 Retriever를 조합한 앙상블 Retriever를 사용한 예이다.
BM25는 주어진 쿼리에 대해 문서와의 연관성을 평가하는 랭킹 함수로 사용되는 알고리즘으로,TF-IDF 계열의 검색 알고리즘 중 SOTA 인 것으로 알려져 있다.
우선 rank_bm25를 설치한다.
pip install rank_bm25
소스코드
from dotenv import load_dotenv
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
load_dotenv()
question = "갤럭시 S21의 특징은?"
doc_list_1 = [
"Galaxy S9의 특징은 저렴하다는 것이다",
"Galaxy S9의 배터리는 3000 mAh이다",
"Galaxy S10의 카메라는 Triple rear cameras이다. ",
"Galaxy S20의 Display는 6.2-inch Dynamic AMOLED이다.",
"Galaxy S20의 저장공간은 128G이다",
"Galaxy S21의 Ram은 8GB이다",
]
embedding = OpenAIEmbeddings()
faiss_vectorstore = FAISS.from_texts(
doc_list_1, embedding, metadatas=[{"source": 2}] * len(doc_list_1)
)
faiss_retriever = faiss_vectorstore.as_retriever(search_kwargs={"k": 2})
faiss_results = faiss_retriever.invoke(question)
print(f"####################### vector 검색 결과 #################")
for doc in faiss_results:
print(doc.page_content)
bm25_retriever = BM25Retriever.from_texts(
doc_list_1, metadatas=[{"source": 1}] * len(doc_list_1)
)
bm25_retriever.k = 2
bm25_result = bm25_retriever.invoke(question)
print(f"####################### bm25 검색 결과 #################")
for doc in bm25_result:
print(doc.page_content)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
)
docs = ensemble_retriever.invoke(question)
print(f"####################### ensemble 검색 결과 #################")
for doc in docs:
print(doc.page_content)
실행결과
####################### vector 검색 결과 #################
Galaxy S20의 Display는 6.2-inch Dynamic AMOLED이다.
Galaxy S21의 Ram은 8GB이다
####################### bm25 검색 결과 #################
Galaxy S21의 Ram은 8GB이다
Galaxy S20의 저장공간은 128G이다
####################### ensemble 검색 결과 #################
Galaxy S21의 Ram은 8GB이다
Galaxy S20의 Display는 6.2-inch Dynamic AMOLED이다.
Galaxy S20의 저장공간은 128G이다
위의 코드는 3가지를 모두 실행해본 결과이다.
- Vector Retriever로 검색
- BM25로 검색
- Ensemble Retriever로 검색
우선 "갤럭시 S21의 특징"으로 검색을 했고 1번의 Vector 검색 결과를 보면 S20의 특징이 우선 조회되는 것을 알 수 있다. S20과 S21보다는 특징이라는 키워드로 모든 제품의 특징이 우선 조회되는 듯 하다. 그래서 S21로 검색이 우선 되게 2번에서와 같이 BM25를 사용하게 되면 S21이 우선 조회가 되는 것을 알 수 있다.
3번에서는 Vector와 BM25의 조회 결과를 조합하는 EnsembleRetriever를 사용하는 예제이다. EnsembleRetriever의 검색결과에서는 S21이 우선 검색되는 것을 확인할 수 있다.