Você pode integrar o MongoDB Vector Search ao LangChain4j para construir aplicativos LLM. Este tutorial demonstra como começar a usar o MongoDB Vector Search com o LangChain4j para realizar pesquisas semânticas em seus dados e criar uma implementação simples deRAG. Especificamente, você executa as seguintes ações:
Configure o ambiente.
Instancie o modelo de incorporação.
Use o MongoDB como um armazenamento de incorporação.
Armazene dados personalizados em seu cluster MongoDB .
Execute as seguintes query de pesquisa vetorial:
Pesquisa semântica.
Pesquisa semântica com pré-filtragem de metadados.
Implemente o RAG usando o MongoDB Vector Search para responder a perguntas sobre seus dados.
Plano de fundo
LangChain4j é um framework que simplifica a criação de aplicativos LLM em Java. LangChain4j combina conceitos e funcionalidades do LangChain, Haystack, LlamaIndex e outras fontes. Você pode usar este framework para uma variedade de casos de uso, incluindo pesquisa semântica e RAG.
Ao integrar o MongoDB Vector Search com o LangChain4j, você pode usar o MongoDB como um banco de dados vetorial e usar o MongoDB Vector Search para implementar RAG usando documentos semanticamente semelhantes para responder a queries. Para saber mais sobre RAG, consulte Geração Aumentada de Recuperação (RAG) com MongoDB.
Pré-requisitos
Para concluir este tutorial, você deve ter o seguinte:
Um dos seguintes tipos de cluster MongoDB :
Um cluster do Atlas executando a versão 6.0.11 do MongoDB, 7.0.2, ou posterior. Certifique-se de que seu endereço IP esteja incluído na lista de acesso do seu projeto Atlas.
Um sistema local do Atlas criado utilizando o Atlas CLI. Para saber mais, consulte Criar uma implantação de Atlas local.
Um cluster MongoDB Community ou Enterprise com Search e Vector Search instalados.
Uma chave de API da Voyage AI. Você deve ter uma conta com tokens disponíveis para solicitações de API. Para saber mais sobre como registrar uma conta Voyage AI, consulte o site da Voyage AI.
Uma chave de API da OpenAI. Você deve ter uma conta da OpenAI com créditos disponíveis para solicitações de API. Para aprender mais sobre como registrar uma conta OpenAI, consulte o website de API OpenAI.
Java Development Kit (JDK) versão 8 ou posterior.
Um ambiente para configurar e executar um aplicação Java . Recomendamos que você use um ambiente de desenvolvimento integrado (IDE) como IntelliJ IDEA ou Eclipse IDE para configurar Maven ou Gradle para construir e executar seu projeto.
Configurar o ambiente
Primeiro, você deve configurar o ambiente para este tutorial, o que inclui adicionar as dependências necessárias e definir as variáveis de ambiente.
Crie um novo aplicativo Java.
Abra seu IDE e crie um novo projeto Java, definindo as seguintes configurações:
Nome: LangChain4jSampleApp
Linguagem: Java
Sistema de construção: Maven
JDK: qualquer versão maior que
8
Talvez você veja uma opção para incluir um código de exemplo. Selecionar esta opção pode ajudá-lo a verificar se o seu ambiente está funcionando e localizar o arquivo do aplicativo que você editará nas etapas seguintes.
Adicione dependências.
Adicione as seguintes dependências à array
dependencies
no arquivopom.xml
do seu projeto. Essas dependências adicionam as bibliotecas LangChain4j, Voyage AI API para LangChain4j e MongoDB Java Sync Driver ao seu aplicativo:pom.xml<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-mongodb-atlas</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-voyage-ai</artifactId> <version>1.1.0-beta7</version> </dependency> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> <version>5.4.0</version> </dependency> Em seguida, adicione uma entrada
dependencyManagement
abaixo da sua lista de dependências para o Bill of Materials (BOM) do LangChain4j:pom.xml<dependencyManagement> <dependencies> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-bom</artifactId> <version>1.1.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Para aprender mais sobre o BOM do LangChain4j, veja a página Introdução na documentação do LangChain4j.
Depois de terminar de editar o arquivo
pom.xml
, recarregue o projeto para garantir que as dependências estejam instaladas.
Importar classes e métodos.
Localize o arquivo principal do aplicativo Main.java
em seu projeto. Substitua quaisquer importações existentes pela seguinte lista de importações:
import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import dev.langchain4j.data.document.Metadata; import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.voyageai.VoyageAiEmbeddingModel; import dev.langchain4j.store.embedding.EmbeddingMatch; import dev.langchain4j.store.embedding.EmbeddingSearchRequest; import dev.langchain4j.store.embedding.EmbeddingSearchResult; import dev.langchain4j.store.embedding.filter.comparison.*; import dev.langchain4j.store.embedding.mongodb.IndexMapping; import dev.langchain4j.store.embedding.mongodb.MongoDbEmbeddingStore; import org.bson.Document; import java.io.*; import java.util.*;
Mais adiante neste tutorial, você usará essas classes e os métodos para criar incorporações vetoriais e consultar dados.
Defina variáveis de ambiente.
Dependendo do seu IDE, pode haver várias maneiras de definir variáveis de ambiente que o seu aplicativo pode recuperar. Para definir variáveis de ambiente no IntelliJ, você deve criar uma configuração de executar para seu aplicativo. Para aprender mais, consulte a seção Sistema Operacional da página Configuração de executar/depuração: aplicativo na documentação do IntelliJ.
Defina as seguintes variáveis de ambiente:
MONGODB_URI
: Defina como para a string de conexão do MongoDB .VOYAGE_AI_KEY
: Defina a sua chave de API do Voyage AI.
Observação
Sua string de conexão deve usar o seguinte formato:
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net/?<settings>
Para saber mais sobre como obter sua string de conexão, consulte o tutorial Introdução ao Atlas.
Instanciar o Modelo de Incorporação
Nesta etapa, você instancia um modelo de incorporação que usa o Voyage AI para converter texto em dados de exemplo em embeddings vetoriais.
Adicione o seguinte código ao seu arquivo Main.java
para instanciar o modelo de incorporação usando sua chave de API da Voyage AI e selecionando voyage-3-large
como o modelo:
EmbeddingModel embeddingModel = VoyageAiEmbeddingModel.builder() .apiKey(embeddingApiKey) .modelName("voyage-3-large") .build();
Para aprender mais sobre o modelo voyage-3-large
, veja a publicação no blog sobre voyage-3 & voyage-3-lite no website da Voyage AI.
Use o MongoDB como armazenamento de incorporação
Nesta seção, você instancia o MongoDB como um banco de dados vetorial, também chamado de armazenamento vetorial ou de incorporação. Ao instanciar o armazenamento de incorporação, o LangChain4j cria automaticamente um índice do MongoDB Vector Search em seus dados.
Observação
Acesso necessário
Para criar um índice do MongoDB Vector Search, você deve ter acessoProject Data Access Admin
ou superior ao projeto MongoDB.
Este código executa as seguintes ações:
Cria uma instância
MongoClient
que está conectada à sua implantação do Atlas.Define o número de dimensões na definição do índice de pesquisa vetorial para a dimensão de incorporação do modelo de IA. O índice de pesquisa vetorial resultante tem a seguinte definição:
{ "fields": [ { "type": "vector", "path": "embedding", "numDimensions": 1024, "similarity": "cosine" } ] } Configura sua collection MongoDB especificando os seguintes parâmetros:
langchain4j_test.vector_store
como a coleção MongoDB para armazenar os documentos.vector_index
como o índice a ser usado para consultar o armazenamento de incorporação.
Como o booleano createIndex
está configurado para true
, a instância do armazenamento de incorporação cria automaticamente o índice de pesquisa vetorial. O código inclui um atraso para possibilitar a criação bem-sucedida de índices.
Adicione o seguinte código ao seu arquivo Main.java
:
MongoClient mongoClient = MongoClients.create(uri); System.out.println("Instantiating the embedding store..."); // Set to false if the vector index already exists Boolean createIndex = true; IndexMapping indexMapping = IndexMapping.builder() .dimension(embeddingModel.dimension()) .metadataFieldNames(new HashSet<>()) .build(); MongoDbEmbeddingStore embeddingStore = MongoDbEmbeddingStore.builder() .databaseName("search") .collectionName("langchaintest") .createIndex(createIndex) .indexName("vector_index") .indexMapping(indexMapping) .fromClient(mongoClient) .build(); if (createIndex) { // Creating a vector search index can take up to a minute, // so this delay allows the index to become queryable try { Thread.sleep(15000); } catch (InterruptedException e) { throw new RuntimeException(e); } }
Para aprender mais sobre as classes e métodos usados no código anterior, consulte a documentação da API do pacote dev.langchain4j.store.embedding.mongodb.
Armazenar dados personalizados
Nesta seção, você cria documentos de exemplo, usa o modelo de incorporação para converter o texto em incorporações e persiste os dados no MongoDB.
Este código executa as seguintes ações:
Cria uma lista de documentos de amostra que inclui os campos
text
emetadata
.Converte o conteúdo do campo
text
em incorporações e persiste os dados no MongoDB. O código inclui um atraso para acomodar o tempo necessário para a conversão vetorial.
Adicione o seguinte código ao seu arquivo Main.java
:
ArrayList<Document> docs = new ArrayList<>(); docs.add(new Document() .append("text", "In Zadie Smith's new novel, the true story of a heated nineteenth-century criminal trial connects to the unrest of current times.") .append("metadata", new Metadata(Map.of("author", "A")))); docs.add(new Document() .append("text", "Emperor penguins are the tallest and heaviest of all penguin species, standing up to 4 feet.") .append("metadata", new Metadata(Map.of("author", "D")))); docs.add(new Document() .append("text", "Penguins are flightless seabirds that live almost exclusively below the equator. Some island-dwellers can be found in warmer climates.") .append("metadata", new Metadata(Map.of("author", "C")))); docs.add(new Document() .append("text", "Patagonia is home to five penguin species - Magellanic, Humboldt, Gentoo, Southern Rockhopper and King.") .append("metadata", new Metadata(Map.of("author", "B")))); System.out.println("Persisting document embeddings..."); for (Document doc : docs) { TextSegment segment = TextSegment.from( doc.getString("text"), doc.get("metadata", Metadata.class) ); Embedding embedding = embeddingModel.embed(segment).content(); embeddingStore.add(embedding, segment); } // Delay for persisting data try { Thread.sleep(5000); } catch (InterruptedException e) { throw new RuntimeException(e); }
Executar queries no Vector Search
Esta seção demonstra como executar consultas em seus dados vetorizados.
Realize uma pesquisa semântica.
Este código executa uma query de pesquisa semântica para a frase "Where do penguins live?"
e retorna os três resultados mais relevantes. Ele também imprime uma pontuação que indica o quão bem cada resultado corresponde à query.
Adicione o seguinte código ao seu arquivo Main.java
:
String query = "Where do penguins live?"; Embedding queryEmbedding = embeddingModel.embed(query).content(); EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder() .queryEmbedding(queryEmbedding) .maxResults(3) .build(); System.out.println("Performing the query..."); EmbeddingSearchResult<TextSegment> searchResult = embeddingStore.search(searchRequest); List<EmbeddingMatch<TextSegment>> matches = searchResult.matches(); for (EmbeddingMatch<TextSegment> embeddingMatch : matches) { System.out.println("Response: " + embeddingMatch.embedded().text()); System.out.println("Author: " + embeddingMatch.embedded().metadata().getString("author")); System.out.println("Score: " + embeddingMatch.score()); }
Response: Penguins are flightless seabirds that live almost exclusively below the equator. Some island-dwellers can be found in warmer climates. Author: C Score: 0.829620897769928 Response: Patagonia is home to five penguin species - Magellanic, Humboldt, Gentoo, Southern Rockhopper and King. Author: B Score: 0.7459062337875366 Response: Emperor penguins are the tallest and heaviest of all penguin species, standing up to 4 feet. Author: D Score: 0.6908764839172363
(Opcional) Realize uma pesquisa semântica com filtragem de metadados.
Para realizar uma pesquisa com filtro de metadados, você pode usar classes do pacote dev.langchain4j.store.embedding.filter.comparison
. Essas classes permitem que você crie filtros que comparem valores de metadados com valores especificados para restringir os resultados retornados pela pesquisa.
Este exemplo filtra documentos nos quais o valor do campo author
é "B"
ou "C"
. Em seguida, ele executa uma consulta de pesquisa semântica para a frase "Where do penguins live?"
.
Substitua o código que instancia uma instância EmbeddingSearchRequest
na etapa anterior pelo seguinte código:
EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder() .queryEmbedding(queryEmbedding) .filter(new IsIn("author", List.of("B", "C"))) .maxResults(3) .build();
Response: Penguins are flightless seabirds that live almost exclusively below the equator. Some island-dwellers can be found in warmer climates. Author: C Score: 0.8520907163619995 Response: Patagonia is home to five penguin species - Magellanic, Humboldt, Gentoo, Southern Rockhopper and King. Author: B Score: 0.7666836977005005
Para saber mais sobre a pré-filtragem de metadados, consulte Pré-filtro de Vector Search do MongoDB.
Dica
Para obter mais informações, consulte a referência da API.
Use seus dados para dar resposta a perguntas.
Esta seção demonstra uma implementação de RAG que usa o framework LangChain4j e a Vector Search do MongoDB . Agora que você usou a Vector Search do MongoDB para recuperar documentos semanticamente semelhantes, use os exemplos de código a seguir para solicitar que o LLM responda às perguntas usando informações de documentos armazenados no MongoDB.
Configure seu projeto para RAG.
Adicione as seguintes dependências à array
dependencies
no arquivopom.xml
do seu projeto, mas não remova nenhuma das dependências que você já adicionou. Essas dependências adicionam os serviços de AI LangChain4j e a API OpenAI para as bibliotecas LangChain4j ao seu aplicativo:pom.xml<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>1.1.0</version> </dependency> Depois de terminar de editar o arquivo
pom.xml
, recarregue o projeto para garantir que as dependências estejam instaladas.Adicione as seguintes importações à sua lista de importações no seu arquivo
Main.java
:import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import dev.langchain4j.service.AiServices; import dev.langchain4j.model.chat.ChatLanguageModel; import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.rag.content.retriever.ContentRetriever; import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; Defina a variável de ambiente
OPENAI_KEY
para a sua chave de API da OpenAI. Você utiliza esta chave para criar um modelo de chat que gera uma resposta à sua query.
Carregue os dados de amostra.
Nesta etapa, você importa dados de uma fonte externa para o Atlas. Baixe o arquivo de dados de amostra rainforest-docs.json do repositório GitHub docs-code-examples
. Os documentos neste arquivo contêm informações sobre plantas, animais e condições climáticas na floresta tropical.
Envie este arquivo para o diretório resources
no seu projeto, que está no mesmo nível do diretório java
que contém os arquivos do seu aplicativo.
Você deve processar os dados em um formato utilizável do qual possa criar embeddings e persistir no Atlas. Este código define o método loadJsonDocuments()
que executa as seguintes ações:
Recupera os dados de amostra do seu diretório
resources
usando a classeClassLoader
.Analisa os documentos JSON em uma
List
de instâncias do MongoDBDocument
utilizando a classeObjectMapper
Adicione o seguinte código ao seu arquivo Main.java
fora do método principal:
private static List<Document> loadJsonDocuments(String resourcePath) throws IOException { // Loads file from resources directory using the ClassLoader InputStream inputStream = Main.class.getClassLoader().getResourceAsStream(resourcePath); if (inputStream == null) { throw new FileNotFoundException("Resource not found: " + resourcePath); } // Parses JSON file to List of MongoDB Documents ObjectMapper objectMapper = new ObjectMapper(); List<Document> documents = objectMapper.readValue(inputStream, new TypeReference<>() {}); return documents; }
Em seguida, adicione o seguinte código no corpo do método principal para chamar o método loadJsonDocuments()
e carregar seus documentos:
System.out.println("Loading documents from file..."); String resourcePath = "rainforest-docs.json"; List<Document> documents = loadJsonDocuments(resourcePath);
Armazene incorporações de vetores no Atlas.
Nesta etapa, você cria incorporações vetoriais a partir de seus documentos de amostra e as armazena no Atlas.
Este código converte o conteúdo dos campos text
nos documentos de amostra em embeddings e persiste os dados no Atlas. O código inclui um atraso para acomodar o tempo necessário para a conversão de vetores.
Adicione o seguinte código ao seu arquivo Main.java
:
System.out.println("Persisting document embeddings..."); for (Document doc : documents) { TextSegment segment = TextSegment.from( doc.getString("text"), new Metadata(doc.get("metadata", Map.class))); Embedding embedding = embeddingModel.embed(segment).content(); embeddingStore.add(embedding, segment); } try { Thread.sleep(5000); } catch (InterruptedException e) { throw new RuntimeException(e); }
Instancie o modelo de chat e especifique o recuperador de conteúdo.
Nesta etapa, você instancia um modelo de chat da OpenAI para dar resposta a perguntas com base em seus dados. Você também especifica um recuperador de conteúdo que apresenta documentos relevantes para informar a resposta elaborada pelo modelo de chat.
Este código executa as seguintes ações:
Instancia o modelo de chat usando sua chave de API OpenAI
Cria o recuperador de conteúdo com as seguintes especificações:
Recupere no máximo
3
documentos relevantesRecupera documentos que possuem uma pontuação de relevância de no mínimo
0.75
Adicione o seguinte código ao seu arquivo Main.java
no corpo do método principal:
String chatApiKey = System.getenv("OPENAI_KEY"); ChatLanguageModel chatModel = OpenAiChatModel.builder() .apiKey(chatApiKey) .modelName("gpt-4") .build(); ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder() .embeddingStore(embeddingStore) .embeddingModel(embeddingModel) .maxResults(3) .minScore(0.75) .build();
Dica
Filtragem de metadados
Você pode implementar a filtragem de metadados no seu ContentRetriever
utilizando o método construtor filter()
e passando uma instância de Filter
. Veja o exemplo de filtragem de metadados na etapa anterior para aprender a construir um Filter
.
Crie o assistente de chat.
Crie uma interface Assistant
simples que implemente a API de Serviços de IA no seu aplicativo. Crie um arquivo de interface chamado Assistant.java
no mesmo nível do seu arquivo Main.java
.
Defina a interface Assistant
:
package org.example; public interface Assistant { String answer(String question); }
No seu arquivo Main.java
, instancie o Assistant
:
Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(chatModel) .contentRetriever(contentRetriever) .build();
Realize consultas nos seus dados.
Finalmente, execute uma query nos seus dados de amostra. Adicione o seguinte código ao seu arquivo Main.java
para executar uma consulta e imprimir o resultado:
String ragQuery = "What types of insects live in the rainforest?"; String output = assistant.answer(ragQuery); System.out.println("Response:\n" + output);
Response: In the rainforest, there are numerous species of insects such as beetles, butterflies, moths, wasps, bees, flies, and ants. Of the many insects that live in the rainforest, ants are particularly important as they play a crucial role in nutrient recycling and aeration of the soil. Moreover, many of these insects are involved in the processes of pollination and decomposition. The adaptations these insects have developed enable their survival in the rainforest's specific conditions, characterized by heavy rainfall.
Próximos passos
O MongoDB também fornece os seguintes recursos para desenvolvedores:
Como criar um aplicativo RAG com o LangChain4j tutorial do site da DEV Community