Spring Boot et OpenAI - Une incursion dans l’AI générative

Spring Boot, un Framework très utilisé pour le développement d’applications Java modernes et évolutives, se rencontre avec OpenAI, une entreprise de recherche en intelligence artificielle axée sur la promotion et le développement de l’intelligence artificielle responsable. Bien que ces deux technologies opèrent dans des domaines d’expertise distincts, il est envisageable de les fusionner pour créer des applications captivantes.

Dans cet article, nous verrons quelques-unes des techniques d’ingénierie de prompt (invites) à l’aide de Spring AI

Qu’est-ce que Spring AI

L’initiative Spring AI, vise à simplifier la création d’application qui intègre des fonctions d’intelligence artificielle, à la rendre plus simple et à éviter toute complexité inutile.

Cette initiative prend inspiration de projets Python largement reconnus tels que LangChain et LlamaIndex. Néanmoins, il est important de souligner que Spring AI ne se contente pas d’être une simple copie de ces projets.

Spring AI repose sur la conviction que la prochaine génération d’applications d’IA générative ne sera pas restreinte exclusivement aux seuls passionnés de Python.

Générer le projet Spring Boot

Pour simplifier la génération de votre projet, vous pouvez utiliser le projet Spring Initializr ou encore Spring Cli, les starters sont disponibles pour aider à mettre en place les dépendances et les classes essentielles.

Il existe également une collection d’exemples d’applications pour vous aider à explorer les fonctionnalités du projet Spring AI.

Voici à quoi ressemble mon projet Spring Boot généré (dans mon cas, j’ai utilisé IntelliJ IDEA).

image

Le fichier pom.xml

Pour notre projet, nous aurons besoin de l’artefact spring-ai-openai-spring-boot-starter

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>0.8.0-SNAPSHOT</version>
</dependency>

Ce starter nous aide à mettre en place l’ensemble des dépendances et classes essentielles pour travailler.

image
Spring Starter est un terme spécifique à l’écosystème de Spring Boot. Les starters facilitent la mise en place rapide d’une application Spring Boot avec les fonctionnalités souhaitées.

Dans un prochain article, nous explorerons l’auto-configuration fournie par Spring Boot afin de mieux comprendre et maîtriser la configuration des composants, ainsi que d’apprendre à les personnaliser.

image

La version actuelle est la 0.8.0, à la date de rédaction de cet article.

Nous utilisons une version Snapshot du projet. Le projet Spring AI fournit des artefacts dans les dépôts Spring Milestone et Snapshot. Vous devez ajouter des références aux référentiels Spring Milestone et/ou Snapshot dans votre fichier pom.xml.

Pour un projet Maven, il faut ajouter :

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>

Voici le contenu du fichier pom.xml de notre projet :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>fr.sciam.blog</groupId>
    <artifactId>spring-ai</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-spring-ai</name>
    <description>Demo App Spring AI</description>
    <properties>
        <java.version>21</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
            <version>0.8.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>

</project>

Alors, sans plus attendre, commençons à coder.

La configuration du projet

Spring AI prend en charge ChatGPT, le modèle de langage AI d’OpenAI.

Le projet Spring AI définit une propriété de configuration nommée spring.ai.openai.api-key que vous devez définir sur la valeur de la clé API.

Pour obtenir la clé de l’API, créer un compte sur la platform openai et générez une API Keys.

Voici la configuration dans le fichier application.yml :

spring:
  ai:
    openai:
      api-key: <VOTRE_API_KEY>

Vous pouvez alternativement utiliser un fichier application.properties

spring.ai.openai.api-key=<VOTRE_API_KEY>

Le Controller

Nous allons utiliser OpenAiChatClient une implémentation de ChatClient pour OpenAI que vous pourrez vous faire injecter via le constructeur dans votre classe. Voici un exemple :

package fr.sciam.springai.controller;

import org.springframework.ai.chat.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/ai/")
public class DemoOpenAiController {

    private final ChatClient chatClient;

    public DemoOpenAiController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
}

Les Modèles et la Température

Les Modèles

Les modèles d’IA sont des algorithmes conçus pour traiter et générer des informations, imitant souvent les fonctions cognitives humaines.

En apprenant des modèles et des informations à partir de grands ensembles de données, ces modèles peuvent générer des prédictions, des textes, des images ou d’autres résultats, améliorant ainsi diverses applications dans tous les secteurs.

Le modèle par défaut fourni par Spring AI est gpt-3.5-turbo, pour en savoir plus sur les modèles, c’est par ici

La notion de température

D’un point de vue technique, la notion de température est étroitement associée à la notion d’échantillonnage, qui implique de choisir une réponse parmi plusieurs possibilités en fonction de leurs probabilités respectives. La température agit comme un paramètre de mise à l’échelle pour ces probabilités.

D’un point de vue humain, la température est un paramètre utilisé pour réguler le degré de créativité et de prise de risque dans les réponses générées par les modèles GPT.

En modulant la température, il devient possible d’obtenir des réponses plus ou moins créatives, cohérentes ou diversifiées, en fonction des exigences spécifiques de l’application ou de l’utilisateur.

Vous pouvez ajuster cette valeur sur une échelle de 0 à 1 en fonction de vos besoins spécifiques.

Spring AI configure par défaut la température à 0,7, un échantillonnage proportionnel aux probabilités du modèle, qui représente un compromis entre la créativité et la cohérence.

Le Prompt

Dans le domaine de l’intelligence artificielle, on utilise fréquemment le terme prompt pour décrire une directive ou une demande spécifiée à un modèle de langage ou à un système d’IA. Un prompt peut consister en une phrase ou une série de mots fournie par l’utilisateur pour solliciter des informations ou générer une réponse du modèle.

Supposons que vous utilisiez un modèle de langage génératif tel que GPT-3 ou 4. Dans ce cas, vous pourriez soumettre un exemple d’instruction tel que "écrit du code Java clean…​" pour obtenir une réponse générée par le modèle. Le prompt agit comme le point initial pour l’IA, lui permettant de comprendre la nature de la tâche à effectuer.

La génération de texte avec L’IA

Spring AI fournit la classe Prompt qui sert de support structuré à une séquence d’objets Message, chacun représentant une partie du prompt complet. Chaque message présent dans l’instruction a une fonction unique, caractérisée par des différences dans son contenu et son objectif.

Les fonctions de ces messages sont variées, englobant des aspects tels que les questions de l’utilisateur, les réponses générées par l’intelligence artificielle ou des détails contextuels pertinents. Cette structure simplifie les interactions complexes et nuancées avec les modèles d’IA, car l’instruction est constituée de plusieurs messages, chacun jouant un rôle spécifique dans la conversation.

package fr.sciam.blog.springai.controller;

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.prompt.Prompt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/ai/")
public class DemoOpenAiController {

    private final ChatClient chatClient;

    public DemoOpenAiController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping("demo-a")
    public ChatResponse generateText(@RequestParam(value = "message") String message) {
        var prompt = new Prompt(message);
        return chatClient.generate(prompt);
    }
}

Une surcharge de la méthode generate de ChatClient prend également un objet de type String en paramètre et renvoie simplement une chaine de caractère, comme dans l’exemple ci-dessous :

@GetMapping("demo-a")
public String generateText(@RequestParam(value = "message") String message) {
    return chatClient.generate(message);
}

De plus, le constructeur surchargé de la classe Prompt accepte une série d’instances du type Message, chacune ayant des rôles et des intentions différents, comme illustré ci-dessous.

package fr.sciam.blog.springai.controller;

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.Generation;
import org.springframework.ai.prompt.Prompt;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.ai.prompt.SystemPromptTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/ai/")
public class DemoOpenAiController {

    private final ChatClient chatClient;

    public DemoOpenAiController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping("/demo-b")
    public List<Generation> generateText3(@RequestParam(value = "message") String message) {

        var systemPromptTemplate = new SystemPromptTemplate("Vous êtes une assistant IA très utile");
        var systemMessage = systemPromptTemplate.createMessage();

        var promptTemplate = new PromptTemplate("traduire la phrase {query}");
        var userMessage = promptTemplate.createMessage(Map.of("query", message));

        var prompt = new Prompt(List.of(systemMessage, userMessage));

        return chatClient.generate(prompt).getGenerations();
    }
}

Le test de l’application

Pour tester l’application, vous pouvez utiliser un client REST, dans mon cas, j’utilise postman

Voici les résultats de mes tests lorsque j’interroge le endpoint OpenAI en passant par notre application.

image
image
image
image

Conclusion

Dans cet article, nous avons posé les bases de l’intégration de Spring AI avec OpenAI et exploré quelques techniques de prompt (invites). Dans les prochains articles, nous verrons comment intégrer Spring AI à Azure OpenAI.