đ€ Augmente les capacitĂ©s de ton IA avec LangChain4j đŠ
Je vous propose la suite de lâarticle prĂ©cĂ©dent nous ayant permis la dĂ©couverte de LangChain4j au travers de Quarkus.
âčïž Je vous laisse donc y jeter un oeil pour toute la phase dâinstallation, de prĂ©requis nĂ©cessaires Ă la bonne comprĂ©hension de cet article.
Lors de ce premier article, nous avons vu ensemble comment dĂ©velopper notre premier chat bot. Celui-ci Ă©tait trĂšs simple et il fallait attendre que le modĂšle distant fabrique lâensemble de la rĂ©ponse avant de lâavoir en retour. Pas trĂšs pratique et convivial.
Cette fois-ci, je vous propose dâajouter quelques fonctionnalitĂ©s rendant notre chat bot plus âintelligentâ.
On va donc le faire se comporter comme un chat bot normal : streamer sa réponse.
On va aussi lui ajouter un peu de contexte afin quâil connaisse plus de choses essentielles đ !
âčïž Lâensemble du code source se trouve dans le repository GitHub discover-langchain4j
đ Activation du mode streaming
Câest la premiĂšre fonctionnalitĂ© que nous allons rajouter : cela permet de rendre le bot plus convivial et de ne pas avoir Ă attendre sans trop savoir quand il va nous rĂ©pondre đ
.
Pour activer cette fonctionnalitĂ©, câest assez simple : nous allons utiliser Mutiny.
Mais câest quoi me direz-vous đ€š ?
En deux mots : cela vous permet dâajouter une notion dâasynchronisme dans votre dĂ©veloppement et de basculer dans ce que lâon appelle la programmation reactive.
Lâobjectif ? Permettre Ă notre IA dâenvoyer son dĂ©but de rĂ©ponse avant mĂȘme dâavoir envoyĂ© lâensemble de la rĂ©ponse.
đ Ajout de lâasynchronisme
Quarkus et son extension quarkus-langchain4j vont encore grandement nous aider.
âčïž Nous repartons du code de lâarticle prĂ©cĂ©dent, si vous souhaitez plus de dĂ©tails nâhĂ©sitez pas Ă vous reporter Ă lâarticle đ.
Nous allons donc modifier notre service OllamaService.java pour quâil supporte le mode streaming :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package fr.wilda.quarkus;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import io.quarkiverse.langchain4j.RegisterAiService;
import io.smallrye.mutiny.Multi;
// AI service bean registration
@RegisterAiService
public interface OllamaAIService {
// Context message
@SystemMessage("You are an AI assistant.")
// Prompt customisation
@UserMessage("Answer as best possible to the following question: {question}. The answer must be in a style of a virtual assistant and use emoji.")
String askAQuestion(String question);
// Context message
@SystemMessage("You are an AI assistant.")
// Prompt customisation
@UserMessage("Answer as best possible to the following question: {question}. The answer must be in a style of a virtual assistant and use emoji.")
// Multi use is enough to activate streaming mode
Multi<String> askAQuestionStreamingMode(String question);
}
â ïž Notez-bien ici lâutilisation de lâinterface io.smallrye.mutiny.Multi
qui permet âdâactiverâ le mode streaming.
Lâextension se charge de lâactiver lors de ses requĂȘtes au modĂšle đ.
A noter que seul le type String
est, pour lâinstant, supportĂ© pour le mode streaming mais des Ă©tudes dâĂ©volutions sont en cours â ïž
Maintenant, nous allons faire Ă©voluer notre partie API pour quâelle puisse profiter de cette arrivĂ©e dâinformations au fil de lâeau.
𧩠Modification de lâAPI Rest
LâidĂ©e est de proposer une ressource qui va ĂȘtre streamĂ©e au fur et Ă mesure.
On met donc Ă jour la classe AIAssistant
qui expose le endpoint hal9000
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package fr.wilda.quarkus;
import org.jboss.resteasy.reactive.RestQuery;
import io.smallrye.mutiny.Multi;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
// Endpoint root path
@Path("hal9000")
public class AIAssistant {
// AI Service injection to use it later
@Inject
OllamaAIService ollamaAIService;
// ask resource exposition with POST method
@Path("ask")
@POST
public String ask(String question) {
// Call the Mistral AI chat model
return ollamaAIService.askAQuestion(question);
}
// Stream response
@Path("streaming")
@GET
public Multi<String> streaming(@RestQuery("question") String question) {
// Call the Mistral AI chat model
return ollamaAIService.askAQuestionStreamingMode(question);
}
}
On a rajouté une ressource streaming
qui retourne Multi<String>
, Quarkus fera le reste.
Ensuite il suffit dâaller sur lâURL http://localhost:8080/hal9000/streaming?question="What is the answer to the Ultimate Question of Life,the Universe, and Everything?"
đ Ajoutons un peu de contexte
Lâintelligence des diffĂ©rents modĂšles que lâon utilise dĂ©pend grandement des donnĂ©es utilisĂ©es mais aussi de quand date la derniĂšre indexation de ces donnĂ©es (oui je sais que ce nâest pas le terme standard mais ça permet de se comprendre đ).
Essayons ce prompt, voulez-vous : Can you tell me more about Stéphane Philippart?
Voilà la réponse donnée:
1
2
3
4
đ Hello! StĂ©phane Philippart is a renowned figure in the tech industry, particularly in Belgium.
đ§đȘđ» He's known for his expertise in Information Technology (IT) and Digital Transformation. StĂ©phane has spent over two decades in the tech sector, holding various key positions in leading companies.
đâš His achievements include co-founding several successful startups and contributing significantly to their growth.
He's also a sought-after speaker at industry events, sharing his insights on digital transformation trends._
Flatteur mais trĂšs loin de la rĂ©alitĂ© non đ€š ?
đïž Le RAG Ă la rescousse
Rien dâĂ©tonnant dans cette rĂ©ponse :
- je ne suis pas trÚs connu et donc pas étonnant de pas avoir beaucoup de données sur moi
- mon prĂ©nom, assez commun, fait que lâhallucination avec dâautres StĂ©phane nâest pas Ă©tonnante
- la plupart des éléments publiques datent de 2-3 ans et souvent les modÚles ont été entraßnés sur des données plus anciennes
En quoi le RAG va nous aider ?
Le RAG ou encore Retrieval Augmented Generation va vous permettre dâajouter des donnĂ©es non connues de votre modĂšle pour lui donner un contexte qui correspond Ă votre domaine fonctionnel.
Pour ajouter ce contexte on va prendre une source de données, par exemple des fichiers, puis les transformer dans un format permettant une recherche par similitudes, dans ce cas une base de données vectorielle.
Une fois ce contenu ajoutĂ©, lors de requĂȘtes envoyĂ©es au modĂšle, celui-ci va pouvoir se baser sur ces donnĂ©es supplĂ©mentaires pour contextualiser sa rĂ©ponse.
Le RAG se diffĂ©rencie dâune autre technique, le transfert learning, par le fait que lâon utilise le modĂšle tel quel en lui ajoutant des donnĂ©es / du contexte.
Le transfert learning va consister Ă rĂ©-entrainer un modĂšle pour un use case diffĂ©rent de celui dâorigine, cela demande donc plus de calculs et une phase dâentraĂźnement lĂ oĂč le RAG se fait au runtime.
đ Les donnĂ©es Ă rajouter
Je vous lâai dit, on peut choisir plusieurs types de donnĂ©es. Dans mon cas, je vais choisir un fichier texte.
1
2
Stéphane Philippart is a world-renowned developer advocate in the field of cloud computing. He is also the CTO of Tours' biggest meetup.
Tours is well known for its famous rillettes.
𧩠Activation du RAG
Pour utiliser le RAG il va falloir deux choses :
- un moyen de transformer nos données en vecteurs
- un moyen dâajouter ces donnĂ©es dans la chaĂźne dâinterrogation de notre modĂšle
LĂ encore, vous vous en doutez, Quarkus et LangChain4j vont nous ĂȘtre dâun grand secours !
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- To add RAG capabilities -->
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-easy-rag</artifactId>
<version>0.13.0</version>
</dependency>
<!-- Inner process embedding model -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-embeddings-all-minilm-l6-v2-q</artifactId>
<version>0.30.0</version>
</dependency>
Merci Ă lâextension Quarkus qui, par le simple ajout de la dĂ©pendance quarkus-langchain4j-easy-rag
, active le mode Easy RAG.
Notez lâajout de la dĂ©pendance dev.langchain4j:langchain4j-embeddings-all-minilm-l6-v2-q
qui me permet dâavoir un embedding model in process.
Jâai choisi cela plutĂŽt que dâutiliser le endpoint dâembedding de Mistral car en mode Ollama il nâest pas accessible avec LangChain4j.
Au chargement de lâapplication on voit que le mode RAG est activĂ© avec les bonnes donnĂ©es :
1
2024-05-05 20:12:23,987 INFO [io.qua.lan.eas.run.EasyRagRecorder] (Quarkus Main Thread) Ingesting documents from path: ./src/main/resources/rag/, path matcher = glob:**, recursive = true
RĂ©essayons de demander au modĂšle sâil connaĂźt des choses sur StĂ©phane Philippart !
Lâappel Ă lâURL http://localhost:8080/hal9000/streaming?question="Can you tell me more about StĂ©phane Philippart?"
donne cette fois :
1
2
3
đ Hey there! StĂ©phane Philippart,đšâđ» is a globally recognized developer advocate in the cloud computing domain! *claps*
His expertise is highly sought after, making him a key figure in this innovative field.đĄMoreover, StĂ©phane holds an impressive title as the CTO of Tours' biggest meetup!
đą This city in France, famously known for its scrumptious rillettes,đ„đ is where he makes a significant impact`
Pas forcĂ©ment plus vrai mais mieux quand mĂȘme non ? đ
â ïž Ce petit exemple doit vous faire allumer quelques alertes dans votre cerveau : on ne peut dĂ©finitivement pas faire confiance aux rĂ©sultats dâune IA que lâon peut si facilement biaiser en quelques lignes de codes â ïž
En conclusion
JâespĂšre que vous avez pu, simplement, vous rendre compte comme il est assez facile avec Quarkus et LangChain4j dâajouter des capacitĂ©s Ă notre application de chat bot. Je vais continuer Ă ajouter quelques autres choses plus ou moins utiles dans les articles suivants đ.
Si vous ĂȘtes arrivĂ©s jusque lĂ merci de mâavoir lu et si il y a des coquilles nâhĂ©sitez pas Ă me faire une issue ou PR đ.
Merci Ă ma relectrice, Fanny, qui vous permet de lire cet article sans avoir trop les yeux qui saignent đ.
Lâensemble des sources des exemples est disponible dans le repository GitHub langchain4j-discovery.
Comments