[RAG 튜토리얼 1] RAG 개념

[RAG 튜토리얼 1] RAG 개념

어디서 부터 시작해야 할까?

커스텀 GPT, RAG, Cursor AI, Langchain, MCP, A2A...

요즘 GPT와 AI 기반 생산성 도구들이 쏟아지듯 나오고 있습니다.

하지만 정작 저는 기술 뉴스와 유튜브 등을 통해 이들 기술을 눈으로만 익히고 실제 활용은 아직도 브라우저에서 ChatGPT 창 하나 열고 질문 -> 답변만 주고받는 방식에 머물러 있었죠.

💡
좀 더 나만의 환경에서 내가 원하는 방식으로 내가 주고 싶은 문맥을 줘가면서 GPT를 활용 할 순 없을까?

이런 생각을 실현하기 위한 시작점으로 저는 RAG (Retrieval-Augmented Generation)를 선택했습니다.

이 시리즈는 RAG의 개념부터, GPT를 기반으로 한 나만의 인터페이스를 만들어가는 실습 과정을 초보자인 제 시선에서 직접 구현하고, 기록하는 튜토리얼입니다.

단순히 ChatGPT를 활용하는 것을 넘어서
“GPT를 내 맥락 안에 넣고, 내가 주도하는 환경”을 만들어보기 위한 여정입니다.

기초부터 하나씩, 예제 코드와 함께,
GPT 활용의 본질과 확장성을 자연스럽게 체득할 수 있도록 구성해봤습니다.

그럼 [RAG 튜토리얼 1] 개념을 시작합니다.

RAG란 무엇인가

RAG는 Retrieval-Augmented Generation의 약자입니다. 말 그대로, 검색(Retrieval)을 보강(Augmented)해서 생성(Generation)한다는 의미입니다.

기존의 GPT 같은 LLM은 질문을 받으면 자신이 훈련 중에 학습한 데이터 안에서만 답을 만들어냅니다. 하지만 이 방식에는 명확한 한계가 있습니다:

  • 최신 정보가 반영되지 않음
  • 특정 도메인 지식 부족
  • 헛소리(환각 hallucination)를 할 수 있음

이 문제를 해결하기 위해 등장한 방식이 바로 RAG 구조입니다. RAG는 GPT가 자신의 지식에만 의존하지 않고, 외부에서 관련 정보를 검색해서 가져오고, 그 정보를 바탕으로 더 정확하고 풍부한 답변을 생성하게 합니다.

제목 내용 설명
Retrieval 검색 질문과 관련된 정보를 벡터 DB 등에서 찾아옴
Augmented 보강된 검색한 내용을 GPT가 받아들여 문맥으로 사용
Generation 생성 그 문맥을 기반으로 자연어로 응답 생성

RAG 작동 구조

RAG는 아래 구조로 작동 됩니다.
1. 사용자 질문: MES 에서 생산부터 출하까지 어떤 흐름으로 이어져? 같은 질문
2. 임베딩(Embedding): 질문을 수치 벡터로 전환
3. 검색(Retrieval): 미리 저장된 벡터 DB에서 유사도가 높은 문서/코드/텍스트 검색
4. 생성(Generation): 검색된 내용을 바탕으로 GPT가 응답 생성

  • 용어정리
    • 임베딩: 문장을 벡터로 변환
    • 청크: 원본 문서를 적절한 단위로 잘라냄
    • 벡터: 숫자의 1차원 배열 [1, -2.3, 4]
    • 벡터 DB에 저장한다: 벡터와 해당하는 텍스트를 함께 저장
    • LLM: 수 많은 텍스트를 학습한 인공지능. ChatGPT, Gemini, LLaMA 등
    • 검색: 질문벡터와 DB에 저장된 기존 벡터들의 유사도를 계산하는 것
    • 결과: 가장 유사한 벡터의 텍스트(payload)를 꺼냄

예를 들어 니체의 책 '짜라투스트라는 이렇게 말했다' 책 한권을 벡터 DB에 저장한다고 할 때 적절한 청크(200~300자 기준)으로 아래와 같이 청크가 나올 수 있습니다.

Chunk 1

나는 너희가 의미를 창조하길 바란다. 인간은 극복되어야 할 무엇이다. 초인은 인간의 목적이며, 너희는 스스로를 넘어서야 한다. 인간은 다리이며, 초인을 향한 다리다.

Chunk

나는 인간의 작은 행복을 바라지 않는다. 너희는 의미 없는 만족에 안주하지 말고 스스로 운명을 만들라. 그대가 던지는 삶의 물음에 대답할 수 있어야 한다.

Chunk 3

너희는 신을 죽였다. 이제 너희는 새로운 가치를 만들어야 한다. 옛 신의 그림자 아래 살 수 없고, 새로운 태양 아래서 너희의 의미를 세워야 한다.

아래는 위 청크들을 임베딩한 예시 입니다.

Chunk ID 임베딩 예시
chunk_001 [0.031, -0.142, 0.089, 0.227, -0.013, 0.391, -0.034, ...]
chunk_002 [0.043, -0.178, 0.104, 0.199, -0.027, 0.402, -0.020, ...]
chunk_003 [0.025, -0.122, 0.094, 0.211, -0.011, 0.386, -0.038, ...]

이제 이 데이터들은 벡터 DB에 아래와 같은 형태(JSON-LIKE)로 저장됩니다.

[
  {
    "id": "chunk_001",
    "text": "나는 너희가 의미를 창조하길 바란다. 인간은 극복되어야 할 무엇이다...",
    "embedding": [0.031, -0.142, 0.089, 0.227, -0.013, 0.391, -0.034, ...],
    "metadata": {
      "book": "짜라투스트라는 이렇게 말했다",
      "chapter": "서문",
      "chunk_index": 1
    }
  },
  {
    "id": "chunk_002",
    "text": "나는 인간의 작은 행복을 바라지 않는다. 너희는 의미 없는 만족에 안주하지 말고...",
    "embedding": [0.043, -0.178, 0.104, 0.199, -0.027, 0.402, -0.020, ...],
    "metadata": {
      "book": "짜라투스트라는 이렇게 말했다",
      "chapter": "서문",
      "chunk_index": 2
    }
  },
  {
    "id": "chunk_003",
    "text": "너희는 신을 죽였다. 이제 너희는 새로운 가치를 만들어야 한다...",
    "embedding": [0.025, -0.122, 0.094, 0.211, -0.011, 0.386, -0.038, ...],
    "metadata": {
      "book": "짜라투스트라는 이렇게 말했다",
      "chapter": "서문",
      "chunk_index": 3
    }
  }
]

임베딩 모델 선택

RAG 시스템의 핵심은 "의미를 잘 파악해서 문장 간 유사도를 정확히 비교하는 것" 으로 임베딩 품질이 매우 중요합니다.

저는 임베딩 모델로 OpenAI의 모델과 BAAI(중국, 국가연구소)의 모델인 BGE 를 비교한 후 본 튜터리얼에서는 API 호출을 통해 사용할 수 있는 OpenAI의 모델을 사용했습니다.

항목 OpenAI text-embedding-3-small BGE bge-m3-small
제작사 OpenAI (미국) BAAI (중국, 국가 연구소)
라이선스 유료 ($0.02 / 1M tokens) 무료 (Apache 2.0)
벡터 차원 1536 512
다국어 지원 보통 수준 강력 (100개+ 언어, 한국어 포함)
장문 지원 8192 tokens 최대 8192 tokens
검색 방식 Dense (임베딩 기반) Dense + Sparse + Multi-vector
RAG 적합도 GPT 기반과 호환 최고 무료로 뛰어난 성능
사용 편의성 매우 쉬움 (API만 있으면 됨) 설치 필요 (Hugging Face + 로컬 실행)
실시간 응답 속도 빠름 (OpenAI 서버) 빠름 (로컬, 단 GPU 있으면 더 좋음)

OpenAI의 text-embedding-3-small 을 사용하면 1권 분량의 책 임베딩 비용으로 약 3원 정도 발생합니다.

임베딩 차원이란?
문장을 숫자 벡터로 표현 할 때 숫자가 몇 개 인지를 의미.
모델 벡터 차원 수 예시 형태
text-embedding-3-small 1536차원 [0.12, -0.87, ..., 1.02] (숫자 1536개)
bge-m3-small 512차원 [0.09, -0.12, ..., 0.77] (숫자 512개)

차원이 높을 수록 문장의 의미를 더 정교하게 표현 가능하지만, 그만큼 연산량이 많아지고 Vector DB의 저장 공간도 늘어납니다.

항목 의미
차원이 크다 (1536) 유사도 비교 정확도 높아짐, 연산량 증가
차원이 작다 (512) 속도 빠름, 경량화에 유리, 정확도는 다소 낮을 수 있음
차원 수는 통일해야 함 Vector DB 컬렉션 안의 모든 벡터는 같은 차원이어야 함(같은 임베딩 사용)

Langchain이란?

위에서 살펴본 RAG 작동 구조를 다시 보면

문서, 코드 저장시

  1. 저장하려는 문서, 코드 등을 불러오고
  2. 청크로 나누고
  3. 임베딩 -> 벡터 DB에 저장

질문시

  1. 질문을 임베딩
  2. 벡터 DB에서 관련 문서 검색
  3. GPT에게 문맥 전달

의 과정을 거치게 됩니다.

이 모든 걸 코드에서 직접 구현하려면 아래와 같은 복잡성이 존재합니다.

  • Embedding 모델 직접 연결
  • 벡터 DB API 따로 호출
  • GPT API 요청 직접 구성
  • 프롬프트 구조 수동 관리

이럴 때 Langchain 을 쓰면 위의 복잡한 단계를 한 줄 한 줄 명확하게 연결합니다.

Langchain은 오픈소스 기반의 RAG 프레임워크입니다. LLM과 벡터 DB, 프롬프트 등을 연결하는 체인을 구성할 수 있도록 도와주는 도구입니다.

기능 설명
체인 구성 여러 LLM 호출, 조건 분기, 도구 호출 등을 연결해서 자동화 파이프라인 생성
문서 기반 질문 응답 RAG 구현: 질문을 벡터 DB에서 검색해 GPT로 답변 생성
에이전트 실행 GPT가 도구를 직접 사용해 액션 실행 (계산기, 검색 등)
툴 통합 Google 검색, Python REPL, SQL 쿼리 등 외부 도구와 연동
메모리 저장 GPT가 대화 내용을 장기 기억하도록 state 유지

Langchain의 대체 프레임워크로는 아래와 같은 제품들이 있습니다.

프레임워크 특징
LlamaIndex 문서 기반 RAG에 특화된, 더 간결하고 쉬운 대안
Haystack 전통 검색 시스템과 잘 통합되는 RAG 엔진
Flowise LangChain 기반의 GUI 도구 – 블록 연결하듯 구성
Semantic Kernel MS에서 만든 GPT 오케스트레이션 도구 (C#/Python 기반)
  • Langchain vs LlamaIndex
기준 LangChain LlamaIndex
기능 확장성 체인 구성, 에이전트, 툴 연동 등 다양한 기능 지원 주로 문서 검색 & RAG에 최적화됨
러닝 커브 약간 복잡함 (체인 설계와 도구 사용 이해 필요) 상대적으로 간단함 (문서 기반 QA에 집중)
유연성 다양한 LLM & 툴 조합, 조건 흐름 처리 가능 문서 소스, 임베딩, 검색 등 문서 특화 구성에 강점
RAG 실험용 여러 기능 실험에 적합 빠르게 문서 기반 QA 구축에 적합

본 튜터리얼에서는 향후 여러 LLM 호출 시나리오를 대비하여 Langchain 을 활용해서 RAG 실습을 진행 할 예정입니다.

실습준비

실습 준비로 openai의 gpt 모델 api를 사용할 수 있도록 API Key를 생성하고 결제정보를 입력해 줍니다.

  • API Key 생성

https://platform.openai.com/settings/organization/api-keys

  • 결제정보 입력
설정 예시: 크레딧이 5달러 이하로 떨어지면 자동으로 10달러로 복원

https://platform.openai.com/settings/organization/billing/overview

실습

  • python 3.13.2
  • poetry 사용
    • version 2.1.1
Introduction | Documentation | Poetry - Python dependency management and packaging made easy
Introduction Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. Poetry offers a lockfile to ensure repeatable installs, and can build your project for distribution. System requirements Poetry requires Python 3.9+. It is multi-platform and the goal is to make it work equally well on Linux, macOS and Windows.

프로젝트 생성

 poetry new embedding-test
 cd embedding-test
 poetry add openai python-dotenv

프로젝트 루트에 .env 생성

src/embedding_test/app.py 생성

  • .env 코드
OPENAI_API_KEY=dd...
  • app.py 코드
from openai import OpenAI
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

text = (
    "나는 너희가 의미를 창조하길 바란다. 인간은 극복되어야 할 무엇이다. "
    "초인은 인간의 목적이며, 너희는 스스로를 넘어서야 한다. "
    "인간은 다리이며, 초인을 향한 다리다."
)

# OpenAI 임베딩 요청
response = client.embeddings.create(
    input=text,
    model="text-embedding-3-small"
)

embedding_vector = response.data[0].embedding

# 앞의 100개 요소만 출력
print("임베딩 벡터 (앞 100차원):")
print(embedding_vector[:100])

코드 실행

poetry run python ./src/embedding_test/app.py

실행 결과

요약

  • 앞으로 튜토리얼에서 사용할 기술
    • LLM: OpenAI (gpt-3.5-turbo)
    • Embedding: OpenAI (text-embedding-3-small)
    • RAG Framework: Langchain

내용은 2편에서 이어집니다.

Read more

[Terraform 튜토리얼 1-6] 중복 없애다 망한 썰 – DRY 원칙, 정말 항상 맞을까?

[Terraform 튜토리얼 1-6] 중복 없애다 망한 썰 – DRY 원칙, 정말 항상 맞을까?

개발자라면 한 번쯤 들어봤을 말, "Don't Repeat Yourself", 줄여서 DRY 원칙. 이건 소프트웨어 개발에서 아주 중요한 원칙이에요. 중복을 줄이면 버그도 줄고, 유지 보수도 쉬워지고, 코드도 깔끔해지죠. 그런데… Terraform 같은 IaC 세계에서도 DRY가 무조건 좋을까요? 🤔 DRY가 뭔데? DRY 원칙의 핵심은 딱 하나: "같은 걸 반복해서 쓰지 마." * 상수 값, 로직, 설정

By Chansong
[Terraform 튜토리얼 1-5] 선언형 vs 명령형: Terraform은 왜 선언형인가?

[Terraform 튜토리얼 1-5] 선언형 vs 명령형: Terraform은 왜 선언형인가?

Terraform을 쓰다 보면 종종 듣게 되는 말이 하나 있어요: Terraform은 "선언형(Declarative)" 도구다. 그런데 이게 도대체 무슨 뜻일까요? "명령형(Imperative)"이랑은 뭐가 다르고, 왜 Terraform은 선언형일까요? 🧠 선언형과 명령형, 개념부터 정리 구분 선언형 (Declarative) 명령형 (Imperative) 핵심 개념 무엇이 되어야 하는지만 선언 어떻게 할지를 하나하나 명령 예시 “난 스테이크 먹을래” “고기

By Chansong
[Terraform 튜토리얼 1-4] 모듈이 정리가 안 될 땐, 응집도(Cohesion)를 의심하라

[Terraform 튜토리얼 1-4] 모듈이 정리가 안 될 땐, 응집도(Cohesion)를 의심하라

인프라를 코드로 관리할 때, 좋은 모듈을 만드는 핵심 개념 중 하나가 바로 응집도(Cohesion)입니다. 이 단어가 좀 낯설게 느껴질 수 있지만, 사실 우리는 매일 응집도가 높은 시스템 속에서 살고 있어요. ✅ 응집도란? 하나의 모듈이 하나의 책임 또는 기능에만 집중하는 정도 응집도가 높은 모듈은 말 그대로 한 가지 일에만 집중합니다. 그래서

By Chansong
[Terraform 튜토리얼 1-3] 내부는 감추고, 필요한 것만 보여줘 – 캡슐화란?

[Terraform 튜토리얼 1-3] 내부는 감추고, 필요한 것만 보여줘 – 캡슐화란?

Encapsulation, 캡슐화라고 하면 뭔가 개발자스럽고 어려워 보이죠? 객체지향 프로그래밍 할 때나 듣던 단어 같고요. 그런데 이 개념은, Terraform 같은 Infrastructure as Code(IaC)에서도 아주 중요합니다. 이번 글에서는 "캡슐화가 무엇이고", "왜 필요한지", 그리고 "Terraform에서는 어떻게 쓰이는지"를 쉽게 풀어보겠습니다. ✅ 캡슐화, 한 마디로 뭐야? “필요한 것만 보이게 하고, 나머지는 숨기는 것”

By Chansong