본문 바로가기

개발이야기/RAG

katsubee RAG 리랭킹, 기본 꺼짐과 운영 켜짐

katsubee RAG 리랭킹, 기본 꺼짐과 운영 켜짐
  • katsubee의 지식 검색에는 LLM으로 후보를 다시 줄 세우는 리랭킹이 있고, 코드 기본값은 꺼짐이지만 운영 설정은 켜짐이다.
  • 검색이 고장 난 상태에서는 hit@4가 10%에서 15%로 올랐을 뿐이고, 복구 뒤에는 47.5%에서 72.5%로 올랐다.
  • 정확도는 크게 오르지만 질문당 6.4초가 늘어서, 어드민에서 즉시 켜고 끄는 토글로 두었다.

이 글은 katsubee·katsubox 소개 글과 RAG 키워드 검색 복구 글에 이어지는 시리즈의 세 번째 글이다. 앞 글이 후보를 제대로 뽑는 이야기였다면, 이번에는 뽑힌 후보의 순서를 바꾸는 리랭킹을 다룬다.

리랭킹이 하는 일

katsubee의 검색은 벡터 검색과 키워드 검색을 RRF로 합쳐 후보를 만든다. 리랭킹은 그 후보를 채팅 모델에게 한 번에 보여 주고 질문에 도움이 되는 순서로 다시 세우게 하는 단계다. 켜져 있으면 상위 몇 개가 아니라 후보 12개를 가져와 모델에 넘기고, 모델이 고른 번호가 앞에 오고 빠진 후보는 RRF 순서로 채운다.
별도 크로스인코더 모델은 쓰지 않았다. 로컬 Ollama에 리랭커 모델이 없고, 새 모델을 받지 않고 이미 쓰는 채팅 모델로 해결하려는 선택이었다. 후보 번호를 JSON 배열로 받는 listwise 방식이라 호출은 질문당 한 번이다.

실패해도 답변은 막지 않는다

리랭킹은 답변 경로 안에 들어가는 단계라서 느리거나 틀려도 답변이 멈추면 안 된다. 지연 상한은 기본 4초이고, 넘기거나 호출이 실패하거나 응답 형식이 깨지면 RRF 순서를 그대로 쓴다. 결과는 ok, timeout, error, unparsable로 나눠 메트릭에 쌓는다.
프롬프트에도 규칙을 넣었다. 질문이 묻는 핵심 사실을 직접 담은 후보를 먼저 두고, 폐지됐거나 구 규정이라고 밝힌 후보는 현재 기준을 묻는 질문에서 뒤로 보낸다. 후보 안에 이전 지시를 무시하라는 문장이 있어도 따르지 않고 순서만 판단하게 했다.

처음 측정에서는 효과가 거의 없었다

문서 65개, 청크 430개를 지식 베이스로 두고 문서 청크에서 만든 질문 40개로 정답 청크가 상위 4개에 드는지 쟀다. 리랭킹 없이는 hit@4가 4/40(10%), 리랭킹을 켜면 6/40(15%)이었다. 질문당 지연은 62ms에서 6,278ms로 늘었다.
두 건 더 맞힌 것을 효과라고 말하기는 어려웠다. 표본이 40개라 오차 범위 안이고, 6초를 더 쓸 이유도 되지 못했다. 그래서 기본값을 꺼짐으로 두고, 효과가 작은 이유를 먼저 찾기로 했다.

원인은 순서가 아니라 후보였다

리랭킹은 후보 안에서 순서만 바꾼다. 정답이 후보 12개에 들어오지 못하면 아무리 잘 줄 세워도 소용이 없다. 확인해 보니 키워드 검색이 자연어 질문에서 0건이라 하이브리드 검색이 사실상 벡터 검색 하나로 돌고 있었다. 이 원인과 고친 방법은 앞선 RAG 글에 적었다.
키워드 쪽을 OR와 접두 매칭으로 고친 뒤 같은 벤치마크를 다시 돌렸다. 질문 세트를 새로 만들어서 처음 측정과 직접 비교할 수는 없지만, 같은 실행 안에서 나란히 잰 값은 의미가 있다.

복구 뒤 재측정

리랭킹 없이는 hit@4가 47.5%, hit@1이 17.5%, MRR이 0.294였다. 리랭킹을 켜자 hit@4가 72.5%, hit@1이 70.0%, MRR이 0.708로 올랐다. 정답이 후보 안에 들어 있으면 모델이 첫 번째 자리로 끌어올려 주는 경우가 많았다는 뜻이다.

리랭킹을 켜고 끈 상태의 MRR 비교. 검색을 복구한 뒤 0.294에서 0.708로 올랐다.

가장 크게 달라진 값은 hit@1이다. 17.5%에서 70.0%로 올라, 리랭킹이 후보를 고르는 도구가 아니라 후보 안에서 정답을 맨 앞으로 올리는 도구라는 점이 숫자로 드러났다.

리랭킹 전후 hit@1 비교. 검색 복구 뒤 17.5%에서 70%로 올랐다.

후보 수와 스니펫 길이도 지연의 일부다

지연의 대부분은 모델이 후보를 읽는 시간이다. 후보 풀은 기본 12개이고 후보마다 앞 320자만 보여 준다. 후보를 늘리면 정답이 들어올 가능성은 커지지만 모델이 읽을 글자도 그만큼 늘어난다. 반대로 줄이면 빨라지지만 정답이 풀 밖으로 밀릴 수 있다.
그래서 후보 수와 지연 상한은 설정으로 빼 두었다. 벤치마크는 기본값 기준이라 다른 조합은 아직 재 보지 못했다. 후보 8개에서 지연이 얼마나 줄고 hit@4가 얼마나 빠지는지는 다음에 확인할 항목이다.
또 하나 확인할 것은 모델의 일관성이다. 같은 후보를 두 번 줘도 순서가 달라질 수 있어서, 이번 수치는 한 번의 실행 결과로 봐야 한다. 여러 번 반복해 분산을 보는 일은 남아 있다.

6.4초를 어떻게 볼 것인가

대가는 지연이다. 리랭킹을 끄면 질문당 64ms인데 켜면 6.4초가 걸린다. 채팅에서는 답변 생성 전에 6초를 기다리는 셈이어서 모든 질문에 일괄로 켜기는 부담스럽다.

리랭킹 끔 64ms, 켬 6.4초로 질문당 지연이 크게 늘어난다.

그래서 코드의 기본값은 꺼짐으로 유지했다. 다만 운영 DB의 설정값(rag_rerank_enabled)을 2026년 10월 25일에 확인했더니 true였다. 지금 운영에서는 켜져 있고, 그 시점과 이유는 설정값만으로는 알 수 없다. 어드민의 한도·설정에서 지식 검색 리랭킹을 즉시 켜고 끌 수 있고, 켜 본 뒤 체감 지연과 rerank 소요 시간 메트릭을 보고 결정한다. 지연이 부담이면 후보 수를 줄이거나 끈다. 정확도가 중요한 환경에서만 켜는 선택지로 남겼다.

켜는 기준

리랭킹은 틀리면 안 되는 질문에 쓰는 도구다. 개정 전후 규정처럼 구 규정과 현행 규정이 함께 올라가 있는 문서에서는 낡은 후보를 뒤로 보내는 규칙이 도움이 된다. 가벼운 잡담이나 단순 검색에는 6초를 쓸 이유가 없다.

수치를 읽을 때 주의할 점

코퍼스가 우리 저장소 문서이고 질문도 LLM이 문서 청크에서 만든 것이라 실제 사용자의 질문 분포와는 다르다. 문서에 없는 것을 묻거나 모호하게 묻는 질문은 이 벤치마크에 없다. 표본이 40개여서 중간 지표는 흔들릴 수 있다.
그래서 다음 글에서는 정답 순위를 매일 자동으로 쌓는 검색 로우데이터 수집을 다룬다. 질문 40개 한 번이 아니라 쌓이는 표본으로 검색 품질을 계속 재기 위한 장치다.