본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 24. 16:44

하이브리드 검색(Hybrid Search)이 우리가 계속해서 추천하는 지루한 기본값인 이유

요약

벡터 전용 RAG 시스템이 최신 제품명이나 특정 기술 용어를 검색하지 못하는 한계를 설명합니다. 이를 해결하기 위해 의미론적 검색(Dense Vector)과 키워드 기반 검색(BM25)을 결합한 하이브리드 검색 및 RRF 알고리즘의 필요성을 강조합니다.

핵심 포인트

  • 벡터 검색은 의미론적 유사성에는 강하나 정확한 토큰 매칭에는 취약함
  • 최신 제품명, 약어, 코드 식별자 검색 시 벡터 검색 오류 발생 가능
  • 하이브리드 검색은 벡터 검색과 BM25를 결합하여 성능을 보완함
  • RRF(Reciprocal Rank Fusion)는 파라미터 조정 없이 효율적인 결과 병합 가능

우리가 함께 일하는 한 창업자가 2주 동안 혼란스러운 오류를 디버깅하고 있었습니다. 내부 AI 어시스턴트가 벡터 데이터베이스(Vector Database) 내의 세 가지 서로 다른 청크(Chunk)에 정확한 문구가 포함되어 있음에도 불구하고 "GPT-4o pricing"에 관한 콘텐츠를 찾지 못했습니다. "OpenAI model costs"라고 물으면 올바른 결과가 반환되었습니다. 하지만 "GPT-4o pricing"이라고 물으면 18개월 전의 GPT-3에 대한 토론이 반환되었습니다. 이것이 모든 벡터 전용 RAG(Retrieval-Augmented Generation) 시스템이 겪는 실패 모드입니다. 팀은 임베딩 모델(Embedding Model)을 교체하려던 참이었습니다. 하지만 실제 해결책은 단 세 줄의 설정이었습니다.

벡터 검색(Vector Search)이 실제로 잘하는 것은 무엇일까요?
밀집 벡터 검색(Dense Vector Search)은 의미론적 유사성(Semantic Similarity)에 탁월합니다. "How do I cancel my subscription"은 임베딩 모델이 두 문구가 의미론적으로 가깝다는 것을 학습했기 때문에 "Account termination procedure"라는 제목의 문서와 매칭됩니다. 유의어, 의역, 교차 언어 매칭 등 이 모든 것이 모델이 해당 문구들이 같은 의미라는 것을 알 수 있을 만큼 충분한 텍스트를 학습했기 때문에 작동합니다.

밀집 벡터(Dense Vectors)가 잘하지 못하는 것은 임베딩 모델이 자주 보지 못했거나 다른 문맥에서 본 용어에 대한 정확한 토큰 매칭(Exact-token Matching)입니다. "GPT-4o"는 최근 제품명으로, 임베딩 모델이 훈련될 당시에는 존재하지 않았을 가능성이 높습니다. 모델은 이를 서브워드 토큰(Subword Tokens)의 시퀀스로 취급하며, 하나의 단위로서의 강력한 개념을 가지고 있지 않습니다. 만약 후자("GPT-4o pricing")가 매우 다른 문맥에 둘러싸인 청크에 나타난다면, "GPT-4o pricing"과 "GPT-3 cost" 사이의 코사인 거리(Cosine Distance)가 "GPT-4o pricing"과 "GPT-4o pricing" 사이의 거리보다 더 작아질 수도 있습니다.

이는 다음과 같은 경우에 해당합니다:

  • 제품명, 특히 최신 제품명 (Claude 4, Llama 3.2, GPT-4o)
  • 내부 약어 및 코드 (X100, PRJ-2024-Q3)
  • 코드 문서의 함수 및 식별자 이름
  • 오류 코드 및 스택 트레이스(Stack Trace) 파편
  • 좁은 도메인의 희귀한 기술 용어

이러한 쿼리의 경우, BM25(Lucene과 Elasticsearch가 20년 동안 사용해 온 것과 동일한 키워드 점수 산정 알고리즘)가 벡터 검색보다 훨씬 더 뛰어난 성능을 발휘합니다.

하이브리드 검색(Hybrid Search)의 실체

하이브리드 검색(Hybrid Search)은 두 가지 검색기(Retriever)를 모두 실행하고 그 결과를 결합합니다. 벡터 검색기(Vector Retriever)는 코사인 유사도(Cosine Similarity)를 기준으로 상위 k개의 결과를 반환합니다. BM25 검색기(BM25 Retriever)는 토큰 중첩 점수(Token-overlap Score)를 기준으로 상위 k개의 결과를 반환합니다. 이후 병합 함수(Merge Function, 가장 흔하게는 상호 순위 결합(Reciprocal Rank Fusion, RRF))가 이들의 합집합을 재정렬하여 하나의 정렬된 리스트로 만듭니다.

상호 순위 결합(RRF)이 '지루한 선택'인 데에는 이유가 있습니다. 이 방식은 파라미터가 필요 없습니다(Parameterless). 조정해야 할 가중치도 없고, 씨름해야 할 정규화(Normalization)도 없습니다. 각 문서의 점수는 해당 문서가 나타나는 모든 검색기에 대해 1 / (k + rank)를 합산한 값이며, 여기서 k는 작은 상수(통상적으로 60)입니다. 두 검색기 모두에서 순위가 높은 문서는 상단으로 떠오릅니다. 한쪽 검색기에서만 순위가 높은 문서는 병합된 리스트에 여전히 나타나지만 더 낮은 순위에 위치하게 됩니다. 벡터와 BM25의 가중치를 명시적으로 설정하려는 팀들(예: "벡터 0.7 + 키워드 0.3")은 대개 일주일 동안 가중치를 튜닝하는 데 시간을 허비한 뒤, RRF가 재현율(Recall) 측면에서 2% 이내의 차이만 보이면서도 튜닝이 전혀 필요 없었다는 사실을 깨닫게 됩니다.

우리가 기본값으로 제공하는 것

Sapota가 시작하는 모든 새로운 RAG 프로젝트에서 기본 검색 설정은 RRF를 사용하는 하이브리드 방식입니다. 벡터 전용도 아니고, BM25 전용도 아닙니다. 둘 다를 결합(Fused)한 방식입니다. 사용할 가치가 있는 벡터 데이터베이스(Vector Database)들에서는 구현이 매우 간단합니다. Qdrant는 버전 1.10부터 하이브리드 검색을 네이티브로 지원해 왔습니다. 밀집 벡터(Dense Vector) 필드와 함께 희소 벡터(Sparse Vector) 필드를 정의하고, 인덱싱(Indexing) 시점에 둘 다 채운 뒤, 검색 시점에 둘 다 쿼리하면 됩니다. Weaviate는 단일 하이브리드 쿼리 파라미터를 통해 내장된 하이브리드 검색을 제공합니다. Elasticsearch를 사용하는 것이 상관없다면, dense_vector 필드 타입을 사용하여 이를 수행할 수 있습니다. 하이브리드를 지원하지 않는 벡터 데이터베이스(구버전 Pinecone, Chroma, FAISS)를 이미 사용 중인 팀의 경우, 경량 라이브러리(100만 개 미만의 문서라면 Python의 rank_bm25로 충분합니다)를 사용하여 별도의 BM25 인덱스를 추가하고 애플리케이션 코드에서 병합합니다. 지연 시간(Latency) 오버헤드는 약 30% 정도 발생하지만, 그만한 가치가 있습니다.

순수 벡터 검색만으로 충분할 때

우리가 항상 하이브리드 방식을 권장하는 것은 아닙니다.

벡터 검색만으로 충분한 진정한 사례들: 코퍼스(Corpus)가 희귀 식별자가 없는 순수 자연어 산문인 경우(일반 지식 콘텐츠, 제품명을 언급하지 않는 고객 서비스 FAQ, 내부 정책 문서 등). 쿼리 분포가 진정으로 의역(Paraphrase) 비중이 높은 경우(사용자가 같은 질문을 50가지 방식으로 다르게 물어보고 시스템이 그것이 같은 의미임을 알기를 기대하는 경우). 코퍼스의 규모가 충분히 작아(문서 10,000개 미만) BM25의 노이즈가 정밀도(Precision)의 이점보다 큰 경우. 이것들은 실제 사례들입니다. 하지만 팀들이 가정하는 것보다 훨씬 드뭅니다. 대부분의 프로덕션 코퍼스에는 일부 제품명, 기술 용어, 그리고 희귀하지만 중요한 식별자들이 포함되어 있습니다. 하이브리드(Hybrid) 방식은 밀집 벡터(Dense Vector)의 의미론적 강점을 희생하지 않으면서 이 모든 것을 처리합니다.

창업자에게 일어난 변화
평가(Eval) 실패를 확인한 후 진단에 15분이 걸렸습니다. 해결책은 세 가지 변경 사항이었습니다: 기존 Qdrant 컬렉션에 희소 벡터(Sparse Vector) 필드를 추가했습니다. 기존 임베딩 모델과 BM25 희소 인코더(BM25 Sparse Encoder)를 모두 사용하여 재색인(Re-index)했습니다(Qdrant는 내장된 희소 모델로서 BM25를 지원합니다). 애플리케이션의 검색 호출을 단일 밀집 쿼리(Single Dense Query)에서 RRF 퓨전(RRF Fusion)을 사용하는 하이브리드 쿼리로 전환했습니다. 총 배포 시간: 반나절. 실패했던 쿼리 클래스의 재현율(Recall)은 30% 미만에서 90% 이상으로 올라갔습니다. 잘 작동하던 쿼리들의 재현율은 일정하게 유지되었습니다. 지연 시간(Latency)은 p50 기준 80ms에서 110ms로 증가했습니다.

창업자는 왜 이것이 기본값이 아니었는지 물었습니다. 답은 대부분의 벡터 데이터베이스 튜토리얼과 시작 가이드가 순수 밀집 벡터 검색을 먼저 다루기 때문입니다. 그것이 새롭고 흥미로운 기능이기 때문입니다. BM25는 20년이나 되었고 흥미롭지 않습니다. 이 둘을 결합하는 것은 벤더 자체 사이트의 블로그 포스트를 쓸 만큼의 가치가 없다고 여겨지기에, 대부분의 팀은 이 조합이 실제 프로덕션에서 원하는 것이라는 사실을 배우지 못합니다.

희소 인코더(Sparse Encoders)에 관한 참고 사항
클래식한 BM25를 넘어, 트랜스포머(Transformer) 모델을 통해 희소 벡터를 생성하는 새로운 클래스의 "학습된 희소(Learned Sparse)" 인코더(SPLADE, BGE-M3 희소 모드)가 존재합니다.

이러한 인코더들은 대부분의 벤치마크에서 BM25보다 뛰어난 성능을 보이며, v2 시스템을 구축할 때 고려할 가치가 있습니다. v1 단계에서는 일반적인 BM25만으로도 충분합니다. 학습된 희소(Learned Sparse) 인코더를 통해 얻는 미미한 개선 효과는, 희소 검색(Sparse Retrieval) 자체를 추가함으로써 얻는 개선 효과보다 작습니다.

만약 당신의 검색이 당연히 나와야 할 결과를 놓치고 있다면: 만약 당신의 AI 어시스턴트가 정확한 문구(Exact Phrase)로 검색했을 때 인덱스에 분명히 존재한다고 증명할 수 있는 콘텐츠를 찾지 못한다면, 그 실패의 원인은 모델이 아니라 거의 항상 검색(Retrieval) 레이어에 있습니다. Sapota는 평가 세트(Eval Set)를 생성하고, 실패하는 쿼리 클래스를 식별하며, 작동 가능한 PR(Pull Request) 형태로 하이브리드 설정을 전달하는 1주일간의 검색 감사(Retrieval Audit) 서비스를 제공합니다. AI 엔지니어링 페이지를 통해 연락해 주시고, 실제 운영 환경에서 실패하고 있는 세 가지 예시 쿼리를 보내주세요. 진단에는 보통 한 번의 통화면 충분합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0