[RAG] 4. 검색 : 벡터만 믿었다가 데인 이야기

RAG 실전 가이드 4편 - 벡터 검색의 함정

작성자

카테고리:

* 이 게시물은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

(RAG 시리즈 ④) 하이브리드 검색과 리랭킹

임베딩 검색을 붙여놓고 한동안 만족했다. 뜻이 비슷한 문서를 곧잘 찾아오니까. 그러다 사용자가 제품 모델명을 정확히 넣고 물었는데 엉뚱한 걸 가져오는 걸 보고 정신이 들었다.

의미 검색(밀집 검색)은 “비슷한 뜻”엔 강하지만 “정확히 이 단어”엔 약하다. XR-2200 같은 제품 코드, 사람 이름, 딱 떨어지는 숫자 — 이런 건 뜻이 비슷하고 말고가 없다. 글자가 맞아야 한다. 그래서 옛날 방식인 키워드 검색을 같이 돌렸다. BM25라고, 질문에 든 단어가 문서에 얼마나 자주·드물게 나오는지로 점수를 매기는 고전적인 방법인데, 정확한 토큰 매칭엔 여전히 이만한 게 없다.

둘을 같이 쓰는 걸 하이브리드 검색이라고 부른다. 두 점수를 그냥 가중 합산해도 되지만, 밀집 점수와 BM25 점수는 스케일이 딴판이라 섞기가 까다롭다. 그래서 나는 점수 대신 순위를 병합하는 RRF(Reciprocal Rank Fusion)를 쓴다. 각 검색에서 몇 등 했는지의 역수를 더하는 방식이라 점수 스케일을 안 타서 편하다. 이거 넣고 나서 “정확히 그 단어” 질문이 확 잡혔다. 요즘은 사실상 이게 기본이다.

RRF는 점수 스케일을 안 타서 구현이 단순하다. 각 검색에서의 순위 역수를 더하는 게 전부다.

def rrf(dense_ids, bm25_ids, k=60):
    scores = {}
    for ranking in (dense_ids, bm25_ids):
        for rank, doc_id in enumerate(ranking):
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    return sorted(scores, key=scores.get, reverse=True)

한 가지 더 얹은 게 리랭킹(reranking)이다. 여기엔 개념이 하나 있다. 벡터 검색에 쓰는 모델은 질문과 문서를 따로 벡터로 만들어 거리를 재는 바이 인코더라 빠른 대신 대충 본다. 반면 리랭킹에 쓰는 크로스 인코더는 질문과 문서를 한 쌍으로 같이 넣어 관련도를 매기기 때문에 훨씬 정밀하다. 대신 느려서 전체 문서엔 못 돌린다.

그래서 순서를 이렇게 짠다. 하이브리드 검색으로 일단 상위 20~30개를 넉넉히 뽑는다(빠른 1차). 그다음 그 후보만 리랭킹 모델(Cohere Rerank, Voyage Rerank 같은)한테 넘겨 정밀하게 다시 줄 세운다(느린 2차). 최종적으로 상위 서너 개만 LLM에 넣는다. 넓게 건지고, 좁게 추리는 구조다.

RRF가 순위를 바꾸는 모양

RRF의 효과를 가상의 예로 눈에 보이게 하면 이렇다. “XR-2200 배터리 교체”라는 질문에서 —

              벡터 검색 순위   BM25 순위    RRF 점수(1/(60+r) 합)
배터리 일반 가이드      1위          8위        0.0164 + 0.0147 = 0.0311
XR-2200 매뉴얼        7위          1위        0.0149 + 0.0164 = 0.0313  ← 역전
XR-3000 매뉴얼        2위         12위        0.0161 + 0.0139 = 0.0300

벡터만 보면 ‘배터리 일반 가이드'(뜻이 비슷)가 1등이지만, BM25가 XR-2200이라는 글자를 정확히 잡아준 덕에 RRF 합산에서 매뉴얼이 올라온다. 두 검색이 각자 다른 것을 보고, 병합이 그 시야를 합친다 — 하이브리드의 효과가 이 세 줄에 다 있다.

리랭커가 꼭 필요할까

필수는 아니다. 하이브리드만으로 충분한 경우도 많다. 다만 문서가 많고 ‘정답이 3위 아래에 자주 묻힌다‘ 싶으면 리랭커가 확 끌어올린다. 비용과 지연이 늘어나니, 먼저 하이브리드로 재보고 부족할 때 얹는 순서를 권한다. 여기서도 원칙은 같다 — 측정 없이 넣지 말 것. 앞 편 청킹과 함께 검색 품질의 두 축이다.

이게 왜 중요하냐면, 애매한 걸 스무 개씩 프롬프트에 밀어넣으면 답이 오히려 흐려지고 돈도 더 든다. 진짜 관련 있는 서너 개만 남기면 답이 또렷해지고 비용도 준다. 리랭킹은 한 번 더 호출하는 만큼 지연이 붙으니, 검색만으로 이미 충분히 정확하다면 굳이 안 넣어도 된다. 반대로 후보는 그럴듯한데 순위가 자꾸 어긋난다면 리랭킹이 제일 확실한 약이다.

자주 묻는 질문 (FAQ)

벡터 검색만으로는 왜 부족한가요?

벡터는 의미는 잘 잡지만 정확한 키워드·고유명사·숫자에는 약합니다. 그래서 키워드(BM25) 검색과 결합한 하이브리드 검색 + 리랭킹이 더 안정적입니다.

리랭커(reranker)는 꼭 필요한가요?

필수는 아닙니다. 다만 1차 검색 결과를 정밀 재정렬해 상위 정확도를 크게 끌어올립니다. 지연·비용이 늘어나는 트레이드오프를 보고 도입 여부를 정하세요.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다