본문 바로가기

AI

[LLM] RAG (Retrieval-Augmented Generation)

반응형

1. RAG ?

RAG (Retrieval-Augmented Generation) LLM 새로운 정보를 검색하고 통합할 있도록 하는 기술이다. LLM 외부 데이터 소스에서 정보를 검색한 , 결과를 기반으로 응답을 생성하는 구조로 구성된다.

 

LLM 단독으로 사용했을 없는 사실을 생성하는 Hallucination 문제나, 최신 데이터 부족으로 인한 문제 등이 발생한다. RAG 사용하면 모델의 학습에 사용된 데이터 이외에 새로운 추가 정보를 제공함으로 이러한 문제들을 해결할 있다. 또한 응답 생성에 참고해야 하는 내용을 제공함으로 사용자가 원하는 내용을 정확하게 얻을 있다.

2. RAG 핵심 개념 동작 흐름

https://aws.amazon.com/what-is/retrieval-augmented-generation/

1) Indexing

사전 준비 단계로 RAG 구성하기 위해 데이터를 검색 가능한 형태로 변환하고 저장하는 단계이다. 문서를 chunk 단위로 분할하고 분할한 텍스트로 embedding 생성한다. 그리고 생성된 결과를 Vector DB 저장하여 추후 검색 가능한 상태로 준비한다.

2) Retrieval

사용자의 질문과 관련된 문서를 찾는 단계이다. 사용자 질문을 embedding 하여 vector 변환하고 변환된 쿼리로 유사도 계산을 통해 Vector DB 에서 관련성이 높은 문서들을 조회한다.

3) Augmentation & Genaration

검색된 결과를 기반으로 프롬프트를 구성하고 답변을 생성하는 단계이다. 검색 결과를 필터링하거나 re-ranking 통해 가공하여 사용한다.

 

그렇게 가공된 검색 결과와 사용자 질문에 프롬프트 엔지니어링을 적용하여 구성한 프롬프트를 LLM 전달하고 결과를 사용자에게 반환한다.

- Vector DB

문서 검색시에 단순한 키워드 검색이 아닌 의미 기반 검색을 위해서는 embedding 통해 데이터를 저장하고 이를 조회할 있어야 한다. 이를 위해서 사용되는 것이 Vector DB 이다.

 

미리 필요한 데이터들을 Vector DB 저장해두고 Retrieval 문서를 검색할 때에 사용한다.

3. RAG 구현 예제

이번에는 RAG 구현 예제를 작성해보려 한다. RAG 활용한 예제를 작성하기에 앞서 RAG 사용하지 않은 코드를 작성하고 똑같은 질문에 대해서 RAG 유무에 따라 어떻게 결과가 달라지는지 비교해보려 한다.

 

예제 쿼리는 chatGPT 로 생성했는데, 실제로 존재하지 않는 가상의 기술에 대한 질문을 한다. 이를 통해 관련 정보가 없는 질문에 대답할 때와 RAG 를 통해 해당 기술과 관련된 정보를 제공받았을 때의 답변 차이를 비교해보겠다.

 

먼저 RAG 를 사용하지 않고 LLM 쿼리를 실행하는 에제이다. Vector DB 나 특별한 데이터 관련 작업 없이 바로 OpenAI client 에게 쿼리를 요청한다.

 

from openai import OpenAI


LLM_MODEL = "gpt-5"
QUERY = "What is AcmeDB optimized for?"

client = OpenAI()

response = client.responses.create(
    model=LLM_MODEL,
    input=[
        {"role": "user", "content": QUERY}
    ]
)

print(response.output_text)

 

코드를 실행한 결과는 아래와 같이 출력된다. "AcmeDB" 라는 기술에 대해서 정보가 없어서 대답을 할 수 없다는 응답을 반환했다.

 

I’m not sure which “AcmeDB” you mean—there are multiple projects and products with that name. Could you share a link or a brief description? With the specific AcmeDB in question, I can tell you exactly what it’s optimized for.

 

이번에는 RAG 를 통해 "AcmeDB" 에 대한 정보를 제공해주고 쿼리를 실행해보곘다.

 

쿼리를 날리기 앞서 chroma db 를 사용하여 AcmeDB 에 대한 정보를 가지고 있는 vector DB 를 먼저 생성한다. 그 다음 vector db 에 쿼리를 실행해서 질문과 관련된 문서들을 조회한다. 그리고 조회된 문서를 기반으로 LLM 모델에 전송할 프롬프트를 구성했다.

 

from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction
from openai import OpenAI

import chromadb


LLM_MODEL = "gpt-5"
EMBEDDING_MODEL = "text-embedding-3-small"
COLLECTION_NAME="my-collection"
QUERY = "What is AcmeDB optimized for?"

client = OpenAI()

# vector db 초기화
chroma_client = chromadb.Client()
embedding_function = OpenAIEmbeddingFunction(model_name=EMBEDDING_MODEL)
collection = chroma_client.create_collection(
    name=COLLECTION_NAME,
    embedding_function=embedding_function
)

# 문서 저장
documents = [
    "AcmeDB is a distributed database optimized for write-heavy workloads. It uses LSM-tree and supports horizontal scaling."
]
collection.add(
    documents=documents,
    ids=["1"]
)

# 관련 문서 조회
results = collection.query(
    query_texts=[QUERY],
    n_results=1
)
documents = results["documents"][0]

# prompt 생성
context = "\n".join(documents)

prompt = f"""
Answer based only on the context below.

Context:
{context}

Question:
{QUERY}
"""

response = client.responses.create(
    model=LLM_MODEL,
    input=[
        {"role": "user", "content": prompt}
    ]
)

print(response.output_text)

 

rag 기반으로 구성한 프롬프트의 질문 결과는 아래와 같이 출력되었다. vector DB 에 저장한 문서의 내용과 일치하는 것을 확인할 수 있다.

 

Write-heavy workloads.

 

[Reference]

- https://ko.wikipedia.org/wiki/%EA%B2%80%EC%83%89%EC%A6%9D%EA%B0%95%EC%83%9D%EC%84%B1

- https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8_%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81

반응형

'AI' 카테고리의 다른 글

[LLM] LangChain  (0) 2026.03.28
[LLM] Vector, Embedding  (0) 2026.03.21
[LLM] OpenAI SDK Quickstart  (0) 2026.03.09
[LLM] LLM Provider 와 OpenAI API  (0) 2026.02.11