들어가기 전에
RAG의 성능을 평가했더니 점수가 낮게 나왔다고 가정해보겠습니다.
Recall이 낮을 수도 있고, 답변 정확도가 기대보다 떨어질 수도 있습니다. 사용자들이 계속 비슷한 질문을 다시 묻거나 답변에 도움이 되지 않았다는 평가를 남길 수도 있죠. 문제가 있다는 사실은 알게 되었습니다. 그런데 점수가 낮다는 것만으로는 무엇을 고쳐야 할지 알 수 없습니다.
임베딩 모델을 바꿔야 할까요? 문서를 나누는 방법을 바꿔야 할까요? 검색 결과를 더 많이 가져와야 할까요? 아니면 LLM에 전달하는 명령을 수정해야 할까요?
원인을 확인하지 않고 여러 설정을 한꺼번에 바꾸면 운이 좋을 때는 점수가 오를 수 있습니다. 하지만 어떤 변경이 효과가 있었는지는 알기 어렵습니다. 점수가 오히려 떨어졌을 때도 어느 부분을 되돌려야 하는지 판단하기 힘들죠.
RAG는 하나의 모델이 아니라 여러 과정이 이어진 구조입니다.
문서 준비
→ 문서 내용 읽기
→ 문서를 작은 조각으로 나누기
→ 질문과 관련된 조각 찾기
→ 검색 결과 순서 정하기
→ LLM에 전달할 내용 고르기
→ 답변 만들기
이 중 어느 한 곳에서 정보가 빠져도 최종 답변은 틀릴 수 있습니다.
그래서 RAG를 개선하려면 실패한 질문을 모아서 각 질문이 어느 단계에서 잘못되었는지 나눠봐야 합니다.
이처럼 오류 사례를 살펴보고 원인을 찾는 작업을 Error Analysis라고 합니다. 그리고 반복해서 나타나는 실패 원인을 일정한 기준으로 나눈 것을 Failure Taxonomy, 즉 실패 유형 분류라고 합니다.
이번 글에서는 어려운 용어보다 실제 RAG의 흐름을 따라가면서 실패 원인을 단계별로 나눠보겠습니다.
점수만 봐서는 어디를 고쳐야 할지 알 수 없습니다
다음과 같은 질문이 있다고 가정해보겠습니다.
질문: 입사 1년 미만 직원의 연차는 어떻게 발생하나요?
회사 규정에는 다음 내용이 있습니다.
입사 1년 미만인 직원은 1개월을 개근할 때마다 1일의 유급휴가가 발생합니다.
그런데 RAG가 다음과 같이 답했습니다.
입사 1년 미만인 직원에게는 연차가 발생하지 않습니다.
최종 답변은 틀렸습니다.
하지만 답변이 틀렸다는 사실만으로는 원인을 알 수 없습니다. 다음과 같은 가능성이 모두 있기 때문입니다.
회사 규정 문서가 RAG에 등록되지 않았을 수 있습니다.
- 문서를 읽어오는 과정에서 해당 문장이 빠졌을 수 있습니다.
- 문서를 나누면서 조건과 결론이 서로 다른 조각으로 나뉘었을 수 있습니다.
- 답이 들어 있는 조각이 검색 결과에 포함되지 않았을 수 있습니다.
- 검색은 되었지만 순위가 너무 낮았을 수 있습니다.
- 최종적으로 LLM에 전달할 내용을 고르는 과정에서 제외되었을 수 있습니다.
- 근거가 전달되었지만 LLM이 내용을 잘못 사용했을 수 있습니다.
- 결과는 모두 같은 오답이지만 고쳐야 하는 부분은 전혀 다릅니다.
문서가 등록되지 않았다면 문서 수집 과정을 고쳐야 합니다. 검색 순위가 낮다면 검색 방식이나 문서 순서를 다시 정하는 과정을 살펴봐야 합니다. 근거가 제대로 전달되었는데도 답변이 틀렸다면 LLM과 답변 생성 과정을 확인해야 하죠.
Error Analysis의 목적은 오답을 단순히 세는 것이 아닙니다.
정답을 만드는 데 필요한 정보가 어느 단계에서 사라졌는지 찾는 것입니다.
RAG의 흐름을 먼저 나눠보겠습니다
실패 유형을 만들기 전에 RAG가 답변을 만드는 흐름을 간단히 나눠보겠습니다.
1. 원본 문서를 준비합니다.
2. PDF나 웹 페이지에서 내용을 읽어옵니다.
3. 읽어온 내용을 작은 조각으로 나눕니다.
4. 질문과 가까운 문서 조각을 찾습니다.
5. 찾은 결과를 관련성이 높은 순서로 정리합니다.
6. 그중 일부를 골라 LLM에 전달합니다.
7. LLM이 전달받은 내용을 바탕으로 답변합니다.
여기서 작은 문서 조각을 청크라고 합니다.
PDF나 웹 페이지에서 글자와 표를 꺼내오는 작업은 파싱이라고 합니다. 질문과 관련된 문서를 찾는 과정은 검색 또는 Retrieval이라고 부릅니다.
용어가 어렵게 느껴질 수 있지만 역할은 단순합니다.
파싱
→ 문서를 읽을 수 있는 글로 바꾸는 과정
청킹
→ 긴 문서를 검색하기 좋은 크기로 나누는 과정
검색
→ 질문에 필요한 문서 조각을 찾는 과정
순서 조정
→ 찾은 문서 중 더 중요한 문서를 위로 올리는 과정
최종 문맥 구성
→ LLM에 실제로 보여줄 문서를 고르는 과정
답변 생성
→ 선택된 문서를 읽고 최종 답변을 만드는 과정
각 과정이 정상적으로 동작했는지 차례대로 확인하면 실패 원인을 찾기 쉬워집니다.
필요한 문서가 처음부터 없는 경우
가장 먼저 확인할 것은 답의 근거가 들어 있는 문서가 RAG에 등록되어 있는지입니다.
사용자는 최신 환불 정책을 물었지만 RAG에는 이전 정책만 등록되어 있을 수 있습니다. 사내 규정 문서 중 일부가 누락되었거나, 특정 부서의 문서만 수집되지 않았을 수도 있죠. 예를 들어 사용자가 다음과 같이 질문했습니다.
2026년에 변경된 출장비 기준을 알려주세요.
그런데 RAG에 등록된 문서는 2025년 출장비 규정뿐입니다.
이 경우 검색 방법을 아무리 개선해도 2026년 기준을 찾을 수 없습니다. 존재하지 않는 문서를 검색할 수는 없기 때문입니다.
이 유형의 실패는 다음과 같은 경우에 발생합니다.
- 필요한 문서가 아직 등록되지 않았습니다.
- 새로운 문서가 동기화되지 않았습니다.
- 특정 폴더나 저장소가 수집 대상에서 빠졌습니다.
- 삭제된 문서를 계속 참조하고 있습니다.
- 최신 문서 대신 이전 버전만 등록되어 있습니다.
- 접근 권한 때문에 일부 문서를 가져오지 못했습니다.
확인할 내용은 단순합니다.
- 답의 근거가 원본 자료에 실제로 존재하는가?
- 그 원본 자료가 RAG의 문서 목록에도 존재하는가?
- 현재 사용해야 할 문서 버전이 맞는가?
문서 자체가 없다면 개선해야 할 곳은 검색 모델이 아닙니다. 문서 수집, 동기화, 권한, 버전 관리 과정을 먼저 살펴봐야 합니다.
문서를 읽어오는 과정에서 정보가 빠진 경우
원본 문서는 등록되어 있지만 문서 내용을 읽어오는 과정에서 중요한 정보가 사라질 수도 있습니다.
PDF 파일을 예로 들어보겠습니다.
사람이 PDF를 열어보면 표 안에 다음과 같은 정보가 보입니다.
| 구분지원 | 금액 |
| 국내 출장 | 50,000원 |
| 해외 출장 | 100,000원 |
그런데 PDF에서 글자를 추출한 결과는 다음처럼 나올 수 있습니다.
구분 지원 금액
국내 출장
해외 출장
금액이 빠져버렸습니다. 이 상태에서 문서를 아무리 잘 나누고 검색해도 정확한 금액은 찾을 수 없습니다.
다음과 같은 문서에서 이런 문제가 자주 발생할 수 있습니다.
표가 많은 PDF
여러 열로 구성된 문서
스캔된 이미지 형태의 문서
그래프나 그림 안에 정보가 들어 있는 문서
복잡한 HTML 구조를 가진 웹 페이지
글자가 겹치거나 깨진 PDF
이 실패를 찾으려면 원본 문서와 실제로 저장된 텍스트를 비교해야 합니다.
원본에는 답이 있는가?
추출된 텍스트에도 같은 내용이 있는가?
표의 행과 열 관계가 유지되었는가?
제목과 본문 순서가 뒤섞이지 않았는가?
숫자, 날짜, 단위가 빠지지 않았는가?
원본에는 답이 있지만 추출된 텍스트에는 없다면 파싱 과정의 문제입니다.
이 경우에는 PDF 처리 도구를 바꾸거나, 표를 별도로 읽거나, 이미지 문서에 글자 인식 과정을 추가하는 방법을 검토해야 합니다.
문서를 나누면서 문맥이 끊긴 경우
긴 문서를 한 번에 검색하기 어려우므로 일반적으로 여러 개의 청크로 나눕니다.
그런데 문서를 나누는 위치가 좋지 않으면 정답에 필요한 내용이 서로 다른 청크로 분리될 수 있습니다.
원본 문서에 다음과 같은 내용이 있다고 가정해보겠습니다.
입사 1년 미만 직원의 연차 기준
1개월을 개근한 직원에게는 1일의 유급휴가가 발생합니다.
문서를 잘못 나누면 다음처럼 될 수 있습니다.
청크 1: 입사 1년 미만 직원의 연차 기준
청크 2: 1개월을 개근한 직원에게는 1일의 유급휴가가 발생합니다.
두 번째 청크만 보면 누구에게 적용되는 규정인지 알기 어렵습니다.
반대로 첫 번째 청크만 검색되면 실제 연차가 어떻게 발생하는지 알 수 없습니다.
다음과 같은 경우도 있습니다.
문장의 앞부분과 뒷부분이 서로 다른 청크로 나뉩니다.
표의 제목과 표 내용이 분리됩니다.
조항의 적용 대상과 실제 기준이 분리됩니다.
예외 조건과 본문이 서로 다른 청크에 들어갑니다.
질문에 필요한 여러 문장이 너무 멀리 떨어져 있습니다.
청킹 문제를 확인하려면 답이 들어 있는 청크만 보지 말고 앞뒤 청크도 함께 살펴봐야 합니다.
이 청크만 읽어도 의미를 이해할 수 있는가?
질문의 조건과 답이 같은 청크에 있는가?
제목이나 상위 항목이 함께 포함되어 있는가?
앞뒤 청크가 없으면 주어나 대상이 사라지지 않는가?
청킹이 원인이라면 청크 크기, 겹치는 범위, 문장을 나누는 기준을 조정할 수 있습니다.
문단 단위로 나누거나, 제목을 각 청크에 함께 넣거나, 작은 청크를 검색한 뒤 더 큰 상위 문단을 LLM에 전달하는 방법도 사용할 수 있습니다.
답이 들어 있는 문서가 검색되지 않은 경우
문서도 있고, 내용도 정상적으로 읽혔으며, 청크 안에 정답도 잘 들어 있습니다.
그런데 사용자의 질문을 입력했을 때 해당 청크가 검색 결과에 전혀 나타나지 않을 수 있습니다.
질문이 다음과 같다고 가정해보겠습니다.
계정 없애면 예전 주문 기록도 바로 지워지나요?
문서에는 다음과 같이 적혀 있습니다.
회원 탈퇴가 완료된 뒤 개인정보는 파기합니다.
다만 관계 법령에 따라 거래 기록은 5년간 보관합니다.
사용자는 계정 없애기, 예전 주문 기록이라는 표현을 사용했습니다. 문서에는 회원 탈퇴, 거래 기록이라는 표현이 사용되었습니다.
사람은 두 표현이 비슷하다는 것을 이해할 수 있지만 사용하는 검색 방식에 따라 관련 문서를 놓칠 수 있습니다.
다음과 같은 경우 검색 누락이 발생할 수 있습니다.
사용자와 문서가 서로 다른 표현을 사용합니다.
약어나 회사 내부 용어를 검색 모델이 이해하지 못합니다.
질문에 오타가 있습니다.
질문에 여러 조건이 함께 들어 있습니다.
숫자, 날짜, 버전 같은 조건을 놓쳤습니다.
검색 결과 수가 너무 적게 설정되어 있습니다.
문서에 설정된 필터가 잘못되었습니다.
이 유형인지 확인하려면 정답 청크가 최초 검색 결과에 포함되었는지 봐야 합니다.
예를 들어 상위 20개까지 검색했는데도 정답 청크가 없다면 검색 과정에서 놓친 것입니다.
정답 청크 존재: 예
상위 20개 검색 결과 포함: 아니요
판단:
검색 누락
이 경우에는 임베딩 모델, 키워드 검색, 질문 변환, 검색 결과 수, 필터 조건 등을 살펴볼 수 있습니다.
찾기는 했지만 순위가 너무 낮은 경우
정답 청크가 검색 결과에 포함되었더라도 순위가 너무 낮으면 실제 답변에는 사용되지 못할 수 있습니다.
예를 들어 최초 검색 결과가 다음과 같다고 가정해보겠습니다.
| 순위 | 검색 결과 |
| 1위 | 2025년 연차 규정 |
| 2위 | 연차 신청 절차 |
| 3위 | 휴가 사용 안내 |
| 4위 | 근태 관리 규정 |
| 5위 | 입사 1년 미만 직원의 연차 기준 |
정답 문서는 5위에 있습니다. LLM에 상위 3개만 전달한다면 정답 문서는 검색되었지만 최종 답변에는 사용되지 않습니다.
이 경우는 검색 누락과 다릅니다.
검색 누락
→ 정답 문서가 후보 결과에 아예 없음
순위 문제
→ 정답 문서는 후보에 있지만 너무 아래에 있음
순위가 낮아지는 이유는 다음과 같습니다.
질문과 비슷한 단어가 많은 문서가 위에 올라옵니다.
정답 청크가 너무 짧아 의미가 충분히 표현되지 않습니다.
연도나 대상 같은 중요한 조건이 검색 점수에 약하게 반영됩니다.
키워드 점수와 의미 검색 점수의 비율이 적절하지 않습니다.
문서 순서를 다시 정하는 모델이 질문을 잘못 판단합니다.
이 문제를 찾으려면 정답 청크의 순위를 기록해야 합니다.
최초 검색 순위: 5위
LLM에 전달하는 문서 수: 3개
판단:
정답 문서를 찾았지만 순위가 낮아 사용되지 못함
이 경우에는 검색 결과를 합치는 방식이나 Reranker, 즉 문서의 순서를 다시 정하는 과정을 개선할 수 있습니다.
최종 문맥을 만들면서 빠진 경우
정답 청크가 높은 순위로 검색되었는데도 LLM에 전달되지 않을 수 있습니다.
검색 결과를 그대로 모두 전달하는 것이 아니라, 중복을 제거하거나 길이를 줄이고, 정해진 글자 수 안에 들어오도록 다시 고르는 과정이 있기 때문입니다.
예를 들어 최초 검색 결과에는 정답 청크가 2위로 들어 있습니다.
1위: 연차 신청 절차
2위: 입사 1년 미만 직원의 연차 발생 기준
3위: 연차 사용 기한
4위: 연차 촉진 제도
5위: 미사용 연차 처리
그런데 최종적으로 LLM에 전달된 내용에는 2위 문서가 없습니다.
LLM에 전달된 문서:
1위, 3위, 4위
다음과 같은 이유로 제외될 수 있습니다.
중복 문서로 잘못 판단되었습니다.
글자 수 제한 때문에 뒤쪽 내용이 잘렸습니다.
문서를 합치는 과정에서 일부 내용이 빠졌습니다.
최종 문서 수를 줄이는 과정에서 제외되었습니다.
권한이나 보안 필터가 적용되었습니다.
긴 문서의 앞부분만 남고 정답 부분은 잘렸습니다.
이 유형은 검색 결과만 기록해서는 찾기 어렵습니다.
최초 검색 결과와 LLM에 실제로 전달된 내용을 따로 저장해야 합니다.
최초 검색 결과에 정답이 있는가?
→ 예
최종 전달 내용에 정답이 있는가?
→ 아니요
판단:
최종 문맥 구성 과정에서 제외됨
이 경우에는 검색 모델보다 문서 중복 제거, 길이 제한, 문서 선택 규칙을 확인해야 합니다.
근거가 있는데도 답변이 틀린 경우
마지막으로 답이 들어 있는 문서가 LLM에 제대로 전달되었는데도 틀린 답변이 나올 수 있습니다.
LLM에 다음 내용이 전달되었다고 가정해보겠습니다.
입사 1년 미만인 직원은 1개월을 개근할 때마다
1일의 유급휴가가 발생합니다.
그런데 답변은 다음과 같습니다.
입사 1년 미만인 직원은 1년이 지나야 연차를 사용할 수 있습니다.
정답을 만들 수 있는 정보가 충분히 주어졌는데도 내용을 잘못 사용했습니다. 다음과 같은 경우가 있을 수 있습니다.
LLM이 문서보다 자신이 알고 있던 내용을 우선했습니다.
여러 문서의 서로 다른 내용을 섞었습니다.
질문의 조건을 잘못 이해했습니다.
숫자나 날짜를 잘못 읽었습니다.
문서에 없는 내용을 추측해서 추가했습니다.
답변 형식을 따르느라 중요한 내용을 생략했습니다.
긴 문맥 안에서 정답 부분을 놓쳤습니다.
이 유형을 확인하려면 LLM에 전달된 문맥만으로 정답을 만들 수 있었는지 살펴봐야 합니다.
최종 문맥에 정답 근거가 있는가?
→ 예
생성된 답변이 근거와 일치하는가?
→ 아니요
판단:
답변 생성 과정의 문제
이 경우에는 프롬프트, 사용하는 LLM, 문서 배치 순서, 답변 검증 방법 등을 살펴봐야 합니다. 근거가 없는데 답변을 틀린 것과, 근거가 있는데도 틀린 것은 서로 다른 실패입니다.
같은 오답이라도 고쳐야 할 곳은 다릅니다
지금까지 살펴본 실패를 한 줄로 이어보면 다음과 같습니다.
문서가 없음
→ 문서는 있지만 읽지 못함
→ 읽었지만 잘못 나눔
→ 잘 나눴지만 검색하지 못함
→ 검색했지만 순위가 낮음
→ 순위는 높지만 최종 전달에서 빠짐
→ 전달은 했지만 답변을 잘못 만듦
최종적으로 사용자에게 보이는 결과는 모두 오답일 수 있습니다. 하지만 개선해야 할 부분은 단계마다 다릅니다.
| 실패한 위치 | 먼저 확인할 부분 |
| 문서 준비 | 수집 범위, 동기화, 문서 버전 |
| 문서 읽기 | PDF 처리, 표 추출, 글자 인식 |
| 문서 나누기 | 청크 크기, 문단 경계, 앞뒤 문맥 |
| 검색 | 임베딩, 키워드 검색, 질문 변환, 필터 |
| 순서 정하기 | 검색 점수 조합, Reranker |
| 최종 문맥 만들기 | 중복 제거, 길이 제한, 문서 선택 |
| 답변 만들기 | 프롬프트, LLM, 답변 검증 |
이렇게 나눠두면 오답이 발생했을 때 무조건 임베딩 모델부터 바꾸거나, 프롬프트부터 수정하는 일을 줄일 수 있습니다.
실패 유형은 어떻게 기록하면 좋을까요?
실패 유형을 만들었다면 실제 평가 결과에 표시할 수 있어야 합니다. 다음과 같은 형태로 기록할 수 있습니다.
failure_case = {
"question": "입사 1년 미만 직원의 연차는 어떻게 발생하나요?",
"expected_answer": "1개월 개근 시 1일의 유급휴가가 발생합니다.",
"generated_answer": "1년이 지나야 연차가 발생합니다.",
"source_document_exists": True,
"parsed_text_contains_answer": True,
"answer_chunk_exists": True,
"answer_chunk_retrieved": True,
"answer_chunk_rank": 2,
"answer_chunk_in_final_context": True,
"answer_supported_by_context": False,
"failure_type": "GENERATION_ERROR",
}
각 항목은 다음 질문에 답합니다.
source_document_exists
→ 원본 문서가 등록되어 있는가?
parsed_text_contains_answer
→ 읽어온 텍스트에 정답이 남아 있는가?
answer_chunk_exists
→ 답이 들어 있는 청크가 만들어졌는가?
answer_chunk_retrieved
→ 검색 결과에 정답 청크가 포함되었는가?
answer_chunk_rank
→ 정답 청크가 몇 위에 있었는가?
answer_chunk_in_final_context
→ LLM에 실제로 전달되었는가?
answer_supported_by_context
→ 답변이 전달된 근거와 일치하는가?
처음부터 모든 항목을 자동으로 판단하기는 어렵습니다.
평가 데이터가 적을 때는 사람이 실패 사례를 직접 확인하면서 표시해도 됩니다.
중요한 것은 완벽한 자동 분류 시스템을 만드는 것이 아니라 같은 기준으로 실패 원인을 계속 기록하는 것입니다.
간단한 규칙으로 실패 유형 나눠보기
기록된 정보를 이용하면 간단한 규칙으로 실패 유형을 나눌 수 있습니다.
def classify_rag_failure(case: dict) -> str:
if not case["source_document_exists"]:
return "DOCUMENT_MISSING"
if not case["parsed_text_contains_answer"]:
return "PARSING_LOSS"
if not case["answer_chunk_exists"]:
return "CHUNKING_LOSS"
if not case["answer_chunk_retrieved"]:
return "RETRIEVAL_MISS"
max_context_rank = case.get("max_context_rank", 5)
if case["answer_chunk_rank"] > max_context_rank:
return "RANKING_MISS"
if not case["answer_chunk_in_final_context"]:
return "CONTEXT_DROP"
if not case["answer_supported_by_context"]:
return "GENERATION_ERROR"
return "NO_FAILURE"
각 결과의 의미는 다음과 같습니다.
DOCUMENT_MISSING
→ 필요한 원본 문서가 없음
PARSING_LOSS
→ 문서를 읽는 과정에서 정답이 사라짐
CHUNKING_LOSS
→ 문서를 나누면서 정답 문맥이 깨짐
RETRIEVAL_MISS
→ 정답 청크가 검색되지 않음
RANKING_MISS
→ 검색은 되었지만 순위가 너무 낮음
CONTEXT_DROP
→ 최종 전달 내용을 만들면서 정답이 빠짐
GENERATION_ERROR
→ 근거가 전달되었지만 답변이 근거와 다름
이 코드는 실패 원인을 완벽하게 판단하는 도구는 아닙니다.
예를 들어 청킹 문제와 검색 문제는 동시에 발생할 수도 있습니다. 정답 문서가 여러 개라면 일부만 검색되었는지 별도로 확인해야 합니다. 생성된 답변이 일부만 맞는 경우도 있죠. 그래도 처음 Error Analysis를 시작할 때는 이런 단순한 기준표가 도움이 됩니다.
하나의 실패 원인만 고를 필요는 없습니다
실제 RAG에서는 여러 문제가 동시에 발생할 수 있습니다.
예를 들어 청크가 너무 작아서 의미가 부족해지고, 그 결과 검색 순위도 낮아질 수 있습니다.
청킹 문제
→ 청크에서 적용 대상이 사라짐
→ 질문과의 관련성이 낮게 계산됨
→ 검색 순위가 내려감
→ 최종 문맥에서 제외됨
이 경우 최종적으로는 CONTEXT_DROP이 발생했지만 시작점은 청킹일 수 있습니다.
그래서 실패 사례에는 하나의 결과만 기록하기보다 필요하다면 주된 원인과 함께 영향을 준 원인을 따로 표시할 수 있습니다.
failure_case = {
"primary_failure": "CHUNKING_LOSS",
"secondary_failures": [
"RANKING_MISS",
"CONTEXT_DROP",
],
}
다만 처음부터 너무 세밀하게 분류하면 관리하기 어려워질 수 있습니다.
먼저 가장 직접적인 실패 지점을 하나 고르고 반복해서 나타나는 사례가 많아졌을 때 세부 유형을 추가하는 편이 좋습니다.
자동 점수와 사람이 확인한 원인을 함께 봐야 합니다
검색 Recall이나 답변 정확도 같은 점수는 문제가 얼마나 자주 발생하는지 보여줍니다. 실패 유형 분석은 왜 문제가 발생했는지 보여줍니다. 두 가지는 역할이 다릅니다.
평가 점수
→ 문제가 얼마나 큰가?
실패 유형 분석
→ 어디에서 문제가 생겼는가?
예를 들어 Recall@5가 0.6이라는 사실만으로는 개선 방법을 결정하기 어렵습니다.
실패 질문 40개를 직접 확인했더니 다음과 같은 결과가 나올 수 있습니다.
| 실패 원인 | 질문 수 |
| 문서 누락 | 5개 |
| 파싱 문제 | 3개 |
| 청킹 문제 | 12개 |
| 검색 누락 | 8개 |
| 순위 문제 | 9개 |
| 답변 생성 문제 | 3개 |
이 결과에서는 임베딩 모델을 바로 교체하는 것보다 청킹과 순위 문제를 먼저 살펴보는 것이 효과적일 수 있습니다.
반대로 다음과 같은 결과라면 상황이 다릅니다.
| 실패 원인 | 질문 수 |
| 문서 누락 | 22개 |
| 파싱 문제 | 2개 |
| 청킹 문제 | 3개 |
| 검색 누락 | 5개 |
| 순위 문제 | 4개 |
| 답변 생성 문제 | 4개 |
이 경우에는 검색 방식을 개선하기 전에 빠진 문서를 먼저 등록해야 합니다.
좋은 Error Analysis는 감으로 수정할 부분을 고르는 대신, 실제 실패 수를 기준으로 우선순위를 정하게 해줍니다.
실패 사례를 볼 때 확인할 순서
실패한 질문을 분석할 때는 문서 준비 단계부터 차례대로 확인하는 것이 좋습니다.
1. 원본 문서에 답이 있는지 확인합니다.
2. 해당 문서가 RAG에 등록되어 있는지 확인합니다.
3. 읽어온 텍스트에 답이 남아 있는지 확인합니다.
4. 답이 들어 있는 청크가 만들어졌는지 확인합니다.
5. 정답 청크가 최초 검색 결과에 포함되었는지 확인합니다.
6. 정답 청크의 검색 순위를 확인합니다.
7. LLM에 실제로 전달된 내용에 포함되었는지 확인합니다.
8. 최종 답변이 전달된 근거와 일치하는지 확인합니다.
앞 단계가 실패했다면 뒤 단계를 확인할 필요가 없을 수도 있습니다. 원본 문서 자체가 없다면 검색 순위를 확인해도 의미가 없습니다. 정답 청크가 만들어지지 않았다면 LLM의 답변 생성 능력을 먼저 의심할 이유도 없죠.
이 순서대로 확인하면 실패 지점을 비교적 빠르게 좁힐 수 있습니다.
질문 유형도 함께 기록하면 더 잘 보입니다
실패 원인과 함께 질문의 유형도 기록하는 것이 좋습니다.
단순한 사실 질문
숫자나 날짜를 묻는 질문
조건이 여러 개 들어간 질문
두 대상을 비교하는 질문
여러 문서를 함께 봐야 하는 질문
표 안의 정보를 묻는 질문
이전 대화가 있어야 이해되는 질문
문서에 답이 없는 질문
예를 들어 전체적으로 검색 누락이 많아 보이지만, 자세히 확인하면 표 안의 숫자를 묻는 질문에서만 문제가 발생할 수 있습니다.
이 경우 임베딩 모델보다 표를 읽어오는 과정이 실제 원인일 가능성이 큽니다.
또는 단순 질문은 잘 처리하지만 여러 문서가 필요한 질문에서 Recall이 낮을 수도 있습니다. 평균 점수 하나만 보면 이런 차이가 가려질 수 있습니다.
실패 유형은 서비스에 맞게 바꿔야 합니다
모든 RAG가 같은 문서와 같은 질문을 다루는 것은 아닙니다. 사내 규정 RAG에서는 문서 버전과 적용 대상이 중요할 수 있습니다. 쇼핑몰 RAG에서는 상품 옵션, 재고, 가격의 최신 상태가 중요할 수 있습니다. 재무 문서에서는 숫자와 기간이 중요하고, 법률 문서에서는 조항과 예외 조건이 중요할 수 있습니다.
그래서 기본 실패 유형에 서비스에 맞는 항목을 추가할 수 있습니다. 예를 들어 사내 규정 RAG라면 다음 유형이 필요할 수 있습니다.
이전 버전 문서를 검색함
적용 대상이 다른 규정을 검색함
예외 조항을 함께 찾지 못함
쇼핑몰 RAG라면 다음 유형을 추가할 수 있습니다.
품절된 상품 정보를 답변함
옵션별 가격을 구분하지 못함
상품 설명과 배송 정책을 혼동함
중요한 것은 논문이나 도구의 분류를 그대로 가져오는 것이 아닙니다. 실제 서비스에서 반복해서 발생하는 실패를 기준으로 분류 체계를 만들어야 합니다.
중간 정리
| 실패 유형 | 어떤 상태인가 | 먼저 확인할 부분 |
| 문서 누락 | 답이 들어 있는 원본 문서가 없음 | 수집 범위, 동기화, 문서 버전 |
| 파싱 문제 | 원본에는 있지만 읽어온 내용에는 없음 | PDF 처리, 표 추출, 글자 인식 |
| 청킹 문제 | 답에 필요한 문맥이 여러 조각으로 끊김 | 청크 크기, 문단 경계, 겹치는 범위 |
| 검색 누락 | 정답 청크가 검색 결과에 없음 | 임베딩, 키워드 검색, 질문 변환, 필터 |
| 순위 문제 | 정답 청크가 있지만 너무 아래에 있음 | 점수 결합, Reranker |
| 최종 문맥 누락 | 검색되었지만 LLM에 전달되지 않음 | 문서 선택, 중복 제거, 길이 제한 |
| 답변 생성 문제 | 근거가 전달되었지만 답변이 틀림 | 프롬프트, LLM, 답변 검증 |
실패 원인을 찾을 때는 다음 질문을 순서대로 확인하면 됩니다.
답이 들어 있는 문서가 있는가?
문서에서 답을 제대로 읽어왔는가?
답이 이해 가능한 형태로 나뉘었는가?
정답 청크가 검색되었는가?
충분히 높은 순위에 있었는가?
LLM에 실제로 전달되었는가?
LLM이 근거에 맞게 답했는가?
이 질문에 답하다 보면 정보가 처음 사라진 지점을 찾을 수 있습니다.
마치며
RAG의 점수가 낮다는 사실은 문제를 발견하는 시작점입니다. 하지만 점수만으로는 무엇을 고쳐야 하는지 알 수 없습니다.
같은 오답이라도 필요한 문서가 없어서 발생할 수 있고, 문서를 읽는 과정에서 정보가 빠져서 발생할 수도 있습니다.
청킹으로 문맥이 끊기거나, 정답 문서가 검색되지 않거나, 검색 순위가 낮아서 LLM에 전달되지 않을 수도 있죠.
근거가 정상적으로 전달되었는데도 LLM이 잘못 답할 수도 있습니다. 그래서 실패한 질문을 다음과 같이 단계별로 나눠봐야 합니다.
문서 준비 문제인지
문서 처리 문제인지
청킹 문제인지
검색 문제인지
순위 문제인지
최종 문맥 구성 문제인지
답변 생성 문제인지
이렇게 실패 원인을 나누면 개선 방향도 분명해집니다.
문서가 없다면 수집 과정을 고치고, 표의 정보가 사라졌다면 문서를 읽는 방식을 고쳐야 합니다. 검색이 되지 않았다면 검색 방식을 살펴보고, 검색은 되었지만 순위가 낮다면 문서 순서를 조정하는 과정을 개선해야 합니다.
근거가 모두 전달되었는데 답변이 틀렸을 때 비로소 LLM과 프롬프트를 먼저 살펴볼 수 있습니다.
Error Analysis의 핵심은 모든 오답을 한 종류로 취급하지 않는 것입니다.
실패를 원인별로 나누고 개수를 세어보면, 전체 성능을 가장 많이 막고 있는 지점을 찾을 수 있습니다. 이 지점이 현재 RAG에서 먼저 해결해야 할 병목입니다.
그리고 병목을 찾은 다음에는 한 번에 여러 부분을 바꾸기보다 하나씩 변경해보면서 성능이 실제로 개선되는지 확인해야 합니다.
참고 자료
'AI' 카테고리의 다른 글
| [바미] 검색 결과는 몇 개까지 봐야 할까? - 상위 K개 평가 이해하기 (0) | 2026.07.25 |
|---|---|
| [바미] 좋은 RAG 평가는 좋은 문제에서 시작됩니다. (1) | 2026.07.24 |
| [바미] RAG가 틀렸을 때 RAG의 문제일까? LLM의 문제일까? (2) | 2026.07.23 |
| [바미] RAG 검색 성능은 어떻게 평가할까? - Precision부터 NDCG까지 (2) | 2026.07.22 |
| [바미] Claude Sonnet 5가 공개되었습니다. (0) | 2026.07.01 |