
RAG(Retrieval-Augmented Generation)를 구현할 때 처음에는 문서를 임베딩하고, 사용자의 질문과 유사한 문서를 벡터 검색으로 가져오면 충분하다고 생각하기 쉽습니다. 하지만 실제 데이터를 대상으로 검색을 구성해 보면, 의미가 비슷한 문서를 찾는 것만으로는 정확한 답변을 생성하기 어렵다는 것을 알 수 있습니다.
제품명이나 문서 번호처럼 정확한 일치가 필요한 정보가 누락되기도 하고, 질문과 의미는 비슷하지만 실제 조건에는 맞지 않는 문서가 검색되기도 합니다. 또한 검색된 문서가 많거나 내용이 길어지면, 정작 중요한 정보가 LLM의 컨텍스트 안에서 제대로 활용되지 못하는 문제도 발생합니다.
결국 RAG의 답변 품질을 높이기 위해서는 단순히 벡터 검색의 성능만 살펴보는 것이 아니라, 검색 결과를 어떻게 보강하고 정제하여 LLM에 전달할 것인지 함께 고민해야 합니다.
이번 글에서는 RAG의 검색 정확도를 개선하기 위해 알아본 다음 방법들을 정리합니다.
각 방법이 필요한 이유와 동작 방식, 그리고 RAG 파이프라인에서 어떤 역할을 담당하는지를 중심으로 살펴보겠습니다.
Hybrid Search란?
왜 벡터 검색만으로 부족한가?
: 벡터 검색은 문장의 전체적인 ‘맥락’을 파악하는 데 뛰어나지만, 수치화된 유사도에 의존하기 때문에 다음과 같은 치명적인 데이터 누수(Data Leakage) 현상이 발생합니다.
: 벡터 검색은 충분한 검색 기능을 제공하지만, 모델이 사전에 학습하지 않은 ‘새로운 도메인’의 데이터를 다룰 때 한계를 보입니다.
(1) 도메인 특화 용어 및 미학습 단어 처리의 한계(Out-of-Distribution 문제)
(2) 희소 데이터(Sparse Data) 및 고유 식별자 검색 실패
A-1234-X), 부품 번호, 특정 날짜, 사람 이름 등은 의미적 유사성보다 글자 그대로의 일치가 훨씬 중요합니다. 벡터 검색은 A-1234-X를 비슷한 모델명인 A-1234-Y와 가깝게 인식하여 잘못된 정보를 가져올 확률이 높습니다.BM25 알고리즘의 핵심 원리
: BM25는 전통적인 키워드 검색의 한계를 수학적으로 보완한 알고리즘으로, 현대 검색 엔진(Elasticsearch, Solr 등)의 기본 랭킹 알고리즘으로 채택될 만큼 강력합니다.
(1) TF-IDF 기반
: 단순 TF-IDF는 특정 단어가 문서에 많이 나올수록 점수가 무한히 상승합니다. 하지만 BM25는 ‘단어 빈도 포화’ 개념을 도입하여 효율성을 높였습니다.
(2) 정확한 토큰 매칭
: 질문에 포함된 키워드와 본문의 키워드를 ‘토큰(Token)’ 단위로 정확히 대조하는 방식을 취합니다.
검색 엔진 상세 비교: Vector vs BM25
| 구분 | 의미론적 검색(Vector Search) | 키워드 검색(BM25) |
|---|---|---|
| 핵심 가치 | 맥락과 의도(Context) | 정확성과 희소성(Precision) |
| 매칭 방식 | 유사한 의미를 가진 공간적 근접도 매칭 | 텍스트 토큰의 물리적 일치 여부 매칭 |
| 주요 장점 | • 유의어·동의어 처리 능력이 탁월함 • 다국어 검색 및 문장형 질문에 강함 • “혈당 조절 방법” 검색 시 “인슐린 요법” 탐색 가능 | • 특정 고유 명사, 제품 번호 검색 시 오차가 없음 • 도메인 특화 용어에 대해 즉각적인 반응성 보유 • 계산 비용이 저렴하고 인덱싱 속도가 빠름 |
| 치명적 단점 | • 할루시네이션: 단어는 달라도 벡터가 가깝다는 이유로 전혀 다른 사실을 가진 문서를 가져올 수 있음 • 전문 용어(OOD) 매칭 실패 | • 어휘 불일치(Vocabulary Gap): 사용자가 “노트북”이라고 검색했을 때 본문에 “휴대용 컴퓨터”만 있다면 검색 실패 • 문맥 이해 불가 |
방식별 강점과 약점
| 검색 방식 | 강점(Strengths) | 약점(Weaknesses) |
|---|---|---|
| 벡터 검색(Semantic) | 문맥 및 의미 이해: “혈당 수치” 검색 시 “당뇨병 관리”를 찾는 등 동의어·유의어를 자동으로 파악하여 지능적인 검색이 가능합니다. | 정밀도 부족: 모델이 학습하지 않은 전문 용어(OOD)나 모델 번호, 사람 이름 같은 고유 명사의 정확한 매칭(Exact Match)에 취약합니다. |
| BM25(Keyword) | 정확한 키워드 매칭: 별도 학습 없이도(Zero-shot) 문서 내 특정 단어의 존재 여부를 파악하며, 새로운 도메인 데이터에 즉각 대응할 수 있습니다. | 어휘 불일치 문제: 검색어와 본문의 단어 형태가 조금만 달라도 찾지 못하며, 텍스트의 실제 의미나 맥락을 전혀 유추하지 못합니다. |
| Hybrid(결합) | 최상의 검색 품질: 벡터의 ‘지능’과 BM25의 ‘정확성’을 결합하여, 전문 용어 누락 문제를 해결하고 다양한 검색 시나리오에서 정확도를 극대화합니다. | 리소스 및 튜닝: 두 가지 인덱스(밀집·희소 벡터)를 모두 관리해야 하는 비용이 들며, 서비스 성격에 맞는 가중치() 최적화 과정이 필수적입니다. |
⇒ 하이브리드 검색은 벡터 검색이 놓치기 쉬운 ‘특정 도메인의 전문 키워드’를 BM25가 보완해 주고, BM25가 찾지 못하는 ‘동의어와 문맥’을 벡터 검색이 찾아주어 환각(Hallucination) 방지와 검색 정확도를 극대화하는 강력한 대안으로 활용됩니다.
벡터 검색과 키워드 검색의 결합 방식
(1) 가중치 기반 병합(Weight-based Merging / Alpha 파라미터)
: alpha 파라미터를 활용한 가중치 조절 방식(Pinecone)
alpha 값을 0.5로 설정하면 두 검색 방식의 점수가 균등하게 혼합된 기본 하이브리드 검색이 됩니다.alpha 값을 1.0으로 설정하면 100% 밀집 벡터(의미론적) 검색만 수행하게 됩니다.pubmed_qa)에서는 alpha 값을 0.3으로 설정하여 전통적인 키워드 매칭의 가중치를 조금 더 높였을 때 검색 결과가 가장 크게 향상되었습니다.(2) 상호 순위 융합(Reciprocal Rank Fusion, RRF)
: LlamaIndex 등에서 강력하게 추천하는 방식인 RRF는 개별 검색 결과의 ‘점수’가 아닌 ‘순위(Rank)’를 활용합니다. 두 검색 엔진의 점수 체계(예: 0~1 vs 10~100)가 서로 달라도 안정적으로 통합할 수 있습니다.
기타 방식 → LlamaIndex에서 제공
상대적 점수 융합(Relative Score Fusion)
분포 기반 점수 융합(Distribution-Based Fusion)
단순 융합(Simple Fusion)
상호 순위 융합(Reciprocal Rank Fusion, RRF)
Re-ranking이란
Re-ranking(재랭킹)은 1차적으로 검색된 문서 후보군을 대상으로 사용자의 질문과의 연관성을 다시 정밀하게 계산하여 가장 적합한 문서가 최상단에 오도록 순위를 재배치하는 과정입니다.
RAG 파이프라인상에서는 Retrieval(검색) 단계와 Generation(생성) 단계 사이에 위치합니다.
Retrieval(1차 검색) → Re-ranking(재정렬) → Generation(답변 생성)
코드 블록(블로그용)
| **구분** | **System Prompt(시스템 프롬프트)** | **RAG(검색 증강 생성)** | **비고** |
| --- | --- | --- | --- |
| **데이터 위치** | 프롬프트 상단(컨텍스트 윈도우 내부) | 외부 데이터베이스(Vector DB 등) | 내부 컨텍스트 vs 외부 DB |
| **용량 제한** | 모델의 토큰 제한에 걸림(**매우 작음**) | 사실상 **무제한**(수백만 개 가능) | 확장성 및 데이터 규모 차이 |
| **제공 방식** | 사람이 직접 **수동으로 삽입** | 질문에 맞는 문서 **자동 검색·제공** | 자동화된 검색 프로세스 |
| **비용 효율성** | 매 요청마다 전체 토큰 소모(**고비용**) | 필요한 청크만 사용하여 **비용 절약** | 운영 효율성 및 경제성 |
| **유지 보수** | 데이터 변경 시 **프롬프트 수동 수정** | DB 갱신 시 **자동으로 최신 지식 반영** | 최신성 유지의 편의성 |
Cross-encoder vs Bi-encoder
→ 문장의 의미를 비교하는 두 가지 방식입니다.
(1) Bi-encoder(바이 인코더)
→ Bi-encoder는 질문과 문서를 각각 독립적으로 숫자(벡터)로 바꾼 뒤, 그 숫자들 사이의 거리를 계산하는 방식입니다.
(2) Cross-encoder(크로스 인코더)
→ Cross-encoder는 질문과 문서를 하나의 쌍(Pair)으로 묶어서 동시에 모델에 입력하는 방식입니다.
[질문 + 문서]를 한꺼번에 입력받아 모델이 두 문장의 모든 단어를 서로 대조하며 연관성 점수를 직접 계산합니다.| 구분 | Bi-encoder | Cross-encoder |
|---|---|---|
| 입력 방식 | 질문과 문서를 각각 독립적으로 인코딩하여 개별 임베딩 벡터를 생성 | 질문과 문서를 동시에 하나의 네트워크로 통과시켜 0과 1 사이의 유사도 점수를 직접 출력 |
| 속도 | 매우 빠름. 벡터 데이터베이스를 활용하여 수초 내에 대규모 유사도 비교 가능 | 매우 느림. 임베딩을 미리 만들어 둘 수 없어 모든 (질문, 문서) 쌍에 대해 모델 추론 연산을 새로 해야 함 |
| 정확도 | 상대적으로 낮음 | 문장 간의 문맥을 깊이 있게 교차 분석하므로 월등히 뛰어난 성능(정확도)을 보임 |
| 사용 위치 | 1차 검색 단계(Retrieval) | 2차 재정렬 단계(Re-ranking) |
| 데이터 규모 | 수백만 건 이상 처리 가능 | 수십~수백 건으로 제한 |
Cross-encoder를 검색 단계가 아닌 Re-ranking 단계에서 사용하는 이유(속도 vs 정확도 트레이드오프)
이유: ‘비용’과 ‘시간’ 때문입니다. 즉, 속도와 정확도 간의 트레이드오프(Trade-off) 때문입니다.
Two-stage Retrieval 패턴: Bi-encoder로 후보 선별 → Cross-encoder로 재정렬
→ 대규모 데이터에서 원하는 정보를 찾을 때 ‘속도’와 ‘정확도’라는 두 마리 토끼를 잡기 위해 사용하는 표준적인 아키텍처입니다.
Step 1) 후보 선별(Candidate Retrieval) - Bi-encoder
→ 빠르고 효율적인 Bi-encoder를 사용하여 전체 문서 데이터베이스에서 질문과 관련된 상위 K개(예: Top-100)의 후보 문서를 신속하게 추출합니다.
Step 2) 재정렬(Re-ranking) - Cross-encoder
→ 1단계에서 뽑힌 소수의 후보군을 대상으로 훨씬 더 정밀하게 순위를 다시 매기는 단계입니다.
Cohere Rerank(상용 Re-ranking API)
(1) Cohere Rerank의 동작 방식
→ 기존의 검색 시스템(Elasticsearch, Pinecone, LangChain 등) 뒤에 ‘필터’처럼 붙여서 사용합니다.
(2) Cohere Rerank의 장점
압도적인 성능(특히 한국어를 포함한 다국어)
개발 및 운영 비용 절감
문서 구조에 강함(Semi-structured Data)
긴 문맥 처리(Long Context)
메타데이터 필터링
⇒ ‘메타데이터’ 조건을 만족하는 문서로만 검색 범위를 제한하는 기법입니다.
& 왜 필요할까?
벡터 유사도 기반의 의미론적 검색은 ‘의미’만 비슷하면 조건에 맞지 않는 문서도 관련성이 높다고 판단하여 상위 결과로 가져올 수 있습니다.
ex) ‘2026년 의료 급여 혜택’을 찾아야 하는데, 유사한 ‘2020년 의료 급여 혜택’ 문서를 찾아서 잘못된 정보를 가져올 수 있습니다.
→ 따라서 이러한 할루시네이션 오류의 원인이 되는 현상을 방지하기 위해 필수적입니다.
& 구현 방식
LangChain
search_kwargs={"filter": {"year": "2026"}} 형태로 검색 범위를 좁히는 파라미터를 넘겨 구현합니다.LlamaIndex
Metadata Filters를 적용하여 특정 키와 값이 일치하거나 날짜 범위에 포함되는 문서만 쿼리하도록 설정할 수 있습니다.컨텍스트 압축
⇒ 1차로 검색된 긴 문서 청크들 중에서 사용자의 질문에 답하는 데 실제로 필요한 핵심 문장이나 정보만을 추출하거나 요약하여 LLM에 전달될 프롬프트를 압축하는 기법입니다.
& 왜 필요할까?
→ RAG의 고질적인 문제는 “검색된 문서가 너무 길고 노이즈가 많다”는 점입니다.
이를 해결하기 위해 검색된 결과물(Document)을 LLM에 넘기기 전 ‘다이어트’시키는 과정입니다.
| 방식 | 설명 | 특징 |
|---|---|---|
| LLM Chain Extractor | LLM이 각 문서를 읽고 질문과 관련된 부분만 다시 작성하거나 추출합니다. | 가장 정확하지만 추가적인 LLM 호출 비용과 지연 시간(Latency)이 발생합니다. |
| Embeddings Filter | 질문 벡터와 각 문서 내부의 문장·단락 벡터를 비교해 유사도가 낮은 부분을 제거합니다. | LLM을 사용하지 않아 빠르고 저렴하지만, 문맥 이해도는 다소 낮습니다. |
| Document Reordering | 압축은 아니지만, 가장 중요한 정보를 프롬프트의 최상단이나 최하단으로 재배치합니다. | ‘Lost in the Middle’ 해결에 매우 효과적입니다. |
& 구현 방식 예시
LangChain
ContextualCompressionRetriever라는 특수 컴포넌트를 사용합니다.LlamaIndex
마무리
RAG의 성능은 사용하는 LLM의 성능뿐만 아니라, 질문에 적합한 문서를 얼마나 정확하게 찾아서 전달하느냐에 따라 크게 달라집니다. 관련성이 낮거나 조건에 맞지 않는 문서가 검색되면, 성능이 좋은 LLM을 사용하더라도 정확한 답변을 생성하기 어렵습니다.
이번에 살펴본 검색 보강 방법은 각각 다음과 같은 역할을 담당합니다.
이를 하나의 파이프라인으로 정리하면 다음과 같습니다.
사용자 질문
↓
메타데이터 조건 추출
↓
Hybrid Search
(Vector Search + BM25)
↓
검색 결과 통합
(RRF 또는 가중치 기반 병합)
↓
Re-ranking
↓
컨텍스트 압축
↓
LLM 답변 생성
중요한 점은 모든 서비스에 동일한 검색 구성을 적용하는 것이 아니라, 실제 데이터와 질문 유형에 맞게 각 단계의 비중을 조절해야 한다는 것입니다. 일반적인 문장형 질문이 많다면 벡터 검색의 비중을 높일 수 있고, 제품 번호나 법령명처럼 정확한 키워드가 중요하다면 BM25의 비중을 높이는 방식으로 조정할 수 있습니다.
또한 Re-ranking에 전달할 후보 문서 수, 최종적으로 LLM에 전달할 문서 수, 메타데이터 필터의 조건, 컨텍스트 압축 방식에 따라서도 검색 품질과 응답 속도, 운영 비용이 달라집니다.
따라서 RAG 검색 보강은 특정 기술 하나를 적용하는 작업이라기보다 다음 세 가지 요소 사이의 균형을 찾는 과정이라고 정리할 수 있습니다.
검색 범위는 넓게 확보하고, 문서 순위는 정밀하게 조정하며, LLM에는 필요한 정보만 전달한다.
향후에는 실제 데이터셋을 기준으로 각 검색 방식의 정확도와 응답 시간을 비교하고, Hybrid Search의 가중치와 Re-ranking 후보 개수 등을 조정하면서 서비스에 적합한 검색 파이프라인을 구성해 볼 수 있을 것 같습니다.