For AI agents: the complete documentation index is available at https://docs.ovhcloud.com/fr/llms.txt, the full documentation bundle is available at https://docs.ovhcloud.com/fr/llms-full.txt, and this page is available as Markdown at https://docs.ovhcloud.com/fr/guides/public-cloud/ai-machine-learning/ai-endpoints-rag-chatbot-langchain4j.md.

AI Endpoints - Développer un chatbot de discussion RAG avec LangChain4j

Voir en Markdown

Apprenez à construire un chatbot RAG (Retrieval Augmented Generation) en utilisant Java et LangChain4j

Info

AI Endpoints est couvert par les Conditions particulières OVHcloud Public Cloud (voir l’Annexe 10 – « Conditions spécifiques – AI Endpoints »).

Introduction

Dans ce tutoriel, nous allons vous montrer comment créer un chatbot RAG (Retrieval Augmented Generation) qui améliore les réponses en intégrant vos propres documents personnalisés au contexte du LLM.

Pour cela, nous allons utiliser LangChain4j, un framework basé sur Java inspiré de LangChain, conçu pour simplifier l’intégration des LLM (Large Language Models) dans les applications. Notez que LangChain4j n’est pas officiellement maintenu par l’équipe de LangChain, malgré la ressemblance des noms.

Associé aux AI Endpoints d’OVHcloud, qui proposent à la fois des modèles LLM et des modèles d’embedding, il devient facile de créer des assistants avancés et prêts pour la production.

Définition

RAG (Retrieval Augmented Generation) : plutôt que de s’appuyer uniquement sur les connaissances intégrées d’un modèle, le RAG injecte vos propres données dans le prompt afin d’améliorer la pertinence des réponses.

Voici comment cela fonctionne :

  • Vos documents sont convertis en vecteurs à l’aide d’un modèle d’embedding.
  • Lorsque l’utilisateur pose une question, celle-ci est également transformée en vecteur.
  • Une recherche de similarité est effectuée pour trouver les segments de données les plus pertinents.
  • Ceux-ci sont transmis au LLM en tant que contexte, permettant des réponses fiables et précises.

En pratique

Configurer l’environnement

Afin d’utiliser facilement les API AI Endpoints, créez un fichier .env pour stocker les variables d’environnement :

OVH_AI_ENDPOINTS_MODEL_NAME=Mistral-7B-Instruct-v0.3
OVH_AI_ENDPOINTS_URL=https://oai.endpoints.kepler.ai.cloud.ovh.net/v1
OVH_AI_ENDPOINTS_EMBEDDING_MODEL_URL=https://bge-m3.endpoints.kepler.ai.cloud.ovh.net/api/text2vec
OVH_AI_ENDPOINTS_ACCESS_TOKEN=<ai-endpoints-api-token>

Veillez à remplacer la valeur du token (OVH_AI_ENDPOINTS_ACCESS_TOKEN) par la vôtre. Si vous n’en avez pas encore, suivez les instructions du guide AI Endpoints - Premiers pas.

Bien entendu, vous pouvez modifier les valeurs des variables d’environnement ci-dessus pour utiliser un autre LLM ou un autre modèle d’embedding.

Optionnel : configuration PostgreSQL

Si vous souhaitez conserver vos embeddings de documents entre les sessions ou les partager entre plusieurs services, vous pouvez utiliser une instance PostgreSQL avec l’extension pgvector.

Définissez les variables d’environnement suivantes pour configurer votre base de données :

export DATABASE_HOST=your-pgvector-host
export DATABASE_USER=your-pgvector-user
export DATABASE_PASSWORD=your-pgvector-password

Cette étape est toutefois optionnelle. En effet, si vous êtes simplement en phase de test ou si vous ne disposez pas d’une base de données PostgreSQL, LangChain4j prend également en charge un embedding store en mémoire. Cela permet de démarrer facilement sans avoir à configurer d’infrastructure externe.

Pour utiliser l’embedding store en mémoire, il vous suffira de remplacer la configuration de l’embedding store dans le code que nous allons écrire plus loin :

EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

Installer les librairies

Créez ensuite un fichier requirements.txt avec les librairies suivantes :

langchain
langchain-mistralai
langchain_community
langchain_chroma
argparse
unstructured
langchainhub
python-dotenv

Puis, lancez l’installation de ces dépendances :

pip install -r requirements.txt

Configurer le projet

Mettez à jour votre fichier de configuration pom.xml :

`<properties>`
  <langchain4j.version>0.33.0</langchain4j.version>
</properties>

`<dependencies>`
  `<dependency>`
    `<groupId>dev.langchain4j</groupId>`
    `<artifactId>langchain4j</artifactId>`
    `<version>${langchain4j.version}</version>`
  </dependency>
  `<dependency>`
    `<groupId>dev.langchain4j</groupId>`
    `<artifactId>langchain4j-ovh-ai</artifactId>`
    `<version>${langchain4j.version}</version>`
  </dependency>
  `<dependency>`
    `<groupId>dev.langchain4j</groupId>`
    `<artifactId>langchain4j-mistral-ai</artifactId>`
    `<version>${langchain4j.version}</version>`
  </dependency>
  `<dependency>`
    `<groupId>dev.langchain4j</groupId>`
    `<artifactId>langchain4j-pgvector</artifactId>`
    `<version>${langchain4j.version}</version>`
  </dependency>
</dependencies>

Créer la classe RAGStreamingChatbot

L’implémentation complète du chatbot RAG est disponible ci-dessous :

package com.ovhcloud.examples.aiendpoints;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.model.mistralai.MistralAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;


public class RAGStreamingChatbot {
  private static final Logger _LOG = LoggerFactory.getLogger(RAGStreamingChatbot.class);
  private static final String OVH_AI_ENDPOINTS_ACCESS_TOKEN = System.getenv("OVH_AI_ENDPOINTS_ACCESS_TOKEN");
  private static final String OVH_AI_ENDPOINTS_MODEL_NAME = System.getenv("OVH_AI_ENDPOINTS_MODEL_NAME");
  private static final String OVH_AI_ENDPOINTS_URL = System.getenv("OVH_AI_ENDPOINTS_URL"); 
  private static final String OVH_AI_ENDPOINTS_EMBEDDING_MODEL_URL = System.getenv("OVH_AI_ENDPOINTS_EMBEDDING_MODEL_URL"); 

  interface Assistant {
    TokenStream chat(String userMessage);
  }

  public static void main(String[] args) {
    MistralAiStreamingChatModel streamingChatModel = MistralAiStreamingChatModel.builder()
        .apiKey(OVH_AI_ENDPOINTS_ACCESS_TOKEN)
        .modelName(OVH_AI_ENDPOINTS_MODEL_NAME)
        .baseUrl(OVH_AI_ENDPOINTS_URL)
        .maxTokens(512)
        .build();

    Assistant assistant = AiServices
        .builder(Assistant.class)
        .streamingChatLanguageModel(streamingChatModel)
        .build();

    _LOG.info("\n💬: What is AI Endpoints?\n");

    TokenStream tokenStream = assistant.chat("Can you explain me what is AI Endpoints?");
    _LOG.info("🤖: ");
    tokenStream
        .onNext(_LOG::info)
        .onError(Throwable::printStackTrace)
        .start();
  }
}

Notez que le chatbot utilisera le mode streaming, comme expliqué dans le tutoriel Développer un chatbot avec mémoire en utilisant LangChain4j.

Tester le chatbot sans base de connaissances

Comme vous pouvez le voir ci-dessous, le LLM donne une réponse, mais pas celle attendue.

chatbot sans RAG

Cela n’a rien de surprenant, puisque le modèle a été entraîné avant qu’OVHcloud ne crée AI Endpoints. Le modèle ne connaît pas cette plateforme.

C’est pourquoi nous allons créer une base de connaissances, afin d’améliorer les réponses du LLM.

Préparer votre base de connaissances

Créez un dossier nommé rag-files, situé dans src/main/resources/rag-files, et placez-y vos fichiers .txt, .md ou autres documents textuels. Ceux-ci seront convertis en embeddings et utilisés lors de la récupération.

Vous trouverez un exemple de fichier dans notre dépôt GitHub public-cloud-examples.

Transformer le texte en vecteurs à l’aide d’AI Endpoints

Pour cela, nous allons créer des chunks à partir de notre document. Un chunk est une partie du document qui sera transformée en vecteur.

Il est ensuite utilisé pour effectuer une recherche de similarité. Il s’agit d’une phase délicate, et dans cet exemple, le découpage en chunks est basé sur le nombre de caractères. Dans un cas d’usage plus complexe, vous créerez des chunks en fonction du sens du texte.

public class RAGStreamingChatbot {

  // ...

  public static void main(String[] args) {
     // Load the document and split it into chunks
    DocumentParser documentParser = new TextDocumentParser();
    Document document = loadDocument(
            Path.of(ClassLoader.getSystemResource("rag-files/content.txt").toURI()),
            documentParser);
    DocumentSplitter splitter = DocumentSplitters.recursive(300, 0);

    List<TextSegment> segments = splitter.split(document);

    // ...
  }
}

Ensuite, vous transformez le texte en vecteurs et vous les stockez.

Si vous ne disposez pas d’une instance PostgreSQL managée, vous pouvez utiliser l’embedding store en mémoire mentionné précédemment (uniquement à des fins de test).

public class RAGStreamingChatbot {
  // ...

  private static final String DATABASE_HOST = System.getenv("DATABASE_HOST");
  private static final String DATABASE_USER = System.getenv("DATABASE_USER");
  private static final String DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD");


  public static void main(String[] args) {
    // ...

    EmbeddingStore<TextSegment> embeddingStore = PgVectorEmbeddingStore.builder()
                    .host(DATABASE_HOST)
                    .port(20184)
                    .database("rag_demo")
                    .user(DATABASE_USER)
                    .password(DATABASE_PASSWORD)
                    .table("rag_embeddings")
                    .dimension(768)
                    .createTable(false)
                    .build();

    // If you haven't a PostgreSQL database, you can use an in-memory embedding store
    // EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

    embeddingStore.addAll(embeddings, segments);
    ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(5)
        .minScore(0.9)
        .build();
    // ...

  }
}

Utiliser cette fonctionnalité RAG pour votre chatbot

Ajouter la fonctionnalité RAG au chatbot est simple : il suffit d’ajouter le ContentRetriever à l’Assistant dans la classe RAGStreamingChatbot :

public class RAGStreamingChatbot {
  // ...

  interface Assistant {
    TokenStream chat(String userMessage);
  }

  public static void main(String[] args) {
    // ...

    Assistant assistant = AiServices
        .builder(Assistant.class)
        .streamingChatLanguageModel(streamingChatModel)
        .contentRetriever(contentRetriever)
        .build();
    // ...
  }
}

À ce stade, vous avez terminé le développement de la classe RAGStreamingChatbot :

package com.ovhcloud.examples.aiendpoints;

import static dev.langchain4j.data.document.loader.FileSystemDocumentLoader.loadDocument;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.mistralai.MistralAiStreamingChatModel;
import dev.langchain4j.model.ovhai.OvhAiEmbeddingModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.pgvector.PgVectorEmbeddingStore;

public class RAGStreamingChatbot {
  private static final Logger _LOG = LoggerFactory.getLogger(RAGStreamingChatbot.class);
  private static final String DATABASE_HOST = System.getenv("DATABASE_HOST");
  private static final String DATABASE_USER = System.getenv("DATABASE_USER");
  private static final String DATABASE_PASSWORD = System.getenv("DATABASE_PASSWORD");
  private static final String OVH_AI_ENDPOINTS_ACCESS_TOKEN = System.getenv("OVH_AI_ENDPOINTS_ACCESS_TOKEN");
  private static final String OVH_AI_ENDPOINTS_MODEL_NAME = System.getenv("OVH_AI_ENDPOINTS_MODEL_NAME");
  private static final String OVH_AI_ENDPOINTS_URL = System.getenv("OVH_AI_ENDPOINTS_URL"); 
  private static final String OVH_AI_ENDPOINTS_EMBEDDING_MODEL_URL = System.getenv("OVH_AI_ENDPOINTS_EMBEDDING_MODEL_URL"); 

  interface Assistant {
    TokenStream chat(String userMessage);
  }

  public static void main(String[] args) {
     // Load the document and split it into chunks
    DocumentParser documentParser = new TextDocumentParser();
    Document document = loadDocument(
        RAGStreamingChatbot.class.getResource("/rag-files/content.txt").getFile(),
        documentParser);
    DocumentSplitter splitter = DocumentSplitters.recursive(300, 0);

    List<TextSegment> segments = splitter.split(document);

    // Do the embeddings and store them in an embedding store
    EmbeddingModel embeddingModel = OvhAiEmbeddingModel.builder()
        .apiKey(OVH_AI_ENDPOINTS_ACCESS_TOKEN)
        .baseUrl(OVH_AI_ENDPOINTS_EMBEDDING_MODEL_URL)
        .build();

    List<Embedding> embeddings = embeddingModel.embedAll(segments).content();

    EmbeddingStore<TextSegment> embeddingStore = PgVectorEmbeddingStore.builder()
                    .host(DATABASE_HOST)
                    .port(20184)
                    .database("rag_demo")
                    .user(DATABASE_USER)
                    .password(DATABASE_PASSWORD)
                    .table("rag_embeddings")
                    .dimension(768)
                    .createTable(false)
                    .build();

    // If you haven't a PostgreSQL database, you can use an in-memory embedding store
    // EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
    embeddingStore.addAll(embeddings, segments);
    ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(5)
        .minScore(0.9)
        .build();

    MistralAiStreamingChatModel streamingChatModel = MistralAiStreamingChatModel.builder()
        .apiKey(OVH_AI_ENDPOINTS_ACCESS_TOKEN)
        .modelName(OVH_AI_ENDPOINTS_MODEL_NAME)
        .baseUrl(OVH_AI_ENDPOINTS_URL)
        .maxTokens(512)
        .build();

    Assistant assistant = AiServices
        .builder(Assistant.class)
        .streamingChatLanguageModel(streamingChatModel)
        .contentRetriever(contentRetriever)
        .build();

    _LOG.info("\n💬: What is AI Endpoints?\n");

    TokenStream tokenStream = assistant.chat("Can you explain me what is AI Endpoints?");
    _LOG.info("🤖: ");
    tokenStream
        .onNext(_LOG::info)
        .onError(Throwable::printStackTrace)
        .start();
  }
}

Grâce à votre base de connaissances, notre nouveau chatbot répondra avec des informations pertinentes issues de votre source de données personnalisée.

chatbot avec RAG

Conclusion

Vous avez désormais créé un chatbot RAG (Retrieval-Augmented Generation) utilisant vos propres documents et la plateforme OVHcloud AI Endpoints. L’intégration de LangChain avec Chroma et les modèles d’embedding rend la mise en œuvre du RAG simple et même prête pour la production.

Aller plus loin

Si vous souhaitez aller plus loin et déployer votre chatbot dans le cloud, afin de rendre votre interface accessible à tous, consultez les articles et tutoriels suivants :

Pour une formation ou une assistance technique sur la mise en œuvre de nos solutions, contactez votre commercial ou consultez la page Professional Services pour obtenir un devis et faire analyser votre projet par nos experts.

Votre avis nous intéresse !

N’hésitez pas à nous faire part de vos questions, retours et suggestions concernant AI Endpoints et ses fonctionnalités :

  • Dans le canal #ai-endpoints du serveur Discord OVHcloud, où vous pouvez échanger avec la communauté et les équipes OVHcloud.
Cette page vous a-t-elle aidé ?