벡터 데이터베이스로서의 Spring AI와 Elasticsearch

Spring AI와 Elasticsearch를 사용하여 완전한 AI 애플리케이션 구축하기.

Elasticsearch는 업계 최고 수준의 생성형 AI 도구 및 다양한 공급업체와 기본적으로 연동됩니다. Elastic 벡터 데이터베이스를 활용해 진행 중인 RAG 기본 넘어서기 또는 프로덕션 수준 앱 구축 웨비나를 확인해 보세요.

사용 사례에 가장 적합한 검색 솔루션을 구축하려면 무료 클라우드 체험판을 시작하거나 로컬 기기에서 Elastic을 지금 사용해 보세요.

이제 Spring AI를 정식으로 사용할 수 있으며, 첫 번째 안정적인 릴리스 1.0을 Maven Central에서 다운로드할 수 있습니다. 좋아하는 LLM과 벡터 데이터베이스를 사용하여 완벽한 AI 애플리케이션을 구축하는 데 바로 사용해 보세요. 또는 최종 애플리케이션을 사용하여 리포지토리로 바로 이동하세요.

스프링 AI란 무엇인가요?

AI 분야의 급속한 발전에 힘입어 상당한 개발 기간을 거쳐 이제 Java로 구현된 종합적인 AI 엔지니어링 솔루션인 Spring AI 1.0을 사용할 수 있게 되었습니다. 이번 릴리스에는 AI 엔지니어를 위한 필수적인 새 기능이 다수 포함되어 있습니다.

Java와 Spring은 이러한 AI 물결에 뛰어들 수 있는 최적의 위치에 있습니다. 수많은 기업이 Spring Boot를 기반으로 업무를 운영하고 있으며, 이를 통해 이미 수행 중인 업무에 AI를 매우 쉽게 연결할 수 있습니다. 기본적으로 번거로움 없이 비즈니스 로직과 데이터를 이러한 AI 모델에 바로 연결할 수 있습니다.

Spring AI는 다음과 같은 다양한 AI 모델과 기술을 지원합니다:

  • 이미지 모델: 텍스트 프롬프트가 주어진 이미지를 생성합니다.
  • 전사 모델: 오디오 소스를 가져와 텍스트로 변환합니다.
  • 임베딩 모델: 임의의 데이터를 의미론적 유사성 검색에 최적화된 데이터 유형인 벡터로 변환합니다.
  • 채팅 모델: 익숙하실 겁니다! 어딘가에서 잠깐이라도 대화를 나눈 적이 있을 것입니다.

채팅 모델은 AI 분야에서 가장 많은 관심을 받고 있는 분야이며, 당연히 훌륭합니다! 문서를 수정하거나 시를 쓰는 데 도움을 받을 수 있습니다. (아직은 농담을 부탁하지 마세요...) 멋진 기능이지만 몇 가지 문제가 있습니다.

AI 과제에 대한 스프링 AI 솔루션

Spring AI에서 이러한 문제와 그 해결책을 살펴보세요.

문제해결책
일관성채팅 모델은 개방적이고 주의가 산만해지기 쉽습니다.전체 모양과 구조를 관리하기 위한 시스템 프롬프트를 제공할 수 있습니다.
메모리AI 모델에는 메모리가 없으므로 특정 사용자가 보낸 메시지와 다른 사용자의 메시지를 연관시킬 수 없습니다.대화의 관련 부분을 저장할 수 있는 메모리 시스템을 제공할 수 있습니다.
격리AI 모델은 고립된 작은 샌드박스에서 생활하지만, 필요할 때 호출할 수 있는 도구에 대한 액세스 권한을 부여하면 정말 놀라운 일을 할 수 있습니다.Spring AI는 AI 모델에 환경의 도구에 대해 알려주면 AI 모델이 사용자에게 호출을 요청할 수 있는 도구 호출을 지원합니다. 이 멀티 턴 상호 작용은 모두 투명하게 처리됩니다.
개인 데이터AI 모델은 똑똑하지만 전지전능하지는 않습니다! 그들은 여러분의 독점 데이터베이스에 무엇이 있는지 알지 못하며, 저희도 여러분이 알기를 원하지 않을 것이라고 생각합니다!기본적으로 강력한 문자열 연결 연산자를 사용하여 모델이 질문을 보기 전에 요청에 텍스트를 입력하는 방식으로 프롬프트를 채워서 응답을 알려야 합니다. 원하는 경우 배경 정보를 입력하세요. 어떤 것을 보내고 어떤 것을 보내지 말아야 하는지 어떻게 결정하나요? 벡터 저장소를 사용하여 관련 데이터만 선택하여 전송합니다. 이를 검색 증강 생성 또는 RAG라고 합니다.
환각AI 채팅 모델은 채팅을 좋아합니다! 그리고 때때로 그들은 너무 자신만만해서 무언가를 만들어낼 수 있습니다.합리적인 결과를 확인하려면 한 모델을 사용하여 다른 모델의 결과를 검증하는 평가를 사용해야 합니다.

물론 어떤 AI 애플리케이션도 고립된 섬은 없습니다. 오늘날의 최신 AI 시스템과 서비스는 다른 시스템 및 서비스와 통합되었을 때 가장 잘 작동합니다. 모델 컨텍스트 프로토콜( )을 사용하면 작성된 언어에 관계없이 AI 애플리케이션을 다른 MCP 기반 서비스와 연결할 수 있습니다. 이 모든 것을 더 큰 목표를 향해 나아가는 에이전트 워크플로에 통합할 수 있습니다.

가장 좋은 점은? 기본적으로 모든 것을 위한 편리한 스타터 종속성이 Spring Initializr에서제공되므로 모든 Spring Boot 개발자에게 익숙한 관용구 및 추상화를 기반으로 구축하면서 이 모든 작업을 수행할 수 있습니다.

Spring AI는 사용자가 익히 알고 있고 기대하는 구성에 대한 관례적인 설정을 제공하는 편리한 Spring Boot 자동 구성을 제공합니다. 그리고 Spring AI는 Spring Boot의 액추에이터와 마이크로미터 프로젝트를 통해 통합 가시성을 지원합니다. 또한 GraalVM 및 가상 스레드와도 잘 작동하므로 확장성이 뛰어난 매우 빠르고 효율적인 AI 애플리케이션을 구축할 수 있습니다.

왜 엘라스틱서치인가

Elasticsearch는 전체 텍스트 검색 엔진이라는 것은 이미 알고 계실 겁니다. 그렇다면 이 프로젝트에 이 기술을 사용하는 이유는 무엇일까요? 벡터 스토어이기도 합니다! 데이터는 전문 옆에 있는 아주 좋은 데이터입니다. 다른 주목할 만한 장점도 있습니다:

  • 매우 간편한 설정
  • 오픈소스
  • 수평적 확장성
  • 조직의 자유 형식 데이터 대부분은 이미 Elasticsearch 클러스터에 있을 것입니다.
  • 완벽한 검색 엔진 기능
  • Spring AI에 완전히 통합되었습니다!

모든 것을 고려할 때, Elasticsearch는 훌륭한 벡터 저장소를 위한 모든 상자를 확인하므로 이를 설정하고 애플리케이션 구축을 시작해 보겠습니다!

Elasticsearch 시작하기

데이터베이스에 호스팅된 데이터와 상호 작용하는 데 사용할 UI 콘솔인 Elasticsearch와 Kibana가 모두 필요합니다.

Docker 이미지와 Elastic.co 홈페이지의 장점 덕분에 로컬 컴퓨터에서 모든 것을 사용해 볼 수 있습니다. 여기로 이동하여 아래로 스크롤하여 curl 명령을 찾아 실행한 후 셸에 바로 파이프합니다:

이렇게 하면 Elasticsearch와 Kibana를 위한 Docker 이미지를 가져와 구성하기만 하면 몇 분 후에 연결 자격 증명이 완료되어 로컬 컴퓨터에서 실행할 수 있습니다.

또한 Elasticsearch 인스턴스와 상호 작용하는 데 사용할 수 있는 두 개의 서로 다른 URL이 있습니다. 메시지가 표시되면 브라우저에서 http://localhost:5601 을 가리킵니다.

로그인할 때 필요한 사용자 이름 elastic 및 비밀번호(위의 출력 예시에서는 각각 elasticw1GB15uQ)도 콘솔에 인쇄되어 있습니다.

앱 통합하기

Spring 초기화 페이지로 이동하여 다음 종속성을 사용하여 새 Spring AI 프로젝트를 생성합니다:

  • Elasticsearch Vector Store
  • Spring Boot Actuator
  • GraalVM
  • OpenAI
  • Web

가장 최신 버전인 Java(이 글을 쓰는 시점 기준으로 Java 24 이상)와 원하는 빌드 도구를 선택해야 합니다. 이 예제에서는 Apache Maven을 사용하고 있습니다.

Generate 을 클릭한 다음 프로젝트의 압축을 풀고 원하는 IDE로 프로젝트를 가져옵니다. (저희는 IntelliJ IDEA를 사용하고 있습니다.)

먼저 Spring Boot 애플리케이션에 대한 연결 세부 정보를 지정해 보겠습니다. application.properties, 에 다음을 입력합니다:

또한 Spring AI의 벡터 저장소 기능을 통해 데이터 구조 측면에서 Elasticsearch 측에 필요한 모든 것을 초기화할 수 있으므로 지정해 주세요:

이 데모에서는 OpenAI, 특히 임베딩 모델과 채팅 모델을 사용하겠습니다( Spring AI가 지원하는 한 원하는 서비스를 자유롭게 사용하세요).

임베딩 모델은 데이터를 Elasticsearch에 저장하기 전에 데이터의 임베딩을 생성하는 데 필요합니다. OpenAI가 작동하려면 API key 을 지정해야 합니다:

SPRING_AI_OPENAI_API_KEY 같은 환경 변수로 정의하여 소스 코드에 자격 증명을 숨기지 않도록 할 수 있습니다.

파일을 업로드할 예정이므로 서블릿 컨테이너에 업로드할 수 있는 데이터의 양을 사용자 지정해야 합니다:

거의 다 왔습니다! 코드 작성에 들어가기 전에 이것이 어떻게 작동하는지 미리 살펴봅시다.

컴퓨터에서 다음 파일 (보드 게임 규칙 목록)을 다운로드하여 test.pdf 으로 이름을 바꾸고 ~/Downloads/test.pdf 에 넣었습니다.

파일은 /rag/ingest 엔드포인트로 전송됩니다(로컬 설정에 따라 경로를 변경하세요):

몇 초 정도 걸릴 수 있습니다...

그 뒤에서 데이터는 데이터의 임베딩을 생성하는 OpenAI로 전송되고, 그 데이터는 벡터와 원본 텍스트 모두 Elasticsearch에 기록됩니다.

그 데이터와 그 안에 포함된 모든 임베딩이 바로 마법이 일어나는 곳입니다. 그런 다음 VectorStore 인터페이스를 사용하여 Elasticsearch를 쿼리할 수 있습니다.

전체 흐름은 다음과 같습니다:

  • HTTP 클라이언트가 선택한 PDF를 Spring 애플리케이션에 업로드합니다.
  • Spring AI는 PDF에서 텍스트 추출을 처리하고 각 페이지를 800자 단위의 청크로 분할합니다.
  • OpenAI는 각 청크에 대한 벡터 표현을 생성합니다.
  • 그런 다음 청크된 텍스트와 임베딩이 모두 Elasticsearch에 저장됩니다.

마지막으로 쿼리를 발행합니다:

관련 답변을 드리겠습니다:

멋지네요! 이 모든 것이 어떻게 작동하나요?

  • HTTP 클라이언트가 Spring 애플리케이션에 질문을 제출합니다.
  • Spring AI는 OpenAI로부터 질문의 벡터 표현을 가져옵니다.
  • 이 임베딩을 통해 저장된 Elasticsearch 청크에서 유사한 문서를 검색하고 가장 유사한 문서를 검색합니다.
  • 그런 다음 Spring AI는 질문과 검색된 컨텍스트를 OpenAI로 전송하여 LLM 답변을 생성합니다.
  • 마지막으로 생성된 답변과 검색된 컨텍스트에 대한 참조를 반환합니다.

Java 코드를 자세히 살펴보고 실제로 어떻게 작동하는지 확인해 보겠습니다.

우선, 메인 클래스: 모든 스프링 부트 애플리케이션에 기본으로 제공되는 표준 메인 클래스입니다.

볼 것이 없습니다. 계속 진행...

다음은 기본 HTTP 컨트롤러입니다:

컨트롤러는 단순히 파일 수집을 처리하기 위해 구축한 서비스를 호출하여 파일을 Elasticsearch 벡터 저장소에 쓰고, 동일한 벡터 저장소에 대한 쿼리를 용이하게 하기만 하면 됩니다.

서비스를 살펴보겠습니다:

이 코드는 모든 수집을 처리합니다. 바이트 단위의 컨테이너인 Spring 프레임워크 Resource 가 주어지면, Spring AI의 PagePdfDocumentReader 를 사용하여 PDF 데이터( .PDF 파일로 추정 - 임의의 입력을 허용하기 전에 반드시 유효성을 검사해야 합니다!)를 읽은 다음 Spring AI의 TokenTextSplitter 를 사용하여 토큰화하고, 마지막으로 결과 List<Document>VectorStore 구현인 ElasticsearchVectorStore 에 추가합니다.

/rag/ingest 엔드포인트로 파일을 전송한 후 브라우저를 열어 localhost:5601 으로 이동하고 왼쪽 사이드 메뉴에서 Dev Tools 으로 이동합니다. 여기에서 쿼리를 실행하여 Elasticsearch 인스턴스의 데이터와 상호 작용할 수 있습니다.

다음과 같이 쿼리를 실행합니다:

이제 재미있는 부분은 사용자 쿼리에 대한 응답으로 데이터를 어떻게 다시 가져올 수 있을까요?

다음은 directRag 이라는 메서드에서 쿼리를 구현한 첫 번째 컷입니다.

코드는 매우 간단하지만 여러 단계로 세분화해 보겠습니다:

  1. VectorStore 을 사용하여 유사도 검색을 수행합니다.
  2. 모든 결과가 주어지면 기본 Spring AI Document를 가져와서 텍스트를 추출하여 모두 하나의 결과로 연결합니다.
  3. VectorStore 의 결과를 모델에게 보내고 모델에게 수행할 작업을 지시하는 프롬프트와 사용자의 질문을 함께 보냅니다. 응답을 기다렸다가 반환합니다.

검색 증강 세대인 RAG입니다. 벡터 저장소의 데이터를 사용하여 모델이 수행하는 처리 및 분석에 정보를 제공한다는 아이디어입니다. 이제 어떻게 하는지 알았으니 더 이상 그럴 필요가 없기를 바랍니다! 어쨌든 이렇게는 안 됩니다: Spring AI의 어드바이저가 이 과정을 더욱 간소화해 드립니다.

어드바이저를 사용하면 애플리케이션과 벡터 스토어 사이에 추상화 계층을 제공하는 것 외에 주어진 모델에 대한 요청을 사전 및 사후 처리할 수 있습니다. 빌드에 다음 종속성을 추가하세요:

advisedRag(String question) 라는 메서드를 클래스에 추가합니다:

모든 RAG 패턴 로직은 QuestionAnswerAdvisor 에 캡슐화되어 있습니다. 그 외의 모든 것은 ChatModel 으로 요청하는 것과 동일합니다! 멋지네요!

전체 코드는 GitHub에서 다운로드할 수 있습니다.

결론

이 데모에서는 Docker 이미지를 사용하고 로컬 머신에서 모든 작업을 수행했지만, 여기서는 프로덕션에 적합한 AI 시스템과 서비스를 구축하는 것이 목표입니다. 이를 실현하기 위해 할 수 있는 몇 가지 방법이 있습니다.

우선, 스프링 부트 액추에이터를 추가하여 토큰 소비를 모니터링할 수 있습니다. 토큰은 모델에 대한 특정 요청의 복잡성(때로는 달러와 센트)에 대한 비용의 대리인입니다.

이미 클래스 경로에 Spring Boot 액추에이터가 있으므로 다음 프로퍼티를 지정하여 모든 메트릭을 표시하기만 하면 됩니다(멋진 Micrometer.io 프로젝트에서 캡처한):

애플리케이션을 다시 시작합니다. 쿼리를 작성한 다음 http://localhost:8080/actuator/metrics 으로 이동합니다. "token"를 검색하면 애플리케이션에서 사용 중인 토큰에 대한 정보를 확인할 수 있습니다. 계속 지켜보시기 바랍니다. 물론 Elasticsearch용 Micrometer의 통합을 사용하여 이러한 메트릭을 푸시하고 Elasticsearch가 선택한 시계열 데이터베이스로 작동하도록 할 수도 있습니다!

그런 다음 Elasticsearch와 같은 데이터 저장소나 OpenAI 또는 기타 네트워크 서비스에 요청을 할 때마다 IO를 수행하게 되며, 종종 그 IO가 실행되는 스레드를 차단한다는 점을 고려해야 합니다. Java 21 이상 버전에는 확장성을 획기적으로 개선하는 논-블럭킹 가상 스레드가 제공됩니다. 다음으로 활성화합니다:

마지막으로, 애플리케이션과 데이터가 잘 성장하고 확장할 수 있는 곳에서 호스팅하는 것이 좋습니다. 애플리케이션을 실행할 위치에 대해 이미 생각해 보셨겠지만, 데이터를 어디에 호스팅할 것인가? Elastic Cloud를 추천해도 될까요? 안전하고, 비공개적이며, 확장 가능하고, 다양한 기능을 제공합니다. 가장 좋아하는 부분은? 원하는 경우, 사용자가 아닌 Elastic이 호출기를 착용하는 서버리스 에디션을 받으실 수 있습니다!

관련 콘텐츠

최첨단 검색 환경을 구축할 준비가 되셨나요?

충분히 고급화된 검색은 한 사람의 노력만으로는 달성할 수 없습니다. Elasticsearch는 여러분과 마찬가지로 검색에 대한 열정을 가진 데이터 과학자, ML 운영팀, 엔지니어 등 많은 사람들이 지원합니다. 서로 연결하고 협력하여 원하는 결과를 얻을 수 있는 마법 같은 검색 환경을 구축해 보세요.

직접 사용해 보세요