Elasticsearch를 임베딩 저장소로 활용한 LangChain4j

LangChain4j(Java용 LangChain)에는 임베딩 저장소로 Elasticsearch가 있습니다. 이를 사용하여 일반 Java로 RAG 애플리케이션을 빌드하는 방법을 알아보세요.

Elasticsearch를 직접 체험하려면 당사의 샘플 노트북을 살펴보거나, 무료 클라우드 체험판을 시작하거나, 지금 바로 로컬 기기에서 Elastic을 사용해 보세요.


이전 포스트에서 LangChain4j가 무엇이며 어떻게 사용하는지 알아보았습니다:

  • ChatLanguageModel 를 구현하여 LLM과 토론하고 ChatMemory
  • 메모리에 채팅 기록을 유지하여 LLM과의 이전 토론의 맥락을 기억할 수 있습니다.

이 블로그 게시물에서는 그 방법을 다룹니다:

  • 텍스트 예제에서 벡터 임베딩 만들기
  • Elasticsearch 임베딩 스토어에 벡터 임베딩 저장하기
  • 유사한 벡터 검색

임베딩 만들기

임베딩을 만들려면 사용할 EmbeddingModel 을 정의해야 합니다. 예를 들어 이전 게시물에서 사용한 것과 동일한 미스트랄 모델을 사용할 수 있습니다. 올라마와 함께 실행 중이었습니다:

모델은 텍스트에서 벡터를 생성할 수 있습니다. 여기에서 모델에서 생성된 차원 수를 확인할 수 있습니다:

텍스트에서 벡터를 생성하려면 다음을 사용할 수 있습니다:

또는 텍스트, 가격, 출시일 등을 필터링할 수 있도록 메타데이터를 제공하려는 경우 Metadata.from() 을 사용할 수 있습니다. 예를 들어, 여기에 게임 이름을 메타데이터 필드로 추가합니다:

이 코드를 실행하려면 Step5EmbedddingsTest.java 클래스를 확인하세요.

벡터를 저장하기 위해 Elasticsearch 추가하기

LangChain4j는 인메모리 임베딩 스토어를 제공합니다. 간단한 테스트를 실행할 때 유용합니다:

하지만 이 데이터스토어는 모든 것을 메모리에 저장하고 서버에 무한한 메모리가 없기 때문에 훨씬 더 큰 데이터세트에서는 이 방법이 작동하지 않을 수 있습니다. 따라서 임베딩을 Elasticsearch에 저장하는 대신 "elastic" 데이터와 함께 확장 및 축소할 수 있습니다. 이를 위해 프로젝트에 Elasticsearch를 추가해 보겠습니다:

아시다시피, 프로젝트에 Elasticsearch TestContainers 모듈을 추가하여 테스트에서 Elasticsearch 인스턴스를 시작할 수 있도록 했습니다:

Elasticsearch를 임베딩 저장소로 사용하려면 "" 에서 LangChain4j 인메모리 데이터 저장소에서 Elasticsearch 데이터 저장소로 전환하기만 하면 됩니다:

이렇게 하면 벡터가 Elasticsearch의 default 인덱스에 저장됩니다. 인덱스 이름을 더 의미 있는 이름으로 변경할 수도 있습니다:

이 코드를 실행하고 싶으시다면 Step6ElasticsearchEmbedddingsTest.java 클래스를 확인하세요.

유사한 벡터 검색

유사한 벡터를 검색하려면 먼저 이전에 사용한 것과 동일한 모델을 사용하여 질문을 벡터 표현으로 변환해야 합니다. 이미 그렇게 했기 때문에 다시 하는 것은 어렵지 않습니다. 이 경우 메타데이터는 필요하지 않습니다:

이 질문의 표현으로 검색 요청을 작성하고 임베딩 스토어에 첫 번째 상위 벡터를 찾도록 요청할 수 있습니다:

이제 결과를 반복하여 메타데이터에서 가져온 게임 이름 및 점수와 같은 일부 정보를 인쇄할 수 있습니다:

예상한 대로 "아웃런" 이 첫 번째 히트작이 됩니다:

이 코드를 실행하고 싶으시다면 Step7SearchForVectorsTest.java 클래스를 확인하세요.

비하인드 스토리

Elasticsearch 임베딩 저장소의 기본 구성은 백그라운드에서 대략적인 kNN 쿼리를 사용하고 있습니다.

하지만 임베딩 스토어에 기본 설정(ElasticsearchConfigurationKnn)과 다른 설정(ElasticsearchConfigurationScript)을 제공하면 변경할 수 있습니다:

ElasticsearchConfigurationScript 구현은 script_score 함수를 사용하여 쿼리를 cosineSimilarity 백그라운드에서 실행합니다.

기본적으로 전화할 때입니다:

이제 호출합니다:

이 경우 "주문" 결과는 변경되지 않지만 cosineSimilarity 호출은 근사치를 사용하지 않고 일치하는 각 벡터에 대한 코사인을 계산하기 때문에 점수만 조정됩니다:

이 코드를 실행하고 싶으시다면 Step7SearchForVectorsTest.java 클래스를 확인하세요.

결론

텍스트에서 임베딩을 얼마나 쉽게 생성할 수 있는지, 그리고 두 가지 다른 접근 방식을 사용하여 Elasticsearch에서 가장 가까운 이웃을 저장하고 검색하는 방법에 대해 알아보았습니다:

  • 기본값 ElasticsearchConfigurationKnn 옵션과 함께 대략적이고 빠른 knn 쿼리 사용
  • ElasticsearchConfigurationScript 옵션과 함께 정확하지만 느린 script_score 쿼리 사용

다음 단계는 여기서 배운 내용을 바탕으로 전체 RAG 애플리케이션을 구축하는 것입니다.

관련 콘텐츠

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

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

직접 사용해 보세요