프로덕션 RAG 시스템에 Hybrid Search 도입한 후기

문제 상황

사내 문서 검색 RAG 시스템을 운영 중인데, 벡터 검색만으로는 정확한 키워드 매칭이 필요한 쿼리에서 성능이 떨어졌다. 특히 제품명, 코드명 같은 고유명사나 정확한 용어 검색에서 관련 없는 문서가 상위에 노출되는 문제가 반복되었다.

Hybrid Search 구조

벡터 검색과 키워드 검색을 병행하기로 결정했다. Pinecone에 벡터를 저장하고, Elasticsearch에 동일 문서를 인덱싱했다.

def hybrid_search(query: str, top_k: int = 10):
    # 벡터 검색
    embedding = get_embedding(query)
    vector_results = pinecone_index.query(
        vector=embedding,
        top_k=top_k * 2
    )
    
    # BM25 키워드 검색
    bm25_results = es_client.search(
        index="documents",
        body={
            "query": {"match": {"content": query}},
            "size": top_k * 2
        }
    )
    
    # RRF로 병합
    return reciprocal_rank_fusion(
        [vector_results, bm25_results],
        k=60
    )

Reciprocal Rank Fusion

두 검색 결과를 병합하는 방식으로 RRF를 사용했다. 각 문서의 랭킹을 기반으로 점수를 계산하는 방식이라 가중치 튜닝이 필요 없어서 간단했다.

def reciprocal_rank_fusion(results_list, k=60):
    scores = {}
    for results in results_list:
        for rank, doc in enumerate(results, 1):
            doc_id = doc['id']
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

결과

프로덕션 적용 후 2주간 모니터링한 결과:

  • 정확한 키워드 검색 정확도 대폭 개선
  • 의미 기반 검색도 기존 수준 유지
  • 레이턴시는 평균 150ms에서 280ms로 증가했지만 허용 범위
  • ES 클러스터 비용이 추가되었지만 사용자 만족도 상승으로 정당화됨

벡터 검색과 키워드 검색은 상호보완적이다. RAG 시스템에서 정확도가 중요하다면 Hybrid Search 도입을 고려할 만하다.