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 대안으로 제안된 마크다운 위키 패턴