Naive RAG (기본 RAG)

1. Naive RAG (기본 RAG)

1.1 Naive RAG란 무엇인가요?

Naive RAG는 RAG의 출발점입니다. “Naive”라는 단어는 “순진한” 또는 “단순한”이라는 뜻인데, 말 그대로 가장 단순하고 직관적인 방식으로 RAG를 구현한 것입니다. 복잡한 기법 없이 “검색하고, 찾은 내용을 AI에게 주고, 답변을 받는다”는 RAG의 핵심 아이디어만 그대로 구현합니다.

Naive RAG의 동작 흐름을 한 문장으로 요약하면 이렇습니다. 사용자가 질문하면, 그 질문을 벡터로 변환(임베딩)한 후,  데이터베이스에서 유사한 벡터를 가진 문서 조각을 찾아서(Top-K), 그 문서 조각과  질문을 함께 LLM에게 전달합니다. LLM은 전달받은 문서를 참고해서 답변을 생성합니다.

1.2 Naive RAG는 어떻게 동작하나요?

RAG의 이름은 영어 Retrieval-Augmented Generation의 약어이고, RAG를 구성하는 세 단어가 뒤에서 다룰 두 단계의 핵심 과정을 담고 있습니다.

구체적으로 보면, Retrieval(검색)은 실행 단계에서 질문을 벡터로 변환하여 유사한 문서 조각을 찾는 부분에 해당합니다. Generation(생성)은 그 검색된 조각들을 LLM에게 전달하고 LLM이 답변을 생성하는 부분입니다. Augmented(증강)는 이 두 과정의 관계를 설명하는 단어로, LLM의 기본 생성 능력을 외부 검색을 통해 보강한다는 의미입니다.

준비 단계(인덱싱)는 RAG 이름 자체에는 직접 포함되지 않지만, Retrieval(검색)이 가능하도록 사전에 준비해야 하는 필수 기반 단계입니다. 즉, 인덱싱 없이는 검색(Retrieval)이 일어날 수 없으므로 중요한 역할을 하지만, RAG의 이름은 실행 시점에서의 핵심 메커니즘인 “검색 → 생성”에 초점을 맞추고 있습니다.

준비 단계(인덱싱)에서는 문서를 일정한 크기(페이지, 문단 등)로 나눈 후, 각 문서 조각을 임베딩을 통해 숫자 배열(벡터)로 변환합니다. 이렇게 변환하면 조각들 간의 유사도를 계산할 수 있습니다. 예를 들어 “오늘 날씨가 좋다”와 “오늘 기후가 화창하다”라는 두 문장이 의미적으로 유사하다는 것을 알 수 있습니다. 이 원리는 단어뿐 아니라 문장, 문단 단위로도 확장됩니다. 이렇게 문서를 나누어 얻은 문서 조각을 숫자 배열(벡터)로 변환한 후, 벡터 데이터베이스에 저장합니다.

실행 단계(검색 및 생성)에서는 사용자가 질문을 하면 질문을 숫자 배열(벡터)로 변환하여 데이터베이스에 저장된 모든 문서 조각의 숫자 배열(벡터)과 비교해서 유사한 문서 조각들을 찾습니다. 예를 들어 상위 5개의 유사한 조각을 찾아 LLM에게 “이 자료를 참고해서 답변해줘”라고 전달합니다. LLM은 전달받은 문서 조각을 참고하여 사용자의 질문에 맞는 자연스러운 답변을 생성합니다.

1.3 Naive RAG의 핵심: 언제 실패하는지 이해하기

Naive RAG를 공부하는 진짜 목적은 “잘 동작할 때”를 이해하는 것이 아니라 “언제 실패하는지”를 이해하는 것입니다. Naive RAG의 실패 패턴을 이해해야 왜 Advanced RAG가 필요한지 깨닫게 됩니다.

실패 패턴 1: 컨텍스트 과다 (Context Overload)

LLM에는 한 번에 처리할 수 있는 텍스트 양의 제한이 있습니다. 이를 “컨텍스트 윈도우”라고 부릅니다. 검색 결과가 너무 많거나 각 문서가 너무 길면, 텍스트 크기 제한 너머에 존재하는 중요한 정보가 LLM에게 전달되지 못할 수 있습니다. 

예를 들어 “회사 복지 제도에 대해 알려줘”라고 질문했는데, 검색 결과로 복지 관련 문서 20개가 나왔다고 가정해봅시다. 이 20개 문서를 모두 LLM에게 전달하면 어떻게 될까요? 첫째, 컨텍스트 윈도우를 초과해서 일부가 전달되지 못합니다.  둘째, LLM이 너무 많은 정보 속에서 핵심을 파악하지 못하고 두서없는 답변을 할 수 있습니다. 셋째, 처리해야 할 토큰이 많아져서 비용이 증가합니다. 

실패 패턴 2: 관련 없는 문서 포함 (Irrelevant Document Inclusion)

벡터 유사도 검색은 “의미적으로 비슷한” 문서를 찾지만, “질문에 답하는 데 필요한” 문서를 찾는 것은 아닙니다. 이 둘은 미묘하게 다릅니다.

예를 들어 “Python에서 리스트 정렬하는 방법”을 검색했는데, “Python 리스트의 역사와 설계 철학”이라는 문서가 높은 유사도로 검색될 수 있습니다. 둘 다 “Python”과 “리스트”라는 키워드를 공유하니까요. 하지만 사용자가 원하는 것은 정렬 방법이지, 역사가 아닙니다. 이런 관련 없는 문서가 컨텍스트에 포함되면 LLM이 혼란스러워하거나, 잘못된 정보를 바탕으로 답변할 수 있습니다.

실패 패턴 3: 모호한 질문 처리 실패

Naive RAG는 질문을 있는 그대로 검색에 사용합니다. 사용자가 “그거 어떻게 해?”라고 물으면, “그거”가 무엇인지 알 수 없어서 엉뚱한 문서를 찾아올 수 있습니다. 또한 “연봉 어떻게 됨?”처럼 구어체로 물으면, 문서에 있는 “급여 체계”, “보상 정책”같은 표현과 매칭이 안 될 수 있습니다.

실패 패턴 4: 정보가 여러 문서에 분산된 경우

“A 제품과 B 제품의 차이점은?”이라는 질문에 답하려면 A 제품에 대한 문서와 B 제품에 대한 문서가 모두 필요합니다. 하지만 Naive RAG의 단순한 검색으로는 두 정보를 균형 있게 가져오지 못할 수 있습니다. A 제품 문서만 5개 검색되고 B 제품 문서는 하나도 없을 수 있습니다. 

1.4 Naive RAG의 장점

이런 한계에도 불구하고 Naive RAG에는 분명한 장점이 있습니다.

첫째, 구조가 간단하기 때문에 이해하기 쉽고 구현하기도 쉽습니다. RAG를 처음 배우는 사람이 개념을 익히기에 가장 좋은 방법입니다. 복잡한 파이프라인 없이 핵심 원리를 파악할 수 있습니다.

둘째, 빠르게 프로토타입을 만들 수 있습니다. “RAG가 우리 서비스에 적합한지” 테스트해보고 싶을 때, 며칠 안에 동작하는 시스템을 만들어서 검증할 수 있습니다.

셋째, 단순한 질문에는 충분히 잘 동작합니다. FAQ 챗봇처럼 “배송 기간이 얼마나 걸려요?”, “반품은 어떻게 하나요?”같은 명확하고 단순한 질문에 답하는 용도라면 Naive RAG만으로도 좋은 성능을 낼 수 있습니다.

1.5 Naive RAG가 가르쳐주는 것

Naive RAG의 진정한 가치는 “왜 Advanced RAG가 필요한지”를 깨닫게 해준다는 것입니다. Naive RAG를 직접 구현하고 운영해보면, “검색 결과가 왜 이렇게 엉뚱하지?”, “왜 관련 없는 문서가 섞여 들어오지?”, “질문을 조금만 바꿔서 검색하면 더 좋은 결과가 나오는데…”라는 생각을 하게 됩니다. 이런 문제의식이 바로 Advanced RAG로 발전하는 동기가 됩니다.

따라서 RAG를 제대로 배우고 싶다면, Naive RAG부터 시작해서 그 한계를 직접 경험해보세요. 그래야 이후에 배울 다양한 기법들이 왜 필요한지, 어떤 문제를 해결하는지 체감할 수 있습니다.

댓글 남기기