-
Spring AI 시리즈 7화 – RAG 구축하기 (2): Chroma 연동 실습과 문서 기반 검색기술과 산업/언어 및 프레임워크 2025. 6. 9. 19:24728x90
Spring AI에서 Chroma Vector DB를 연동해 RAG 시스템을 구성하는 방법을 실습 중심으로 소개합니다. 문서 인덱싱, 벡터 저장, 유사도 기반 검색, LLM 응답까지의 전체 파이프라인을 구성합니다.
이전 글에서 우리는 RAG의 구조와 Vector Store의 역할에 대해 분석했습니다.
이번 글에서는 그 개념을 실제 코드로 구현해보는 단계입니다.
Spring AI가 제공하는 Chroma 연동 기능을 활용해 문서를 벡터로 저장하고,
유사 문서를 검색한 뒤 LLM에 전달하는 전 과정을 구현해보겠습니다.
개발 환경 준비
- Java 17+
- Spring Boot 3.2.x
- Spring AI 0.8.0
- Chroma (로컬 실행)
- OpenAI 또는 Hugging Face API 키
1. 의존성 추가
Chroma와 EmbeddingClient, LLM 호출을 위해 다음과 같이 의존성을 구성합니다.
Maven 설정
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>0.8.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-vectorstore-chroma</artifactId> <version>0.8.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-document</artifactId> <version>0.8.0</version> </dependency>
2. application.yml 설정
spring: ai: openai: api-key: ${OPENAI_API_KEY} embedding: options: model: text-embedding-ada-002 chroma: database: ./data/chroma
- text-embedding-ada-002는 OpenAI에서 제공하는 대표적인 임베딩 모델입니다.
- Chroma DB는 로컬 파일로 저장되며, 재시작해도 유지됩니다.
3. 문서 인덱싱 기능 구현
텍스트나 문서 파일을 분할하고 임베딩한 후, Chroma VectorStore에 저장합니다.
@Service public class DocumentIndexer { private final VectorStore vectorStore; public DocumentIndexer(VectorStore vectorStore) { this.vectorStore = vectorStore; } public void indexText(String content) { Document doc = new Document(content); vectorStore.add(List.of(doc)); } }
Spring AI의 Document 객체는 단순 문자열뿐 아니라,
PDF, HTML, Markdown, Plain text 등 다양한 형태의 문서를 로딩하는 기능을 제공합니다.
4. 유사 문서 검색 기능
사용자의 질문을 임베딩한 뒤, 벡터 유사도 기반으로 관련 문서를 검색합니다.
@Service public class DocumentSearcher { private final VectorStore vectorStore; public DocumentSearcher(VectorStore vectorStore) { this.vectorStore = vectorStore; } public List<Document> search(String query) { return vectorStore.similaritySearch(query); } }
검색 결과는 List<Document>로 반환되며,
각 Document에는 텍스트 내용과 함께 메타데이터도 포함되어 있어 후처리 가능성이 높습니다.
5. LLM 응답 생성: 검색 결과를 Prompt로 삽입
RAG의 핵심은 이 검색된 문서를 LLM에게 전달하는 방식에 있습니다.
@Service public class RAGService { private final ChatClient chatClient; private final DocumentSearcher searcher; public RAGService(ChatClient chatClient, DocumentSearcher searcher) { this.chatClient = chatClient; this.searcher = searcher; } public String ask(String question) { List<Document> docs = searcher.search(question); StringBuilder context = new StringBuilder(); for (Document doc : docs) { context.append(doc.getContent()).append("\n"); } String prompt = String.format(""" 다음은 참고 문서입니다: %s 위 문서를 바탕으로 다음 질문에 답해주세요: %s """, context.toString(), question); return chatClient.call(prompt).getResult().getOutput().getContent(); } }
6. REST 컨트롤러로 연동
@RestController @RequestMapping("/rag") public class RAGController { private final RAGService ragService; public RAGController(RAGService ragService) { this.ragService = ragService; } @GetMapping("/ask") public String ask(@RequestParam String q) { return ragService.ask(q); } }
이제 /rag/ask?q=회사 복지제도는 어떻게 되나요?
같은 식으로 질문을 보내면, 벡터 기반으로 관련 문서를 찾고,
그 내용을 기반으로 GPT가 답변하게 됩니다.
실전 팁
- 문서가 너무 길 경우, TextSplitter를 사용해 청크 단위로 분할
- 인덱싱 시 메타데이터(예: 파일명, 문서 출처 등)도 함께 저장 가능
- Chroma는 로컬에서 빠르게 테스트할 수 있으나,
운영 환경에서는 Milvus, Weaviate, Qdrant와 같은 고성능 저장소 고려 필요
정리
기능 기술 요소
텍스트 → 벡터 EmbeddingClient (text-embedding-ada-002) 벡터 저장 ChromaVectorStore 질문 → 유사 문서 검색 similaritySearch(query) 검색 결과 삽입 → 응답 생성 ChatClient.call(prompt) Spring AI는 이 전체 과정을 모듈별로 분리해 두었기 때문에
단계별로 교체하거나 확장하는 데 부담이 적습니다.728x90'기술과 산업 > 언어 및 프레임워크' 카테고리의 다른 글
FastAPI 시리즈 14화 - CORS 설정과 보안 헤더 적용하기 (1) 2025.06.09 Spring Boot 고급 시리즈 4화 – 프로파일 기반 구성 전략 완전 정복 (0) 2025.06.09 Spring Boot 고급 시리즈 3화 – 트랜잭션 전파와 고립 수준, 언제 어떻게 사용할까? (2) 2025.06.05 Spring AI 시리즈 6화 – RAG 구축하기 (1): Vector Store란 무엇인가 (3) 2025.06.05 Spring Framework 시리즈 13화 – @Controller와 @RestController 내부 구조와 처리 흐름 (0) 2025.06.05