RAG (Retrieval-Augmented Generation)

2026-04-07

개념

LLM은 학습 데이터에 없는 정보를 모른다. 내 노트, 사내 문서, 최근 뉴스 같은 건 답할 수 없다. RAG는 질문하기 전에 관련 문서를 검색해서 LLM에 같이 넘기는 구조다.

  • Retrieval — 관련 문서 검색
  • Augmented — 검색 결과를 프롬프트에 붙임
  • Generation — LLM이 그걸 보고 답변 생성

전부 주는 게 아니라 관련된 것만 골라서 준다. 노트가 200개여도 질문과 관련된 3~5개만 넘긴다.

왜 필요한가

  • 모델 재학습은 비싸다 — 새 문서 생길 때마다 fine-tuning 할 수 없음
  • 컨텍스트 윈도우는 유한하다 — 전체 문서를 프롬프트에 다 붙일 수 없음
  • 출처가 필요하다 — "이 답변은 어디서 나왔나?"를 증빙할 수 있어야 함
  • 프라이빗 문서 — 사내 문서는 공개 모델이 학습한 적 없음

전체 흐름

[사전 준비 — 한 번만]
문서 → 청킹 (적당한 크기로 자름) → 임베딩 (텍스트→벡터) → 벡터 DB에 저장

[질문할 때 — 매번]
질문 → 임베딩 → 벡터 DB에서 유사한 문서 검색 → 검색 결과 + 질문을 LLM에 전달 → 답변

임베딩

텍스트를 숫자 배열(벡터)로 변환하는 것. 의미가 비슷한 텍스트는 벡터도 비슷하다.

"접근 제어" → [0.023, -0.041, 0.087, ...]
"RBAC"     → [0.025, -0.039, 0.091, ...]  # 비슷한 벡터
"날씨"     → [-0.512, 0.331, -0.087, ...]  # 다른 벡터

그래서 "접근 제어"로 검색하면 "RBAC" 문서가 나온다. 키워드가 달라도 의미가 같으면 찾아준다.

임베딩 방식

OpenAI API 로컬 모델
비용 유료 (토큰당 과금) 무료
속도 네트워크 필요 즉시
품질 높음 (1536/3072차원) 괜찮음 (384~768차원)
한국어 좋음 다국어 모델이면 괜찮음

임베딩은 연산이 가벼워서 로컬로 충분하다. 문서 1만 개여도 CPU로 몇 분이면 끝난다. 한국어 섞인 문서는 intfloat/multilingual-e5-small(384차원) 같은 다국어 모델이 무난하다.

from sentence_transformers import SentenceTransformer

model = SentenceTransformer("intfloat/multilingual-e5-small")
vector = model.encode("RBAC는 역할 기반 접근 제어로...")

벡터 DB

임베딩된 벡터를 저장하고 유사도 검색하는 DB. 일반 DB의 WHERE 대신 코사인 유사도로 검색한다.

  • ChromaDB — 로컬, 설치 간단, 개인 프로젝트에 적합
  • Pinecone — 클라우드, 대규모 서비스용
  • pgvector — PostgreSQL 확장. 기존 RDB와 함께 쓸 때
import chromadb

client = chromadb.PersistentClient(path="./chroma_data")
collection = client.get_or_create_collection("notes")

# 저장
collection.add(
    documents=["RBAC는 역할 기반 접근 제어..."],
    embeddings=[vector],
    metadatas=[{"title": "RBAC", "tags": "security"}],
    ids=["rbac_chunk_1"],
)

# 검색
results = collection.query(
    query_embeddings=[query_vector],
    n_results=3,
)

청킹

긴 문서를 적당한 크기로 잘라야 한다. 통째로 넣으면 검색 정확도가 떨어지고, 너무 잘게 자르면 맥락이 없어진다.

  • 고정 크기 — 500자씩 자르기. 단순하지만 문맥이 끊길 수 있음
  • 의미 단위 — 마크다운 ## 헤딩 기준으로 자르기. 구조화된 문서에 적합
  • 오버랩 — 앞뒤 100자씩 겹치게 자르기. 문맥 유지
  • Recursive — 큰 단위(##)로 먼저 자르고 너무 길면 작은 단위(\n\n)로 재분할

코드로 짜는 부분 vs AI가 하는 부분

단계 누가 하나
파일 읽기 내 코드
frontmatter 파싱 내 코드
청킹 내 코드
텍스트 → 벡터 변환 임베딩 모델 (로컬 or API)
벡터 저장/검색 내 코드 (ChromaDB 사용)
검색 결과 보고 답변 생성 LLM API

AI가 하는 건 임베딩이랑 답변 생성 두 군데. 나머지는 전부 엔지니어가 설계하고 짠다.

새 문서 추가 시

RAG 자체는 읽기 전용 구조다. 새 문서가 추가되면 ingest 파이프라인을 다시 돌려야 한다.

새 노트 → 청킹 → 임베딩 → 벡터 DB에 추가

기존 문서가 이미 벡터로 있으니까, 새 문서와 기존 문서의 관계를 바로 파악할 수 있다. 이걸 활용하면 자동 태깅, 자동 백링크 같은 Agent 기능을 만들 수 있다.

더 보기

  • [[RAG-한계와-보완]] — 할루시네이션, 청킹 모호함 등 구조적 한계와 대응
  • [[Hybrid-Search]] — 벡터 + 키워드 검색 결합
  • [[Reranker]] — Cross-Encoder로 2차 재평가
  • [[GraphRAG]] — 벡터 + 지식 그래프 결합
  • [[Agentic-RAG]] — Agent가 검색을 반복·판단하는 패턴
  • [[Karpathy-LLM-Knowledge-Bases]] — RAG 대안으로 제안된 마크다운 위키 패턴

Backlinks

sunshinemoon · 2026