rag에 대해 공부를 하고 있다. 그중 가장 중요하다고 생각이 들었던, 개념과 특징을 명확히 짚고 넘어가야 할듯한 RRF & rerank & pro-retrieval/post-retrieval에 대해 최종적으로 정리해보자.
rag 과정 순서도
사용자 질문 → 임베딩 → 벡터 검색 (✅ hybrid search) → ✅ 리랭킹 → 상위 N개 문맥 선택 → LLM 답변 생성
cross encoder 예시 (rerank)
Input: "Query: 9월 전력 사용량은? Context: 9월 최대 전력은 93.2GW였습니다."
Output: 관련성 점수 (e.g. 0.87)
# ❗ dense retriever와 달리, **문서와 질문을 함께 한 input으로 LLM에 넣어 점수를 예측**
✅ 왜 벡터 검색 후에 쓰는가?
🔎 키워드 기반 검색 Lexical Search: BM25 같은 sparse 벡터 알고리즘 통해 키워드 기반 매칭
🔎 유사도 기반 검색 Semantic Search: 의미론적으로 유사한 검색 결과 반환
→ Hybrid Search는 각 검색 방법의 장점만을 추려 사용
👓 어떻게 두 검색 결과를 결합하나?


👓 어떻게 구현하나?
EnsembleRetriever → 각기 다른 쿼리 응답의 조합 위해 RRF 채택from langchain.retrievers import EnsembleRetriever
from langchain_community.vectorstores import OpenSearchVectorSearch
...
# Ensemble Retriever(앙상블 검색)
ensemble_retriever = EnsembleRetriever(
retrievers=[opensearch_lexical_retriever, opensearch_semantic_retriever],
weights=[0.50, 0.50]
)
search_hybrid_result = ensemble_retriever.get_relevant_documents(query)
# 실제 LLM을 호출할 때 context로 EnsembleRetriever의 결과인 search_hybrid_result를 전달하면 Hybrid Search를 수행할 수 있다.
HybridRetriever ← BM25Retriever + EmbeddingRetriever텍스트의 빈도와 관련성을 기준으로 순위를 매기는 BM25 (전통적 키워드 검색에 적합)
문서와 검색어를 임베딩 벡터로 변환하여 유사도 기반 문서 간의 의미적 연관성을 찾아줌 (벡터 기반 검색 적합 - 시멘틱 검색 처리)
→ 키워드 검색과 시멘틱 검색을 동시에 수행한 후, 두 결과를 결합하여 사용자에게 반환 (키워드와 의미적 유사성 동시에 고려) + 검색 결과의 가중치 조정, 특정 방식에 더 비중 ↑ 둘 수 있다
🔎 질의 Query: 사용자가 “문장”을 작성해 검색을 한다
🔎 RAG: Hallucination을 최소화하기 위해 최신 정보를 검색하고 이를 생성 단계에서 사용
⇒ 이렇게 정보의 순서를 조정하는 단계를 rerank
기존 벡터 검색을 위해 사용하는 구조가 Bi-encoder ↔ rerank를 위한 구조는 Cross-encoder

한국어 reranker: https://huggingface.co/Dongjin-kr/ko-reranker
model_path = "Dongjin-kr/ko-reranker"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForSequenceClassification.from_pretrained(model_path)
model.eval()
with torch.no_grad():
inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors='pt', max_length=512)
scores = model(**inputs, return_dict=True).logits.view(-1, ).float()
scores = exp_normalize(scores.numpy())
print(np.round(scores * 100, 2))
다국어 reranker: https://huggingface.co/BAAI/bge-reranker-v2-m3
tokenizer = AutoTokenizer.from_pretrained('BAAI/bge-reranker-v2-m3')
model = AutoModelForSequenceClassification.from_pretrained('BAAI/bge-reranker-v2-m3')
model.eval()
with torch.no_grad():
inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors='pt', max_length=512)
scores = model(**inputs, return_dict=True).logits.view(-1, ).float()
scores = exp_normalize(scores.numpy())
print(np.round(scores * 100, 2))
Improve Retrieval Augmented Generation (RAG) with Re-ranking
The concern here is that by only considering the top_k responses, we might miss out on valuable context that could improve the accuracy of the LLM’s responses.
This limitation highlights the need for a more robust approach to selecting and providing context to the LLM, ensuring that it has access to the most relevant information to generate accurate responses.
However, during the conversion of documents into vectors, there’s potential for information loss as vectors represent content in a compressed numerical format.
Additionally, larger documents often need to be divided into smaller chunks for embedding into vector format, making it challenging to maintain the context across all the smaller parts.
🔎 The reason why we can’t simply send all search results from vector search to the LLM is twofold:
🔎 As part of refining RAG implementation, one crucial step is re-ranking.
A re-ranking model is a type of model that calculates a matching score for a given query and document pair.
👉 In summary, the initial step involves retrieving relevant documents from a large dataset using vector search due to its speed.
Once these related documents are obtained, re-ranking is applied to prioritize the most relevant ones at the top.
These top-ranked documents, which align closely with the user’s query, are then passed to the LLM to enhance the accuracy and precision of results.
[우아한 스터디] RAG 성능을 끌어올리는 Pre-Retrieval (Ensenble Retriever) 와 Post-Retrieval (Re-Rank)
🔎 Pre-retrieval (Ensemble Retriever)
: 여러 retriever를 입력으로 받아 → get_relevant_documents() 메서드 결과를 앙상블 → RRF 기반 결과 재순위화
# BM25 리트리버 생성 (Sparse Retriever)
bm25_retriever = BM25Retriever.from_documents(docs)
# FAISS 리트리버 생성 (Dense Retriever)
faiss_retriever = vectorstore_faiss.as_retriever(search_kwargs={'k': 5})
# 앙상블 리트리버 생성
self.retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.5, 0.5] # 가중치 설정 (가중치의 합은 1.0)
🔎 Post-Retrieval
[RAG 시리즈] Hybrid Search 와 재순위화 알고리즘 (RRF 를 곁들인..)
🔎 Hybrid Search는 왜 등장하였는가?
→ 이러한 문제를 해결하기 위해, LLM에 질문과 유사도가 높은 context를 답변 생성 전에 전달하여 → 보다 높은 정확도의 답변을 반환하도록 하는 RAG 기술 대두
⇒ 이를 해결하기 위해 유사도에 더해, 키워드 기반 검색을 함께 활용하는 Hybrid Search 기술 생김.
🔎 Hybrid Search란?
= 키워드 기반 검색 Lexical Search + 유사도 기반 검색 Semantic Search
🔎 EnsembleRetriever란?
= 여러 retriever를 입력으로 받아 검색 결과 앙상블 & RRF 기반 결과 재순위화
🔎 Ensemble Retriever를 활용하지 못하는 경우
→ Lexical search 결과와 Semantic search 결과 결합 위해 재순위화 알고리즘 사용
https://github.com/Judy-Choi/rag_series/blob/main/note_4/main.ipynb
기본적으로 Hybrid Retrieval에는 RRF와 CC 방법이 있다.

한국어 Reranker를 활용한 검색 증강 생성(RAG) 성능 올리기 | Amazon Web Services
🔎 Reranking은 RAG가 생성한 후보 문서들에 대해 질문에 대한 관련성 및 일관성을 판단하여 문서의 우선순위를 재정렬하는 것
→ 질문과 관련성 있는 문서들을 컨텍스트의 상위권에 위치시킴 ⇒ 답변의 정확도 ↑
