하이브리드 검색은 키워드 검색과 의미론적 검색을 EnsembleRetriever로 통합
정확한 키워드 매칭과 의미적 유사성을 동시에 고려하여 검색 수행
두 검색 방식의 장점을 결합하여 더 포괄적이고 정확한 결과 도출
검색 성능 향상을 위해 각 방식의 가중치 조정이 가능
키워드와 의미 기반 검색의 시너지 효과로 더 향상된 검색 성능 실현 가능
from langchain.retrievers import EnsembleRetriever
# 앙상블 검색기 생성
ensemble_retrievers = [chroma_k_retriever, bm25_retriever]
ensemble_retriever = EnsembleRetriever(
retrievers=ensemble_retrievers,
weights=[0.5, 0.5] # 각 검색기의 가중치
)
# 검색기를 사용하여 검색
query = "리비안이 설립된 연도는?"
retrieved_docs = ensemble_retriever.invoke(query)
for doc in retrieved_docs:
print(f"{doc.page_content} [출처: {doc.metadata['source']}]")
print("="*200)
- 출력
[출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.는 2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.
**주요 정보:** [출처: data\리비안_KR.md]
========================================================================================================================================================================================================
[출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
- **회사 유형:** 상장
- **거래소:** NASDAQ: RIVN
- **설립:** 2009년 6월, 플로리다 주 록ledge
- **설립자:** R. J. 스캐린지
- **본사:** 미국 캘리포니아 주 어바인
- **서비스 지역:** 북미
- **주요 인물:** R. J. 스캐린지 (CEO)
- **제품:** 전기 자동차, 배터리
- **생산량 (2023):** 57,232대
- **서비스:** 전기 자동차 충전, 자동차 보험
- **수익 (2023):** 44억 3천만 미국 달러
- **순이익 (2023):** -54억 미국 달러
- **총 자산 (2023):** 168억 미국 달러 [출처: data\리비안_KR.md]
========================================================================================================================================================================================================
[출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**EV 충전**
...
합성된 데이터는 품질 검증과 수동 수정 과정을 거쳐 정제
테스트용 데이터는 다양한 유형의 질문과 답변 패턴을 포함해야 함
신뢰할 수 있는 검색 성능 평가를 위해 고품질 테스트 데이터 확보가 중요
# 기존에 생성해 둔 테스트셋 로드
# 테스트셋 로드
import pandas as pd
df_qa_test = pd.read_excel("data/testset.xlsx")
print(f"테스트셋: {df_qa_test.shape[0]}개 문서")
df_qa_test.head(2)
K-RAG 패키지 사용
K-RAG 포스트 참조
Hit Rate, MRR, mAP@k, NDCG@k 계산
# 테스트 데이터셋의 특정 행에 있는 컨텍스트 데이터를 Document 객체 리스트로 변환
from langchain_core.documents import Document
context_docs = []
for i, row in df_qa_test.iterrows():
row_docs = []
for doc in eval(row['reference_contexts']):
row_docs.append(Document(page_content=doc))
context_docs.append(row_docs)
print(f"컨텍스트 문서: {len(context_docs)}개 문서")
print("="*200)
print(context_docs[0])
- 출력
컨텍스트 문서: 49개 문서
========================================================================================================================================================================================================
[Document(metadata={}, page_content='Tesla, Inc.는 미국의 다국적 자동차 및 청정 에너지 회사입니다. 이 회사는 전기 자동차(BEV), 고정형 배터리 에너지 저장 장치, 태양 전지판, 태양광 지붕널 및 관련 제품/서비스를 설계, 제조 및 판매합니다. 2003년 7월 Martin Eberhard와 Marc Tarpenning이 Tesla Motors로 설립했으며, Nikola Tesla를 기리기 위해 명명되었습니다. Elon Musk는 2004년 Tesla의 초기 자금 조달을 주도하여 2008년에 회장 겸 CEO가 되었습니다.')]
from krag.tokenizers import KiwiTokenizer
from krag.retrievers import KiWiBM25RetrieverWithScore
# BM25 검색기 초기화 (k=3)
retriever_bm25_kiwi = KiWiBM25RetrieverWithScore(
documents=korean_docs,
kiwi_tokenizer=KiwiTokenizer(model_type='knlm', typos='basic'),
k=3,
)
# BM25 검색기를 사용하여 문서 검색
question = df_qa_test['user_input'].iloc[0]
print("질문:", question)
print("="*200)
context = df_qa_test['reference_contexts'].iloc[0]
print("관련 문서:", context)
print("="*200)
# BM25 검색
retrieved_docs = retriever_bm25_kiwi.invoke(question)
# 검색 결과 출력
for doc in retrieved_docs:
print(f"BM25 점수: {doc.metadata["bm25_score"]:.2f}")
print(f"\n{doc.page_content}\n[출처: {doc.metadata['company']}]")
print("-"*200)
- 출력
질문: Tesla, Inc.는 미국에서 어떤 역할을 하고 있으며, 이 회사의 주요 제품과 서비스는 무엇인가요?
========================================================================================================================================================================================================
관련 문서: ['Tesla, Inc.는 미국의 다국적 자동차 및 청정 에너지 회사입니다. 이 회사는 전기 자동차(BEV), 고정형 배터리 에너지 저장 장치, 태양 전지판, 태양광 지붕널 및 관련 제품/서비스를 설계, 제조 및 판매합니다. 2003년 7월 Martin Eberhard와 Marc Tarpenning이 Tesla Motors로 설립했으며, Nikola Tesla를 기리기 위해 명명되었습니다. Elon Musk는 2004년 Tesla의 초기 자금 조달을 주도하여 2008년에 회장 겸 CEO가 되었습니다.']
========================================================================================================================================================================================================
BM25 점수: 18.42
[출처] 이 문서는 테슬라에 대한 문서입니다.
----------------------------------
Tesla, Inc.는 미국의 다국적 자동차 및 청정 에너지 회사입니다. 이 회사는 전기 자동차(BEV), 고정형 배터리 에너지 저장 장치, 태양 전지판, 태양광 지붕널 및 관련 제품/서비스를 설계, 제조 및 판매합니다. 2003년 7월 Martin Eberhard와 Marc Tarpenning이 Tesla Motors로 설립했으며, Nikola Tesla를 기리기 위해 명명되었습니다. Elon Musk는 2004년 Tesla의 초기 자금 조달을 주도하여 2008년에 회장 겸 CEO가 되었습니다.
[출처: 테슬라]
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
BM25 점수: 17.78
...
# 전체 테스트 데이터셋에 대하여 평가지표 계산
from langchain_core.retrievers import BaseRetriever
from krag.evaluators import RougeOfflineRetrievalEvaluators
def evaluate_qa_test(df_qa_test: pd.DataFrame, retriever: BaseRetriever, k=2) -> dict:
"""
테스트 데이터셋에 대한 검색 결과 평가
"""
context_docs = []
retrieved_docs = []
df_test = df_qa_test.copy()
for idx, _ in df_test.iterrows():
question = df_test['user_input'].iloc[idx]
context_doc = [Document(page_content=doc) for doc in eval(df_test['reference_contexts'].iloc[idx])]
context_docs.append(context_doc)
retrieved_doc = retriever.invoke(question)
retrieved_docs.append(retrieved_doc)
# 평가자 인스턴스 생성
evaluator = RougeOfflineRetrievalEvaluators(
actual_docs=context_docs,
predicted_docs=retrieved_docs,
match_method='rouge1',
threshold=0.8,
)
# 평가지표 계산
hit_rate = evaluator.calculate_hit_rate(k=k)['hit_rate']
mrr = evaluator.calculate_mrr(k=k)['mrr']
map_score = evaluator.calculate_map(k=k)['map']
ndcg = evaluator.calculate_ndcg(k=k)['ndcg']
print(f"K={k}")
print("-"*200)
print(f"Hit Rate: {hit_rate:.3f}")
print(f"MRR: {mrr:.3f}")
print(f"MAP: {map_score:.3f}")
print(f"NDCG: {ndcg:.3f}")
print("="*200)
print()
result = {
'hit_rate': hit_rate,
'mrr': mrr,
'map': map_score,
'ndcg': ndcg,
}
return pd.Series(result)
# 평가 (k=1)
retriever_bm25_kiwi.k = 1
result_bm25_k1 = evaluate_qa_test(df_qa_test, retriever_bm25_kiwi, k=1)
- 출력
K=1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Hit Rate: 0.286
MRR: 0.735
MAP: 0.510
NDCG: 1.000
========================================================================================================================================================================================================
# Chroma 검색기 초기화
retriever_chroma_db = chroma_db.as_retriever(
search_kwargs={"k": 5},
)
# 평가 (k=1)
result_chroma_db_k1 = evaluate_qa_test(df_qa_test, retriever_chroma_db, k=1)
- 출력
K=1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Hit Rate: 0.286
MRR: 0.673
MAP: 0.480
NDCG: 1.000
========================================================================================================================================================================================================