Génération de texte par IA générative en Java avec PaLM et LangChain4J

1. Introduction

Dernière mise à jour : 27/11/2023

Qu'est-ce que l'IA générative ?

L'IA générative ou l'intelligence artificielle générative fait référence à l'utilisation de l'IA pour créer de nouveaux contenus, comme du texte, des images, de la musique, de l'audio et des vidéos.

L'IA générative s'appuie sur des modèles de fondation (grands modèles d'IA) qui peuvent effectuer plusieurs opérations en même temps et réaliser des tâches prêtes à l'emploi, telles que la synthèse, les questions/réponses, la classification, etc. De plus, les modèles de fondation ne nécessitent qu'un entraînement minimal et peuvent être adaptés à des cas d'utilisation ciblés avec très peu d'exemples de données.

Comment fonctionne l'IA générative ?

L'IA générative s'appuie sur un modèle de ML (machine learning) pour apprendre les schémas et les relations dans un ensemble de données de contenus créés manuellement. puis utilise ces schémas pour générer de nouveaux contenus.

La méthode la plus courante pour entraîner un modèle d'IA générative consiste à utiliser l'apprentissage supervisé. Le modèle se voit attribuer un ensemble de contenus créés manuellement et des étiquettes correspondantes. Il apprend ensuite à générer du contenu semblable au contenu créé par un humain et doté des mêmes étiquettes.

Quelles sont les applications courantes de l'IA générative ?

L'IA générative traite un grand volume de contenus, générant des insights et des réponses sous forme de texte, d'images et de formats conviviaux. Voici des exemple d'utilisations de l'IA générative :

  • Améliorer les interactions client grâce à des fonctionnalités optimisées de chat et de recherche
  • Explorer de grandes quantités de données non structurées grâce à des interfaces conversationnelles et des résumés
  • Faciliter les tâches répétitives en répondant aux appels d'offres, en localisant le contenu marketing dans cinq langues et en vérifiant la conformité des contrats client, etc.

Quelles sont les offres d'IA générative disponibles dans Google Cloud ?

Avec Vertex AI, interagissez avec des modèles de fondation, personnalisez-les et intégrez-les à vos applications, sans aucune connaissance du ML. Accédez aux modèles de fondation dans Model Garden, ajustez-les via une UI simple sur Generative AI Studio ou utilisez-les dans un notebook de data science.

La fonctionnalité Search and Conversation de Vertex AI offre aux développeurs le moyen le plus rapide de créer des moteurs de recherche et des chatbots optimisés par l'IA générative.

Duet AI est un outil collaboratif optimisé par l'IA, disponible sur Google Cloud et les IDE, pour vous aider à gagner en efficacité.

Sur quoi porte cet atelier de programmation ?

Cet atelier de programmation se concentre sur le grand modèle de langage (LLM) PaLM 2, hébergé sur Google Cloud Vertex AI, qui englobe tous les produits et services de machine learning.

Vous utiliserez Java pour interagir avec l'API PaLM, en association avec l'orchestrateur de framework LLM LangChain4j. Vous passerez en revue différents exemples concrets pour tirer parti du LLM afin de répondre à des questions, générer des idées, extraire des entités et du contenu structuré, et résumer des informations.

Parlez-moi du framework LangChain4j.

Le framework LangChain4J est une bibliothèque Open Source permettant d'intégrer des grands modèles de langage dans vos applications Java. Pour ce faire, il orchestre différents composants, tels que le LLM lui-même, mais aussi d'autres outils comme les bases de données vectorielles (pour les recherches sémantiques), les chargeurs et les séparateurs de documents (pour analyser les documents et en tirer des enseignements), les analyseurs de sortie, etc.

c6d7f7c3fd0d2951.png

Points abordés

  • Configurer un projet Java pour utiliser PaLM et LangChain4J
  • Comment effectuer votre premier appel au modèle de texte PaLM pour générer du contenu et répondre à des questions
  • Extraire des informations utiles à partir de contenu non structuré (extraction d'entités ou de mots clés, sortie au format JSON)
  • Comment effectuer la classification de contenu ou l'analyse des sentiments avec le few-shot prompting

Prérequis

  • Connaissances du langage de programmation Java
  • Un projet Google Cloud
  • Un navigateur tel que Chrome ou Firefox

2. Préparation

Configuration de l'environnement au rythme de chacun

  1. Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

  • Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères non utilisée par les API Google. Vous pourrez toujours le modifier.
  • L'ID du projet est unique parmi tous les projets Google Cloud et non modifiable une fois défini. La console Cloud génère automatiquement une chaîne unique (en général, vous n'y accordez d'importance particulière). Dans la plupart des ateliers de programmation, vous devrez indiquer l'ID de votre projet (généralement identifié par PROJECT_ID). Si l'ID généré ne vous convient pas, vous pouvez en générer un autre de manière aléatoire. Vous pouvez également en spécifier un et voir s'il est disponible. Après cette étape, l'ID n'est plus modifiable et restera donc le même pour toute la durée du projet.
  • Pour information, il existe une troisième valeur (le numéro de projet) que certaines API utilisent. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
  1. Vous devez ensuite activer la facturation dans la console Cloud pour utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour désactiver les ressources et éviter ainsi que des frais ne vous soient facturés après ce tutoriel, vous pouvez supprimer le projet ou les ressources que vous avez créées. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300 $.

Démarrer Cloud Shell

Bien que Google Cloud puisse être utilisé à distance depuis votre ordinateur portable, nous allons nous servir de Cloud Shell pour cet atelier de programmation, un environnement de ligne de commande exécuté dans le cloud.

Activer Cloud Shell

  1. Dans Cloud Console, cliquez sur Activer Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si vous démarrez Cloud Shell pour la première fois, un écran intermédiaire s'affiche pour vous expliquer de quoi il s'agit. Si cet écran s'est affiché, cliquez sur Continuer.

d95252b003979716.png

Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.

7833d5e1c5d18f54.png

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez réaliser une grande partie, voire la totalité, des activités de cet atelier de programmation dans un navigateur.

Une fois connecté à Cloud Shell, vous êtes en principe authentifié, et le projet est défini avec votre ID de projet.

  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :
gcloud auth list

Résultat de la commande

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet :
gcloud config list project

Résultat de la commande

[core]
project = <PROJECT_ID>

Si vous obtenez un résultat différent, exécutez cette commande :

gcloud config set project <PROJECT_ID>

Résultat de la commande

Updated property [core/project].

3. Préparer votre environnement de développement

Dans cet atelier de programmation, vous allez utiliser le terminal et l'éditeur de code Cloud Shell pour développer vos programmes Java.

Activer les API Vertex AI

  1. Dans la console Google Cloud, assurez-vous que le nom de votre projet s'affiche en haut de la console Google Cloud. Si ce n'est pas le cas, cliquez sur Sélectionner un projet pour ouvrir le sélecteur de projet, puis sélectionnez le projet de votre choix.
  2. Si vous n'êtes pas dans la partie Vertex AI de la console Google Cloud, procédez comme suit :
  3. Dans le champ Rechercher, saisissez Vertex AI, puis appuyez sur Entrée.
  4. Dans les résultats de recherche, cliquez sur Vertex AI. Le tableau de bord Vertex AI s'affiche.
  5. Cliquez sur Activer toutes les API recommandées dans le tableau de bord Vertex AI.

Cela activera plusieurs API, mais la plus importante pour l'atelier de programmation est aiplatform.googleapis.com, que vous pouvez également activer sur la ligne de commande, dans le terminal Cloud Shell, en exécutant la commande suivante :

$ gcloud services enable aiplatform.googleapis.com

Créer la structure du projet avec Gradle

Pour compiler vos exemples de code Java, vous utiliserez l'outil de compilation Gradle et la version 17 de Java. Pour configurer votre projet avec Gradle, dans le terminal Cloud Shell, créez un répertoire (ici, palm-workshop), puis exécutez la commande gradle init dans ce répertoire :

$ mkdir palm-workshop
$ cd palm-workshop

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
  1: no - only one application project
  2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 1

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4

Project name (default: palm-workshop): 
Source package (default: palm.workshop): 

> Task :init
Get more help with your project: https://docs.gradle.org/7.4/samples/sample_building_java_applications.html

BUILD SUCCESSFUL in 51s
2 actionable tasks: 2 executed

Vous allez créer une application (option 2), en utilisant le langage Java (option 3), sans utiliser de sous-projets (option 1), en utilisant la syntaxe Groovy pour le fichier de compilation (option 1), sans utiliser de nouvelles fonctionnalités de compilation (option non), en générant des tests avec JUnit Jupiter (option 4), et pour le nom du projet, vous pouvez utiliser palm-workshop, et de même pour le package source, vous pouvez utiliser palm.workshop.

La structure du projet se présente comme suit :

├── gradle 
│   └── ...
├── gradlew 
├── gradlew.bat 
├── settings.gradle 
└── app
    ├── build.gradle 
    └── src
        ├── main
        │   └── java 
        │       └── palm
        │           └── workshop
        │               └── App.java
        └── test
            └── ...

Mettez à jour le fichier app/build.gradle pour ajouter les dépendances nécessaires. Vous pouvez supprimer la dépendance guava si elle est présente et la remplacer par les dépendances du projet LangChain4J et de la bibliothèque de journalisation pour éviter les messages d'erreur liés à l'absence de journaliseur :

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // Logging library
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
}

LangChain4j comporte deux dépendances :

  • un sur le projet principal,
  • et un pour le module Vertex AI dédié.

Pour utiliser Java 17 afin de compiler et d'exécuter nos programmes, ajoutez le bloc suivant sous le bloc plugins {} :

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

Il reste une modification à apporter : mettez à jour le bloc application de app/build.gradle pour permettre aux utilisateurs de remplacer la classe principale à exécuter sur la ligne de commande lors de l'appel de l'outil de compilation :

application {
    mainClass = providers.systemProperty('javaMainClass')
                         .orElse('palm.workshop.App')
}

Pour vérifier que votre fichier de compilation est prêt à exécuter votre application, vous pouvez exécuter la classe principale par défaut qui affiche un simple message Hello World! :

$ ./gradlew run -DjavaMainClass=palm.workshop.App

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

Vous êtes maintenant prêt à programmer avec le grand modèle de langage textuel PaLM à l'aide du projet LangChain4j.

Pour référence, voici à quoi devrait ressembler le fichier de compilation app/build.gradle complet :

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

java {
    toolchain {
        // Ensure we compile and run on Java 17
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'
}

application {
    mainClass = providers.systemProperty('javaMainClass').orElse('palm.workshop.App')
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

4. Effectuer votre premier appel au modèle de texte de PaLM

Maintenant que le projet est correctement configuré, il est temps d'appeler l'API PaLM.

Créez une classe nommée TextPrompts.java dans le répertoire app/src/main/java/palm/workshop (à côté de la classe App.java par défaut), puis saisissez le contenu suivant :

package palm.workshop;

import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;

public class TextPrompts {
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(500)
            .build();

        Response<String> response = model.generate("What are large language models?");

        System.out.println(response.content());
    }
}

Dans ce premier exemple, vous devez importer la classe Response et le modèle de langage Vertex AI pour PaLM.

Ensuite, dans la méthode main, vous allez configurer le modèle de langage à l'aide du compilateur pour VertexAiLanguageModel afin de spécifier :

  • le point de terminaison ;
  • le projet,
  • la région ;
  • l'éditeur ;
  • et le nom du modèle (text-bison@001).

Maintenant que le modèle de langage est prêt, vous pouvez appeler la méthode generate() et transmettre votre "requête" (c'est-à-dire votre question ou vos instructions à envoyer au LLM). Ici, vous posez une question simple sur ce que sont les LLM. N'hésitez pas à modifier ce prompt pour tester différentes questions ou tâches.

Pour exécuter cette classe, exécutez la commande suivante dans le terminal Cloud Shell :

./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

Un résultat semblable aux lignes suivantes doit s'afficher :

Large language models (LLMs) are artificial intelligence systems that can understand and generate human language. They are trained on massive datasets of text and code, and can learn to perform a wide variety of tasks, such as translating languages, writing different kinds of creative content, and answering your questions in an informative way.

LLMs are still under development, but they have the potential to revolutionize many industries. For example, they could be used to create more accurate and personalized customer service experiences, to help doctors diagnose and treat diseases, and to develop new forms of creative expression.

However, LLMs also raise a number of ethical concerns. For example, they could be used to create fake news and propaganda, to manipulate people's behavior, and to invade people's privacy. It is important to carefully consider the potential risks and benefits of LLMs before they are widely used.

Here are some of the key features of LLMs:

* They are trained on massive datasets of text and code.
* They can learn to perform a wide variety of tasks, such as translating languages, writing different kinds of creative content, and answering your questions in an informative way.
* They are still under development, but they have the potential to revolutionize many industries.
* They raise a number of ethical concerns, such as the potential for fake news, propaganda, and invasion of privacy.

Le générateur VertexAILanguageModel vous permet de définir des paramètres facultatifs qui ont déjà des valeurs par défaut que vous pouvez remplacer. Voici quelques exemples :

  • .temperature(0.2) : pour définir le degré de créativité de la réponse (0 correspond à un faible degré de créativité et souvent à une réponse plus factuelle, tandis que 1 correspond à des résultats plus créatifs)
  • .maxOutputTokens(50) : dans l'exemple, 500 jetons ont été demandés (3 jetons équivalent à environ 4 mots), en fonction de la longueur souhaitée pour la réponse générée.
  • .topK(20) : pour sélectionner un mot au hasard parmi un nombre maximal de mots probables pour la complétion de texte (de 1 à 40)
  • .topP(0.95) : pour sélectionner les mots possibles dont la probabilité totale correspond à ce nombre à virgule flottante (entre 0 et 1)
  • .maxRetries(3) : si vous dépassez le quota de demandes par période, vous pouvez demander au modèle de réessayer l'appel trois fois, par exemple.

Les grands modèles de langage sont très puissants. Ils peuvent répondre à des questions complexes et gérer une grande variété de tâches intéressantes. Dans la section suivante, nous allons examiner une tâche utile : extraire des données structurées à partir de texte.

5. Extraire des informations à partir de texte non structuré

Dans la section précédente, vous avez généré une sortie textuelle. Cela ne pose pas de problème si vous souhaitez afficher directement cette sortie à vos utilisateurs finaux. Mais si vous souhaitez récupérer les données mentionnées dans cette sortie, comment extraire ces informations du texte non structuré ?

Supposons que vous souhaitiez extraire le nom et l'âge d'une personne à partir de sa biographie ou de sa description. Vous pouvez demander au grand modèle linguistique de générer des structures de données JSON en modifiant la requête comme suit (c'est ce qu'on appelle couramment l'ingénierie des requêtes) :

Extract the name and age of the person described below.

Return a JSON document with a "name" and an "age" property, 
following this structure: {"name": "John Doe", "age": 34}
Return only JSON, without any markdown markup surrounding it.

Here is the document describing the person:
---
Anna is a 23 year old artist based in Brooklyn, New York. She was 
born and raised in the suburbs of Chicago, where she developed a 
love for art at a young age. She attended the School of the Art 
Institute of Chicago, where she studied painting and drawing. 
After graduating, she moved to New York City to pursue her art career. 
Anna's work is inspired by her personal experiences and observations 
of the world around her. She often uses bright colors and bold lines 
to create vibrant and energetic paintings. Her work has been 
exhibited in galleries and museums in New York City and Chicago.
---

JSON: 

Modifiez l'appel model.generate() dans la classe TextPrompts pour lui transmettre l'intégralité de la requête textuelle ci-dessus :

Response<String> response = model.generate("""
    Extract the name and age of the person described below.
    Return a JSON document with a "name" and an "age" property, \
    following this structure: {"name": "John Doe", "age": 34}
    Return only JSON, without any markdown markup surrounding it.
    Here is the document describing the person:
    ---
    Anna is a 23 year old artist based in Brooklyn, New York. She was born and 
    raised in the suburbs of Chicago, where she developed a love for art at a 
    young age. She attended the School of the Art Institute of Chicago, where 
    she studied painting and drawing. After graduating, she moved to New York 
    City to pursue her art career. Anna's work is inspired by her personal 
    experiences and observations of the world around her. She often uses bright 
    colors and bold lines to create vibrant and energetic paintings. Her work 
    has been exhibited in galleries and museums in New York City and Chicago.    
    ---
    JSON: 
    """
);

Si vous exécutez cette requête dans notre classe TextPrompts, elle devrait renvoyer la chaîne JSON suivante, que vous pouvez analyser avec un analyseur JSON tel que la bibliothèque GSON :

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
{"name": "Anna", "age": 23}

BUILD SUCCESSFUL in 24s
2 actionable tasks: 1 executed, 1 up-to-date

Oui. Anna a 23 ans !

6. Modèles de requêtes et requêtes structurées

Au-delà des questions-réponses

Les grands modèles de langage comme PaLM sont très efficaces pour répondre aux questions, mais vous pouvez les utiliser pour de nombreuses autres tâches. Par exemple, essayez les requêtes suivantes dans Generative AI Studio (ou en modifiant la classe TextPrompts). Remplacez les mots en majuscules par vos propres idées et examinez le résultat :

  • Traduction : "Traduis la phrase suivante en français : YOUR_SENTENCE_HERE"
  • Résumer : "Résume le document suivant : COLLEZ_VOTRE_DOC"
  • Génération de contenu créatif : "Écris un poème sur TOPIC_OF_THE_POEM"
  • Programmation : "Comment écrire une fonction Fibonacci en PROGRAMMING_LANGUAGE ?"

Modèles de requêtes

Si vous avez essayé les requêtes ci-dessus pour des tâches de traduction, de résumé, de génération créative ou de programmation, vous avez remplacé les valeurs d'espace réservé par vos propres idées. Toutefois, au lieu de manipuler des chaînes de caractères, vous pouvez également profiter des modèles d'invite, qui vous permettent de définir ces valeurs d'espace réservé et de remplir les espaces vides avec vos données par la suite.

Remplacez l'intégralité du contenu de la méthode main() par le code suivant pour découvrir un exemple de requête gourmande et créative :

VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(300)
            .build();

PromptTemplate promptTemplate = PromptTemplate.from("""
    Create a recipe for a {{dish}} with the following ingredients: \
    {{ingredients}}, and give it a name.
    """
);

Map<String, Object> variables = new HashMap<>();
variables.put("dish", "dessert");
variables.put("ingredients", "strawberries, chocolate, whipped cream");

Prompt prompt = promptTemplate.apply(variables);

Response<String> response = model.generate(prompt);

System.out.println(response.content());

et en ajoutant les importations suivantes :

import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;

import java.util.HashMap;
import java.util.Map;

Exécutez ensuite à nouveau l'application. Le résultat doit se présenter sous la forme suivante :

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
**Strawberry Shortcake**

Ingredients:

* 1 pint strawberries, hulled and sliced
* 1/2 cup sugar
* 1/4 cup cornstarch
* 1/4 cup water
* 1 tablespoon lemon juice
* 1/2 cup heavy cream, whipped
* 1/4 cup confectioners' sugar
* 1/4 teaspoon vanilla extract
* 6 graham cracker squares, crushed

Instructions:

1. In a medium saucepan, combine the strawberries, sugar, cornstarch, water, and lemon juice. Bring to a boil over medium heat, stirring constantly. Reduce heat and simmer for 5 minutes, or until the sauce has thickened.
2. Remove from heat and let cool slightly.
3. In a large bowl, combine the whipped cream, confectioners' sugar, and vanilla extract. Beat until soft peaks form.
4. To assemble the shortcakes, place a graham cracker square on each of 6 dessert plates. Top with a scoop of whipped cream, then a spoonful of strawberry sauce. Repeat layers, ending with a graham cracker square.
5. Serve immediately.

**Tips:**

* For a more elegant presentation, you can use fresh strawberries instead of sliced strawberries.
* If you don't have time to make your own whipped cream, you can use store-bought whipped cream.

Délicieux !

Les modèles d'invite vous permettent de fournir les paramètres requis avant d'appeler la méthode de génération de texte. C'est un excellent moyen de transmettre des données et de personnaliser les requêtes pour différentes valeurs fournies par vos utilisateurs.

Comme son nom l'indique, la classe PromptTemplate crée un modèle d'invite. Vous pouvez attribuer des valeurs aux éléments d'espace réservé en appliquant une carte des noms et des valeurs d'espace réservé.

Requêtes structurées (FACULTATIF)

Si vous souhaitez utiliser une approche orientée objet plus riche, vous pouvez également structurer vos requêtes à l'aide de l'annotation @StructuredPrompt. Vous annotez une classe avec cette annotation, et ses champs correspondent aux espaces réservés définis dans l'invite. Voyons cela en action.

Nous aurons d'abord besoin de nouvelles importations :

import java.util.Arrays;
import java.util.List;
import dev.langchain4j.model.input.structured.StructuredPrompt;
import dev.langchain4j.model.input.structured.StructuredPromptProcessor;

Nous pouvons ensuite créer une classe statique interne dans notre classe TextPrompts qui collecte les données nécessaires pour transmettre les espaces réservés dans l'invite décrite dans l'annotation @StructuredPrompt :

@StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}")
static class RecipeCreationPrompt {
    String dish;
    List<String> ingredients;
}

Ensuite, instanciez cette nouvelle classe et fournissez-lui le plat et les ingrédients de notre recette, puis créez et transmettez le prompt à la méthode generate() comme précédemment :

RecipeCreationPrompt createRecipePrompt = new RecipeCreationPrompt();
createRecipePrompt.dish = "salad";
createRecipePrompt.ingredients = Arrays.asList("cucumber", "tomato", "feta", "onion", "olives");
Prompt prompt = StructuredPromptProcessor.toPrompt(createRecipePrompt);

Response<String> response = model.generate(prompt);

Au lieu de combler les lacunes à l'aide d'une carte, vous pouvez utiliser un objet Java avec des champs qui peuvent être complétés automatiquement par votre IDE, de manière plus sûre en termes de type.

Voici le code complet si vous souhaitez coller plus facilement ces modifications dans votre classe TextPrompts :

package palm.workshop;

import java.util.Arrays;
import java.util.List;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;
import dev.langchain4j.model.input.structured.StructuredPrompt;
import dev.langchain4j.model.input.structured.StructuredPromptProcessor;

public class TextPrompts {

    @StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}")
    static class RecipeCreationPrompt {
        String dish;
        List<String> ingredients;
    }
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(300)
            .build();

        RecipeCreationPrompt createRecipePrompt = new RecipeCreationPrompt();
        createRecipePrompt.dish = "salad";
        createRecipePrompt.ingredients = Arrays.asList("cucumber", "tomato", "feta", "onion", "olives");
        Prompt prompt = StructuredPromptProcessor.toPrompt(createRecipePrompt);

        Response<String> response = model.generate(prompt);
        
        System.out.println(response.content());
    }
}

7. Classer du texte et analyser les sentiments

Comme vous l'avez appris dans la section précédente, vous allez découvrir une autre technique d'ingénierie des requêtes pour que le modèle PaLM classe du texte ou analyse les sentiments. Parlons des requêtes few-shot. Il s'agit d'une méthode permettant d'améliorer vos requêtes en ajoutant quelques exemples qui aideront le modèle linguistique à mieux comprendre votre intention et à s'orienter dans la direction souhaitée.

Retravaillons notre classe TextPrompts pour profiter des modèles de requête :

package palm.workshop;

import java.util.Map;

import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;

public class TextPrompts {
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(10)
            .build();

        PromptTemplate promptTemplate = PromptTemplate.from("""
            Analyze the sentiment of the text below. Respond only with one word to describe the sentiment.

            INPUT: This is fantastic news!
            OUTPUT: POSITIVE

            INPUT: Pi is roughly equal to 3.14
            OUTPUT: NEUTRAL

            INPUT: I really disliked the pizza. Who would use pineapples as a pizza topping?
            OUTPUT: NEGATIVE

            INPUT: {{text}}
            OUTPUT: 
            """);

        Prompt prompt = promptTemplate.apply(
            Map.of("text", "I love strawberries!"));

        Response<String> response = model.generate(prompt);

        System.out.println(response.content());
    }
}

Notez l'approche qui consiste à proposer quelques exemples d'entrées et de sorties dans la requête. Il s'agit des "quelques exemples" qui aident le LLM à suivre la même structure. Lorsque le modèle reçoit une entrée, il doit renvoyer une sortie qui correspond au modèle d'entrée/sortie.

L'exécution du programme ne devrait renvoyer que le mot POSITIVE, car les fraises sont aussi délicieuses !

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
POSITIVE

L'analyse des sentiments est également un scénario de classification de contenu. Vous pouvez appliquer la même approche de few-shot prompting pour classer différents documents dans différentes catégories.

8. Félicitations

Félicitations, vous venez de créer votre première application d'IA générative en Java à l'aide de LangChain4j et de l'API PaLM. Vous avez découvert en cours de route que les grands modèles de langage sont très puissants et capables de gérer diverses tâches telles que les questions/réponses, l'extraction de données, la synthèse, la classification de texte, l'analyse des sentiments, etc.

Et ensuite ?

Consultez les ateliers de programmation suivants pour aller plus loin avec PaLM en Java :

Complément d'informations

Documents de référence