← Lecture Note
M3이론45분 · ~18 슬라이드

RAG — 검색 증강 생성

환각을 끊고, 출처를 박는다

학습 목표

RAG 를 '벡터 검색 + 근거 강제'로 이해하고, 환각 차단을 설계 단계에서 내재화한다.

LLM은 강력하지만 두 가지 근본적인 한계를 가집니다. RAG는 그 한계를 데이터 설계로 돌파하는 핵심 패턴입니다. 이 모듈을 제대로 이해하면 "모델이 틀리는 문제"가 아니라 "시스템이 틀리는 문제"로 시각이 전환됩니다.

LLM의 두 가지 한계

Knowledge Cutoff(지식 단절): 모델은 학습 시점 이후 발생한 사건을 알지 못합니다. 오늘 기준 Claude 4.x의 컷오프는 2025년 초반이므로, 그 이후 변경된 회사 정책·제품 스펙·법령 개정 내용은 모델 안에 없습니다.

Hallucination(환각): 모델은 모르는 것을 "모른다"고 말하는 대신 그럴듯한 내용을 생성하는 경향이 있습니다. 특히 도메인 특화 문서, 사내 데이터, 고유명사가 결합될수록 환각 빈도가 높아집니다.

RAG(Retrieval-Augmented Generation)는 이 두 한계를 동시에 완화합니다. 질문이 들어오면 관련 문서를 먼저 검색해 컨텍스트로 주입하고, 모델은 그 근거에서만 답하도록 설계합니다.

Embedding과 벡터공간 직관

텍스트를 벡터로 변환한다는 것은, 의미가 비슷한 문장을 고차원 공간에서 가까이 배치한다는 뜻입니다. 이 강의에서는 text-embedding-3-small(1536차원)을 사용합니다.

"환불 정책이 어떻게 되나요?"  →  [0.12, -0.84, 0.33, ...]  ← 1536개 숫자
"반품은 언제까지 가능한가요?"  →  [0.11, -0.81, 0.35, ...]  ← 거의 같은 방향
"파이썬 클로저란?"           →  [0.72,  0.19, -0.60, ...]  ← 전혀 다른 방향

의미 거리는 코사인 유사도로 측정합니다.

Cosine Similarity 수식

$$\text{sim}(A, B) = \frac{A \cdot B}{|A| \cdot |B|}$$

내적을 두 벡터의 크기로 나눈 값으로, 결과는 −1 ~ 1 사이입니다. 1에 가까울수록 의미가 유사합니다. 길이(토큰 수)가 달라도 방향만 비교하기 때문에 문서 길이 편향이 없다는 장점이 있습니다.

의사코드로는 다음과 같습니다.

function cosineSim(a: number[], b: number[]): number {
  const dot = a.reduce((s, v, i) => s + v * b[i], 0)
  const normA = Math.sqrt(a.reduce((s, v) => s + v * v, 0))
  const normB = Math.sqrt(b.reduce((s, v) => s + v * v, 0))
  return dot / (normA * normB)
}

이 함수 하나로 별도 Vector DB 없이 RAG의 핵심 검색 로직이 완성됩니다.

우리의 선택: No-Vector-DB RAG

접근장점단점적합 규모
pgvectorSQL과 통합, 관리 간편셋업 비용수만~수십만 건
Pinecone완전관리형, 빠름유료, 외부 의존수백만 건 이상
Upstash Vector서버리스 친화무료 한도 제한수만 건
in-memory + Vercel Blob의존성 제로, Vercel에 최적화1만 건 초과 시 느려짐1만 건 미만

이 강의가 선택한 방식은 마지막 행입니다. 청크 벡터를 JSON으로 직렬화해 Vercel Blob에 저장하고, 요청 시 로드해 코사인 유사도를 전수 계산합니다. 1만 건 미만에서는 Cold Start 포함 200~400ms 이내로 처리 가능하며, 추가 인프라 없이 프로덕션 배포까지 이어집니다.

주의: 문서 건수가 1만을 초과할 시점에 Upstash Vector나 pgvector로 마이그레이션하는 계획을 미리 설계해 두세요. 청크 스키마만 동일하게 유지하면 검색 레이어 교체가 수월합니다.

청킹 전략

문서를 어떻게 나누는가는 검색 품질에 직결됩니다.

전략방식적합 상황
Fixed글자 수/토큰 수로 고정 분할구조 없는 텍스트, 빠른 프로토타입
Semantic문장·단락 경계 기준 분할일반 문서, 블로그
Speaker발화자 전환 기준 분할회의록, 인터뷰 스크립트
Recursive단락→문장→어절 순 재귀 분할중첩 구조, 기술 문서

청크 크기는 보통 300~600 토큰을 권장합니다. 너무 작으면 컨텍스트가 부족하고, 너무 크면 검색 노이즈가 늘어납니다. 각 청크에는 source(파일명), page, chunkIndex 같은 메타데이터를 함께 저장해 출처 인용에 활용합니다.

평가 지표

RAG 파이프라인을 배포한 뒤 세 가지 지표로 품질을 측정합니다.

  • Faithfulness: 모델이 검색된 청크 내용만 사용해 답했는가. (근거 이탈 여부)
  • Answer Relevance: 답변이 원래 질문에 얼마나 관련 있는가.
  • Top-K Recall: 정답 청크가 상위 K개 검색 결과 안에 포함되는 비율. K=3 또는 K=5가 일반적.

환각 차단 4패턴

환각은 모델 문제이기 이전에 시스템 설계 문제입니다. 다음 네 가지를 파이프라인에 내재화하세요.

  1. Score 임계값: 코사인 유사도가 0.75 미만인 청크는 컨텍스트에 포함하지 않습니다. 낮은 점수의 청크를 억지로 넣으면 오히려 환각을 유발합니다.

  2. 출처 인용 강제: 시스템 프롬프트에 "반드시 [출처: {source}] 형식으로 근거를 표기하라"를 명시합니다. 인용이 불가능한 내용은 생성하지 못하게 됩니다.

  3. 청크 사이즈 조정: 답변이 단편적이면 청크를 키우고, 무관한 내용이 섞이면 청크를 줄입니다. 청크 크기는 고정값이 아니라 평가 루프로 조정하는 하이퍼파라미터입니다.

  4. 찾을 수 없으면 솔직히: 임계값을 넘긴 청크가 없을 때 "관련 문서를 찾지 못했습니다"라고 명시적으로 응답하도록 분기 처리합니다. 이 분기가 없으면 모델은 빈 컨텍스트로 답을 지어냅니다.

설계 원칙: RAG의 목적은 모델을 "더 똑똑하게" 만드는 것이 아니라, 답변의 범위를 문서로 제한하는 것입니다. 근거 없이 유창한 답변보다 근거 있는 짧은 답변이 프로덕션에서 훨씬 안전합니다.

핵심 정리

  • LLM의 Knowledge Cutoff와 Hallucination을 데이터 설계로 보완하는 것이 RAG의 역할이다.
  • text-embedding-3-small(1536차원) + 코사인 유사도 직접 구현으로 별도 Vector DB 없이 1만 건 미만 RAG를 운영한다.
  • 청크는 300~600 토큰, source/page/chunkIndex 메타데이터를 반드시 함께 저장한다.
  • 평가는 Faithfulness·Answer Relevance·Top-K Recall 세 지표로 파이프라인을 측정한다.
  • 환각 차단은 score 임계값 + 출처 인용 강제 + 청크 사이즈 조정 + 미발견 시 솔직 응답 네 가지로 구성한다.
  • 청크 스키마를 일관되게 유지하면, 규모가 커질 때 pgvector·Upstash로의 마이그레이션 비용을 최소화할 수 있다.