
재현율(Recall) 60%가 정확도(Accuracy) 90%를 의미했을 때: RAG 측정에 관한 이야기
요약
RAG 시스템에서 검색 재현율(Recall)과 답변 정확도(Accuracy) 사이의 불일치 현상을 분석합니다. 하이브리드 검색과 리랭커 도입만으로는 해결되지 않는 성능 격차의 원인을 탐구합니다.
핵심 포인트
- 재현율이 낮아도 답변 정확도가 높게 나타나는 역설적 상황 발생
- 하이브리드 검색과 리랭커 도입이 재현율 개선에 한계가 있음을 확인
- 단순 지표보다 리트리버가 가져온 실제 청크의 내용을 직접 검토하는 것이 중요
- 정답 정보가 검색된 다른 청크에 포함되어 있을 가능성 고려 필요
검색 재현율(Retrieval recall)은 0.60에 머물러 움직이지 않았습니다. 하이브리드 검색(Hybrid search)도 아무런 도움이 되지 않았습니다. 리랭커(Reranker)는 단 하나의 질문만을 구제했을 뿐이며, 그 대가로 쿼리당 몇 초의 시간을 소모했습니다. 모든 것을 마침내 설명해 준 숫자는 그 어떤 기술에서도 나오지 않았습니다. 그것은 리트리버(Retriever)가 실제로 무엇을 가져왔는지 읽어보는 것에서 나왔습니다.
공존해서는 안 될 두 숫자
payments-rag는 두 개의 SEPA 결제 규칙서에 대한 작은 RAG 시스템입니다. 한 가지 평가(Eval)는 레이블이 지정된 페이지가 검색된 상위 5개 청크(Chunks) 안에 포함되는지 확인합니다. 다른 하나는 최종 답변이 정확한지 확인합니다.
두 평가는 서로 일치하지 않았습니다. Recall@5는 0.60, 즉 10개 중 6개로 나타났습니다. 답변 평가는 100점 만점에 84.8점으로, 90%의 통과율을 보였습니다. 만약 올바른 페이지가 10번 중 4번이나 상위 5위 안에 들지 못한다면, 어떻게 10번 중 9번의 답변이 괜찮게 나올 수 있을까요? 그 격차가 바로 이야기의 핵심이었습니다.
하이브리드 검색: 개선 효과 없음
하이브리드 검색(Hybrid retrieval)은 당연한 첫 번째 시도였습니다. 벡터 유사도(Vector similarity)와 키워드 검색(Keyword search)을 결합하는 방식입니다. (첫 번째 실행은 어처구니없는 이유로 고장 난 것처럼 보였습니다. Postgres의 plainto_tsquery가 기본적으로 모든 쿼리 단어를 AND로 연결했기 때문입니다. 실제 측정 전에 연산자를 수정했습니다.)
공정한 결과는 0.60에서 0.60이었습니다. 변화가 없었습니다. 벡터 검색이 기본값으로 유지되었습니다.
리랭커(Reranker)의 한계
리랭커(Reranker)는 유행하는 다음 단계였고, 실제로 수치를 0.60에서 0.70으로 올렸습니다. 하지만 0.70은 무작위로 도달한 지점이 아니었습니다.
리랭커는 가져올 수 있는 모든 페이지를 상위 5위 안으로 올렸습니다. 나머지 누락된 것들은 애초에 검색되지 않았기 때문에, 아무리 순서를 재조정해도 그들에게 도달할 수 없었습니다. 메커니즘을 이해하기 위해 구축할 가치는 있지만, 쿼리당 몇 초의 비용이 들며 평가용으로만 머물게 됩니다.
누락된 것은 누락이 아니었다
재현율(Recall)의 실패는 매우 다른 두 가지 유형의 실패를 숨기고 있습니다. 즉, 콘텐츠가 검색되었으나 순위가 낮게 매겨졌거나, 혹은 아예 검색되지 않았거나 둘 중 하나입니다. 재순위화(Reranking)와 하이브리드(Hybrid) 방식은 검색된 결과의 순서만 바꿀 뿐이므로, 두 번째 유형의 실패에는 영향을 미칠 수 없습니다. 이 둘을 구분하기 위해, 저는 네 가지 실패 사례 각각에 대해 검색(Retrieval)을 다시 실행하고, 검색된 모든 청크(Chunk)의 전체 텍스트에서 정답 팩트(Fact) 자체를 검색했습니다. 라벨링된 페이지가 아니라, 바로 그 팩트 말입니다.
네 가지 중 세 가지는 제가 라벨링하지 않은 페이지의 검색된 청크 안에 해당 팩트가 포함되어 있었습니다. 저의 골든 셋(Golden set)은 여러 페이지 중 하나의 올바른 페이지를 가리키고 있었고, recall@5는 검색기가 다른 올바른 페이지를 찾아냈다는 이유로 검색기에 벌점을 부여했습니다. 저는 화요일 내내 시스템이 고장 났다고 확신하며 시간을 보냈습니다. 하지만 고장 난 것이 아니었습니다.
"top-k 내의 라벨링된 페이지" 대신 "검색된 모든 청크 내 팩트 존재 여부"를 계산하자, 검색 점수는 9/10로 나타났으며, 이는 정답 평가(Answer eval)의 통과율과 정확히 일치했습니다. 두 수치가 일치하게 된 것입니다.
네 번째 실패 사례인 통화(Currency)가 진짜 문제입니다. "Euro"는 검색된 어떤 청크에도 나타나지 않았으며, 통화는 정답 평가에서 0점을 기록한 유일한 질문이었습니다. 모든 LLM은 SEPA가 유로화로 운영된다는 것을 알고 있음에도 불구하고, 모델은 근거가 되는 청크(Grounded chunk)가 없다는 이유로 답변을 거부했습니다. 인용 도구(Citation tool)로서는, 학습된 지식으로 공백을 메우는 것보다 명확하게 실패를 드러내는 것이 더 낫습니다.
거친 청크(Coarse chunks): 왜 페이지 순위가 낮은가
애초에 왜 올바른 페이지의 순위가 낮게 매겨졌을까요? 페이지 크기의 각 청크는 수백 개의 단어를 임베딩(Embedding)하며, 정답을 주변의 법적 구조(Legal scaffolding)와 함께 평균화해 버립니다. 사용자의 문구가 명세서(Specification) 자체의 문구에서 멀어질수록 해당 청크의 순위는 낮아집니다. 26페이지에 있는 하나의 팩트가 세 가지 문구로 검색되었을 때의 예시입니다:
같은 사실입니다. 순위(rank)는 당신의 문구가 명세(spec)와 얼마나 떨어져 있는지를 추적합니다.
전이되는 요소
- 튜닝을 하기 전에 "순위가 낮음(ranked low)"과 "검색되지 않음(never fetched)"을 분리하세요. 재순위화(Reranking)와 하이브리드(hybrid) 방식은 검색된 집합을 재정렬할 뿐이며, 누락된 페이지를 마법처럼 불러올 수는 없습니다. 여기서는 두 방식 모두 잘못된 문제를 목표로 삼았습니다.
- 문헌상의 수치는 그대로 적용되지 않습니다. 대규모 코퍼스(Big-corpus)에서의 하이브리드 이득은 2개의 문서와 10개의 질문으로 구성된 세트에는 아무런 의미가 없습니다. 작은 코퍼스는 다르게 동작하며, 10개의 질문은 노이즈가 많은 척도입니다.
- 골든 세트(golden set)를 하나의 페이지가 아닌 사실(fact)에 맞춰 레이블링하세요. 단 하나의 "정답" 페이지를 기준으로 삼으면 실제 적중(hits)을 유령 미스(phantom misses)로 바꾸게 되며, 이것이 바로 이 두 수치가 서로 불일치하게 된 근본적인 이유입니다.
정직한 격차
주의 사항 하나: 어떤 청크에든 사실이 포함되어 있는지 확인하는 소프트 재현율(soft recall)은 여전히 수동 점검 방식이며, 자동화된 평가(built eval)가 아닙니다. 현재로서는 엄격한 6/10 방식을 적용합니다.
나는 이번 주를 시작하며 리트리버(retriever)가 정답을 60%의 확률로 찾는다고 생각했습니다. 하지만 리트리버는 90%의 확률로 정답을 찾고 있었습니다. 틀린 것은 리트리버가 아니라 지표(metric)였습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기


