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, avec un entraînement minimal, les modèles de fondation peuvent être adaptés à des cas d'utilisation ciblés avec très peu de données d'exemple.

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 modèles et les relations d'un ensemble de données de contenus créés par l'humain. Elle utilise ensuite les schémas appris 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 reçoit un ensemble de contenus créés manuellement et les é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 d'IA générative courantes ?

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 :

  • Renforcez les interactions avec les clients grâce à des fonctionnalités de chat et de recherche améliorées.
  • Explorer de vastes quantités de données non structurées à l'aide d'interfaces de conversation et de synthèses
  • Accomplissez les tâches répétitives comme répondre aux appels d'offres, localiser le contenu marketing en cinq langues, vérifier la conformité des contrats des clients, etc.

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

Vertex AI vous permet d'interagir avec des modèles de fondation, de les personnaliser et de les intégrer dans vos applications, même sans expérience en ML. Accédez aux modèles de fondation sur Model Garden, réglez-les via une UI simple dans Generative AI Studio ou utilisez-les dans un notebook de data science.

Vertex AI Search and Conversation 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.

De plus, Duet AI est votre collaborateur alimenté par l'IA, disponible sur Google Cloud et dans les IDE pour vous aider à gagner en efficacité et en rapidité.

Quel est l'objet de cet atelier de programmation ?

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

Vous utiliserez Java pour interagir avec l'API PaLM, ainsi qu'avec l'orchestrateur de framework LLM LangChain4J. Nous étudierons différents exemples concrets qui vous permettront de tirer parti du LLM pour la réponse à des questions, la génération d'idées, l'extraction d'entités et de contenus structurés, ainsi que pour la synthèse.

Dites-m'en plus sur le framework LangChain4J.

Le framework LangChain4J est une bibliothèque Open Source permettant d'intégrer de grands modèles de langage à vos applications Java en orchestrant divers 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), des chargeurs et des séparateurs de documents (pour analyser les documents et en tirer des enseignements), des analyseurs de sortie, etc.

c6d7f7c3fd0d2951.png

Points abordés

  • Configurer un projet Java pour utiliser PaLM et LangChain4J
  • Effectuer votre premier appel au modèle de texte PaLM pour générer du contenu et répondre à des questions
  • Comment extraire des informations utiles d'un contenu non structuré (extraction d'entités ou de mots clés, sortie au format JSON)
  • Classer des contenus ou analyser les sentiments avec peu de plans

Prérequis

  • Connaissance 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, vous allez utiliser Cloud Shell dans 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 vous explique de quoi il s'agit. Si un écran intermédiaire 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 dans Google Cloud, ce qui améliore considérablement les performances du réseau et l'authentification. Une grande partie, voire la totalité, de votre travail dans cet atelier de programmation peut être effectué dans un navigateur.

Une fois connecté à Cloud Shell, vous êtes authentifié et le projet est défini sur 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 est affiché 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 projets, puis sélectionnez le projet souhaité.
  2. Si vous n'êtes pas dans la section Vertex AI de la console Google Cloud, procédez comme suit:
  3. Dans le champ Rechercher, saisissez "Vertex AI", puis saisissez
  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 cet atelier de programmation est aiplatform.googleapis.com, que vous pouvez également activer dans 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), n'utilisez pas de nouvelles fonctionnalités de compilation (option non), en générant des tests avec JUnit Jupiter (option 4). Vous pouvez également utiliser palm-workshop pour le nom du projet.

La structure du projet se présentera comme suit:

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

Mettons à jour le fichier app/build.gradle pour ajouter certaines 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 d'accumuler les messages d'enregistreur manquants:

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'
}

Il existe deux dépendances pour LangChain4J:

  • sur le projet de base,
  • et l'autre pour le module Vertex AI dédié.

Pour compiler et exécuter nos programmes avec Java 17, ajoutez le bloc suivant sous le bloc plugins {}:

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

Autre modification à apporter: mettez à jour le bloc application de app/build.gradle afin de permettre aux utilisateurs de remplacer la classe principale pour qu'ils s'exécutent sur la ligne de commande lorsqu'ils appellent l'outil de compilation:

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

Pour vérifier que le 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 maintenant 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 PaLM

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

Créez une classe appelée TextPrompts.java dans le répertoire app/src/main/java/palm/workshop (avec 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 en utilisant le compilateur pour VertexAiLanguageModel afin de spécifier les éléments suivants:

  • 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 les instructions à envoyer au LLM). Vous posez ici une question simple sur ce que sont les LLM. Mais n’hésitez pas à modifier cette invite pour essayer différentes questions ou tâches.

Pour ce faire, exécutez la commande suivante dans le terminal Cloud Shell:

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

Un résultat semblable à celui-ci 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.

L'outil de création VertexAILanguageModel vous permet de définir des paramètres facultatifs comportant déjà des valeurs par défaut que vous pouvez remplacer. Voici quelques exemples :

  • .temperature(0.2) : pour définir le niveau de création souhaité pour la réponse (0 signifiant une création peu créative et souvent plus factuelle, 1 signifiant un plus grand nombre de créations)
  • .maxOutputTokens(50) : dans cet exemple, 500 jetons ont été demandés (3 jetons équivalent à peu près à 4 mots), en fonction de la durée souhaitée pour la réponse générée.
  • .topK(20) : permet de sélectionner aléatoirement un mot parmi un nombre maximal de mots probables pour compléter le texte (de 1 à 40)
  • .topP(0.95) : pour sélectionner les mots possibles dont la probabilité totale s'additionne à ce nombre à virgule flottante (entre 0 et 1)
  • .maxRetries(3) : si vous dépassez le quota de requêtes par temps, vous pouvez demander au modèle de relancer l'appel trois fois, par exemple

Les grands modèles de langage sont très puissants, ils peuvent fournir des réponses à des questions complexes et sont capables de gérer une grande variété de tâches intéressantes. Dans la section suivante, nous allons nous pencher sur une tâche utile: extraire des données structurées d'un texte.

5. Extraire des informations d'un texte non structuré

Dans la section précédente, vous avez généré une sortie textuelle. Cela ne pose aucun problème si vous souhaitez présenter cette sortie directement à 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 d'une biographie ou d'une description de cette personne. Vous pouvez demander au grand modèle de langage de générer des structures de données JSON en modifiant la requête comme suit (ce que l'on appelle communément "ingénierie de requête"):

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 invite dans notre classe TextPrompts, elle devrait renvoyer la chaîne JSON suivante, que vous pouvez analyser avec un analyseur JSON comme 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 efficaces pour répondre à des questions, mais vous pouvez les utiliser pour bien d'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 leur résultat:

  • Traduction : "Traduis la phrase suivante en français : YOUR_SENTENCE_HERE"
  • Résumé : "Fournissez un résumé du document suivant : PASTE_YOUR_DOC"
  • Génération de créations : "Écris un poème sur TOPIC_OF_THE_POEM"
  • Programmation : "Comment écrire une fonction de Fibonacci en PROGRAMMING_LANGUAGE ?"

Modèles de requêtes

Si vous avez essayé les invites ci-dessus pour des tâches de traduction, de synthèse, de génération de créations ou de programmation, vous avez remplacé les valeurs des espaces réservés par vos propres idées. Mais au lieu de manipuler des chaînes, vous pouvez également utiliser les "modèles d'invite", qui vous permettent de définir ces valeurs d'espace réservé et de remplir le champ vide avec vos données.

Examinons une requête de qualité et créative, en remplaçant l'intégralité du contenu de la méthode main() par le code suivant:

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;

Ensuite, exécutez à nouveau l'application. Le résultat doit se présenter comme suit:

$ ./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 !

Avec les modèles d'invite, vous pouvez transmettre 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 en fonction des différentes valeurs fournies par vos utilisateurs.

Comme le nom de la classe l'indique, la classe PromptTemplate crée un modèle de requête. Vous pouvez attribuer des valeurs aux éléments d'espace réservé en appliquant un mappage de noms et de valeurs d'espace réservé.

Requêtes structurées (FACULTATIF)

Vous pouvez également structurer vos requêtes à l'aide de l'annotation @StructuredPrompt, si vous souhaitez utiliser une approche plus riche axée sur les objets. Vous annotez une classe avec cette annotation. Ses champs correspondent aux espaces réservés définis dans la requête. Voyons cela en action.

Tout d'abord, nous avons 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 la classe TextPrompts, qui rassemble 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;
}

Instanciez ensuite cette nouvelle classe et ajoutez-lui le plat et les ingrédients de la recette. Ensuite, créez l'invite de commande et transmettez-la à 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 via une carte, vous pouvez utiliser un objet Java avec des champs que votre IDE peut renseigner automatiquement, de manière plus sûre.

Voici le code complet si vous souhaitez coller plus facilement ces modifications dans la 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 découvrirez une autre technique d'ingénierie des requêtes permettant au modèle PaLM de classer du texte ou d'analyser les sentiments. Parlons à présent des requêtes few-shot. Il s'agit d'un moyen d'améliorer vos requêtes avec quelques exemples qui aideront le modèle de langage à orienter le modèle de langage dans la direction souhaitée afin de mieux comprendre votre intention.

Retravaillons la classe TextPrompts pour exploiter les 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. Voici les "quelques coups" 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 requête few-shot pour classer différents documents dans des buckets de catégories différents.

8. Félicitations

Félicitations, vous avez créé 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 assez 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 certains des ateliers de programmation suivants pour aller plus loin avec PaLM en Java:

Complément d'informations

Documents de référence