Back to Blog
RAGRetrieval-Augmented GenerationVector StoreEmbeddingCSV

0x01. Simple RAG - 검색 증강 생성의 기본 구조

RAG의 기본 파이프라인(문서 로딩 → 청킹 → 임베딩 → 검색 → 생성)을 이해하고, CSV 데이터와 신뢰성 있는 RAG 구현까지 알아본다.

LLM은 학습 데이터에 포함되지 않은 정보에 대해서는 답변하지 못하거나, 그럴듯하지만 틀린 답변(Hallucination)을 생성한다. 회사 내부 문서, 최신 뉴스, 개인 데이터처럼 LLM이 본 적 없는 정보를 다뤄야 한다면 어떻게 해야 할까?

RAG(Retrieval-Augmented Generation, 검색 증강 생성) 는 이 문제에 대한 가장 실용적인 해답이다. 외부 지식 소스에서 관련 정보를 검색하고, 이를 LLM의 생성 과정에 주입하여 정확하고 근거 있는 답변을 만들어낸다. 모델을 재학습시키지 않고도, 최신 정보나 도메인 특화 지식을 활용할 수 있다는 점이 핵심이다.


RAG의 기본 파이프라인

RAG는 크게 세 단계로 작동한다. 인덱싱(Indexing), 검색(Retrieval), 생성(Generation).

RAG의 핵심 아이디어는 단순하다. "질문에 답하기 전에, 먼저 관련 자료를 찾아서 읽는다." LLM에게 오픈북 시험을 치르게 하는 것과 같다.

1단계: 인덱싱 (Indexing)

인덱싱은 RAG 시스템의 사전 준비 단계다. 나중에 빠르게 검색할 수 있도록 문서를 가공하여 저장하는 과정이다.

  1. 문서 로딩(Document Loading): PDF, 웹 페이지, 텍스트 파일 등 다양한 형식의 문서를 읽어들인다.
  2. 청킹(Chunking): 문서를 일정한 크기의 조각(Chunk)으로 분할한다. LLM의 컨텍스트 윈도우에는 한계가 있기 때문에, 문서 전체를 한 번에 넣을 수 없다. 적절한 크기로 나눠야 검색 정확도도 높아진다.
  3. 임베딩(Embedding): 각 청크를 벡터(Vector) 로 변환한다. 텍스트의 의미를 수백 차원의 숫자 배열로 표현하는 것이다. 의미가 비슷한 텍스트는 벡터 공간에서 가까운 위치에 놓인다.
  4. 벡터 저장소(Vector Store)에 저장: 변환된 벡터들을 벡터 데이터베이스(예: Chroma, Pinecone, FAISS)에 저장한다. 이 데이터베이스는 유사도 기반 검색에 최적화되어 있다.

도서관에 비유하면, 인덱싱은 새 책이 들어왔을 때 내용을 분류하고 색인 카드를 만들어 서가에 꽂아두는 작업이다.

2단계: 검색 (Retrieval)

사용자가 질문을 던지면, 검색 단계가 시작된다.

  1. 질문 임베딩: 사용자의 질문을 인덱싱 때와 동일한 임베딩 모델로 벡터로 변환한다.
  2. 유사도 검색: 질문 벡터와 벡터 저장소에 저장된 청크 벡터들 사이의 코사인 유사도(Cosine Similarity) 등을 계산하여, 의미적으로 가장 유사한 청크 K개를 가져온다.

여기서 중요한 점은 키워드 매칭이 아닌 의미 기반 검색이라는 것이다. "자동차 사고"로 질문해도 "교통 충돌"이라는 표현이 담긴 문서를 찾아낼 수 있다. 임베딩이 단어의 표면적 형태가 아닌 의미를 포착하기 때문이다.

3단계: 생성 (Generation)

검색된 청크들을 질문과 함께 LLM의 프롬프트에 담아 전달한다. 프롬프트는 보통 다음과 같은 구조를 가진다.

다음 컨텍스트를 참고하여 질문에 답하시오.

[컨텍스트]
{검색된 청크 1}
{검색된 청크 2}
...

[질문]
{사용자의 질문}

LLM은 자신의 사전 학습 지식이 아닌, 프롬프트에 제공된 컨텍스트를 근거로 답변을 생성한다. 이를 통해 Hallucination을 줄이고, 특정 문서에 기반한 정확한 답변을 만들어낼 수 있다.


CSV 파일과 RAG: 정형 데이터 다루기

RAG는 비정형 텍스트 문서만을 위한 것이 아니다. 기업의 재무 데이터, 고객 목록, 제품 카탈로그 등 표(Table) 형식의 정형 데이터도 RAG로 다룰 수 있다.

CSV를 RAG에 적용하는 방법

핵심 아이디어는 CSV 파일의 각 행(row)을 하나의 '문서'로 취급하는 것이다.

예를 들어, 다음과 같은 CSV 데이터가 있다고 하자.

제품명가격재고
노트북150만원30개
키보드8만원120개

각 행을 텍스트로 변환하면 이렇게 된다.

"제품명: 노트북, 가격: 150만원, 재고: 30개"
"제품명: 키보드, 가격: 8만원, 재고: 120개"

이 텍스트 덩어리들을 각각 임베딩하여 벡터 저장소에 넣으면, "재고가 가장 많은 제품은?" 같은 자연어 질문으로 정형 데이터를 검색할 수 있게 된다.

왜 유용한가?

SQL을 모르는 비개발자도 자연어로 데이터에 질문할 수 있다는 것이 가장 큰 장점이다. 데이터 분석가가 아니더라도 "지난달 매출이 가장 높은 지역은?"처럼 직관적으로 물어볼 수 있다.

다만, 주의할 점이 있다. 벡터 유사도 검색은 정확한 수치 비교나 집계 연산에는 한계가 있다. "가격이 정확히 150만원인 제품"처럼 정밀한 필터링이 필요한 경우, 벡터 검색만으로는 부족할 수 있다. 이런 경우에는 Text-to-SQL 방식이나 하이브리드 접근이 더 적합하다.


Reliable RAG: 신뢰할 수 있는 답변 만들기

기본 RAG만으로는 부족한 경우가 있다. 검색된 문서가 질문과 관련이 없거나, LLM이 컨텍스트를 무시하고 자체적으로 답변을 생성하는 경우다. 특히 금융, 의료, 법률처럼 정확성이 생명인 분야에서는 답변의 신뢰성을 보장하는 추가적인 장치가 필요하다.

Reliable RAG는 "답변을 잘 생성하는 것"뿐만 아니라, "답변이 틀릴 수 있다는 것을 인지하고 대처하는 것"까지 포함한다.

출처 명시 (Citation)

답변을 생성할 때 어떤 문서의 어떤 부분을 참고했는지 출처를 함께 제공한다. 사용자는 출처를 확인하여 답변의 근거를 직접 검증할 수 있다. 학술 논문이 참고 문헌을 다는 것과 같은 원리다.

자체 신뢰도 평가 (Faithfulness Score)

LLM이 생성한 답변이 검색된 컨텍스트와 얼마나 일치하는지 내부적으로 평가한다. 이를 Faithfulness Score(충실도 점수) 라고 한다. 점수가 기준치 이하로 떨어지면, 답변이 부정확할 수 있음을 사용자에게 경고한다.

이 메커니즘은 LLM이 컨텍스트에 없는 내용을 지어내는 Hallucination을 감지하는 데 효과적이다.

정보 부족 시 답변 거절

검색된 정보가 질문에 답하기에 불충분할 경우, 억지로 답변을 생성하지 않는다. 대신 "제공된 정보로는 해당 질문에 답변할 수 없습니다"와 같이 솔직하게 거절한다.

이것이 왜 중요한가? 틀린 답변을 자신 있게 제시하는 것은 답변하지 않는 것보다 훨씬 위험하기 때문이다. 특히 의사 결정에 영향을 미치는 분야에서는 "모른다"고 말할 수 있는 능력이 신뢰성의 핵심이다.


정리

RAG는 LLM의 한계를 외부 지식으로 보완하는 가장 실용적인 패턴이다. 핵심 내용을 요약하면 다음과 같다.

  • 기본 파이프라인: 문서를 청크로 나누고 임베딩하여 벡터 저장소에 저장(인덱싱) → 질문과 유사한 청크 검색(검색) → 검색된 컨텍스트와 질문을 LLM에 전달하여 답변 생성(생성)
  • CSV 데이터 활용: 정형 데이터의 각 행을 텍스트 문서로 변환하면 자연어 질의응답이 가능해진다. 다만 정밀한 수치 비교에는 한계가 있다.
  • 신뢰성 확보: 출처 명시, 충실도 평가, 정보 부족 시 답변 거절 등의 장치로 RAG의 신뢰도를 높인다.

다음 글에서는 RAG의 검색 품질을 끌어올리는 Advanced RAG 기법들 -- 쿼리 변환, 리랭킹, 하이브리드 검색 등 -- 을 다룰 예정이다.