
RAG(Retrieval-Augmented Generation)가 무엇인지 알아보고 ,
어떤 구성 요소로 이루어져 있는지 LangChain 기반 RAG 파이프라인을 직접 구현해볼 것입니다.
1. RAG란?
RAG(Retrieval-Augmented Generation)란 무엇이고, 왜 필요할까
RAG란?
- RAG는 LLM이 이미 머릿속에 외우고 있는 지식(내부 가중치)에만 의존하지 않고, 질문을 받는 순간 외부의 거대한 서고에서 관련된 책을 찾아(Retrieval) 그 내용을 참고하여 답변을 생성(Generation)하는 기술입니다.
- 검색으로 찾은 외부 지식을 LLM에 주입(agumented)하여 응답을 생성(generation)하는 방법입니다.
- 해당 방법은 LLM의 내부 가중치(파라메트릭 메모리)에만 의존하지 않고 외부 문서를 결합하여 답변을 생성하는 구조를 가집니다.
- 파라메트릭 메모리(Parametric Memory): 모델이 학습을 통해 뇌 세포(가중치)에 새겨넣은 장기 기억입니다.
- 논-파라메트릭 메모리(Non-parametric Memory): 모델 외부(Vector DB 등)에 저장된 백과사전이나 최신 문서들입니다. RAG는 이 두 가지를 결합합니다.
RAG가 필요한 이유는?
- 토큰 제한을 극복할 수 있습니다. (좁은 책상 vs 무한한 창고)
- 문서가 수백,수천건으로 늘어나면 LLM이 처리할 수 있는 컨텍스트가 초과하게 되는데 RAG는 필요한 정보만 찾아서 제공하기에 이를 극복할 수 있습니다.
- 비용 및 운영 효율성을 높혀줍니다.
- 모델을 다시 학습시키는 것(fine-tuning)은 막대한 컴퓨팅 자원이 필요하지만, RAG는 문서 저장소(vector DB)만 업데이트하면 즉시 반영해줍니다.
⇒ RAG는 수천 권의 책 중 질문에 딱 맞는 '포스트잇 몇 장'만 골라냅니다. 좁은 책상 위에는 그 포스트잇만 올려주면 되기 때문에, 전체 문서가 아무리 방대해도 모델은 무리 없이 정확한 답을 내놓을 수 있습니다.
- 비용 및 운영 효율성을 높일 수 있습니다.
- 새로운 지식이 생길 때마다 모델을 다시 학습시키는 것(Fine-tuning)은 학생에게 교과서 전체를 다시 외우게 하고 시험을 다시 치게 하는 것과 같습니다. 시간과 돈(컴퓨팅 자원)이 엄청나게 듭니다.
⇒ RAG는 학생 옆에 최신 백과사전을 놓아주는 '오픈북 테스트' 방식입니다. 지식이 바뀌면 사전의 페이지만 갈아 끼우면 됩니다. 모델을 새로 가르칠 필요가 없어 훨씬 경제적이고 빠릅니다.
- 할루네이션(환각)을 방지할 수 있습니다.
- LLM은 학습 데이터가 없다면 내용을 그럴듯하게 지어내는 경향이 있는데 , 외부의 신뢰할 수 있는 데이터베이스를 참조함으로써 응답의 정확성과 신뢰성을 높일 수 있습니다.
- 근거 기반 답변: RAG는 답변을 생성하기 전 신뢰할 수 있는 외부 문서를 먼저 읽습니다. "이 문서에 근거해서 답해줘"라고 명령하는 것과 같기 때문에, 근거 없는 거짓말을 할 확률이 현격히 줄어듭니다.
- 출처 제시: 답변과 함께 참고한 문서의 링크나 출처를 제공할 수 있어 사용자가 정보의 신뢰도를 직접 검증할 수 있습니다.
⇒ RAG는 답변하기 전에 반드시 '참조 서류'를 먼저 읽습니다. "이 서류의 3페이지에 따르면..."이라고 답하게 하므로 지어낼 확률이 줄어듭니다.
- 정보의 최신성을 유지할 수 있습니다.
- LLM의 학습 시점 이후에 발생하는 정보를 알 수 없는 한계가 존재하는데 , 문서 저장소 갱신을 쉽게 해결할 수 있습니다.
- 학습 기반 모델: 어제 일어난 뉴스나 오늘 아침의 주가 정보를 물으면 엉뚱한 대답을 하거나 모른다고 합니다.
- RAG 기반 모델: 실시간 뉴스나 최신 데이터베이스에서 정보를 먼저 찾은 뒤 답변하므로, 모델을 새로 학습시키지 않고도 최신 정보를 제공할 수 있습니다.
System Prompt와 RAG 방식의 차이는 무엇인가?
: System Prompt와 RAG는 모두 LLM의 답변을 제어하는 기술이지만, '데이터를 어디에 담아두느냐'와 '얼마나 많은 정보를 처리하느냐'에서 결정적인 차이가 있습니다.
(1) System Prompt
→ 답변의 ‘형식’과 ‘태도’를 결정하는 데 특화되어 있습니다.
- 특징 : 모든 대화의 시작점에 위치하며, 대화 내내 모델이 유지해야 할 규칙입니다.
- 장점 : 구현이 쉽고 추가 비용이 많이 들지 않습니다.
- 한계 : 방대한 양의 데이터를 넣으면 토큰 비용이 급증하고 ,모델이 뒤쪽의 명령어를 잊어버리는 ‘중간 유실’ 현상이 발생할 수 있습니다.
(2) RAG
→ 모델이 학습하지 않은 ‘새로운 지식’이나 ‘방대한 문서’를 참조하며 , 답변의 내용과 근거를 보강하는데 특화되어 있습니다.
- 특징 : 사용자의 질문이 들어오는 순간, 수만개의 문서 중 관련된 것만 골라내어 프롬프트에 동적으로 넣어줍니다.
- 장점 : 실시간 정보 업데이트가 가능하며, 수천 페이지의 메뉴얼도 처리할 수 있습니다.
- 한계 : 검색 시스템(Vector DB, Embedding) 구축을 위한 인프라 비용과 기술적 복잡도가 따릅니다.
| 구분 | System Prompt (시스템 프롬프트) | RAG (검색 증강 생성) | 비고 |
|---|
| 데이터 위치 | 프롬프트 상단 (컨텍스트 윈도우 내부) | 외부 데이터베이스 (Vector DB 등) | 컨텍스트 vs 외부 저장소 |
| 용량 제한 | 모델의 토큰 제한에 걸림 (매우 작음) | 사실상 무제한 (수백만 개 가능) | 확장성 측면에서 RAG 우세 |
| 제공 방식 | 사람이 직접 수동으로 삽입 | 질문에 맞는 문서 자동 검색/제공 | 자동화 및 워크플로우 차이 |
| 비용 효율성 | 매 요청마다 전체 토큰 소모 (고비용) | 필요한 청크만 사용하여 비용 절약 | 운영 효율성 극대화 |
| 유지보수 | 지식 변경 시 프롬프트 수동 수정 | DB 갱신 시 자동으로 최신 반영 | 최신성 유지에 유리 |
RAG 파이프라인의 전체 흐름
[ Indexing(문서 → 청크 → 벡터 → 저장) + Retrieval(질문 → 검색 → 생성) ]
1.Indexing ( 색인 과정 → 도서관 구축 단계 )
→ 외부 데이터를 검색 가능한 형태로 준비하는 단계입니다. ( 델이 나중에 정보를 잘 찾을 수 있도록 데이터를 미리 정리해서 창고에 넣는 과정 )
→ 단순한 단어 매칭(키워드 검색)이 아닌, 텍스트의 맥락을 이해하는 '의미론적 검색(Semantic Search)'을 가능하게 만드는 사전 준비 과정입니다
- 문서 로딩 (Document)
- 외부 지식으로 활용할 원본 데이터(PDF, 텍스트, 웹 문서 등)를 시스템으로 불러옵니다.
LangChain 프레임워크에서는 Document Loader(예: PyPDFLoader)가 이 역할을 수행합니다.
- 도서관에 새로운 수만권의 책을 들이는 과정이라고 생각하면됩니다.
- 청킹 (Chunking)
- 로딩된 긴 문서를 모델이 처리하기 좋은 적절한 크기의 조각(Chunk)으로 분할합니다. 보통 200~1000 토큰 크기로 나누며, 문맥이 끊어지는 것을 방지하기 위해 청크 간에 일부분이 겹치도록(overlap) 설정합니다.
- 두꺼운 책을 한 장 한 장 낱개 페이지로 분리하는 과정입니다.
- 임베딩 (Embedding)
- 분할된 텍스트 청크를 컴퓨터가 의미를 계산할 수 있도록 부동 소수점 숫자의 배열(벡터)로 변환합니다. 텍스트의 의미가 비슷할수록 벡터 공간 내에서 서로 가까운 거리를 가지게 됩니다.
- 각 페이지의 내용을 분석해 '정치', '경제', '요리' 같은 좌표 값을 매기는 작업입니다.
- 벡터 저장 (Vector Store)
- 임베딩된 벡터 데이터를 전용 데이터베이스에 저장합니다. FAISS, Chroma, Pinecone 등과 같은 벡터 저장소는 수많은 벡터 중에서 질문과 가장 유사한 벡터를 매우 빠르게 찾아내는 근사 최근접 이웃(ANN) 검색 연산에 최적화되어 있습니다
- 좌표 값이 매겨진 페이지들을 찾기 쉽게 전용 서고에 꽂아두는 것입니다.
2.Retrieval & Generation ( 검색 및 생성: 실시간 답변 단계 )
→ 사용자의 질문에 대해 실제 응답을 반환하는 실시간 처리 과정입니다. ( 사용자가 질문했을 때 창고에서 정보를 꺼내 답변을 만드는 과정 )
- 질문 벡터화 ( Query Embedding )
- 사용자가 질문을 입력하면, 시스템은 문서를 임베딩할 때 사용했던 것과 동일한 임베딩 모델을 사용하여 사용자의 질문을 벡터로 변환합니다.
- 사용자가 "어제 축구 결과 알려줘"라고 하면, 이 질문의 핵심 의미 좌표를 계산합니다.
- 검색 (Retrieval)
- 질문 벡터와 벡터 저장소에 저장된 문서 벡터들 간의 코사인 유사도(Cosine similarity)를 계산하여, 의미적으로 가장 관련성이 높은 상위 K개(Top-K)의 문서 청크를 추출합니다.
- 비서가 창고로 달려가 질문 좌표와 가장 비슷한 위치에 꽂힌 페이지 3~5장을 뽑아옵니다.
- 생성 (Generation)
- 검색을 통해 얻은 외부 문서 조각(Context)들을 원래의 사용자 질문과 결합하여 LLM에 전달할 새로운 프롬프트를 구성합니다. LLM은 이렇게 제공된 신뢰할 수 있는 외부 지식을 바탕으로 답변을 생성하므로, 사실이 아닌 내용을 지어내는 환각(Hallucination) 현상을 방지하고 정확한 답변을 제공하게 됩니다.
- 비서가 질문과 함께 뽑아온 페이지들을 모델의 책상 위에 올려두며 말합니다. "이 페이지들을 참고해서 답변해줘.", 그리고 학생이 비서가 가져다준 페이지를 보고 정확한 근거를 바탕으로 답안지를 작성합니다.
2. RAG에서 사용되는 용어
RAG에서 사용되는 용어
Chunking
- 긴 원본 문서를 LLM이 처리하기 좋은 크기의 작은 텍스트 조각으로 분할하는 과정을 말합니다.
chunk_size
- 분할되는 하나의 텍스트 조각 크기(예: 토큰 수)를 결정합니다.
chunk_overlap
- 조각이 나뉠 때 문맥이 손실되는 것을 방지하기 위해 앞뒤 청크 간 일부분이 겹치도록 설정하는 크기를 의미합니다.
Embedding
- 텍스트의 의미를 컴퓨터가 이해하고 거리를 계산할 수 있도록 부동 소수점 숫자의 배열(벡터)로 변환하는 기술입니다.
- 주요 임베딩 모델
| 모델 계열 | 모델명 | 특징 및 장점 | 기본 차원 (Dimensions) | 비고 |
|---|
| OpenAI | text-embedding-3-small | 가성비와 성능의 균형이 가장 뛰어난 모델입니다. 이전 세대(ada-002)보다 성능은 높고 비용은 저렴합니다. | 1,536 | 차원 축소 가능 |
| OpenAI | text-embedding-3-large | 가장 높은 성능을 제공하는 최신 모델로, 복잡한 다국어 작업 및 전문 지식 검색에 유리합니다. | 3,072 | 차원 축소 가능 |
| Google | Gecko (text-embedding-004) | 구글의 최신 모델로, 매우 가벼우면서도 검색 성능이 뛰어납니다. 한국어 포함 다국어 지원이 강력합니다. | 768 | Vertex AI 기반 |
| Open Source | BGE / E5 (HuggingFace) | HuggingFace에서 제공되는 모델들로, 특정 도메인에 맞춰 직접 튜닝(Fine-tuning)이 가능하며 보안이 중요한 폐쇄망 환경에 적합합니다. | 384 ~ 1,024 | 로컬 서버 운영 가능 |
Vector Store
- 임베딩된 고정 차원 벡터 데이터들을 저장하고 유사도 기반 검색을 고속으로 수행하는 전용 데이터베이스입니다.
- 주요 벡터 저장소(Vector Store) 비교
| 저장소명 | 유형 | 주요 특징 | 적합한 사용 환경 |
|---|
| FAISS (Meta) | 라이브러리 | 초고속 벡터 연산(ANN), 별도 서버 없이 로컬 동작 | 로컬 개발, 소규모 프로젝트, 고성능 연산 필요 시 |
| Chroma | 오픈소스 DB | 설치 간편, 내장 임베딩 지원, 직관적인 사용법 | 프로토타입 개발, 가벼운 오픈소스 DB 선호 시 |
| Pinecone | Managed (SaaS) | 완전 관리형 클라우드 서비스, 뛰어난 대규모 확장성 | 상용 서비스, 인프라 관리 부담을 줄이고 싶은 경우 |
| Qdrant | 오픈소스 DB | Rust 기반 고성능, 강력한 필터링(Payload) 기능 | 정교한 조건이 필요한 복잡한 RAG 서비스 |
Retriever
- 사용자의 질문 벡터를 이용해 벡터 저장소에서 가장 가까운 이웃(k-nearest-neighbor) 청크를 찾아내는 컴포넌트입니다.
Top-K는 검색 결과 중 가장 유사도가 높은 상위 K개의 조각을 몇 개까지 추출하여 모델에게 넘겨줄지를 의미합니다.
Generation
- 검색을 통해 얻은 청크(Context)와 원본 질문을 결합하여 LLM이 최종 답변을 도출하는 단계입니다.
- 앞선 Retriever가 찾아준 신뢰할 수 있는 외부 문서 조각들을 프롬프트에 포함하여 LLM에 전달합니다.
- 이를 통해 LLM이 학습 데이터에 없는 내용을 묻더라도 환각(Hallucination) 없이 정확하고 사실에 기반한 답변을 생성하게 됩니다.
3. 외부 데이터 소스 기반 응답 생성
LLM 단독 응답 vs 외부 데이터를 검색하여 응답하는 방식의 차이
→ 가장 큰 차이는 의존하는 지식의 출처와 정보의 투명성 및 최신성에 있습니다.
- LLM 단독 응답
- 모델이 사전 학습 단계에서 파라미터(가중치) 내부에 저장한 '파라메트릭 메모리(Parametric memory)'에만 의존합니다
- 이로 인해 학습 시점 이후의 정보(지식 컷오프)를 알 수 없고, 추론 과정이 투명하지 않아 출처를 추적할 수 없다는 단점이 있습니다
- 학습 데이터에 포함되지 않은 최신 정보나 특정 기업의 내부 데이터를 알 수 없으며, 기억이 불확실할 경우 '그럴듯한 거짓말'을 하는 경향이 있습니다.
- 외부 데이터 검색 응답 (RAG)
- LLM의 내부 지식에만 의존하지 않고, 모델 외부의 신뢰할 수 있는 데이터 소스(Vector DB 등)에서 질문과 관련된 최신 정보를 실시간으로 찾아내어 답변의 근거로 활용합니다.
- 이를 통해 특정 도메인의 전문 정보를 결합할 수 있으며, 모델 재학습 없이 문서 저장소 갱신만으로 지속적인 최신 지식 업데이트가 가능합니다
API 호출 흐름: 질문 → 임베딩 → 벡터 검색 → 컨텍스트 구성 → LLM 호출
- 질문 (Input): 사용자가 자연어로 질문을 입력합니다.
- 임베딩 (Embedding): 입력된 질문을 텍스트 임베딩 모델(예:
text-embedding-3-small)을 통해 고차원의 숫자 벡터로 변환합니다.
- 벡터 검색 (Vector Search): FAISS나 Chroma와 같은 벡터 저장소(Vector Store)에 질문 벡터를 전달합니다. 벡터 저장소는 코사인 유사도(Cosine similarity) 등을 계산하여 질문과 의미적으로 가장 가까운 상위 K개(Top-K)의 문서 청크(조각)를 찾아냅니다.
- 컨텍스트 구성 (Context Augmentation): 검색된 문서 조각들을 원래의 사용자 질문과 결합하여 "아래 내용을 참고하여 답변해줘"라는 형태의 증강된 프롬프트를 생성합니다.
- LLM 호출 (Generation): 최종 구성된 프롬프트를 LLM(예: GPT-4o, Claude 등)에 전달하여, 제공된 컨텍스트에 기반한 정확한 답변을 생성합니다.
할루시네이션 방지에서 RAG가 하는 역할
→ RAG는 LLM의 가장 고질적인 문제인 환각 현상을 획기적으로 줄여주는 '안전장치' 역할을 합니다.
- RAG는 LLM이 불확실한 내부 기억력에만 의존해 답변을 추측하도록 내버려 두지 않고, 검색을 통해 찾아낸 '신뢰할 수 있는 외부 지식(팩트)'을 프롬프트의 컨텍스트 창에 직접 주입(Augmentation)하는 역할을 합니다
- 모델이 학습하지 못한 최신 정보나 전문 지식을 질문 시점에 직접 주입해줌으로써, 정보 부족으로 인해 발생하는 '추측성 답변'을 원천 차단합니다.
4. LangChain 기반 RAG 파이프라인 구조
RAG 구축 프레임워크
-
LangChain (랭체인)
- 특징: LLM을 활용한 애플리케이션 개발의 표준 프레임워크입니다. RAG뿐만 아니라 에이전트(Agent), 메모리 관리 등 범용적인 기능을 체인(Chain) 형태로 연결합니다.
- 장점: 생태계가 가장 크고 커뮤니티 지원이 활발하여, RAG 외에도 다양한 기능을 확장하기에 좋습니다.
- 연동:
VectorStore 클래스를 통해 다양한 저장소를 일관된 코드로 교체해가며 사용할 수 있습니다.
-
LlamaIndex (라마인덱스)
- 특징: '데이터 연결'에 최적화된 프레임워크입니다. PDF, 노션, 슬랙 등 다양한 외부 데이터를 LLM이 읽기 좋은 구조로 인덱싱하는 데 매우 강력한 기능을 제공합니다.
- 장점: RAG 구현에 특화되어 있어, 복잡한 데이터 구조를 검색 엔진처럼 구축하고 싶을 때 유리합니다.
- 연동: 위에서 언급한 FAISS, Chroma, Pinecone 등 거의 모든 벡터 저장소와 쉽게 통합됩니다.
정리
먼저 RAG(검색 증강 생성)는 LLM이 가진 내부 지식의 한계를 넘어, 외부 데이터베이스에서 관련 정보를 찾아 답변을 생성하는 혁신적인 기술입니다. 이를 통해 모델을 매번 새로 학습시키지 않고도 최신 정보를 반영할 수 있으며, 특히 답변의 근거가 되는 문서를 직접 참조하기 때문에 AI의 고질적인 문제인 할루시네이션(환각 현상)을 획기적으로 줄일 수 있다는 점이 핵심입니다.
RAG 파이프라인은 크게 색인(Indexing)과 검색 및 생성(Retrieval & Generation) 두 단계로 나뉩니다. 색인 과정에서는 방대한 문서를 작은 조각(Chunk)으로 나누어 벡터화한 뒤 저장소에 보관하며, 사용자의 질문이 들어오면 실시간으로 가장 관련성이 높은 조각을 찾아냅니다. 이는 마치 비서가 수만 권의 책 중 필요한 페이지만 골라 모델의 책상 위에 올려두는 '오픈북 테스트'와 같은 원리로 작동합니다.
효율적인 RAG 구축을 위해서는 데이터를 나누는 청킹(Chunking) 전략과 텍스트의 의미를 숫자로 변환하는 임베딩(Embedding) 모델의 선택, 그리고 이를 빠르게 찾아주는 벡터 스토어(Vector Store)의 역할이 매우 중요합니다. 프로젝트의 규모와 환경에 따라 OpenAI의 최신 모델이나 FAISS, Chroma 같은 오픈소스 라이브러리를 적절히 조합하여 최적의 성능을 끌어낼 수 있습니다.
마지막으로 이러한 복잡한 과정을 체계적으로 연결해 주는 것이 바로 LangChain과 같은 프레임워크입니다. LangChain은 데이터 로딩부터 최종 답변 생성까지의 전 과정을 '체인' 형태로 관리하여 개발자가 쉽고 빠르게 강력한 AI 애플리케이션을 구축하도록 돕습니다. 이번 포스팅을 통해 이해한 파이프라인 구조를 바탕으로, 여러분만의 스마트한 지식 베이스 AI를 직접 구현해 보시길 바랍니다.
참고 자료
https://arxiv.org/abs/2005.11401
https://arxiv.org/abs/2312.10997
https://platform.openai.com/docs/guides/embeddings
https://github.com/facebookresearch/faiss/wiki/Getting-started
https://docs.trychroma.com/getting-started
https://python.langchain.com/docs/tutorials/rag/
https://docs.llamaindex.ai/en/stable/getting_started/starter_example/