본문으로 건너뛰기
김신건의 로그

LLM RAG: Retrieval-Augmented Generation

· 수정 · 📖 약 3분 · 1,230자/단어 #ai #llm #rag #retrieval #vector-db #embedding
LLM RAG, RAG, Retrieval Augmented Generation, 검색 증강 생성, 검색 보강 생성

정의

RAG (Retrieval-Augmented Generation) 는 LLM 생성 전에 외부 지식 베이스에서 관련 문서를 검색 하여 프롬프트에 삽입하는 패턴. 최신 정보, 도메인 지식, 사설 데이터 접근이 필요할 때 사용한다.

LLM 파인튜닝 대신 검색으로 외부 지식을 주입하므로 추가 학습 비용 없이 최신 정보를 반영할 수 있다.

왜 필요한가

  • 최신 정보: LLM 학습 컷오프 이후 지식 (뉴스, 법령 개정 등)
  • 도메인 데이터: 회사 내부 문서, 개인 지식 베이스
  • hallucination 감소: 검색된 “출처” 를 명시해 사실성 검증 가능
  • 비용 절감: 파인튜닝 대비 데이터 갱신이 쉬움 (벡터 DB 업서트만 하면 됨)

파이프라인 전체 흐름

flowchart LR
    Q["사용자 질의"] --> E["쿼리 임베딩\n(Embedding Model)"]
    E --> V["벡터 DB 검색\n(ANN 인덱스)"]
    V --> R["상위 K 문서 검색\n(Dense / Sparse / Hybrid)"]
    R --> RR["Reranker\n(Cross-encoder)"]
    RR --> P["프롬프트 조합\nContext + Question"]
    P --> L["LLM\n(GPT-4o, Claude, Gemini)"]
    L --> A["최종 답변"]

인덱싱 파이프라인 (오프라인)

flowchart LR
    D["원본 문서\n(PDF, HTML, DB)"] --> C["Chunking\n500-1000 tokens"]
    C --> EM["Embedding 모델\nbge-large, text-embedding-3"]
    EM --> VS["Vector Store\n(Pinecone, pgvector, Qdrant)"]

핵심 구성 요소

1. 문서 Chunking 전략

문서를 청크 단위로 분할. 청크 크기와 전략이 검색 품질에 직결된다.

전략크기장점단점
고정 크기500 tokens단순문맥 경계에서 끊김
슬라이딩 윈도우500 + 50 overlap문맥 손실 최소화중복 저장
문단/섹션 기반가변의미 단위 유지크기 불균일
계층적 chunking문단 + 섹션요약 + 상세 동시복잡한 인덱싱
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", ".", " ", ""],
)
chunks = splitter.split_text(document)

2. Embedding 모델

각 청크를 고밀도 벡터 (dense vector) 로 변환. 의미적으로 유사한 텍스트는 벡터 공간에서 가깝게 위치한다.

모델차원언어특징
text-embedding-3-small1536다국어OpenAI, 저비용
text-embedding-3-large3072다국어OpenAI, 고성능
bge-large-en-v1.51024영어오픈소스, MTEB 상위
bge-m31024다국어오픈소스, 한국어 우수
nomic-embed-text768영어오픈소스, 로컬 실행 가능
from openai import OpenAI

client = OpenAI()

def embed(text: str) -> list[float]:
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text,
    )
    return response.data[0].embedding

3. Vector Store

임베딩 벡터를 저장하고 ANN (Approximate Nearest Neighbor) 검색을 제공하는 데이터베이스.

솔루션유형특징
Pinecone관리형완전 관리, 서버리스 플랜
Qdrant오픈소스Rust, 고성능, 페이로드 필터
Weaviate오픈소스멀티벡터, GraphQL
Milvus오픈소스대규모, CNCF 프로젝트
pgvectorPostgreSQL 확장기존 PG 통합, HNSW 지원
**[[redis-vector-searchRedis Vector Search]]**Redis 모듈
# pgvector 예시
import psycopg2
from pgvector.psycopg2 import register_vector

conn = psycopg2.connect("postgresql://...")
register_vector(conn)

cursor = conn.cursor()
cursor.execute("""
    SELECT content, embedding <=> %s AS distance
    FROM documents
    ORDER BY distance
    LIMIT 5
""", (query_embedding,))
results = cursor.fetchall()

4. Retrieval 방법

방법설명장점
Dense (벡터)코사인 유사도, HNSW의미적 유사성
Sparse (BM25)단어 빈도 기반정확한 키워드 매칭
HybridDense + Sparse 결합 (RRF)양쪽 장점
RerankerCross-encoder 재순위정확도 향상

RRF (Reciprocal Rank Fusion): Dense 와 Sparse 검색 결과 순위를 합산해 최종 순위 산출. 별도 학습 없이 Hybrid 효과.

5. Reranker

Dense 검색으로 상위 20-50개를 뽑은 뒤, Cross-encoder 모델로 질의-문서 쌍을 직접 스코어링해 재순위한다.

  • cross-encoder/ms-marco-MiniLM-L-12-v2 (오픈소스)
  • Cohere Rerank API (관리형)
from sentence_transformers import CrossEncoder

reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")

pairs = [(query, doc) for doc in candidate_docs]
scores = reranker.predict(pairs)
ranked_docs = [doc for _, doc in sorted(zip(scores, candidate_docs), reverse=True)]
top_k = ranked_docs[:5]

6. Prompt Composition

검색된 문서를 LLM 프롬프트에 조합.

You are a helpful assistant. Answer the question based ONLY on the provided context.
If the answer is not in the context, say "I don't know."

Context:
[Document 1]: {chunk_1}
[Document 2]: {chunk_2}
[Document 3]: {chunk_3}

Question: {user_query}
Answer:

고급 RAG 패턴

HyDE (Hypothetical Document Embeddings)

질의를 임베딩하는 대신, LLM 이 “가상의 답변” 을 먼저 생성한 뒤 그 답변을 임베딩해 검색. 질의와 문서 간 임베딩 공간 불일치 문제를 완화한다.

hypothesis = llm.generate(f"Write a hypothetical answer to: {query}")
hypothesis_embedding = embed(hypothesis)
results = vector_store.search(hypothesis_embedding, k=5)

Multi-Query Rewriting

질의를 여러 관점으로 재작성해 다수의 검색 결과를 합산.

queries = llm.generate(f"Rewrite the following query from 3 different perspectives:\n{query}")
all_results = [vector_store.search(q) for q in queries]
# RRF 로 합산

Query Routing

질의 종류에 따라 다른 인덱스나 도구로 라우팅.

flowchart TD
    Q["사용자 질의"] --> R["Router LLM"]
    R -->|"최신 뉴스"| WS["웹 검색 도구"]
    R -->|"내부 문서"| VS["내부 Vector DB"]
    R -->|"계산 필요"| CALC["계산기 도구"]
    R -->|"일반 질의"| LLM2["LLM 직접 답변"]

평가 지표

지표측정 대상
Recall@KK 개 검색 결과에 정답 포함 비율
MRRMean Reciprocal Rank, 정답 순위
Faithfulness답변이 컨텍스트에 근거한 정도
Answer Relevance답변이 질의에 적절한 정도
Context Precision검색된 문서 중 관련 비율
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_recall

result = evaluate(
    dataset=test_dataset,
    metrics=[faithfulness, answer_relevancy, context_recall],
)
print(result)

함정

WARNING

청크 경계에서 문맥이 잘린다. 고정 크기 chunking 은 문장 중간이나 표 안에서 잘릴 수 있다. 슬라이딩 윈도우 (overlap) 나 문단 기반 chunking 으로 보완해야 한다.

CAUTION

Reranker 후보군이 부족하면 역효과. Dense 검색 1차 후보를 top-5 만 뽑으면, 실제 정답이 애초에 후보에 없을 수 있다. 1차 검색은 top-20 이상, Reranker 로 top-5 압축하는 패턴이 일반적이다.

IMPORTANT

RAG 는 hallucination 을 줄이지 무조건 없애지 않는다. LLM 이 컨텍스트를 무시하고 학습 지식을 사용하는 경우가 있다. “컨텍스트에만 근거해 답하라” 지시 + Faithfulness 평가로 지속 모니터링이 필요하다.

관련 위키

이 글의 용어 (7개)
[LLM Eval] HELM: Holistic Evaluation of Language Modelsai
정의 HELM (Holistic Evaluation of Language Models) 는 Stanford CRFM (Center for Research on Foundation…
[Prompting] One-Shot Promptingai
정의 One-shot prompting 은 프롬프트에 정확히 1개의 입력-출력 예시 를 함께 제공하는 프롬프팅입니다. K=1 인 few-shot 의 특수 케이스이자 zero-sh…
[Redis] Vector Search: HNSW, SVS-VAMANA, Semantic Cachedatabase-internals
정의 Vector Search 는 임베딩 벡터의 거리/유사도 기준으로 근접한 K 개 를 찾는 검색. Redis 는 RediSearch 모듈 (Redis 8 부터는 코어) 과 Va…
[Voice AI] Agent 패턴: Supervisor, Handoff, ReAct, HITLai
정의 복잡한 음성 에이전트 = 여러 sub-agent + 조정 패턴. 단일 LLM 으로 처리하기 어려운 흐름. [!IMPORTANT] 각 sub-agent 내부는 VAD → ST…
[Voice AI] LLM Serving: vLLM, PagedAttention, continuous batchingai
정의 LLM Serving = 자체 호스팅 LLM 을 낮은 TTFT + 높은 throughput 으로 제공. 음성 에이전트의 LLM 단계 지연 결정. | 도구 | 특징 | |--…
[Voice AI] Voice RAG: 지연 병목 + 예측적 프리페치ai
정의 Voice RAG = 음성 에이전트에 RAG (Retrieval-Augmented Generation) 결합. 벡터 DB 조회 가 지연 누적 의 큰 원인이 되므로 예측적 프…
Function Calling / Tool Use: LLM 도구 사용ai
정의 Function Calling (또는 Tool Use) 은 LLM 이 사전 정의된 함수/도구를 호출하기 위한 인자를 JSON 으로 생성 하는 기능. JSON Schema 로…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기