Agentic RAG for Dummies: Agentic 기반 RAG 시스템을 이해하고 구축할 수 있도록 돕는 오픈소스 프로젝트 (feat. LangGraph)

Agentic RAG for Dummies 소개

Agentic RAG for Dummies는 복잡하고 난해할 수 있는 '에이전트 기반 검색 증강 생성(Agentic RAG, Retrieval-Augmented Generation)' 시스템을 누구나 쉽게 이해하고 구축할 수 있도록 설계된 오픈 소스 프로젝트입니다. LangGraph를 기반으로 구축된 이 프로젝트는 단순히 문서를 검색해서 답변하는 기존의 RAG를 넘어, AI가 스스로 판단하고 행동하는 '에이전트(Agent)'의 개념을 도입했습니다.

Agentic RAG for Dummies 소개

최근 RAG 기술은 단순 검색(Naive RAG)에서 에이전틱(Agentic) RAG로 진화하고 있습니다. 이 프로젝트는 최소한의 코드로 생산 수준(Production-ready)의 시스템을 구현하는 것을 목표로 하며, 사용자는 이를 통해 다음과 같은 고급 기능들을 직접 구현해 볼 수 있습니다:

  • 맥락 인식(Context Awareness): 이전 대화 내용을 기억하여 자연스러운 핑퐁 대화가 가능합니다.

  • 능동적 질문(Active Clarification): 사용자의 질문이 모호하면 AI가 역으로 질문하여 의도를 파악합니다(Human-in-the-loop).

  • 병렬 처리(Parallel Processing): 복잡한 질문을 여러 개의 하위 질문으로 나누어 동시에 검색하고 답변을 종합합니다.

  • 자기 교정(Self-Correction): 검색 결과가 불충분하면 스스로 검색어를 수정하여 다시 검색합니다.

Agentic RAG for Dummies 저장소는 학습(Learning Path)구축(Building Path) 이라는 두 가지 트랙을 제공하여, RAG의 기본 개념을 익히려는 초보자부터 실제 서비스를 구축하려는 엔지니어까지 모두를 아우릅니다.

일반 RAG(Naive RAG)와 Agentic RAG 비교

단순히 데이터베이스에서 문서를 찾아오는 기존 방식과 달리, 이 프로젝트에서 소개하고 있는 Agentic RAG는 다음과 같은 결정적인 차이가 있습니다:

특징 기존 RAG (Typical RAG) Agentic RAG (This Repo)
처리 방식 단방향 선형 파이프라인 (검색 → 생성) 순환형 그래프 워크플로우 (LangGraph)
질의 처리 단일 스레드 처리 Multi-Agent Map-Reduce (병렬 처리)
검색 단위 문맥과 정밀도가 상충됨 (Trade-off) 계층적 인덱싱 (정밀도 + 풍부한 문맥)
대화 맥락 이전 대화 기억 못 함 (Stateless) 대화 메모리 (Conversation Memory) 탑재
불명확한 질문 엉뚱한 답변을 하거나 답변 거부 사용자에게 되물어 명확화 (Query Clarification)
유연성 커스터마이징이 어려움 모듈형 아키텍처 (컴포넌트 교체 용이)

Agentic RAG for Dummies 저장소의 차별점

대부분의 RAG 튜토리얼은 기본적인 개념만 보여줄 뿐, 실제 서비스(Production) 수준의 요구사항을 충족하지 못하는 경우가 많습니다. Agentic RAG for Dummies 프로젝트는 학습 자료(Learning materials)즉시 배포 가능한 코드(Deployable code) 를 동시에 제공하여 개념 학습과 실무 적용 사이의 간극을 해결하고자 합니다.

더 구체적으로는 다음과 같은 차별점을 갖습니다:

  • 두 가지 학습 경로: 입문자를 위한 '대화형 노트북(Interactive Notebook)'과 개발자를 위한 '모듈형 프로젝트(Modular Project)' 구조를 모두 제공합니다.

  • 계층적 인덱싱 (Hierarchical Indexing): 작은 청크로 정밀하게 검색하고, 큰 청크로 문맥을 보강하여 정확도와 맥락을 동시에 확보했습니다.

  • 대화 메모리 (Conversation Memory): 이전 대화 내용을 유지하여 사람과 대화하듯 자연스러운 상호작용이 가능합니다.

  • Human-in-the-loop: 질문이 불명확할 경우 AI가 사용자에게 역으로 질문하여 의도를 명확히 합니다.

  • Multi-Agent Map-Reduce: 복잡한 질문을 여러 하위 질문으로 분해하고, 여러 에이전트가 병렬로 처리하여 답변을 완성합니다.

  • 모듈형 아키텍처: 특정 컴포넌트(LLM, DB 등)를 원하대로 쉽게 교체할 수 있는 유연한 구조입니다.

  • LLM 중립성 (Provider-agnostic): Ollama(로컬), OpenAI, Gemini, Claude 등 원하는 모델을 설정 한 줄로 교체하여 사용할 수 있습니다.

  • 완전한 UI 제공: 문서 업로드 및 관리 기능이 포함된 완성형 Gradio 웹 인터페이스를 제공합니다.

Agentic RAG for Dummies의 주요 특징

이 프로젝트에서 소개하는 Agentic RAG 구현의 핵심은 어떻게 문서를 저장하고(Indexing), 어떻게 질문을 처리하는가(Workflow) 에 있습니다.

계층적 문서 인덱싱 (Hierarchical Indexing Strategy)

RAG 시스템의 성능은 '데이터를 어떻게 자르느냐(Chunking)'에 달려 있습니다. 이 프로젝트는 Parent-Child Chunking 전략을 사용하여 검색의 정확도와 답변의 질을 동시에 잡았습니다. 이 전략은 다음과 같은 Parent Chunk와 Child Chunk로 나누어 문서를 저장합니다:

문맥 이해를 위한 Parent Chunks는 다음과 같은 특징을 갖습니다:

  • Markdown 헤더(H1, H2, H3)를 기준으로 문서를 크게 나눕니다.

  • LLM이 답변을 생성할 때 필요한 '전체적인 문맥'을 담고 있습니다.

  • 답변 생성(Generation) 단계에서 LLM에게 제공됩니다.

검색을 위한 Child Chunks는 다음과 같은 특징을 갖습니다:

  • Parent Chunk를 다시 작고 고정된 크기(약 500자)로 잘게 쪼갭니다.

  • 벡터 유사도 검색(Vector Search)의 정확도를 높이기 위해 사용됩니다.

  • 검색(Retrieval) 단계에서 사용됩니다.


이렇게 서로 다른 크기와 목적으로 자른(Chunking) 데이터는 다음과 같이 사용합니다:

  1. 사용자의 질문과 가장 유사한 Child Chunk를 벡터 DB에서 찾습니다.

  2. 찾아진 Child Chunk가 속해 있는 원본 Parent Chunk 전체를 불러옵니다.

  3. LLM은 작은 조각이 아닌, 문맥이 살아있는 Parent Chunk를 읽고 답변을 작성합니다.

4단계 지능형 워크플로우 (Four-Stage Intelligent Workflow)

사용자가 질문을 던지면 시스템은 즉시 검색하지 않고, 다음 4단계를 거쳐 생각을 정리하고 답변합니다. 각 단계들은 다음과 같이 구성됩니다:

1단계. 대화 이해 (Conversation Understanding): 대화 이해 단계에서는 최근 대화 기록을 분석하여 대명사나 생략된 주어를 복원합니다. 예를 들어, 사용자가 "그걸 어떻게 설치해?"라고 물으면, 이전 대화들을 살펴보고 사용자가 언급한 '그것'이 Python에 관한 것이었음을 파악하고 "Python을 어떻게 설치해?"로 내부적인 변환을 수행합니다.

2단계. 질의 명확화 (Query Clarification): 시스템이 질문을 검색하기 전에, 해당 질문이 명확한지 검증하는 단계입니다. 만약 질문이 너무 모호하거나 정보가 부족하다면(예: "오류가 났어"), 시스템은 억지로 검색을 수행하는 대신 사용자에게 "어떤 오류 메시지가 떴나요?"라고 역으로 질문하여 의도를 파악합니다(Human-in-the-loop). 또한, "Python과 JavaScript의 차이점은?"과 같은 복합적인 질문은 검색 정확도를 높이기 위해 "Python의 특징은 무엇인가?"와 "JavaScript의 특징은 무엇인가?"라는 두 개의 구체적인 하위 질문으로 분해(Decompose)합니다.

3단계. 지능형 검색 (Intelligent Retrieval - Map/Reduce): 분해된 질문들은 LangGraph의 Send API를 통해 생성된 여러 개의 서브 에이전트들에 의해 병렬로 처리됩니다. 각 에이전트는 독립적으로 동작하며 할당된 질문에 대해 Child Chunk를 검색합니다. 단순히 검색 결과만 가져오는 것이 아니라, 검색된 내용이 답변하기에 충분한지 스스로 평가(Evaluate)합니다. 만약 정보가 부족하다고 판단되면 검색어를 수정(Rewrite)하여 다시 검색하는 자기 교정(Self-Correction) 과정을 거치며, 결과가 충분하다면 문맥이 풍부한 Parent Chunk를 확보합니다.

4단계. 답변 생성 (Response Generation): 병렬로 실행된 여러 에이전트가 확보한 문서 조각들과 개별 답변들을 하나로 종합(Aggregation)하는 단계입니다. 단순히 정보를 나열하는 것이 아니라, 수집된 모든 정보를 재구성하여 사용자의 원래 질문에 대한 논리적이고 일관성 있는 최종 답변을 생성합니다. 이 과정에서 LLM은 확보된 Parent Chunk의 풍부한 문맥을 활용하여 정확도를 높이며, 답변에 사용된 문서의 출처를 함께 제공하여 신뢰성을 확보합니다.

상세 구현 가이드 (Implementation Deep Dive)

이 프로젝트를 직접 구축하고 커스터마이징하기 위해 반드시 이해해야 할 핵심 구현 단계입니다.

Step 1. 환경 설정 및 기술 스택 (Environment Setup): 이 프로젝트는 특정 벤더에 종속되지 않는 Provider-agnostic 구조를 핵심으로 합니다. 사용자는 langchain_ollama, langchain_google_genai, langchain_openai 중 원하는 라이브러리를 선택하여 llm 객체 선언부만 교체하면 즉시 모델을 변경할 수 있습니다.

# 예: 로컬 개발용 Ollama 설정 (비용 무료)
from langchain_ollama import ChatOllama
llm = ChatOllama(model="qwen3:4b-instruct-2507-q4_K_M", temperature=0)

# 예: 프로덕션용 Google Gemini 설정
# from langchain_google_genai import ChatGoogleGenerativeAI
# llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash-exp", temperature=0)

벡터 데이터베이스로는 Qdrant를 채택했는데, 이는 도커나 별도의 서버 구축 없이 로컬 파일 시스템(path="qdrant_db")에 데이터를 저장할 수 있어 개발 및 테스트 환경 구축이 매우 간편합니다.

또한, 검색 성능을 극대화하기 위해 의미론적 맥락을 파악하는 Dense Embedding(sentence-transformers)과 키워드 일치 여부를 중시하는 Sparse Embedding(Bm25)을 동시에 사용하는 **하이브리드 검색(Hybrid Search)**을 구현하여 정밀도를 높였습니다.

Step 2. PDF의 Markdown 변환 (Document Processing): RAG 시스템의 답변 품질은 입력되는 데이터의 구조에 크게 의존합니다. 이 프로젝트는 단순한 텍스트 추출 대신 pymupdf4llm 라이브러리를 사용하여 PDF 문서를 구조화된 Markdown 포맷으로 변환합니다. to_markdown(doc) 함수를 통해 문서 내의 헤더(H1, H2, H3 등), 리스트, 표 등의 형식을 그대로 보존합니다. 이렇게 변환된 Markdown 헤더는 이후 Parent Chunk를 나누는 논리적 기준점이 되며, 단순히 글자 수로 문서를 자를 때 발생하는 '문맥 절단' 현상을 방지하고 의미 단위로 문서를 관리할 수 있게 해줍니다.

Step 3. 상태 정의 및 데이터 모델링 (State Definition): LangGraph 기반의 복잡한 워크플로우를 제어하기 위해 pydantic을 사용하여 엄격한 상태(State) 모델을 정의합니다. 전체 흐름을 관장하는 State 클래스는 대화 요약, 원본 질문, 재작성된 질문 리스트, 그리고 여러 에이전트로부터 수집된 답변(Accumulated Answers)을 저장합니다. 개별 에이전트의 작업을 위한 AgentState 클래스는 할당된 하위 질문과 검색 결과를 관리합니다. 또한, QueryAnalysis 모델을 통해 LLM이 질문을 분석할 때 '질문이 명확한지(is_clear)', '추가 설명이 필요한지(clarification_needed)' 등의 판단 결과를 구조화된 JSON 형태로 출력하도록 유도하여 시스템의 제어 로직을 명확하게 구현했습니다.

Step 4. 검색 및 평가 로직 (Search & Evaluation Strategy): 에이전틱 RAG의 핵심인 '자기 교정'이 일어나는 단계입니다. 검색 엔진이 문서를 가져오면 무조건 사용하는 것이 아니라, Grade Documents 노드에서 LLM이 "이 문서가 실제로 질문과 관련이 있는가?"를 'yes/no'로 엄격하게 평가합니다. 만약 유효한 문서가 하나도 없다고 판단되면, 에이전트는 답변 생성을 보류하고 질문을 더 나은 검색어(keyword-rich)로 **재작성(Rewrite Query)**하여 다시 검색을 시도합니다. 이 루프(Loop) 과정을 통해 엉뚱한 문서를 보고 답변하는 환각(Hallucination) 현상을 획기적으로 줄이고 답변의 신뢰성을 확보합니다.

프로젝트 구성: 모듈형 아키텍처 (Modular Architecture)

Agentic RAG for Dummies 프로젝트(project/ 폴더)는 각 기능이 독립적인 컴포넌트로 모듈화되어 있어, 개발자가 자신의 요구사항에 맞춰 손쉽게 수정하고 확장할 수 있습니다.

전체 프로젝트 구조 (Project Structure)

전체 코드는 역할에 따라 명확하게 분리되어 있습니다. 특히 corerag_agent 폴더는 이 시스템의 핵심 로직을 담고 있습니다.

project/
├── app.py                  # 메인 Gradio 애플리케이션 진입점 (실행 파일)
├── config.py               # 설정 허브 (모델 선택, 청크 크기, 공급자 설정 등)
├── util.py                 # PDF를 Markdown으로 변환하는 유틸리티
├── document_chunker.py     # 문서 청킹(Chunking) 전략 구현
├── core/                   # RAG 핵심 컴포넌트 오케스트레이션
│   ├── chat_interface.py   # 채팅 인터페이스 로직
│   ├── document_manager.py # 문서 업로드 및 관리
│   └── rag_system.py       # 전체 RAG 시스템 통합 관리
├── db/                     # 데이터 저장소 관리
│   ├── parent_store_manager.py # Parent Chunk(JSON) 저장 관리
│   └── vector_db_manager.py    # Qdrant 벡터 데이터베이스 설정
├── rag_agent/              # LangGraph 기반 에이전트 워크플로우
│   ├── edges.py            # 조건부 라우팅 로직 (다음 단계 결정)
│   ├── graph.py            # 그래프(Graph) 생성 및 컴파일
│   ├── graph_state.py      # 상태(State) 정의
│   ├── nodes.py            # 처리 노드 (요약, 재작성, 검색 수행 등)
│   ├── prompts.py          # 시스템 프롬프트 모음
│   ├── schemas.py          # Pydantic 데이터 모델
│   └── tools.py            # 검색 도구(Tool) 정의
└── ui/                     # 사용자 인터페이스
    └── gradio_app.py       # Gradio UI 컴포넌트 구성

주요 커스터마이징 포인트 (Customization Points)

이 아키텍처는 유연성을 최우선으로 고려하여 설계되었습니다. 다음 파일을 수정하여 나만의 RAG 시스템을 구축할 수 있습니다.

  • 설정 변경 (config.py):

    • LLM 공급자 교체: 코드 변경 없이 Ollama, Claude, OpenAI, Gemini 중 원하는 모델로 즉시 전환할 수 있습니다.
    • 임베딩 모델: 벡터 표현을 위한 임베딩 모델을 변경하여 검색 성능을 튜닝할 수 있습니다.
    • 청크 크기: 검색 정밀도 최적화를 위해 Child 및 Parent 청크의 크기를 조정할 수 있습니다.
  • RAG 에이전트 로직 수정 (rag_agent/ 폴더):

    • 워크플로우 변경: graph.py에서 노드와 엣지를 추가하거나 제거하여 에이전트의 사고 과정을 변경할 수 있습니다.
    • 프롬프트 튜닝: prompts.py에 정의된 시스템 프롬프트를 수정하여 법률, 의료 등 특정 도메인에 특화된 챗봇을 만들 수 있습니다.
    • 검색 도구 확장: tools.py를 수정하여 웹 검색이나 API 호출 등 새로운 검색 기능을 추가할 수 있습니다.
    • 라우팅 로직: edges.py의 조건문을 수정하여 에이전트의 판단 로직(분기 처리)을 제어할 수 있습니다.
  • 문서 처리 파이프라인:

    • Markdown 변환 도구 교체 (util.py): 기본 제공되는 PyMuPDF 외에 Docling이나 PaddleOCR과 같은 다른 도구를 통합하여 문서 인식률을 높일 수 있습니다. (상세 내용은 이곳 참조)
    • 청킹 전략 (document_chunker.py): 기본 Parent-Child 전략 외에 의미론적(Semantic) 청킹이나 하이브리드 접근법 등 사용자 정의 알고리즘을 구현할 수 있습니다.

프로젝트 설치 및 사용

다음과 같이 4개의 PDF 문서들을 예시로 사용하였습니다. 각 링크에서 다운로드하여 사용할 수 있습니다: JavaScript, Blockchain, Microservices, Fortinet

옵션 1: 퀵스타트 노트북 (테스트 및 학습용)

가장 빠르고 간편하게 시작하는 방법으로, Google Colab에서 바로 열어서 실행해보며 컨셉을 익힐 수 있습니다.

  • Google Colab에서 실행:

    1. 저장소 상단의 Open in Colab 배지를 클릭합니다.
    2. 파일 탐색기에서 docs/ 폴더를 생성합니다.
    3. 준비한 PDF 파일들을 docs/ 폴더에 업로드합니다.
    4. 모든 셀을 위에서부터 차례대로 실행합니다.
    5. 마지막 셀 실행 후 하단에 채팅 인터페이스가 나타납니다.
  • 로컬 환경(Jupyter/VSCode)에서 실행:

    1. 필수 패키지를 설치합니다: pip install -r requirements.txt
    2. 선호하는 에디터에서 노트북 파일을 엽니다.
    3. docs/ 폴더에 PDF 파일을 추가합니다.
    4. 셀을 순차적으로 실행하여 채팅을 시작합니다.

옵션 2: 전체 Python 프로젝트 (개발용 권장)

실제 애플리케이션 개발이나 커스터마이징을 원한다면 이 방식을 권장합니다. 먼저 의존성을 설치합니다:

# 저장소 복제
git clone https://github.com/GiovanniPasq/agentic-rag-for-dummies
cd agentic-rag-for-dummies

# 가상 환경 생성 (권장)
python -m venv venv

# 가상 환경 활성화
# macOS/Linux:
source venv/bin/activate
# Windows:
.\venv\Scripts\activate

# 패키지 설치
pip install -r requirements.txt

설치가 완료되면 다음과 같이 애플리케이션을 실행하고, 브라우저에서 http://127.0.0.1:7860에 접속하여 사용할 수 있습니다:

python app.py

옵션 3: Docker 배포

내장된 Ollama 모델(qwen3:4b) 구동에만 약 3.3GB의 메모리가 필요하기 떄문에, Docker 배포 시에는 최소 8GB 이상의 RAM을 Docker에 할당해야 합니다.

먼저 다음과 같은 방식으로 Docker 설치 및 메모리 할당량을 설정합니다:

사용하는 운영체제 및 환경에 맞춰 Docker 설치 후, Docker Desktop 설정에서 메모리 할당량을 8GB 이상으로 설정 (Settings → Resources → Memory)


이후, 로컬에 복제해둔 GitHub 저장소의 Dockerfile 파일을 사용하여 이미지를 빌드하고, 실행합니다:

# 이미지 빌드
docker build -f project/Dockerfile -t agentic-rag .

# 컨테이너 실행
docker run --name rag-assistant -p 7860:7860 agentic-rag

이 때, Windows나 Mac에서 Docker를 사용할 경우, 가상화 오버헤드 및 I/O 작업으로 인해 로컬 Python 실행(옵션 2)보다 20~50% 느릴 수 있습니다. 개발 중에는 옵션 2를 사용하는 것이 쾌적합니다.

만약 NVIDIA GPU를 사용하고 있다면 다음과 같이 Docker 실행 시 GPU를 할당하여 속도를 높일 수 있습니다. 단, 이를 위해서는 NVIDIA Container Toolkit이 설치되어 있어야 합니다.

docker run --gpus all --name rag-assistant -p 7860:7860 agentic-rag

라이선스

Agentic RAG for Dummies 프로젝트는 MIT License 로 공개 및 배포 되고 있습니다. 누구나 자유롭게 수정하고 배포할 수 있습니다.

:notebook: 빠른 시작을 위한 Agentic RAG for Dummies의 Colab 노트북

:github: Agentic RAG for Dummies 프로젝트 GitHub 저장소

더 읽어보기




이 글은 GPT 모델로 정리한 글을 바탕으로 한 것으로, 원문의 내용 또는 의도와 다르게 정리된 내용이 있을 수 있습니다. 관심있는 내용이시라면 원문도 함께 참고해주세요! 읽으시면서 어색하거나 잘못된 내용을 발견하시면 덧글로 알려주시기를 부탁드립니다. :hugs:

:pytorch:파이토치 한국 사용자 모임:south_korea:이 정리한 이 글이 유용하셨나요? 회원으로 가입하시면 주요 글들을 이메일:love_letter:로 보내드립니다! (기본은 Weekly지만 Daily로 변경도 가능합니다.)

:wrapped_gift: 아래:down_right_arrow:쪽에 좋아요:+1:를 눌러주시면 새로운 소식들을 정리하고 공유하는데 힘이 됩니다~ :star_struck:

2개의 좋아요