
하이브리드 RAG 검색: 스택을 복잡하게 만들지 않고 BM25, 벡터 및 리랭킹(Reranking) 활용하기
요약
벡터 검색의 한계를 극복하기 위해 BM25 어휘 검색과 임베딩 기반 의미 검색을 결합한 하이브리드 RAG 아키텍처를 소개합니다. 고유 명사나 희귀 용어 검색 성능을 높이기 위해 랭킹 융합과 리랭킹 과정을 활용하는 방법을 다룹니다.
핵심 포인트
- 벡터 검색은 의미 파악에 강하지만 고유 명사 및 희귀 용어 검색에 취약함
- BM25 기반 어휘 검색을 결합하여 정확한 키워드 일치 성능을 보완
- 랭킹 융합(RRF)과 리랭킹을 통해 최적의 컨텍스트를 LLM에 전달
- 기술 문서나 로그 등 고유 명사가 많은 데이터에는 하이브리드 방식 권장
순수 벡터 검색(Vector search)은 ID, 고유 명사, 희귀 용어가 포함된 질의에서 실패합니다. 하이브리드 RAG 검색은 모델을 호출하기 전에 더 나은 증거를 검색하기 위해 BM25, 임베딩(Embeddings), 리랭킹(Reranking)을 결합합니다.
하이브리드 RAG 검색이란 일반적으로 BM25 또는 전체 텍스트 검색(Full-text search)인 어휘 검색(Lexical retrieval)을 임베딩을 통한 의미론적 검색(Semantic retrieval)과 함께 실행하고, 순위(Rankings)를 병합하여 인용 가능한 증거가 포함된 정렬된 컨텍스트를 LLM에 전달하는 것을 의미합니다.
기본 아키텍처
TL;DR
핵심 키워드는 하이브리드 RAG 검색입니다. 스페인어 검색 의도는 실용적입니다: 벡터 검색이 부족한 시점이 언제인지, 어떻게 BM25를 벡터와 결합하는지, 그리고 이러한 변화가 실제 응답을 개선하는지 어떻게 평가하는지를 이해하는 것입니다.
나의 입장: 만약 당신의 RAG가 기술 문서, 지원, 계약서, 카탈로그, 로그 또는 고유 명사가 포함된 내부 지식에 대해 답변한다면, 벡터 전용(Vector-only) 방식으로 시작해서는 안 됩니다. 하이브리드로 시작하거나, 적어도 전체를 다시 인덱싱(Reindexing)하지 않고도 하이브리드 방식을 활성화할 수 있도록 준비를 해두어야 합니다.
브리핑
하이브리드 RAG 검색이 해결하는 문제
벡터 검색은 의미를 포착하는 데 탁월합니다. 누군가 키를 취소하는 방법이라고 질문하면, 동일한 단어를 사용하지 않더라도 순환(Rotation), 자격 증명(Credentials) 또는 비밀(Secrets)에 대해 설명하는 문서를 찾을 수 있습니다. 이것이 벡터 검색의 가치입니다.
하지만 임베딩(Embeddings)은 정확한 일치 항목에서 걸려 넘어집니다: ERR_CONN_RESET, invoice_2026_041, TenantIsolationPolicy, SKU-A17, 내부 클래스 또는 희귀한 엔드포인트(Endpoint) 같은 것들 말이죠. 인간에게 이러한 토큰은 가장 중요한 단서입니다. 하지만 벡터에게는 노이즈처럼 희석될 수 있습니다.
BM25와 전체 텍스트 검색(Full-text search)은 그 반대로 작동합니다: 어휘적 일치(Lexical matches), 용어 빈도 및 단어의 희귀성에 가중치를 둡니다. 하이브리드 검색은 이 두 가지 신호를 결합하여 시스템이 의미와 정확성 사이에서 하나를 선택해야 하는 상황을 방지합니다.
하이브리드 아키텍처는 어휘적 검색 (Lexical Recall), 의미적 검색 (Semantic Recall), 랭킹 융합 (Ranking Fusion), 리랭킹 (Reranking) 및 평가를 분리합니다. 직관에 의존하여 더 많은 청크 (Chunks)를 집어넣는 것이 아니라, 어떤 증거가 프롬프트 (Prompt)에 전달될 가치가 있는지를 결정합니다.
실전 읽기
최소 아키텍처: 두 개의 검색기와 하나의 융합
기본 패턴은 네 단계로 구성됩니다. 첫째, 쿼리 (Query)를 정규화하고 권한 또는 하드 필터 (Hard Filters)를 적용합니다. 둘째, 인덱싱된 텍스트에 대해 BM25 또는 전체 텍스트 검색 (Full-text search)을 실행합니다. 셋째, 청크 (Chunks)의 임베딩 (Embeddings)에 대해 벡터 검색 (Vector search)을 실행합니다. 넷째, 이질적인 점수 (Scores)를 보정하고 싶지 않을 때 주로 사용하는 상호 순위 융합 (Reciprocal Rank Fusion, RRF)과 같은 안정적인 규칙을 사용하여 두 랭킹을 융합합니다.
핵심은 아무 생각 없이 가공되지 않은 점수 (Raw scores)를 섞지 않는 것입니다. BM25 점수는 코사인 유사도 (Cosine similarity)나 내적 (Inner product)과 같은 의미를 갖지 않습니다. RRF는 절대적인 척도가 아닌 랭킹 순위 (Ranking positions)를 기반으로 작동하기 때문에 문제의 일부를 방지합니다. 만약 어떤 문서가 두 목록 모두에서 상위에 나타나면 순위가 올라갑니다. 만약 한 목록에만 나타난다면 여전히 포함될 수 있지만, 그 힘은 약해집니다.
그 이후에 리랭킹 (Reranking)을 추가할 수 있습니다. 크로스 인코더 (Cross-encoder) 또는 지연 상호작용 (Late-interaction) 리랭커는 쿼리-문서 쌍을 더 세밀하게 살펴보고 소수의 후보군을 재정렬합니다. 이는 비용이 더 많이 들기 때문에, 전체 코퍼스 (Corpus)가 아닌 40~100개의 후보를 검색한 후에 적용하는 것이 일반적입니다.
체크리스트
하이브리드를 사용해야 할 때와 그렇지 않을 때
사용자가 정확한 이름, 오타, 약어, ID, 버전, 경로, 클래스, 제품, 티켓 또는 인터페이스에서 복사한 조각들을 사용하여 질문한다면 하이브리드 검색을 사용하십시오. 이는 개발자 및 기술 지원을 위한 RAG의 일반적인 사례입니다.
또한 코퍼스 (Corpus)가 자연어와 표 (Tables), 긴 문서, API 문서, 변경 로그 (Changelogs), 장애 보고 (Incidents) 및 권한이 필요한 질문이 섞여 있는 경우에도 적합합니다. 이러한 환경에서 벡터 전용 (Vector-only) 방식은 데모에서는 설득력 있게 보일 수 있지만, 특정 용어가 등장하는 운영 환경에서는 실패하는 경우가 많습니다.
코퍼스(Corpus)가 작고, 균질하며, 의미론적으로 단순하다면 유행을 따르기 위해 이를 추가하지 마십시오. 문서가 200개뿐이고 질의(Query)가 개방형이라면, 잘 평가된 벡터 검색(Vector search)만으로도 충분할 수 있습니다. 실용적인 규칙은 측정하는 것입니다. 만약 정확한 키워드 일치 질의를 놓치거나 강력한 인용(Citation)이 없는 답변을 생성한다면, 하이브리드 방식은 더 이상 '추가적인 복잡성'이 아니라 '필수적인 위생(Hygiene)' 요소가 됩니다.
코드: BM25와 벡터를 결합하기 위한 간단한 RRF
rrf.py
from collections import defaultdict
def reciprocal_rank_fusion(result_lists, k=60):
...
검토 사항
확인해야 할 사항
이 예제는 특정 제공업체에 의존하지 않습니다. 아이디어는 의도적으로 단순합니다. 두 개의 리스트를 검색하고, 순위(Position)에 따라 융합하며, 소수의 후보를 리랭킹(Reranking)하고, 인용된 컨텍스트(Context)로만 생성합니다. 이후 bm25_search, vector_search, rerank를 PostgreSQL, Azure AI Search, Qdrant, Weaviate, Pinecone, Elasticsearch 또는 현재 사용 중인 스택으로 교체할 수 있습니다.
도움이 되고 계신가요? 매주 한 번씩 전달됩니다.
개발자를 위한 AI 도구, 에이전트(Agents), MCP, 보안 및 워크플로우(Workflows)를 5분 분량의 이메일로 요약해 드립니다. 스페인어로, 잡음 없이 전달합니다.
PostgreSQL 및 pgvector를 이용한 구현
코퍼스가 트랜잭션 데이터, 테넌트별(Tenant) 권한 또는 다른 시스템으로 복제하고 싶지 않은 조인(Join) 데이터 근처에 있다면 PostgreSQL은 매우 합리적인 선택입니다. tsvector와 tsquery는 전문 검색(Full-text search)을 지원하며, pgvector는 임베딩(Embeddings)의 저장 및 검색 기능을 추가합니다. 많은 내부 제품(Internal products)의 경우, 이러한 조합은 시스템 간의 동기화 및 데이터 누락 문제를 줄여줍니다.
전형적인 설계는 content, metadata, tenant_id, tsv 및 embedding을 동일한 테이블에 저장합니다. 쿼리는 먼저 필수 필터를 적용하고, 전체 텍스트(Full-text) 검색과 벡터 검색(Vector search)을 각각 실행한 뒤, 위치를 계산하고 SQL 또는 애플리케이션 단계에서 RRF(Reciprocal Rank Fusion)로 병합합니다. 중요한 점은 권한(Permissions)이 사후에 적용되는 장식적인 필터가 되어서는 안 된다는 것입니다. 후보군을 검색하기 전에 반드시 적용되어야 합니다.
Postgres가 거대한 코퍼스(Corpus)나 고도화된 관련성(Relevance) 요구사항에 대해 항상 가장 빠른 검색 엔진이 되지는 않을 것입니다. 하지만 운영 가능한 베이스라인(Baseline)으로서의 성능은 강력합니다. 트랜잭션, 백업, 권한, SQL, 조인(Joins)이 가능하며 움직이는 부품(Moving pieces)이 적기 때문입니다. 만약 팀이 두 개의 인덱스를 규율 있게 운영할 수 없다면, 비록 가장 화려하지는 않더라도 더 단순한 아키텍처가 승리할 수 있습니다.
실무적 읽기
전용 엔진을 이용한 구현
Azure AI Search는 하이브리드 검색을 전체 텍스트(Full-text) 쿼리와 벡터(Vector) 쿼리의 병렬 실행으로 문서화하며, 단일 랭킹을 반환하기 위해 RRF를 사용합니다. 이는 BM25, HNSW/eKNN 및 병합(Fusion)을 명확하게 구분하여 설명하므로 읽어볼 만한 가치가 있습니다.
Weaviate는 BM25F와 벡터 검색을 통한 하이브리드 검색을 제공하며, 가중치(Weight)와 병합 방식에 따라 설정할 수 있습니다. Qdrant는 밀집 벡터(Dense vectors), 희소 벡터(Sparse vectors) 및 리랭킹(Reranking)을 포함한 하이브리드 쿼리를 허용합니다. 최근의 문서는 밀집 임베딩(Dense embeddings), 희소 임베딩(Sparse embeddings) 및 후기 상호작용(Late-interaction)을 활용한 인제스션(Ingestion) 패턴을 권장합니다. Pinecone은 희소-밀집(Sparse-dense) 패턴과 인덱스 유형에 따른 하이브리드 인덱스 또는 신호 조합(Combination of signals) 접근 방식을 지원합니다.
결정 기준은 어떤 벡터 데이터베이스(Vector database)가 유행인가가 되어서는 안 됩니다. 다음과 같이 질문하십시오: 권한은 어디에 저장되어 있는가, 임베딩(Embeddings)의 버전을 어떻게 관리할 것인가, 테넌트(Tenant)별로 어떻게 필터링할 것인가, 잘못된 결과를 어떻게 디버깅할 것인가, 리랭킹(Reranking) 비용은 얼마인가, 그리고 인덱스 장애 시 누가 운영할 것인가.
브리핑
튜닝: alpha, top_k 및 리랭킹(Reranking)
제공업체가 alpha와 같은 가중치를 제공한다면, 이를 보편적인 상수로 취급하지 마십시오. ID가 포함된 쿼리는 일반적으로 더 많은 어휘적 신호(Lexical signal)가 필요합니다. 개념적인 쿼리는 일반적으로 더 많은 의미적 신호(Semantic signal)가 필요합니다. 중간값으로 시작할 수 있지만, 쿼리 유형별로 메트릭(Metrics)을 기록해 두십시오.
병합(Fusion) 전과 리랭킹(Reranking) 후의 top_k는 생각보다 더 중요합니다. 후보군을 너무 적게 검색하면 정답 문서가 리랭커(Reranker)에 도달조차 하지 못합니다. 반대로 너무 많이 검색하면 비용, 지연 시간(Latency), 노이즈가 증가합니다. 일반적인 설정은 채널당 30-100개를 검색하여 병합하고, 40-100개를 리랭킹한 뒤, 최종적으로 5-15개의 청크(Chunks)를 LLM에 전달하는 방식입니다.
리랭킹은 정답 후보가 풀(Pool) 안에 있을 때만 보완 효과가 있습니다. 컨텍스트 재현율(Context recall)이 낮다면 비싼 리랭커로 해결하려 하지 마십시오. 청킹(Chunking), 필터링, 쿼리 정규화(Query normalization), 유의어(Synonyms), 필드 인덱싱(Field indexing) 또는 희소/밀집(Sparse/Dense) 조합을 개선하여 해결해야 합니다.
평가: 베이스라인(Baseline)과 비교하지 않고는 하이브리드 방식을 배포하지 마십시오
하이브리드 검색을 활성화하기 전에 작은 데이터셋을 고정하십시오: 실제 질문, 기대되는 문서(있는 경우), 쿼리 카테고리 및 리스크를 포함합니다. 동일한 코퍼스(Corpus)를 사용하여 벡터 전용(Vector-only), BM25 전용(BM25-only), 그리고 하이브리드 방식을 실행하십시오. qrels가 있다면 recall@k, MRR, nDCG를 측정하고, 답변의 근거성(Groundedness)과 쿼리당 비용을 측정하십시오.
제가 찾는 개선은 단순히 합산 점수가 높아지는 것이 아닙니다. 구체적인 사례를 보고 싶습니다: BM25가 구출해낸 정확한 오류, 벡터가 유지해낸 개념적 질문, 리랭커가 퇴출시킨 무관한 문서, 그리고 더 나은 증거를 인용하는 답변과 같은 것들 말입니다.
임베딩(Embeddings), 청킹(Chunking), 프롬프트(Prompt), 리랭커(Reranker), 병합(Fusion)을 동일한 실험에서 한꺼번에 바꾸지 마십시오. 그렇게 하면 무엇이 도움이 되었는지 알 수 없습니다. 하이브리드 검색은 자체적인 베이스라인을 가질 만큼 충분히 큰 변화입니다.
실무 지침
보안, 권한 및 개인정보 보호
RAG에서 위험한 실패는 단순히 잘못된 답변을 하는 것만이 아닙니다. 잘못된 사용자에게 올바른 문서를 검색해 주는 것입니다. 하이브리드 방식에서는 문서가 후보 풀(Candidate pool)에 들어올 수 있는 경로가 더 많아지므로, 테넌트(Tenant) 필터, 권한, 분류 및 날짜 필터는 랭킹(Ranking) 전이나 각 서브쿼리(Sub-query) 단계에서 적용되어야 합니다.
작업에 필요하지 않은 비밀(secrets), 키(keys), 덤프(dumps), 민감한 내부 프롬프트(prompts) 또는 개인 데이터를 인덱싱(indexing)하지 마세요. 코퍼스(corpus)에 티켓, 이메일, 외부 페이지 또는 사용자가 업로드한 문서와 같이 신뢰할 수 없는 콘텐츠가 포함되어 있다면, 해당 청크(chunks)를 지침(instructions)이 아닌 데이터(data)로 취급해야 합니다. 이는 간접적 프롬프트 인젝션(indirect prompt injection)에 대한 방어와 직접적으로 연결됩니다.
관측성(observability)을 위해 문서 ID, 점수(scores), 랭킹(rankings), 적용된 필터 및 인덱스 버전을 기록하세요. 검색된 모든 텍스트를 영구적인 로그에 저장할 필요는 없습니다. 별도의 민감한 데이터베이스를 구축하지 않고도 디버깅(debugging)을 수행하기 위해서는 참조(references)와 통제된 샘플(samples)만으로도 충분한 경우가 많습니다.
하이브리드 RAG에서 흔히 발생하는 오류
- BM25 점수와 벡터(vector) 점수를 마치 동일한 스케일(scale)에 있는 것처럼 병합하는 경우.
- 랭킹(ranking)이 이미 오염된 상태에서 검색(retrieval) 후에 권한 필터를 적용하는 경우.
top_k를 작게 설정해 놓고, 애초에 전달받지도 못한 문서를 찾지 못한다고 리랭커(reranker)를 탓하는 경우.- 제목, 경로, 날짜, 제품, 버전 또는 동점자 처리에 유용한 메타데이터(metadata) 없이 청크(chunks)를 인덱싱하는 경우.
- 평가(evaluation) 시 정확한 질의(exact), 개념적 질의(conceptual), 부정 질의(negative), 멀티홉(multi-hop) 질의를 분리하지 않는 경우.
- 최종 답변만 측정하고 프롬프트(prompt)에 전달된 후보군(candidates)을 저장하지 않는 경우.
- 명백한 청킹(chunking) 문제를 덮기 위해 하이브리드(hybrid) 방식을 추가하는 경우.
일주일 채택 계획
- 1일 차: 40~60개의 실제 질문에 태그를 달고, ID, 오류, 고유 명사, 일반 개념, 권한(permissions), 미응답 질문 등으로 쿼리를 분류합니다.
- 2일 차: 벡터 전용(vector-only) 파이프라인을 실행하고 후보군(candidates), 답변, 인용(citations), 지연 시간(latency), 비용을 저장합니다.
- 3일 차: 동일한 권한 필터를 적용하여 BM25 또는 전체 텍스트 검색(full-text search)을 추가합니다.
- 4일 차: RRF(Reciprocal Rank Fusion)로 병합하고, 프롬프트(prompts)를 수정하기 전에 후보군 풀(candidate pools)을 비교합니다.
- 5일 차: 병합된 후보군에 대해서만 리랭킹(reranking)을 추가하고, 지연 시간을 해치지 않으면서 정확도(precision)가 향상되는지 측정합니다.
- 6일 차: 쿼리 유형별로 top_k를 조정하고, 최소한의 검색 회귀(regression retrieval) 게이트를 생성합니다.
- 7일 차: 트래픽의 작은 비율에 배포하고, 평균값뿐만 아니라 실제 사례들을 검토합니다.
결론
하이브리드 RAG 검색은 아키텍처를 자랑하기 위한 우아한 레이어가 아닙니다. 이는 벡터 전용(vector-only) 방식의 실제 결함, 즉 의미적 유사성(semantic similarity)을 충분한 근거(evidence)와 혼동하는 문제를 해결하기 위한 실질적인 교정책입니다.
저의 권장 사항은 운영 가능한 가장 지루한 파이프라인부터 시작하는 것입니다: 엄격한 필터링, BM25, 벡터, RRF, 선택적 리랭킹(reranking), 인용(citations), 그리고 평가입니다. 이것이 실제 질문에 대한 재현율(recall)과 근거성(groundedness)을 개선한다면, 더 정교한 엔진에 투자할 기술적 명분을 얻게 될 것입니다. 만약 개선되지 않는다면, 그것은 단지 또 다른 비싼 인덱스일 뿐입니다.
자주 묻는 질문 (FAQ)
하이브리드 RAG 검색이란 무엇인가요?
BM25나 전체 텍스트 검색(full-text search)과 같은 어휘 검색(lexical search)을 임베딩(embeddings) 기반의 벡터 검색과 결합하여, 결과를 병합하고 모델에 더 신뢰할 수 있는 컨텍스트(context)를 전달하는 RAG 검색 접근 방식입니다.
왜 임베딩이 있는데도 BM25가 여전히 유용한가요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기