1. Introduction
Dernière mise à jour:05/02/2024
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.
Points abordés
- Configurer un projet Java pour utiliser PaLM et LangChain4J
- Comment extraire des informations utiles d'un contenu non structuré (extraction d'entités ou de mots clés, sortie au format JSON)
- Comment démarrer une conversation avec vos utilisateurs
- Utiliser le modèle de chat pour poser des questions sur votre propre documentation
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
- 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.)
- 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.
- 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
- Dans Cloud Console, cliquez sur Activer Cloud Shell .
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.
Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.
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.
- 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`
- 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
- 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é.
- Si vous n'êtes pas dans la section Vertex AI de la console Google Cloud, procédez comme suit:
- Dans le champ Rechercher, saisissez "Vertex AI", puis saisissez
- Dans les résultats de recherche, cliquez sur "Vertex AI". Le tableau de bord Vertex AI s'affiche.
- 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. Vous appelez le modèle de chat de PaLM pour la première fois
Maintenant que le projet est correctement configuré, il est temps d'appeler l'API PaLM.
Créez une classe appelée ChatPrompts.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.vertexai.VertexAiChatModel;
import dev.langchain4j.chain.ConversationalChain;
public class ChatPrompts {
public static void main(String[] args) {
VertexAiChatModel model = VertexAiChatModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("YOUR_PROJECT_ID")
.location("us-central1")
.publisher("google")
.modelName("chat-bison@001")
.maxOutputTokens(400)
.maxRetries(3)
.build();
ConversationalChain chain = ConversationalChain.builder()
.chatLanguageModel(model)
.build();
String message = "What are large language models?";
String answer = chain.execute(message);
System.out.println(answer);
System.out.println("---------------------------");
message = "What can you do with them?";
answer = chain.execute(message);
System.out.println(answer);
System.out.println("---------------------------");
message = "Can you name some of them?";
answer = chain.execute(message);
System.out.println(answer);
}
}
Dans ce premier exemple, vous devez importer la classe VertexAiChatModel
et le ConversationalChain
de LangChain4J pour faciliter la gestion de l'aspect multitour des conversations.
Ensuite, dans la méthode main
, vous allez configurer le modèle de langage du chat à l'aide du compilateur pour VertexAiChatModel
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 (
chat-bison@001
).
Maintenant que le modèle de langage est prêt, vous pouvez préparer un ConversationalChain
. Il s'agit d'une abstraction de niveau supérieur proposée par LangChain4J pour configurer différents composants afin de gérer une conversation, comme le modèle de langage du chat lui-même, mais éventuellement d'autres composants pour gérer l'historique de la conversation par chat, ou pour connecter d'autres outils tels que des récupérateurs afin d'extraire des informations de bases de données vectorielles. Mais ne vous inquiétez pas, nous y reviendrons plus tard dans cet atelier de programmation.
Ensuite, vous engagerez une conversation multitour avec le modèle de chat afin de poser plusieurs questions interdépendantes. Vous vous interrogez d'abord sur les LLM, puis vous demandez ce que vous pouvez en faire et quels sont des exemples. Comme vous n'avez pas besoin de vous répéter, le LLM sait que "les" signifie LLM, dans le contexte de cette conversation.
Pour démarrer cette conversation multitour, il vous suffit d'appeler la méthode execute()
au niveau de la chaîne. Elle l'ajoute au contexte de la conversation, le modèle de chat génère une réponse et l'ajoute également à l'historique des discussions.
Pour ce faire, exécutez la commande suivante dans le terminal Cloud Shell:
./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts
Un résultat semblable à celui-ci doit s'afficher:
$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts Starting a Gradle Daemon, 2 incompatible and 2 stopped Daemons could not be reused, use --status for details > Task :app:run Large language models (LLMs) are artificial neural networks that are trained on massive datasets of text and code. They are designed to understand and generate human language, and they can be used for a variety of tasks, such as machine translation, question answering, and text summarization. --------------------------- LLMs can be used for a variety of tasks, such as: * Machine translation: LLMs can be used to translate text from one language to another. * Question answering: LLMs can be used to answer questions posed in natural language. * Text summarization: LLMs can be used to summarize text into a shorter, more concise form. * Code generation: LLMs can be used to generate code, such as Python or Java code. * Creative writing: LLMs can be used to generate creative text, such as poems, stories, and scripts. LLMs are still under development, but they have the potential to revolutionize a wide range of industries. For example, LLMs could be used to improve customer service, create more personalized marketing campaigns, and develop new products and services. --------------------------- Some of the most well-known LLMs include: * GPT-3: Developed by OpenAI, GPT-3 is a large language model that can generate text, translate languages, write different kinds of creative content, and answer your questions in an informative way. * LaMDA: Developed by Google, LaMDA is a large language model that can chat with you in an open-ended way, answering your questions, telling stories, and providing different kinds of creative content. * PaLM 2: Developed by Google, PaLM 2 is a large language model that can perform a wide range of tasks, including machine translation, question answering, and text summarization. * T5: Developed by Google, T5 is a large language model that can be used for a variety of tasks, including text summarization, question answering, and code generation. These are just a few examples of the many LLMs that are currently being developed. As LLMs continue to improve, they are likely to play an increasingly important role in our lives. BUILD SUCCESSFUL in 25s 2 actionable tasks: 2 executed
PaLM a répondu à vos trois questions associées.
L'outil de création VertexAIChatModel
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, 400 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
5. Un chatbot utile avec une personnalité !
Dans la section précédente, vous avez commencé à poser immédiatement des questions au chatbot LLM, sans lui donner de contexte particulier. Mais vous pouvez le spécialiser pour devenir un expert dans une tâche particulière ou sur un sujet particulier.
Comment procéder ? En préparant le terrain, vous devez expliquer au LLM la tâche à accomplir, le contexte, en donnant peut-être quelques exemples de ce qu'il doit faire, quel persona il doit avoir, dans quel format vous souhaitez obtenir des réponses et éventuellement un ton si vous voulez que le chatbot se comporte d'une certaine manière.
Cet article sur la création de requêtes illustre bien cette approche avec ce graphique:
https://medium.com/@eldatero/master-the-perfect-chatgpt-prompt-formula-c776adae8f19
Pour illustrer ce point, prenons l'inspiration sur les sites Web prompts.chat, qui listent de nombreuses idées intéressantes et amusantes de chatbots personnalisés pour agir en tant que:
- un traducteur d'emoji pour traduire les messages d'utilisateurs en emoji.
- Un outil d'amélioration des requêtes, qui permet de créer de meilleures requêtes
- un évaluateur de revue, qui vous aide à réviser des articles de recherche.
- un styliste personnel, pour obtenir des suggestions de vêtements.
Voici un exemple permettant de transformer un chatbot LLM en joueur d'échecs. Implémentons cela !
Mettez à jour la classe ChatPrompts
comme suit :
package palm.workshop;
import dev.langchain4j.chain.ConversationalChain;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
public class ChatPrompts {
public static void main(String[] args) {
VertexAiChatModel model = VertexAiChatModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("YOUR_PROJECT_ID")
.location("us-central1")
.publisher("google")
.modelName("chat-bison@001")
.maxOutputTokens(7)
.maxRetries(3)
.build();
InMemoryChatMemoryStore chatMemoryStore = new InMemoryChatMemoryStore();
MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryStore(chatMemoryStore)
.maxMessages(200)
.build();
chatMemory.add(SystemMessage.from("""
You're an expert chess player with a high ELO ranking.
Use the PGN chess notation to reply with the best next possible move.
"""
));
ConversationalChain chain = ConversationalChain.builder()
.chatLanguageModel(model)
.chatMemory(chatMemory)
.build();
String pgn = "";
String[] whiteMoves = { "Nf3", "c4", "Nc3", "e3", "Dc2", "Cd5"};
for (int i = 0; i < whiteMoves.length; i++) {
pgn += " " + (i+1) + ". " + whiteMoves[i];
System.out.println("Playing " + whiteMoves[i]);
pgn = chain.execute(pgn);
System.out.println(pgn);
}
}
}
Voyons cela en détail:
- De nouvelles importations sont nécessaires pour gérer la mémoire du chat.
- Vous instanciez le modèle de chat, mais avec un petit nombre maximum de jetons (ici, 7), car nous voulons simplement générer le prochain coup, et non une dissertation complète sur les échecs !
- Ensuite, créez un magasin de mémoire de chat pour enregistrer les conversations de chat.
- Vous créez une mémoire de chat réelle pour conserver les derniers mouvements.
- Dans la mémoire du chat, vous ajoutez un "système" qui indique au modèle de chat qui il est censé être un joueur d'échecs expert. Le "système" ajoute du contexte, tandis que le terme "utilisateur" et "IA" les messages sont la discussion proprement dite.
- Vous créez une chaîne de conversation qui combine la mémoire et le modèle de chat.
- Ensuite, nous avons une liste de coups pour le blanc, que vous itérez. La chaîne est exécutée avec le coup blanc suivant à chaque fois, et le modèle de chat répond avec le meilleur coup suivant.
Lorsque vous exécutez cette classe avec ces déplacements, vous devriez obtenir le résultat suivant:
$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts Starting a Gradle Daemon (subsequent builds will be faster) > Task :app:run Playing Nf3 1... e5 Playing c4 2... Nc6 Playing Nc3 3... Nf6 Playing e3 4... Bb4 Playing Dc2 5... O-O Playing Cd5 6... exd5
Ouah ! PaLM sait jouer aux échecs ? Pas exactement, mais pendant son entraînement, le modèle a dû voir des commentaires sur les échecs, voire les fichiers PGN (Portable Game Notation) de parties précédentes. Toutefois, ce chatbot ne l'emportera probablement pas face à AlphaZero (l'IA qui bat les meilleurs joueurs de Go, de Shogi et d'échecs). La conversation pourrait dérailler plus tard, le modèle ne se souvenant pas vraiment de l'état réel du jeu.
Les modèles de chat sont très puissants. Ils permettent de créer des interactions riches avec vos utilisateurs et de gérer diverses tâches contextuelles. Dans la section suivante, nous allons nous pencher sur une tâche utile: extraire des données structurées d'un texte.
6. Extraire des informations d'un texte non structuré
Dans la section précédente, vous avez créé des conversations entre un utilisateur et un modèle de langage de chat. Avec LangChain4J, vous pouvez également utiliser un modèle de chat pour extraire des informations structurées d'un 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 avec une requête astucieusement modifiée (c'est ce que l'on appelle communément "ingénierie de requête").
Vous allez mettre à jour la classe ChatPrompts
comme suit:
package palm.workshop;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.UserMessage;
public class ChatPrompts {
static class Person {
String name;
int age;
}
interface PersonExtractor {
@UserMessage("""
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:
---
{{it}}
---
JSON:
""")
Person extractPerson(String text);
}
public static void main(String[] args) {
VertexAiChatModel model = VertexAiChatModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("YOUR_PROJECT_ID")
.location("us-central1")
.publisher("google")
.modelName("chat-bison@001")
.maxOutputTokens(300)
.build();
PersonExtractor extractor = AiServices.create(PersonExtractor.class, model);
Person person = extractor.extractPerson("""
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.
"""
);
System.out.println(person.name);
System.out.println(person.age);
}
}
Examinons les différentes étapes de ce fichier:
- Une classe
Person
est définie pour représenter les détails décrivant une personne (son nom et son âge). - L'interface
PersonExtractor
est créée à l'aide d'une méthode qui, à partir d'une chaîne de texte non structurée, renvoie une instancePerson
instanciée. extractPerson()
est annoté avec une annotation@UserMessage
qui lui associe une requête. Il s'agit de l'invite que le modèle utilisera pour extraire les informations et les renvoyer sous la forme d'un document JSON, qui sera analysé pour vous et non assemblé dans une instancePerson
.
Examinons maintenant le contenu de la méthode main()
:
- Le modèle de chat est instancié.
- Un objet
PersonExtractor
est créé grâce à la classeAiServices
de LangChain4J. - Ensuite, il vous suffit d'appeler
Person person = extractor.extractPerson(...)
pour extraire les informations sur la personne du texte non structuré, puis de récupérer une instancePerson
avec le nom et l'âge.
Exécutez maintenant cette classe à l'aide de la commande suivante:
$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts > Task :app:run Anna 23
Oui. Voici Anna, elle a 23 ans !
Cette approche AiServices
présente un intérêt particulier, car vous utilisez des objets fortement typés. Vous n'interagissez pas directement avec le LLM de chat. À la place, vous travaillez avec des classes concrètes, comme la classe Person pour représenter les informations personnelles extraites, et vous disposez d'une classe PersonExtractor
avec une méthode extractPerson()
qui renvoie une instance Person. Le concept de LLM a disparu. En tant que développeur Java, vous ne faites que manipuler des classes et des objets normaux.
7. Récupération de la Génération augmentée: discuter avec vos documents
Revenons aux conversations. Cette fois, vous pourrez poser des questions sur vos documents. Vous allez créer un chatbot capable de récupérer des informations pertinentes à partir d'une base de données d'extraits de vos documents. Ces informations seront utilisées par le modèle pour "ancrer" ses réponses, au lieu d'essayer de générer des réponses à partir de son entraînement. Ce modèle est appelé RAG, ou Génération augmentée de récupération.
La génération augmentée de récupération se déroule en deux phases:
- Phase d'ingestion : les documents sont chargés, divisés en fragments plus petits, puis une représentation vectorielle de ceux-ci (représentation vectorielle continue) est stockée dans une base de données vectorielle capable d'effectuer des recherches sémantiques.
- Phase de requête : les utilisateurs peuvent désormais poser des questions à votre chatbot sur la documentation. La question sera également transformée en vecteur, et comparée à tous les autres vecteurs de la base de données. Les vecteurs les plus similaires sont généralement liés sémantiquement et sont renvoyés par la base de données vectorielle. Ensuite, le LLM reçoit le contexte de la conversation, les extraits de texte correspondant aux vecteurs renvoyés par la base de données, et il est invité à baser sa réponse en examinant ces extraits.
Préparer vos documents
Pour cette nouvelle démonstration, vous allez poser des questions sur l'architecture de réseau de neurones transformer, mise au point par Google, et c'est ainsi que sont implémentés aujourd'hui tous les grands modèles de langage modernes.
Vous pouvez récupérer l'étude qui décrit cette architecture ("Attention is all you need") à l'aide de la commande wget
pour télécharger le PDF sur Internet:
wget -O attention-is-all-you-need.pdf \ https://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf
Implémenter une chaîne de récupération conversationnelle
Découvrons, petit à petit, comment créer une approche en deux phases, d'abord avec l'ingestion du document, puis l'heure de la requête lorsque les utilisateurs posent des questions sur le document.
Ingestion de documents
La toute première étape de la phase d'ingestion de documents consiste à rechercher le fichier PDF que nous avons téléchargé et à préparer un fichier PdfParser
pour le lire:
PdfDocumentParser pdfParser = new PdfDocumentParser();
Document document = pdfParser.parse(
new FileInputStream(new File("/home/YOUR_USER_NAME/palm-workshop/attention-is-all-you-need.pdf")));
Au lieu de créer le modèle de langage de chat habituel, vous allez d'abord créer une instance d'un modèle "embedding". Il s'agit d'un modèle et d'un point de terminaison particuliers dont le rôle est de créer des représentations vectorielles d'éléments de texte (mots, phrases ou même paragraphes).
VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("YOUR_PROJECT_ID")
.location("us-central1")
.publisher("google")
.modelName("textembedding-gecko@001")
.maxRetries(3)
.build();
Ensuite, vous aurez besoin de quelques cours pour collaborer afin de:
- Chargez et scindez le document PDF en plusieurs morceaux.
- Créer des représentations vectorielles continues pour tous ces fragments
InMemoryEmbeddingStore<TextSegment> embeddingStore =
new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
.documentSplitter(DocumentSplitters.recursive(500, 100))
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
storeIngestor.ingest(document);
EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);
Une instance de InMemoryEmbeddingStore
, une base de données vectorielle en mémoire, est créée pour stocker les représentations vectorielles continues.
Le document est divisé en fragments grâce à la classe DocumentSplitters
. Il va diviser le texte du fichier PDF en extraits de 500 caractères, avec un chevauchement de 100 caractères (avec le morceau suivant, pour éviter de couper des mots ou des phrases, en petits morceaux).
Le magasin "ingestor" associe le séparateur de documents, le modèle de représentation vectorielle continue permettant de calculer les vecteurs et la base de données vectorielle en mémoire. La méthode ingest()
se charge ensuite de l'ingestion.
Maintenant, la première phase est terminée. Le document a été transformé en morceaux de texte avec les représentations vectorielles continues associées, puis stocké dans la base de données vectorielle.
Poser des questions
Il est temps de vous préparer à poser des questions ! Pour démarrer la conversation, vous pouvez créer le modèle de chat habituel:
VertexAiChatModel model = VertexAiChatModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("YOUR_PROJECT_ID")
.location("us-central1")
.publisher("google")
.modelName("chat-bison@001")
.maxOutputTokens(1000)
.build();
Vous avez également besoin d'une classe "retriever" qui va lier la base de données vectorielle (dans la variable embeddingStore
) et le modèle de représentation vectorielle continue. Son rôle est d'interroger la base de données vectorielles en calculant une représentation vectorielle continue pour la requête de l'utilisateur, afin de trouver des vecteurs similaires dans la base de données:
EmbeddingStoreRetriever retriever =
EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);
À ce stade, vous pouvez instancier la classe ConversationalRetrievalChain
(il s'agit simplement d'un nom différent pour le modèle de génération augmentée de récupération):
ConversationalRetrievalChain rag = ConversationalRetrievalChain.builder()
.chatLanguageModel(model)
.retriever(retriever)
.promptTemplate(PromptTemplate.from("""
Answer to the following query the best as you can: {{question}}
Base your answer on the information provided below:
{{information}}
"""
))
.build();
Cette "chaîne" se lie:
- Le modèle de langage de chat que vous avez configuré précédemment.
- Le extracteur compare une requête de représentation vectorielle continue de vecteur aux vecteurs de la base de données.
- Un modèle de requête indique explicitement que le modèle de chat doit répondre en se basant sur les informations fournies (c'est-à-dire sur les extraits pertinents de la documentation dont la représentation vectorielle continue de vecteur est semblable au vecteur de la question de l'utilisateur).
Vous êtes maintenant prêt à poser vos questions !
String result = rag.execute("What neural network architecture can be used for language models?");
System.out.println(result);
System.out.println("------------");
result = rag.execute("What are the different components of a transformer neural network?");
System.out.println(result);
System.out.println("------------");
result = rag.execute("What is attention in large language models?");
System.out.println(result);
System.out.println("------------");
result = rag.execute("What is the name of the process that transforms text into vectors?");
System.out.println(result);
Exécutez le programme avec la commande suivante:
$ ./gradlew run -DjavaMainClass=palm.workshop.ChatPrompts
Dans le résultat, vous devriez voir la réponse à vos questions:
The Transformer is a neural network architecture that can be used for language models. It is based solely on attention mechanisms, dispensing with recurrence and convolutions. The Transformer has been shown to outperform recurrent neural networks and convolutional neural networks on a variety of language modeling tasks. ------------ The Transformer is a neural network architecture that can be used for language models. It is based solely on attention mechanisms, dispensing with recurrence and convolutions. The Transformer has been shown to outperform recurrent neural networks and convolutional neural networks on a variety of language modeling tasks. The Transformer consists of an encoder and a decoder. The encoder is responsible for encoding the input sequence into a fixed-length vector representation. The decoder is responsible for decoding the output sequence from the input sequence. The decoder uses the attention mechanism to attend to different parts of the input sequence when generating the output sequence. ------------ Attention is a mechanism that allows a neural network to focus on specific parts of an input sequence. In the context of large language models, attention is used to allow the model to focus on specific words or phrases in a sentence when generating output. This allows the model to generate more relevant and informative output. ------------ The process of transforming text into vectors is called word embedding. Word embedding is a technique that represents words as vectors in a high-dimensional space. The vectors are typically learned from a large corpus of text, and they capture the semantic and syntactic relationships between words. Word embedding has been shown to be effective for a variety of natural language processing tasks, such as machine translation, question answering, and sentiment analysis.
Solution complète
Pour faciliter le copier-coller, voici l'intégralité du contenu de la classe ChatPrompts
:
package palm.workshop;
import dev.langchain4j.chain.ConversationalRetrievalChain;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.parser.PdfDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.input.PromptTemplate;
import dev.langchain4j.model.vertexai.VertexAiChatModel;
import dev.langchain4j.model.vertexai.VertexAiEmbeddingModel;
import dev.langchain4j.retriever.EmbeddingStoreRetriever;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ChatPrompts {
public static void main(String[] args) throws IOException {
PdfDocumentParser pdfParser = new PdfDocumentParser();
Document document = pdfParser.parse(new FileInputStream(new File("/ABSOLUTE_PATH/attention-is-all-you-need.pdf")));
VertexAiEmbeddingModel embeddingModel = VertexAiEmbeddingModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("YOUR_PROJECT_ID")
.location("us-central1")
.publisher("google")
.modelName("textembedding-gecko@001")
.maxRetries(3)
.build();
InMemoryEmbeddingStore<TextSegment> embeddingStore =
new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor storeIngestor = EmbeddingStoreIngestor.builder()
.documentSplitter(DocumentSplitters.recursive(500, 100))
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
storeIngestor.ingest(document);
EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel);
VertexAiChatModel model = VertexAiChatModel.builder()
.endpoint("us-central1-aiplatform.googleapis.com:443")
.project("genai-java-demos")
.location("us-central1")
.publisher("google")
.modelName("chat-bison@001")
.maxOutputTokens(1000)
.build();
ConversationalRetrievalChain rag = ConversationalRetrievalChain.builder()
.chatLanguageModel(model)
.retriever(retriever)
.promptTemplate(PromptTemplate.from("""
Answer to the following query the best as you can: {{question}}
Base your answer on the information provided below:
{{information}}
"""
))
.build();
String result = rag.execute("What neural network architecture can be used for language models?");
System.out.println(result);
System.out.println("------------");
result = rag.execute("What are the different components of a transformer neural network?");
System.out.println(result);
System.out.println("------------");
result = rag.execute("What is attention in large language models?");
System.out.println(result);
System.out.println("------------");
result = rag.execute("What is the name of the process that transforms text into vectors?");
System.out.println(result);
}
}
8. Félicitations
Félicitations, vous avez créé votre première application de chat par 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 chat de langage sont assez puissants et capables de gérer diverses tâches comme les questions/réponses, même avec votre propre documentation, l'extraction de données et, dans une certaine mesure, il était même capable de jouer aux échecs !
Et ensuite ?
Consultez certains des ateliers de programmation suivants pour aller plus loin avec PaLM en Java:
Complément d'informations
- Cas d'utilisation courants de l'IA générative
- Ressources de formation sur l'IA générative
- Interagir avec PaLM via Generative AI Studio
- IA responsable