26/07/30 IL(I Learned) - RAG (1)

Let's take a break·2026년 8월 5일

RAG(Retrieval-Augmented Generation)와 Vector Database의 이해 및 Spring AI 기반 RAG 구조 학습

이번에는 기존의 생성형 AI(ChatGPT, Gemini 등)가 가지고 있는 한계를 해결하기 위한 RAG(Retrieval-Augmented Generation) 기술을 학습하였다. 이전 프로젝트에서는 LLM에게 사용자의 질문만 전달하여 답변을 생성하는 방식이었다면, 이번 프로젝트에서는 외부 문서를 Vector Database에 저장한 후 질문과 가장 유사한 문서를 검색하여 함께 전달하는 방식을 구현하였다.

이를 통해 LLM이 학습하지 않은 최신 정보나 회사 내부 문서와 같은 데이터를 활용하여 보다 정확한 답변을 생성할 수 있는 구조를 이해하였다. 또한 Spring AI에서 제공하는 VectorStore, EmbeddingModel, QuestionAnswerAdvisor, ChatClient를 활용하여 RAG 시스템을 구성하는 방법을 익혔다.


RAG(Retrieval-Augmented Generation)의 개념

이번 프로젝트에서 가장 먼저 학습한 내용은 RAG의 전체 동작 원리였다.

기존 LLM은 학습된 데이터만을 기반으로 답변을 생성하기 때문에 최신 정보나 학습되지 않은 내용을 질문하면 잘못된 정보를 생성하는 Hallucination(환각) 문제가 발생할 수 있다.

RAG는 이러한 문제를 해결하기 위해 질문과 관련된 문서를 먼저 검색한 후, 검색된 문서를 함께 LLM에 전달하여 답변을 생성하는 방식이다.

RAG의 전체 흐름은 다음과 같다.

사용자 질문

↓

질문 임베딩(Embedding)

↓

Vector Database 검색

↓

유사한 문서 추출

↓

질문 + 검색된 문서

↓

LLM

↓

최종 답변

기존에는 AI가 자신의 학습 데이터만을 이용해 답변을 생성했다면, RAG는 외부 문서를 근거(Context)로 함께 제공하기 때문에 더욱 신뢰성 있는 답변을 생성할 수 있다는 점을 이해하였다.


Embedding의 개념 이해

RAG를 구현하기 위해서는 텍스트를 숫자로 변환하는 과정이 필요하다.

이를 Embedding이라고 한다.

Embedding은 사람이 읽는 문자열을 AI가 계산할 수 있는 고차원의 벡터(Vector)로 변환하는 기술이다.

예를 들어

"사과"

↓

[0.21, -0.43, 0.81, ...]

처럼 하나의 문장이 수백 또는 수천 개의 실수값으로 변환된다.

이 벡터는 단순한 숫자가 아니라 문장의 의미를 포함하고 있기 때문에 의미가 비슷한 문장끼리는 벡터의 위치도 가까워진다.

이번 프로젝트에서는 Google의 Embedding Model을 이용하여 이러한 벡터를 생성하였다.


EmbeddingService 구현

@Service
@RequiredArgsConstructor
public class EmbeddingService {

    @Qualifier("googleGenAiTextEmbedding")
    private final EmbeddingModel embeddingModel;

    public float[] embed(String text) {
        return embeddingModel.embed(text);
    }
}

EmbeddingModel은 텍스트를 벡터로 변환하는 역할을 수행한다.

프로젝트에서는 googleGenAiTextEmbedding Bean을 주입받아 사용하였다.

embeddingModel.embed(text);

메서드를 호출하면 입력한 문자열이 AI 모델을 통해 임베딩되고, 결과는 float[] 형태의 벡터로 반환된다.

이 과정에서 개발자는 벡터 계산 과정을 직접 구현하지 않아도 되며, Spring AI가 내부적으로 Google Embedding API와 통신하여 결과를 받아온다.


Vector Database의 역할

이번 프로젝트에서는 생성된 벡터를 저장하기 위해 Vector Database(VectorStore) 를 사용하였다.

일반적인 데이터베이스는

이름 = 홍길동
나이 = 25

처럼 값을 비교한다.

반면 Vector Database는

질문 벡터

↓

문서 벡터

↓

유사도 계산

을 수행한다.

즉, 문장의 의미를 기준으로 가장 비슷한 문서를 찾는 데이터베이스라는 점을 이해하였다.


Spring AI의 VectorStore

Spring AI에서는 Vector Database를 추상화한 VectorStore 인터페이스를 제공한다.

private final VectorStore vectorStore;

VectorStore는 개발자가 사용하는 추상 인터페이스이며, 내부적으로는 pgvector와 같은 실제 Vector Database와 연결된다.

덕분에 개발자는 특정 Vector DB 구현체에 의존하지 않고 동일한 코드로 다양한 Vector Database를 사용할 수 있다.


ChatClient와 QuestionAnswerAdvisor

@Bean
public ChatClient ragChatClient(
        ChatClient.Builder builder,
        VectorStore vectorStore
) {

이번 프로젝트에서는 ChatClient를 생성하면서 VectorStore를 함께 주입하였다.

이를 통해 ChatClient는 질문을 받을 때마다 VectorStore에서 관련 문서를 검색할 수 있는 구조가 된다.


QuestionAnswerAdvisor

.defaultAdvisors(
    QuestionAnswerAdvisor.builder(vectorStore)

QuestionAnswerAdvisor는 RAG의 핵심 기능을 담당한다.

사용자가 질문하면 내부적으로 다음과 같은 과정을 자동으로 수행한다.

사용자 질문

↓

질문 임베딩

↓

VectorStore 검색

↓

관련 문서 조회

↓

Prompt 생성

↓

LLM 호출

즉, 개발자가 직접

  • 문서를 검색하고
  • Prompt를 조합하는 코드를 작성하지 않아도

Advisor가 자동으로 처리해 준다.


SearchRequest를 이용한 검색 조건 설정

QuestionAnswerAdvisor에서는 검색 방식을 설정할 수 있다.

.searchRequest(
    SearchRequest
        .builder()
        .topK(4)
        .similarityThreshold(0.5)
        .build()
)

여기서 새롭게 학습한 개념은 Top-KSimilarity Threshold이다.

Top-K

.topK(4)

질문과 가장 유사한 문서를 최대 4개까지 검색한다.

예를 들어

검색 결과가

문서1 98%

문서2 94%

문서3 91%

문서4 87%

문서5 82%

라면

Top-K가 4이므로 문서1~문서4까지만 AI에게 전달된다.


Similarity Threshold

.similarityThreshold(0.5)

는 최소 유사도를 의미한다.

예를 들어

문서1 0.91

문서2 0.74

문서3 0.52

문서4 0.31

이라면

Threshold가 0.5이므로

문서4는 제외된다.

이를 통해 검색 품질을 높이고 관련성이 낮은 문서가 AI에게 전달되는 것을 방지할 수 있다는 점을 학습하였다.


System Prompt를 이용한 RAG 응답 제어

.defaultSystem("""
주어진 컨텍스트를 기반으로 할 것.
컨텍스트에 없는 내용은 지어내지 말고
'찾을 수 없다'라고 답할 것.
답변은 마크다운으로 작성
""")

RAG에서는 검색된 문서를 AI에게 전달하는 것만큼 중요한 것이 System Prompt이다.

이번 프로젝트에서는 AI에게 다음과 같은 규칙을 부여하였다.

  • 검색된 문서를 기준으로 답변할 것
  • 문서에 없는 내용은 추측하지 말 것
  • 찾을 수 없으면 없다고 답변할 것
  • 마크다운 형식으로 응답할 것

이를 통해 Hallucination을 줄이고 신뢰성 있는 답변을 생성하는 방법을 학습하였다.


학습한 내용

학습 내용세부 내용
RAG검색(Retrieval)과 생성(Generation)을 결합한 AI 응답 방식
Embedding텍스트를 의미 기반 벡터로 변환하는 과정
EmbeddingModelGoogle Embedding 모델을 이용한 벡터 생성
VectorStore벡터를 저장하고 유사도 검색을 수행하는 인터페이스
ChatClientRAG 기능이 적용된 AI 클라이언트 구성
QuestionAnswerAdvisor질문과 관련된 문서를 검색하여 Prompt에 자동으로 포함
SearchRequestTop-K와 Similarity Threshold를 이용한 검색 조건 설정
System PromptAI가 검색된 문서를 기반으로만 답변하도록 제어하는 방법

느낀 점

이번 프로젝트를 통해 RAG는 단순히 AI에게 질문을 전달하는 기술이 아니라, 검색 시스템과 생성형 AI를 결합하여 답변의 정확성과 신뢰성을 높이는 구조라는 점을 이해할 수 있었다. 특히 Embedding을 통해 문장을 의미 기반의 벡터로 변환하고, Vector Database에서 가장 유사한 문서를 검색한 뒤 QuestionAnswerAdvisor가 이를 자동으로 프롬프트에 포함시키는 과정을 학습하면서 Spring AI가 RAG 파이프라인을 얼마나 효율적으로 추상화하고 있는지 체감할 수 있었다. 또한 Top-K와 Similarity Threshold를 조정하여 검색 결과의 품질을 제어하고, System Prompt를 통해 AI가 문서에 없는 내용을 추측하지 않도록 설정하는 방법을 익히면서 실제 서비스에서 신뢰성 있는 AI 응답을 제공하기 위한 핵심 요소들을 배울 수 있었다.

0개의 댓글