AI는 왜 우리 회사 문서를 모를까?

LLM이 사내 문서를 자동으로 알지 못하는 이유와 Spring AI RAG가 문서를 나누고 검색해 답변에 전달하는 과정을 쉽게 설명합니다.

Spring AI로 챗봇을 넘어 일하는 AI 만들기 5/9

Java·Spring 개발자가 LLM, RAG, Tool Calling, MCP를 공부하며 이해한 것들

이전 글 — 챗봇은 왜 방금 한 말을 잊어버릴까?

새로 입사한 사람에게 “프로젝트 알파를 배포하려면 누구의 승인을 받아야 하나요?”라고 물었다고 해보겠습니다. 이 사람은 개발 지식이 풍부해도 아직 회사의 배포 규정을 읽지 않았습니다. 답을 모르는 이유는 능력이 부족해서가 아니라 필요한 자료를 받지 못했기 때문입니다.

LLM(Large Language Model, 대규모 언어 모델)도 같습니다. 이미 학습된 모델은 우리 회사의 비공개 문서를 자동으로 알거나 읽을 수 없습니다. RAG는 질문과 관련된 문서 조각을 먼저 찾아 현재 요청의 문맥으로 모델에 전달하는 애플리케이션 설계 방식입니다.

이 글의 게시 흐름은 2026년 4월 2일에 놓여 있습니다. 개념과 코드는 2026년 8월 14일의 공식 안정 버전 Spring AI 2.0.0 문서를 기준으로 다시 확인했습니다. Spring AI 2.0.0이 게시일 당시 안정 버전이었다는 뜻은 아니며, 실제 모델·임베딩 모델·Vector DB를 설치하거나 검색 품질을 측정한 기록도 아닙니다.

이 글에 나오는 프로젝트 알파, 승인 규정, 담당자는 흐름 이해를 위한 가상 예시입니다.

회사 문서를 묻자 AI가 멈췄다

AI는 Java 문법이나 일반적인 배포 절차를 설명할 수 있습니다. 그러나 우리 회사의 휴가 규정, 상품 매뉴얼, 프로젝트별 승인 절차는 공개된 일반 지식과 다릅니다.

“인터넷의 수많은 내용을 아는 AI가 왜 내 컴퓨터의 문서 한 장은 모를까?”라는 의문이 생깁니다. 모델이 학습할 때 그 문서를 보지 않았고, 지금 요청에도 문서가 들어오지 않았기 때문입니다.

신입 사원 비유에서 이미 학습된 LLM은 신입 사원입니다. 회사 문서함은 모델이 자동으로 볼 수 없는 외부 지식이고, Retriever(검색기)는 필요한 자료를 찾는 사서입니다. 검색된 Context(현재 답변에 참고하도록 전달한 문맥)를 질문에 붙이는 과정은 Prompt Augmentation(프롬프트 보강), 그 입력을 바탕으로 답을 만드는 과정은 Generation(생성)에 해당합니다.

비유는 경계를 이해하기 위한 도구일 뿐 실제 시스템 전체를 표현하지는 않습니다. 현실에서는 파일 접근 권한, 문서 형식 변환, 검색 정책, 모델 호출과 로그 보안까지 애플리케이션이 설계해야 합니다.

모델이 아는 것과 애플리케이션이 가진 것은 다르다

앞선 4편에서는 지난 대화를 다시 전달하는 Chat Memory를 살펴봤습니다. 하지만 회사 문서는 대화 기록이 아닙니다. 이번에는 대화 밖의 지식을 찾아오는 RAG를 다룹니다.

구분 확인하려는 것 예시
학습 지식 모델이 학습 과정에서 익힌 것은 무엇인가? 언어 패턴, 일반 지식
대화 기억 이번 대화에서 무슨 말을 주고받았는가? 이름, 앞선 질문
외부 지식 회사 문서와 데이터베이스에는 무엇이 있는가? 사내 규정, 상품 매뉴얼

Chat Memory와 RAG는 모두 추가 정보를 현재 요청에 넣을 수 있습니다. 그러나 Chat Memory의 출처는 현재 대화이고, RAG의 출처는 대화 밖의 문서나 데이터입니다.

어느 쪽도 모델의 가중치를 바꾸는 학습 기능이 아닙니다. 애플리케이션이 현재 답에 필요한 정보를 골라 Prompt(모델에 전달하는 전체 지시와 입력)에 포함하는 방식입니다.

모델은 내 문서 폴더를 자동으로 볼 수 없다

Spring Boot 애플리케이션이 파일을 읽을 수 있다고 해서 LLM도 그 파일을 자동으로 읽는 것은 아닙니다. 모델은 회사 네트워크, 데이터베이스, 사내 API를 스스로 돌아다니며 검색하지 않습니다.

로컬 LLM도 내 컴퓨터의 모든 파일을 저절로 아는 것이 아닙니다. 반대로 클라우드 모델도 회사의 비공개 문서를 이미 학습했다고 볼 수 없습니다. 현재 요청에 전달되지 않은 문서는 답변의 근거가 될 수 없습니다.

외부 지식을 쓰려면 애플리케이션이 파일이나 데이터에 접근하는 통로를 명시적으로 만들어야 합니다. 누가 어떤 문서를 읽을 수 있는지 서버에서 확인하고, 필요한 부분만 모델에 전달해야 합니다.

RAG는 모델을 다시 공부시키는 기술이 아니다

RAG(Retrieval-Augmented Generation, 검색 증강 생성)는 질문과 관련 있는 자료를 먼저 찾고, 그 자료를 질문과 함께 모델에 건네 답을 생성하게 하는 방식입니다.

모델 가중치를 새로 학습시키는 방식이 아닙니다. 회사 문서 전체를 매 요청마다 Prompt에 넣는 방식도 아닙니다. 검색기가 관련성이 높다고 판단한 문서 조각을 찾아 현재 요청에 추가합니다.

신입 사원에게 회사 문서함 전체를 건네는 대신, 사서가 질문과 관련된 배포 규정 한 장을 찾아주는 장면과 비슷합니다. 사서가 엉뚱한 문서를 고르거나 오래된 규정을 건네면 답변도 틀릴 수 있습니다.

준비 단계와 질문 단계는 서로 다른 일이다

RAG는 먼저 문서를 검색할 수 있게 준비하고, 질문이 들어오면 관련 조각을 찾는 두 단계로 나눌 수 있습니다.

준비 단계: 문서를 검색할 수 있게 만든다

회사 문서
→ DocumentReader
→ Document
→ 문서 분할
→ Embedding
→ VectorStore 저장

DocumentReader는 PDF나 텍스트 같은 원본을 읽습니다. Document는 내용과 metadata(출처, 문서 종류 같은 부가 정보)를 담는 Spring AI의 문서 표현입니다.

긴 문서는 검색하기 좋은 작은 조각으로 나눕니다. 이를 Chunking(청킹, 문서 분할)이라고 합니다. Spring AI의 DocumentTransformer는 문서를 바꾸는 단계의 공통 역할이고, TokenTextSplitter는 Token 수를 기준으로 문서를 나누는 구현입니다.

Embedding(임베딩, 의미를 비교하기 위한 숫자 표현)은 텍스트를 숫자 배열로 바꿉니다. 임베딩은 문서 요약도 아니고 내용이 참인지 알려주는 점수도 아닙니다.

EmbeddingModel은 이 숫자 표현을 만들고, VectorStore는 벡터와 문서 내용, metadata를 저장해 유사도 검색을 제공합니다. 어떤 임베딩 모델과 저장소를 선택할지는 문서 언어, 운영 환경, 보안과 측정 결과에 따라 달라집니다.

질문 단계: 관련 문서를 찾아 현재 요청에 넣는다

사용자 질문
→ 질문 Embedding
→ VectorStore 유사도 검색
→ 관련 문서 조각 검색
→ 질문과 문서 조각을 모델에 전달
→ 답변 생성

Similarity Search(유사도 검색)는 질문과 의미가 가까운 문서 조각을 찾는 과정입니다. 문자열이 정확히 같은지만 비교하는 것이 아니라 임베딩 공간에서 가까운 후보를 찾습니다.

가깝다는 것은 질문과 관련될 가능성이 있다는 뜻입니다. 문서가 사실인지, 최신인지, 그 사용자가 볼 권한이 있는지까지 보장하지는 않습니다.

모델만 사용할 때와 RAG를 사용할 때

같은 질문을 회사 문서 없이 보낼 때와 관련 문서 조각을 찾아 함께 보낼 때의 차이를 보여줍니다.

1

사용자 질문

프로젝트 알파의 배포 승인자는 누구인가요?
2

질문 임베딩

[0.18, -0.42, …]문장의 의미를 비교하기 위한 숫자 표현
3

VectorStore 검색

휴가 규정 배포 규정보안 규정
4

현재 Context

배포 규정 4조: 프로젝트 알파의 운영 배포는 서비스 책임자의 승인을 받아야 한다.
5

LLM

전달받은 질문과 문맥으로 답변 생성
6

모델 응답

제공된 배포 규정에 따르면 서비스 책임자의 승인이 필요합니다.

현재 단계: 사용자가 회사 내부 규정에 관한 질문을 보냅니다.

프로젝트 알파와 배포 규정, 벡터 값, 답변은 흐름 이해를 위한 가상 예시입니다. 특정 모델이나 회사의 실제 검색·응답 결과가 아닙니다. 클라우드 모델이나 외부 서비스를 사용하면 문서 조각의 전송 경계도 별도로 확인해야 합니다.

RAG를 사용해도 다음 Token을 만든다

3편에서 LLM은 완성된 답을 데이터베이스에서 꺼내는 대신 다음 Token을 반복해서 선택한다고 설명했습니다. RAG를 사용해도 이 생성 원리는 바뀌지 않습니다.

모델은 검색된 문서를 정답지처럼 그대로 반환하지 않습니다. 질문과 문서 조각을 입력으로 받은 뒤 다음 Token 후보를 계산해 답을 만듭니다.

그래서 RAG를 붙여도 환각 가능성이 완전히 사라지지 않습니다. 문서를 잘 찾았더라도 모델이 일부를 빠뜨리거나 잘못 연결할 수 있고, Structured Output으로 JSON 형식을 맞춰도 그 안의 내용이 사실이라는 보장은 없습니다.

Spring AI는 RAG 흐름을 어떻게 연결할까?

Spring AI 2.0.0은 문서를 읽고 바꾸고 저장하는 ETL(Extract, Transform, Load, 추출·변환·적재) 흐름을 제공합니다. DocumentReader, DocumentTransformer, TokenTextSplitter, EmbeddingModel, VectorStore가 준비 단계의 주요 역할입니다.

질문 단계에서는 SearchRequest가 검색 조건을 표현합니다. QuestionAnswerAdvisor는 VectorStore에서 관련 문서를 찾아 사용자 질문의 문맥에 붙이는 기본 RAG 흐름을 ChatClient에 연결합니다.

RetrievalAugmentationAdvisor는 질의 변환, 문서 검색, 검색 결과 보강 같은 단계를 더 세밀하게 조립할 때 쓰는 모듈형 방식입니다. 이 글에서는 두 Advisor를 섞지 않고 기본 흐름인 QuestionAnswerAdvisor만 예제로 사용합니다.

공식 문서 기준으로 QuestionAnswerAdvisor를 쓰려면 다음 모듈이 필요합니다. 실제 임베딩 모델과 VectorStore 구현에는 선택한 제공자에 맞는 별도 의존성과 설정이 필요합니다.

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-vector-store-advisor</artifactId>
</dependency>

문서를 나누어 VectorStore에 저장하기

import java.util.List;

import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;

TokenTextSplitter tokenTextSplitter = TokenTextSplitter.builder().build();

List<Document> documents = documentReader.read();
List<Document> chunks = tokenTextSplitter.split(documents);

vectorStore.write(chunks);

documentReadervectorStore는 애플리케이션이 선택한 문서 형식과 저장소에 맞게 이미 구성됐다고 가정합니다. 원본을 읽고, 조각으로 나누고, 검색할 수 있게 저장하는 핵심 순서만 보여주는 코드입니다.

관련 문서를 찾아 질문과 함께 전달하기

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.model.ChatResponse;

QuestionAnswerAdvisor advisor = QuestionAnswerAdvisor.builder(vectorStore)
    .build();

ChatResponse response = ChatClient.builder(chatModel)
    .build()
    .prompt()
    .advisors(advisor)
    .user(userText)
    .call()
    .chatResponse();

사용자 질문이 들어오면 Advisor가 VectorStore에서 관련 문서를 찾습니다. 검색 결과를 질문의 문맥에 추가한 뒤 ChatClient가 모델을 호출하고, 모델은 전달받은 문맥을 참고해 답을 생성합니다.

두 코드는 Spring AI 2.0.0 공식 문서 기반 학습 예제입니다. 이 Astro 블로그 환경에서 임베딩 모델이나 Vector DB를 설치해 컴파일하거나 실제 검색 결과를 측정한 코드는 아닙니다.

RAG와 Fine-tuning은 무엇이 다를까?

Fine-tuning(미세 조정)은 추가 데이터로 모델의 행동이나 특정 패턴을 조정하는 학습 방식입니다. RAG와 목적이 다르며 어느 한쪽이 항상 더 좋은 대안은 아닙니다.

기준 RAG Fine-tuning
목적 필요한 외부 정보를 찾아 제공 모델의 행동이나 특정 패턴을 조정
문서 변경 반영 색인을 갱신 일반적으로 다시 학습하는 과정 필요
모델 가중치 변경 하지 않음 변경함
요청 시 문서 검색 반드시 하는 것은 아님
최신 사내 문서 질의 주로 적합 단독 대체 수단은 아님

최신 규정처럼 자주 바뀌는 사실을 조회하려면 RAG가 주로 맞습니다. 말투나 특정 작업 방식을 조정하려면 Fine-tuning이 맞을 수 있고, 필요하면 두 방식을 함께 사용할 수도 있습니다.

문서를 넣었다고 끝이 아니다

문서 조각이 너무 크면 관련 없는 내용까지 Prompt에 들어갑니다. 너무 작으면 질문에 필요한 문장이 서로 떨어질 수 있습니다. 임베딩 모델, 검색 결과 수, 유사도 기준도 검색 품질에 영향을 줍니다.

문서가 바뀌었는데 색인을 갱신하지 않으면 오래된 답이 검색될 수 있습니다. 삭제한 문서의 조각이 VectorStore에 남지 않도록 제거와 재색인 절차도 필요합니다. 중복되거나 잘못된 문서는 검색 후보 자체를 흐립니다.

문서를 많이 넣는다고 답변이 자동으로 좋아지지는 않습니다. 관련 없는 Context는 입력 길이와 비용을 늘리고, 모델이 중요한 근거를 놓치게 할 수 있습니다. 검색된 정보가 없거나 모델이 근거를 무시할 때 안전하게 “확인할 수 없다”고 처리하는 정책도 필요합니다.

보안은 별도 설계입니다. VectorStore가 있다고 접근 권한이 자동으로 보호되지 않습니다. 사용자가 볼 수 없는 문서는 검색 단계에서부터 제외해야 하며, 클라이언트가 보낸 userIdtenantId를 검증 없이 필터로 신뢰해서는 안 됩니다.

클라우드 모델을 사용하면 선택된 문서 조각이 외부 모델 API로 전송될 수 있습니다. 데이터 처리 정책, 전송 범위, 로그와 보존 기간을 확인해야 합니다. RAG라는 이름만 붙였다고 사내 문서가 자동으로 안전해지는 것은 아닙니다.

한 단계 더 깊게: VectorStore와 검색 조건

VectorStore는 질문과 문서 조각을 같은 임베딩 공간의 숫자 배열로 표현하고, 거리나 유사도 계산으로 가까운 후보를 찾습니다. 구현에 따라 비교 방식이 다를 수 있으므로 특정 저장소가 항상 cosine similarity를 사용한다고 단정할 수는 없습니다. 벡터 자체도 사람이 읽을 수 있는 정답은 아닙니다.

Spring AI의 SearchRequesttopK, similarityThreshold, metadata filter expression 같은 검색 조건을 설정할 수 있습니다. topK는 가져올 후보 수를 제한하고, threshold는 일정 기준보다 낮은 후보를 거르며, metadata 필터는 문서 종류나 권한 범위를 좁힐 때 사용할 수 있습니다.

후보를 많이 가져오거나 임계값을 높인다고 진실성이 보장되지는 않습니다. 권한 필터 역시 인증된 사용자와 문서 소유권을 서버에서 확인한 뒤 만들어야 합니다.

QuestionAnswerAdvisor는 기본 질문·검색·문맥 추가 흐름을 간단히 연결합니다. RetrievalAugmentationAdvisor는 검색과 증강 단계를 더 세밀하게 구성합니다. Chunking, Top-K, threshold, metadata와 최신성 문제는 다음 편에서 더 자세히 살펴봅니다.

자주 생기는 오해

로컬 LLM이면 내 파일을 자동으로 읽나요?

아닙니다. 파일 접근과 검색 통로를 애플리케이션이 명시적으로 만들고 권한을 확인해야 합니다.

RAG는 회사 문서로 모델을 다시 학습시키나요?

아닙니다. 모델 가중치를 바꾸지 않고 관련 문서 조각을 현재 요청에 추가합니다.

임베딩 값이 높으면 문서가 참인가요?

임베딩은 의미 비교를 위한 표현입니다. 유사도 검색은 가까운 후보를 찾을 뿐 사실성, 최신성, 접근 권한을 판정하지 않습니다.

문서를 많이 넣으면 답변이 좋아지나요?

항상 그렇지 않습니다. 잘못 나눈 조각, 오래된 문서, 관련 없는 검색 결과는 오히려 답변을 흐릴 수 있습니다.

RAG를 쓰면 환각이 없어지나요?

없어지지 않습니다. 검색과 생성 양쪽에 실패 지점이 있으며, 모델은 전달받은 문맥으로 여전히 다음 Token을 생성합니다.

세 줄 요약

  1. LLM은 전달받지 않은 회사 문서를 자동으로 알거나 읽을 수 없습니다.
  2. RAG는 질문과 관련된 문서 조각을 검색해 현재 요청의 문맥으로 모델에 전달합니다.
  3. 검색, 문서 최신성, 권한과 생성 과정에 실패 지점이 있으므로 RAG도 정답을 보장하지 않습니다.

다음 글 — 문서를 넣었는데 RAG는 왜 틀릴까?

관련 문서를 찾아서 모델에 넣어줬는데도, 왜 틀린 답을 할까?

다음 편에서는 Chunking, 검색 품질, Top-K, Similarity Threshold, Metadata Filtering, 문서 최신성과 평가를 살펴봅니다.

공식 문서