
Spring AI는 Spring 생태계에서 LLM(대규모 언어 모델) 기반 애플리케이션을 개발할 수 있도록 설계된 프레임워크입니다. 그중에서도 RAG(Retrieval-Augmented Generation) 파이프라인은 외부 문서를 벡터 스토어에 저장하고, 사용자 질의와 유사한 문서를 검색해 LLM에게 컨텍스트로 제공하는 패턴으로, 할루시네이션(hallucination)을 줄이고 도메인 특화 응답 품질을 높이는 데 효과적입니다. 이 글에서는 Spring AI 1.x 기준으로 RAG 파이프라인을 단계별로 구성하는 방법을 다룹니다.
RAG 파이프라인의 구조 이해
RAG는 크게 두 단계로 나뉩니다.
- Ingestion(문서 적재): 문서를 청크(chunk)로 분할하고 임베딩(embedding) 벡터로 변환해 벡터 스토어에 저장합니다.
- Retrieval + Generation(검색 및 생성): 사용자의 질의를 임베딩해 유사도 검색을 수행한 뒤, 검색 결과를 프롬프트에 삽입해 LLM이 응답을 생성합니다.
Spring AI는 이 두 단계를 DocumentReader, TextSplitter, EmbeddingModel, VectorStore, ChatClient 등의 추상화 계층으로 지원합니다. 각 컴포넌트는 인터페이스 기반으로 설계되어 있어 OpenAI, Azure OpenAI, Ollama 등 다양한 백엔드로 교체할 수 있습니다.
의존성 설정 및 벡터 스토어 구성
Spring Initializr에서 spring-ai-openai-spring-boot-starter와 spring-ai-pgvector-store-spring-boot-starter를 선택하거나, 아래와 같이 pom.xml에 직접 추가합니다.
<!-- pom.xml -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- OpenAI 연동 (Chat + Embedding) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- PGVector 벡터 스토어 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>
</dependencies>application.yml에 API 키와 벡터 스토어 설정을 추가합니다.
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
embedding:
options:
model: text-embedding-3-small # 비용 효율적인 소형 모델
datasource:
url: jdbc:postgresql://localhost:5432/ragdb
username: postgres
password: ${DB_PASSWORD}PGVector를 사용하려면 PostgreSQL에 pgvector 확장이 활성화되어 있어야 합니다. Spring AI Auto-configuration이 활성화되면 VectorStore 빈이 자동으로 등록됩니다.
문서 적재(Ingestion) 파이프라인 구현
문서를 읽어 청크로 분할하고 벡터 스토어에 저장하는 과정입니다. TokenTextSplitter는 토큰 수 기반으로 청크를 나누며, 청크 크기와 오버랩(overlap)을 조정해 검색 품질을 개선할 수 있습니다.
@Service
@RequiredArgsConstructor
public class DocumentIngestionService {
private final VectorStore vectorStore;
public void ingest(Resource resource) {
// 1. PDF 또는 텍스트 파일 읽기
List<Document> rawDocs = new PagePdfDocumentReader(resource).get();
// 2. 청크 분할 — 512 토큰, 64 토큰 오버랩
TextSplitter splitter = new TokenTextSplitter(512, 64, 5, 10000, true);
List<Document> chunks = splitter.apply(rawDocs);
// 3. 임베딩 생성 후 벡터 스토어에 저장
vectorStore.add(chunks);
System.out.println("적재 완료: " + chunks.size() + "개 청크");
}
}적재 완료: 47개 청크PagePdfDocumentReader 외에도 TikaDocumentReader(다양한 문서 포맷 지원), JsonMetadataGenerator(메타데이터 보강) 등을 조합해 파이프라인을 확장할 수 있습니다.
검색 및 생성(RAG Query) 파이프라인 구현
Spring AI 1.x의 ChatClient는 advisors API를 통해 RAG 동작을 선언적으로 구성할 수 있습니다. QuestionAnswerAdvisor는 사용자 질의를 가로채 벡터 스토어 검색 결과를 프롬프트에 자동으로 삽입합니다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/rag")
public class RagController {
private final ChatClient.Builder chatClientBuilder;
private final VectorStore vectorStore;
@GetMapping("/ask")
public String ask(@RequestParam String question) {
// 유사도 높은 상위 5개 문서를 컨텍스트로 제공
SearchRequest searchRequest = SearchRequest.defaults()
.withTopK(5)
.withSimilarityThreshold(0.75); // 0~1, 높을수록 엄격
return chatClientBuilder.build()
.prompt()
.advisors(new QuestionAnswerAdvisor(vectorStore, searchRequest))
.user(question)
.call()
.content();
}
}변경전 — 단순 Chat 호출 (컨텍스트 없음):
// 도메인 문서 없이 LLM 기본 지식에만 의존 → 할루시네이션 발생 가능
chatClient.prompt().user(question).call().content();변경후 — QuestionAnswerAdvisor 적용:
// 벡터 스토어에서 관련 청크를 검색해 프롬프트에 자동 삽입
chatClient.prompt()
.advisors(new QuestionAnswerAdvisor(vectorStore, searchRequest))
.user(question).call().content();similarityThreshold는 0.75 정도를 시작점으로 삼되, 실제 프로젝트의 문서 품질과 쿼리 패턴에 따라 조정하는 것을 권장합니다. 값이 너무 높으면 관련 문서가 누락될 수 있고, 너무 낮으면 노이즈가 증가합니다.
맺음말
Spring AI의 RAG 파이프라인은 DocumentReader → TextSplitter → VectorStore → QuestionAnswerAdvisor의 흐름으로 구성됩니다. 각 컴포넌트가 인터페이스 기반으로 추상화되어 있어, LLM 제공자나 벡터 스토어를 교체할 때 애플리케이션 코드 변경을 최소화할 수 있습니다.
운영 환경에서는 다음 사항을 추가로 고려할 필요가 있습니다.
- 청크 크기 튜닝: 문서 유형(기술 문서 vs. 산문)에 따라 최적 청크 크기가 달라질 수 있습니다.
- 메타데이터 필터링:
FilterExpressionBuilder로 문서 출처, 날짜 범위 등을 조건으로 검색 범위를 좁히면 검색 정밀도를 높일 수 있습니다. - Re-ranking: 초기 검색 결과에 Cohere Rerank 등 교차 인코더를 적용해 최종 컨텍스트 품질을 개선할 수 있습니다.
Spring AI 공식 문서(docs.spring.io/spring-ai)에서 각 컴포넌트의 설정 옵션과 지원 모델 목록을 확인할 수 있습니다. RAG 패턴은 사내 지식 베이스 검색, 고객 지원 챗봇, 문서 기반 Q&A 등 다양한 영역에서 활용될 수 있습니다.
'프로그래밍 PROGRAMMING > 자바 JAVA AND FRAMEWORKS' 카테고리의 다른 글
| API Rate Limiting: 토큰 버킷·슬라이딩 윈도우로 트래픽 제어하기 (0) | 2026.04.15 |
|---|---|
| Spring WebSocket과 STOMP로 실시간 채팅 서버 구현하기 (0) | 2026.04.07 |
| gRPC Spring Boot 서비스 간 통신 구현하기 (0) | 2026.03.26 |
| Spring Batch 5로 대용량 데이터 처리하기 (0) | 2026.03.24 |
| Spring WebFlux + R2DBC 리액티브 DB 연동하기 (1) | 2026.03.21 |