RAG 성능 개선 순서 — 무엇을 재고 어디를 고치나
RAG 성능 개선 방법을 순서대로 정리합니다. 검색 실패와 생성 실패를 가르고, 판정 데이터를 직접 만들고, Recall@k·nDCG·MRR로 기준선을 잰 뒤 한 번에 하나씩 고치는 루프를 다룹니다.
RAG 성능 개선은 모델을 더 좋은 것으로 바꾸는 일이 아니라, 어디가 틀렸는지 먼저 재는 일입니다. 사내 문서에 RAG를 한 번 붙여 봤지만 "검색이 제대로 안 걸린다", "왜 정확도가 안 오르는지 설명하지 못하겠다"에서 멈춘 팀이 많습니다. 이 글은 무엇을 재고 어디를 고칠지 순서를 잡는 방법을 다룹니다. 판정 데이터를 직접 만드는 절차, 지표 세 가지가 각각 보는 것과 놓치는 것, 한 번에 한 가지만 바꾸는 개선 루프까지입니다.
핵심 요약
- RAG는 질문과 관련된 사내 문서를 검색해 그 내용을 모델에 함께 넘겨 답하게 하는 구조입니다. 그래서 틀린 답의 상당수는 생성 이전, 정답 문서가 검색 결과에 없었던 데서 시작합니다.
- 고치기 전에 자를 만듭니다. 우리 질의에 정답 문서와 등급을 붙인 판정 데이터가 없으면 모든 개선이 느낌으로 남습니다.
- Recall@k는 넘길 k개 안에 정답이 들어왔는지, MRR은 첫 정답이 몇 번째인지, nDCG는 등급과 순위를 함께 봅니다. 한 지표만 보면 반드시 놓치는 것이 생깁니다.
- 기준선을 먼저 재고, 한 번에 한 가지만 바꾸고, 실험은 개발용 질의로만 합니다. 시험용 질의는 마지막에 한 번만 씁니다.
- 다음에 고칠 곳은 감이 아니라 쿼리 로그의 제로히트율·재검색률·실패 질의 목록에서 고릅니다.
RAG 성능 개선을 아무 데나 손대면 안 되는 이유
RAG가 엉뚱한 답을 내면 대부분의 팀이 제일 먼저 모델이나 프롬프트를 바꿉니다. 바꾸기 쉽고, 바꾸면 답의 문장이 달라져 뭔가 나아진 느낌이 들기 때문입니다. 그런데 정답이 적힌 문서가 애초에 검색 결과에 없었다면, 모델은 없는 근거로 답을 지어내거나 옆에 있던 문서로 얼버무릴 수밖에 없습니다. 생성 모델은 넘겨받은 문서 안에서만 답할 수 있습니다.
그래서 개선의 첫 갈림길은 "이 틀린 답이 검색 탓인가 생성 탓인가"입니다. 이 질문에 답하지 못한 채 손을 대면, 검색 문제에 프롬프트 처방을 쓰거나 생성 문제에 임베딩 모델을 바꾸는 일이 벌어집니다. 둘 다 효과가 없고, 효과가 없었다는 사실조차 기록에 남지 않습니다.
사내 문서 검색에서 자주 나오는 증상을 예로 들면 이렇습니다. "연가 신청 방법"을 물었는데 연차 규정이 아니라 회의록이 나온다면, 규정 문서가 상위에 오지 못한 검색 문제입니다. "E-1042 오류"를 물었는데 전혀 다른 오류 코드 문서가 나온다면, 숫자와 기호가 섞인 식별자를 검색어로 다루지 못하는 문제입니다. 반대로 정답 문서가 1위로 올라왔는데도 답이 문서 내용과 다르다면, 그때가 생성 쪽을 볼 차례입니다.
틀린 답이 검색 탓인지 생성 탓인지 어떻게 가르나요
가르는 방법은 단순합니다. 틀린 답 하나를 골라, 그 질문에 대해 시스템이 모델에게 넘긴 문서 목록을 그대로 펼쳐 놓고 눈으로 확인합니다. 정답이 적힌 문서가 그 목록 안에 있었는지만 보면 됩니다. 이 확인을 20~30건 반복하면 우리 시스템의 실패가 어느 쪽에 몰려 있는지가 드러납니다.
| 실패 유형 | 확인 방법 | 먼저 볼 곳 |
|---|---|---|
| 검색 실패 | 정답 문서가 상위 k개 안에 아예 없음 | 청크 방식, 토크나이저, 렉시컬·벡터 검색 구성 |
| 순위 밀림 | 정답 문서가 검색은 됐지만 모델에 넘기는 개수 밖에 있음 | 넘기는 개수, 재정렬(리랭크) 단계 |
| 생성 실패 | 정답 문서를 넘겼는데 답이 그 내용과 다름 | 문서를 넘기는 형식, 인용 지시, 문서 개수 과다 |
| 없는 답을 지어냄 | 코퍼스에 답이 없는 질문인데 그럴듯하게 답함 | 근거 없을 때 "모르겠습니다"라고 답하게 하는 규칙 |
경험적으로 사내 문서 RAG를 처음 붙인 구성에서는 위 표의 첫 두 줄이 대부분을 차지합니다. 그렇다고 해서 "우리도 그럴 것"이라고 가정하고 건너뛰면 안 됩니다. 30건만 직접 갈라 봐도 우리 시스템의 분포는 직접 확인할 수 있고, 그 분포가 앞으로 무엇을 고칠지 정합니다.
이 분류를 마치면 대책이 자동으로 좁혀집니다. 검색 실패가 절반을 넘으면 프롬프트를 아무리 다듬어도 소용이 없고, 반대로 검색은 잘 되는데 답이 문서와 다르다면 임베딩 모델을 바꿀 이유가 없습니다.
판정 데이터는 어떻게 직접 만드나요
판정 데이터(qrels)는 "이 질문에 대한 정답 문서는 이것이다"를 사람이 미리 적어 둔 표입니다. 이것이 있어야 구성을 바꿀 때마다 같은 자로 잴 수 있습니다. 만드는 절차는 다음과 같습니다.
- 실제로 들어온 질문을 모읍니다. 쿼리 로그가 있으면 거기서, 없으면 헬프데스크·담당자에게 "요즘 자주 받는 질문"을 받습니다. 지어낸 질문은 실제 표현의 거칢을 담지 못해 쓸모가 떨어집니다.
- 질의 50개 안팎으로 시작합니다. 문서 유형을 고루 덮도록 고르고, 답이 문서에 아예 없는 질문도 몇 개 섞습니다. 거절 동작을 시험할 때 쓰입니다.
- 각 질의마다 현재 검색의 상위 10건을 띄워 놓고 등급을 매깁니다. 2는 답이 그 문서 안에 들어 있음, 1은 관련은 있지만 답은 아님, 0은 무관입니다.
- 상위 10건 밖에 있을 정답 문서를 놓치지 않도록, 문서 제목 검색이나 담당자 확인으로 정답 후보를 따로 찾아 추가합니다. 현재 검색 결과만 보고 판정하면 지금 못 찾는 문서는 영원히 정답으로 등록되지 않습니다.
- 두 사람이 같은 질의 20개를 따로 판정하고 엇갈린 곳을 맞춰 봅니다. 엇갈린 이유를 판정 기준 문장으로 적어 두면 이후 판정이 흔들리지 않습니다.
- 마지막에 개발용과 시험용으로 나눕니다. 실험과 설정 선택은 개발용으로만 하고, 시험용은 최종 보고 때 한 번만 씁니다.
양식은 한 줄에 하나씩 쌓이는 형태가 다루기 편합니다.
{"qid": "q001", "query": "연가 신청은 며칠 전까지 해야 하나요", "doc_id": "hr-rule-014", "grade": 2}
{"qid": "q001", "query": "연가 신청은 며칠 전까지 해야 하나요", "doc_id": "faq-hr-221", "grade": 1}
{"qid": "q002", "query": "E-1042 오류 조치 방법", "doc_id": "manual-err-1042", "grade": 2}
{"qid": "q003", "query": "작년 보안 감사 결론이 뭐였죠", "doc_id": "none", "grade": 0}판정 기준 문장은 세 줄이면 충분합니다. 예를 들어 "답의 핵심 수치나 절차가 문서 안에 그대로 있으면 2", "주제는 같지만 다른 부서·다른 연도면 1", "개정 전 문서는 현행 문서가 따로 있으면 1"처럼 우리 문서의 실제 함정에 맞춰 적습니다.
Recall@k·nDCG·MRR 은 각각 무엇을 보고 무엇을 놓치나요
지표 하나로 검색 품질을 요약할 수는 없습니다. 세 가지가 서로 다른 각도를 보고, 각자 놓치는 것이 분명합니다.
| 지표 | 보는 것 | 놓치는 것 | RAG에서 쓰는 자리 |
|---|---|---|---|
| Recall@k | 상위 k개 안에 정답 문서를 몇 개나 가져왔는가 | 1위인지 10위인지 구분하지 않음 | 모델에 넘기는 개수가 k라면 가장 먼저 볼 주 지표 |
| MRR | 첫 정답이 몇 번째에 나왔는가 | 두 번째 이후의 정답을 보지 않음 | 정답이 하나뿐인 질문이 많을 때 순위 감각용 |
| nDCG@k | 등급(2·1·0)과 순위를 함께 반영해 좋은 문서가 위에 있는지 | 등급을 어떻게 매겼는지에 결과가 좌우됨 | 재정렬 단계의 효과를 볼 때 보조 지표 |
RAG에서는 순서가 있습니다. 모델에 넘길 문서가 5개라면, 그 5개 안에 정답이 들어오는 것이 먼저입니다. 그래서 Recall@5(또는 실제로 넘기는 개수 기준)를 주 지표로 두고, 순위를 다듬는 작업을 평가할 때 nDCG를 함께 봅니다. MRR은 "사용자가 결과 목록을 직접 볼 때" 체감에 가까운 지표라, 검색 결과를 사람에게 그대로 보여 주는 화면이 있다면 비중을 높입니다.
지표를 볼 때 같이 기록해야 하는 것이 하나 더 있습니다. 지연 시간입니다. 품질을 조금 올리는 대신 응답이 몇 배 느려지는 변경은 채택할 수 없는 경우가 많으므로, 질의당 평균과 p95(느린 쪽 100건 중 95번째)를 같은 표에 적습니다. 이 판단을 팀 전체가 같은 기준으로 하게 만드는 훈련은 에이전트 심화 과정에서 다룹니다.
기준선을 먼저 재는 이유와 기록 양식
기준선은 "지금 돌고 있는 구성"의 점수입니다. 아무것도 바꾸지 않은 상태를 먼저 재 두지 않으면, 나중에 무엇을 얼마나 개선했는지 말할 근거가 사라집니다. 기준선을 잴 때는 구성 요소를 전부 적어 둡니다. 청크 방식과 길이, 토크나이저, 임베딩 모델 이름과 버전, 검색 방식, 넘기는 개수까지입니다. 이 중 하나라도 빠지면 나중에 같은 조건을 재현할 수 없습니다.
실험 기록은 한 줄에 한 실험씩 쌓습니다. 표 형태로 남기면 나중에 정렬해서 보기 좋습니다.
날짜 바꾼 것 Recall@5 nDCG@10 MRR p95(ms) 판정
09-08 기준선(고정 800자·공백분리) 0.51 0.44 0.39 180 -
09-09 토크나이저를 형태소로 0.63 0.52 0.47 190 채택
09-10 청크를 400자로 줄임 0.60 0.50 0.45 185 기각
09-11 벡터 검색 추가 후 순위 결합 0.71 0.58 0.53 260 채택위 숫자는 양식을 보여 주기 위한 예시일 뿐, 어떤 구성이 얼마를 낸다는 뜻이 아닙니다. 점수의 절대값은 코퍼스와 판정 기준에 따라 크게 달라지므로, 다른 팀의 수치나 공개 벤치마크 점수와 비교하는 것은 의미가 없습니다. 비교 대상은 언제나 같은 판정 데이터로 잰 우리 기준선입니다.
한 번에 한 가지만 바꾸는 개선 루프
개선 루프는 네 걸음입니다. 지키기 어려운 것은 방법이 아니라 "한 번에 하나"라는 규율입니다.
- 실패 분류표에서 가장 많은 유형을 고르고, 그 유형에 듣는 변경 하나를 가설로 세웁니다. "청크를 제목 구조 기준으로 바꾸면 조항 번호 질의의 Recall@5가 오를 것"처럼 어느 지표가 움직일지 미리 적습니다.
- 그 하나만 바꾸고 개발용 질의로 전체를 다시 잽니다. 두 가지를 같이 바꾸면 효과의 출처를 알 수 없고, 나중에 되돌릴 때도 무엇을 되돌려야 할지 모릅니다.
- 지표와 지연 시간을 기록표에 한 줄 추가하고 채택·기각을 적습니다. 나빠진 시도도 반드시 남깁니다. 기각 기록은 다음 사람이 같은 실험을 반복하는 것을 막아 주는 자산입니다.
- 실패 분류를 다시 하고 1번으로 돌아갑니다. 한 유형을 고치면 실패 분포가 바뀌므로, 다음에 고칠 곳도 바뀝니다.
이 루프에서 가장 많이 어기는 규칙은 시험용 질의를 중간에 들여다보는 것입니다. 개발용 결과가 애매할 때 "시험용으로도 한번 재 보자"는 유혹이 생기는데, 그 순간 시험용은 개발용이 됩니다. 최종 구성을 확정한 뒤 한 번만 재고, 개발용보다 점수가 크게 떨어지면 개발용 질의에 과하게 맞춘 것이므로 무엇에 맞췄는지 한 줄 적어 둡니다.
다음에 고칠 곳을 쿼리 로그에서 고르는 법
판정 데이터는 우리가 미리 정한 질문만 담습니다. 실제 사용자는 그 바깥을 묻습니다. 그래서 운영이 시작되면 쿼리 로그가 다음 개선 지점을 알려 주는 가장 좋은 재료가 됩니다.
세 가지 숫자를 주기적으로 봅니다. 제로히트율은 검색 결과가 0건인 질의의 비율로, 토크나이저나 동의어 사전이 사내 약어를 못 따라가고 있다는 신호인 경우가 많습니다. 재검색률은 사용자가 결과를 받고 곧바로 말을 바꿔 다시 물은 비율로, 결과가 나오긴 했지만 쓸모없었다는 뜻입니다. 인용 검사 실패율은 답에 달린 인용이 실제 넘긴 문서 안에 없거나 근거가 맞지 않은 비율입니다.
이 숫자가 올라간 구간의 질의를 뽑아 판정 데이터에 추가하는 주기와 담당자를 정해 두면, 평가 세트가 시간이 지날수록 실제 사용에 가까워집니다. 추가 주기는 2주나 한 달처럼 짧게 잡고, 한 번에 5~10개씩 늘리는 정도가 유지하기 좋습니다. 다만 쿼리 로그 자체에 개인정보나 사내 기밀이 섞일 수 있으므로 보관 기간과 마스킹 규칙을 함께 정해야 합니다.
자주 겪는 착각
첫째, 모델을 바꾸면 좋아진다는 착각입니다. 임베딩 모델이나 생성 모델을 바꾸는 것은 한 줄 설정 변경이라 제일 먼저 손이 갑니다. 하지만 공개 순위표에서 높은 모델이 우리 한국어 사내 문서에서도 높다는 보장은 없습니다. 순위표는 후보를 서너 개로 줄이는 데만 쓰고, 최종 선택은 우리 판정 데이터로 재서 합니다. 그리고 임베딩 모델을 바꾸면 전체 문서를 다시 색인해야 하므로, 효과를 재기 전에 비용부터 확인해야 합니다.
둘째, 청크만 줄이면 된다는 착각입니다. 조각을 잘게 쪼개면 검색 점수는 올라가 보일 수 있지만, 모델에 넘어가는 문맥이 짧아져 답이 부실해지는 교환이 따라옵니다. 청크는 검색 단위인 동시에 생성 입력이라 한쪽만 보고 정할 수 없습니다. 분할 방식을 우리 문서로 재서 고르는 방법은 RAG 청크 사이즈와 분할 전략에 따로 정리했습니다.
셋째, 검색 결과를 많이 넘기면 안전하다는 착각입니다. 넘기는 개수를 늘리면 정답이 포함될 확률은 오르지만, 관련 없는 문서가 함께 들어가 모델이 엉뚱한 근거를 고르거나 비용과 지연이 늘어납니다. 넘기는 개수는 Recall@k와 답 품질, 지연을 같이 보고 정하는 값입니다. 문맥을 얼마나 넣을지에 대한 일반적인 판단 기준은 컨텍스트 윈도우 관리도 참고할 만합니다.
넷째, 한번 만들어 두면 끝이라는 착각입니다. 문서는 계속 개정되고, 개정 전 문서가 코퍼스에 남아 있으면 옛 규정이 정답처럼 검색됩니다. 삭제와 갱신이 색인에 반영되는 경로를 만들어 두지 않으면 시간이 지날수록 품질이 조용히 내려갑니다. 문서마다 갱신일을 메타데이터로 달아 두고, 같은 주제의 문서가 여럿일 때 최신본을 위로 올리는 규칙을 검색 단계에 넣어 두는 편이 안전합니다.
다섯째, 개선 폭을 미리 약속할 수 있다는 착각입니다. 같은 변경이라도 코퍼스의 성격과 기준선 구성에 따라 효과가 크게 달라집니다. 어떤 팀에서는 토크나이저 교체만으로 체감이 달라지고, 어떤 팀에서는 아무 차이가 없습니다. 그래서 대외적으로 말할 수 있는 것은 "얼마나 오른다"가 아니라 "무엇을 재서 어떻게 판단하는지"입니다. 수치를 약속하는 대신 측정 절차를 약속하는 편이 결국 더 빨리 신뢰를 얻습니다.
정리
RAG 성능 개선의 순서는 재기, 가르기, 하나씩 고치기입니다. 판정 데이터로 자를 만들고, 틀린 답을 검색 실패와 생성 실패로 가르고, 가장 많은 실패 유형에 듣는 변경 하나만 바꿔 같은 자로 다시 재는 일을 반복합니다. 이 순서를 지키면 "무엇을 바꿔 무엇이 얼마나 좋아졌는지"를 항상 말할 수 있고, 효과가 없던 시도까지 팀의 자산으로 남습니다.
이어서 볼 만한 글은 다음과 같습니다. 검색 결과를 얼마나 넘길지 정하는 감각은 컨텍스트 윈도우 관리에, 사내 지식을 모델에 붙이는 다른 방식은 도메인 지식과 컨텍스트에 있습니다. 완성된 검색 기능을 도구로 노출해 에이전트가 직접 호출하게 만들려면 MCP 가이드가 출발점입니다. 청크 설계만 따로 보려면 RAG 청크 사이즈와 분할 전략로 이어집니다. 사내 검색 품질을 팀 과제로 놓고 측정·개선 루프를 함께 돌려 보는 과정은 에이전트 심화 과정에서 다룹니다.
자주 묻는 질문
이 주제를 실습으로 다루는 교육
- P-16 RAG 검색 엔지니어링 (2일)판정 데이터로 청크·BM25·임베딩·하이브리드 검색·리랭커의 효과를 재며 사내 검색을 고친다과정 보기
- AI 에이전트 개발 교육 — 수준별 로드맵반나절 만들기 워크숍부터 설계·평가·보안 1일 심화, 멀티에이전트·MCP·업종별 실전까지과정 보기
우리 팀에 맞는 과정이 무엇인지 모르겠다면 커리큘럼 찾기로 4문항만 답하거나, 무료 상담 신청을 남겨 주세요.