Accéder au contenu principal

Créer des chatbots sensibles au contexte : exploiter le framework LangChain avec ChatGPT

Découvrez comment créer des chatbots sensibles au contexte avec ChatGPT et le framework LangChain.
Actualisé 19 sept. 2026  · 15 min lire

Explorer avec l’IA

ChatGPTClaudePerplexity

Dans le paysage numérique actuel, en constante accélération, la montée en puissance des grands modèles de langage (LLM) a rendu les applications conversationnelles extrêmement populaires. Les chatbots ont transformé notre façon d'interagir avec les applications, les sites web et même les canaux de service client au quotidien.

La capacité à créer votre propre chatbot change la donne : elle permet aux entreprises comme aux particuliers de concevoir des interfaces conversationnelles personnalisées, efficaces et engageantes, adaptées à leurs besoins.

Cet article décompose comment créer un chatbot en Python en exploitant la puissance des LLM. Nous verrons comment créer un chatbot avec ChatGPT, puis l'optimiser avec le framework LangChain.

Si vous débutez avec ChatGPT et LangChain, découvrez notre Introduction aux grands modèles de langage avec GPT et LangChain : code-along ci-dessous :

Cet article couvre tous les points clés pour développer un chatbot optimisé s'appuyant sur ChatGPT. Nous utiliserons un notebook Jupyter avec les bibliothèques openai et langchain installées. Vous pouvez suivre dans ce workbook DataLab.

Dans les sections suivantes, nous verrons comment utiliser l'API OpenAI pour effectuer des appels basiques à ChatGPT, briques de base de notre conversation. Nous ajouterons également de la sensibilité au contexte à notre chatbot avec des structures Python simples. Enfin, nous optimiserons l'implémentation du chatbot et l'historique de conversation avec LangChain et nous explorerons ses fonctionnalités de mémoire.

Appels API ChatGPT de base

Nous allons utiliser ChatGPT comme modèle derrière notre chatbot. Notre première tâche pratique consistera donc à écrire un appel API simple mais complet à ChatGPT, afin d'établir une première interaction.

La fonction Python suivante encapsule l'appel API souhaité à ChatGPT en utilisant uniquement la bibliothèque openai.

import os
import openai

openai_api_key = os.environ["OPENAI_API_KEY"]

def chatgpt_call(prompt, model="gpt-3.5-turbo"):
   response = openai.ChatCompletion.create(
       model=model,
       messages=[{"role": "user", "content": prompt}]
   )
   return response.choices[0].message["content"]

Notez que, dans ce cas, nous utilisons le modèle gpt-3.5-turbo, le plus performant des GPT 3.5 pour le chat, et également l'un des plus abordables. Vous trouverez plus d'informations sur les différents modèles disponibles dans la documentation OpenAI.

Besoin d'aide pour obtenir vos clés d'API OpenAI ? Alors la formation Getting Started with the OpenAI API and ChatGPT est faite pour vous.

Analysons maintenant notre implémentation pas à pas !

La fonction chatgpt_call() est un wrapper autour de l'appel OpenAI ChatCompletion.create qui génère une complétion de chat.

À partir du prompt fourni, la fonction renvoie la réponse correspondante de ChatGPT. Pour un appel réussi, seuls l'identifiant du modèle à utiliser (model) et le prompt souhaité (prompt) sont requis.

La complétion renvoyée par ChatGPT contient des métadonnées en plus de la réponse elle-même. Néanmoins, le texte généré est toujours accessible dans le champ response.choices[0].message[“content”]. Davantage de détails sur le contenu complet d'une complétion sont disponibles dans la documentation OpenAI.

Avec cette implémentation, nous pouvons simplement solliciter ChatGPT en une ligne :

prompt = "My name is Andrea"
response = chatgpt_call(prompt)
print(response)

# Output: Nice to meet you, Andrea! How can I assist you today?

L'appel comme interaction isolée

Remarquez-vous un piège dans l'implémentation ci-dessus ?

Pour vous mettre sur la voie, faisons une relance :

prompt = "Do you remember my name?"
response = chatgpt_call(prompt)
print(response)

# Output: I'm sorry, as an AI language model, I don't have the ability to remember specific information about individual users.

Exact, comme on peut l'observer, chaque appel API est une interaction isolée. Le modèle n'a donc aucun souvenir des prompts précédents ni des réponses fournies. Chaque appel à la fonction chatgpt_call() démarre une nouvelle conversation.

C'est problématique pour construire un chatbot : impossible de tenir une conversation si le modèle ne mémorise pas l'échange en cours. Notre prochaine étape consiste donc à rendre le modèle conscient des interactions précédentes.

Sensibilité au contexte

La sensibilité au contexte permet aux chatbots de comprendre et de répondre de manière appropriée en fonction de la conversation en cours.

En constituant un contexte, les échanges suivants peuvent être personnalisés à partir des précédents, en assurant la continuité et en évitant les répétitions. De plus, avec un chatbot sensible au contexte, l'utilisateur peut poser des questions de clarification ou proposer des ajustements pour corriger des incompréhensions.

Globalement, la sensibilité au contexte améliore le naturel, l'efficacité et l'expérience utilisateur des chatbots. Désormais, nous appellerons l'ensemble des échanges précédents l'historique de conversation ou mémoire.

L'API OpenAI d'origine pour ChatGPT permet déjà d'envoyer l'historique de conversation au modèle avec chaque nouveau prompt. En complément, le framework LangChain propose une gestion plus efficace et économe de la mémoire de ChatGPT.

Comprendre les messages system, assistant et user

Structure de l'historique de conversation de ChatGPT

À ce stade, nous pouvons utiliser la méthode chatgpt_call() en lui fournissant simplement le prompt souhaité. En y regardant de plus près, le prompt est formaté comme un élément de la liste messages. Cette liste est conçue pour conserver l'historique de la conversation, selon un format très précis.

Regardons cela de plus près !

Jusqu'ici, nous avons formaté la liste messages dans chatgpt_call() comme suit :

messages = [{"role": "user", "content": prompt}]

La liste messages stocke l'historique de conversation comme une collection de dictionnaires. Chaque dictionnaire représente un message avec deux paires clé-valeur.

  • La clé role avec la valeur user indique que le message a été envoyé par l'utilisateur.
  • La clé content avec la valeur prompt contient le prompt utilisateur.

C'est un exemple très simple, avec une seule interaction. Bien que la clé content contienne toujours soit le prompt utilisateur soit la réponse du chatbot, la clé role est bien plus polyvalente.

Rôles system, assistant et user

La clé role indique l'auteur du message dans content. Avec ChatGPT, on distingue trois rôles :

  • User. Comme déjà vu, le rôle user correspond à l'utilisateur qui interagit avec le chatbot.
  • Assistant. Le rôle assistant correspond au chatbot.
  • System. Le rôle system sert à fournir des instructions, des consignes et du contexte au chatbot. Les messages système guident les interactions, définissent le comportement, offrent des informations contextuelles et gèrent des échanges spécifiques. Ils s'apparentent à des instructions de haut niveau, invisibles pour l'utilisateur.

Self-made image. Interaction of the different roles in the conversation chain when building a chatbot with chatGPT.

Schéma réalisé par l'autrice. Interaction des différents rôles dans la chaîne de conversation lors de la création d'un chatbot avec ChatGPT.

Constituer un historique de conversation

Nous pouvons maintenant construire notre historique de conversation en exploitant les trois rôles user, assistant et system dans la liste messages.

Compte tenu de nos tests, un historique correctement formaté utilisant ces trois rôles pourrait ressembler à ceci :

messages =  [ 
{'role':'system', 'content':'You are friendly chatbot.'},
{'role':'user', 'content':'Hi, my name is Andrea'},
{'role':'assistant', 'content': "Nice to meet you, Andrea! How can I assist you today?"},
{'role':'user', 'content':'Do you remember my name?'}  ]

Nous pouvons légèrement modifier notre fonction call_chatgpt() pour inclure l'historique de conversation comme paramètre d'entrée :

def call_chatgpt_with_memory(messages, model="gpt-3.5-turbo"):
   response = openai.ChatCompletion.create(
       model=model,
       messages=messages,
   )
   return response.choices[0].message["content"]

Essayons cette nouvelle implémentation !

messages =  [ 
{'role':'system', 'content':'You are friendly chatbot.'},
{'role':'user', 'content':'Hi, my name is Andrea'},
{'role':'assistant', 'content': "Nice to meet you, Andrea! How can I assist you today?"},
{'role':'user', 'content':'Do you remember my name?'}  ]

response = call_chatgpt_with_memory(messages)
print(response)

# Output: Yes, your name is Andrea.

Parfait ! Nous avons réussi à conserver la conscience du contexte, de sorte que le modèle puisse vraiment converser. Il nous faut toutefois un moyen de mettre à jour automatiquement la liste messages.

Historique de conversation automatique

Nous pouvons collecter automatiquement les messages en étoffant un peu notre fonction d'appel API :

def chatgpt_conversation(prompt):
   context.append({'role':'user', 'content':f"{prompt}"})
   response = call_chatgpt_with_memory(context)
   context.append({'role':'assistant',
   'content':f"{response}"})
   return response

Essayons maintenant !

chatgpt_conversation("Hello, my name is Andrea")

# Output: 'Nice to meet you, Andrea! How can I assist you today?'

Et une relance :

chatgpt_conversation("Do you remember my name?")

# Output: 'Yes, your name is Andrea.'

Désormais, l'historique de conversation est mis à jour automatiquement. Enfin, vous pouvez consulter à tout moment l'historique — et sa structure — en affichant la liste messages.

print(messages)

# Output:
[{'role': 'user', 'content': 'Hello, my name is Andrea'},
{'role': 'assistant', 'content': 'Nice to meet you, Andrea! How can I assist you today?'},
{'role': 'user', 'content': 'Do you remember my name?'},
{'role': 'assistant', 'content': 'Yes, your name is Andrea.'}]

Le framework LangChain

Jusqu'ici, on conviendra que notre implémentation produit un chatbot utile, mais pas nécessairement optimisé.

Réinjecter en continu chaque prompt et chaque réponse peut rapidement gonfler le volume de tokens, que ChatGPT devra traiter avant de produire la dernière réponse.

Pour l'instant, nous avons utilisé des opérations .append pour regrouper les interactions passées afin de donner une forme de mémoire au chatbot. Mais la gestion de mémoire peut être bien plus efficace avec des outils dédiés comme LangChain.

LangChain est un framework pour développer des applications propulsées par des modèles de langage. Les chatbots étant l'une des applications phares, LangChain propose une implémentation plus propre de l'historique de conversation, ainsi que des alternatives pour le gérer plus efficacement.

Pour en savoir plus sur LangChain, je vous recommande l'article d'introduction Introduction to LangChain for Data Engineering & Data Applications.

Historique simple avec LangChain

Dans cette section, nous allons voir comment utiliser LangChain pour construire un chatbot.

La bibliothèque langchain remplace la bibliothèque openai utilisée plus haut, puisque le module langchain.llms permet déjà d'interagir avec ChatGPT en deux lignes de code :

# OpenAI key from environment
from langchain.llms import OpenAI
llm = OpenAI()

Une fois le modèle llm chargé, importons l'objet de mémoire qui stockera notre historique. Pour conserver chaque interaction, LangChain propose ConversationBufferMemory :

from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()

Il est temps d'importer ConversationChain, un wrapper qui utilise llm et memory pour envoyer le prompt à ChatGPT et renvoyer ses réponses :

from langchain.chains import ConversationChain

conversation = ConversationChain(
   llm=llm,
   memory=memory
)

Pour soumettre un prompt, on utilise ensuite la méthode .predict :

conversation.predict(input="Hello, my name is Andrea")

# Output: "Hi Andrea, I'm an AI created to help you with whatever you may need. What can I do for you today?"

Activons verbose=True pour observer les informations prises en compte par le modèle pour générer une réponse. Essayons lors d'une relance :

Screenshot of the context available to ChatGPT when creating a completion. Verbose output in green.

Capture d'écran du contexte disponible pour ChatGPT lors de la génération d'une réponse. Sortie verbose en vert.

Vérifions enfin qu'il se souvient parfaitement des échanges précédents :

Screenshot of the context available to ChatGPT when creating a completion. Verbose output in green.

Capture d'écran du contexte disponible pour ChatGPT lors de la génération d'une réponse. Sortie verbose en vert.

Alimenter l'historique

Nous pouvons fournir du contexte supplémentaire au chatbot avec la méthode memory.save_context(). Ainsi, nous rendons le chatbot conscient de tout contenu souhaité, sans devoir le saisir au fil d'une conversation. Dans LangChain, les mots-clés à cet effet sont input et output. Par exemple :

memory.save_context({"input": "Hi"},
                   {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
                   {"output": "Cool"})

Vous pouvez aussi consulter à tout moment le contenu de la mémoire en exécutant print(memory.buffer) ou memory.load_memory_variables({}).

Types de mémoire dans LangChain

LangChain implémente différents types de mémoires pour ChatGPT. La ConversationBufferMemory utilisée plus haut conserve chaque interaction. Mais nous avons vu que réexpédier tout l'historique à chaque échange peut rapidement exploser le nombre de tokens à traiter.

Gardez en tête qu'au-delà de la limite de tokens par interaction, le coût d'usage de ChatGPT dépend aussi du nombre de tokens. Traiter tout l'historique à chaque fois risque donc de revenir cher sur la durée.

Pour éviter de retraiter en continu l'historique, LangChain propose d'autres approches optimisées de gestion de la mémoire. Nous en explorerons une des plus avancées dans la section suivante.

Historique avancé avec LangChain

Une méthode avancée consiste à stocker un résumé des interactions plutôt que chaque échange.

C'est mon approche préférée, car elle permet une gestion optimisée de la mémoire, sans sacrifier l'information des échanges passés.

Allons-y !

# OpenAI key from environment
from langchain.llms import OpenAI
llm = OpenAI()

from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)

Notez que ce type de mémoire utilise le llm pour générer le résumé des interactions précédentes.

Par ailleurs, cette mémoire peut conserver des interactions complètes jusqu'à un nombre maximum de tokens (max_token_limit). Au-delà, l'information des messages est intégrée au résumé.

Pour tester, créons une interaction avec un grand nombre de tokens. Considérons le schedule suivant :

schedule = "There is a meeting at 8am with your product team. \
You will need your powerpoint presentation prepared. \
9am-12pm have time to work on your LangChain \
project which will go quickly because Langchain is such a powerful tool. \
At Noon, lunch at the italian resturant with a customer who is driving \
from over an hour away to meet you to understand the latest in AI. \
Be sure to bring your laptop to show the latest LLM demo."

memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
memory.save_context({"input": "Hello"}, {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"}, {"output": "Cool"})
memory.save_context({"input": "What is on the schedule today?"}, {"output": f"{schedule}"})

Créons ensuite une nouvelle chaîne de conversation avec llm et memory, comme dans les exemples précédents.

conversation = ConversationChain(
   llm=llm,
   memory=memory,
   verbose=True
)

Nous pouvons utiliser .predict pour interroger ChatGPT :

Screenshot of the context available to ChatGPT when creating a completion. Verbose output in green.

Capture d'écran du contexte disponible pour ChatGPT lors de la génération d'une réponse. Sortie verbose en vert.

On observe que le chatbot conserve un résumé de l'historique initial, ce qui réduit le nombre de tokens traités à chaque nouvelle interaction.

Et voilà ! Vous pouvez désormais discuter des heures avec votre chatbot optimisé !

Réglez verbose=False pour une expérience questions-réponses plus agréable dans votre notebook.

Conclusion

Dans cet article, nous avons vu comment construire un chatbot sensible au contexte en nous appuyant sur le célèbre modèle ChatGPT.

Nous avons montré comment un tel chatbot permet des interactions continues. Cette approche itérative crée une boucle de retour permanente, vous permettant de garder le fil des besoins et préférences des utilisateurs tout au long de la conversation.

Nous avons exploré deux principales approches pour gérer l'historique : d'abord avec l'API native de ChatGPT pour un chatbot fonctionnel, puis avec le framework dédié LangChain et un type de mémoire optimisé.

À vous de jouer ! Utilisez maintenant ces briques pour façonner un chatbot adapté à votre cas d'usage.

Si vous souhaitez créer d'autres applications avec LangChain et ChatGPT, le webinar Building AI Applications with LangChain and GPT est fait pour vous. Besoin de vous remettre à niveau en TAL ? Consultez les modules Natural Language Processing in Python !


Andrea Valenzuela's photo
Author
Andrea Valenzuela
LinkedIn
Twitter

Andrea Valenzuela travaille actuellement sur l'expérience CMS à l'accélérateur de particules (CERN) à Genève, en Suisse. Experte en ingénierie et analyse de données depuis six ans, ses fonctions comprennent l'analyse de données et le développement de logiciels. Elle travaille actuellement à la démocratisation de l'apprentissage des technologies liées aux données par le biais de la publication ForCode'Sake sur Medium.

Elle est titulaire d'une licence en ingénierie physique de l'Université polytechnique de Catalogne, ainsi que d'une maîtrise en systèmes interactifs intelligents de l'Université Pompeu Fabra. Son expérience en matière de recherche comprend des travaux professionnels avec des algorithmes OpenAI antérieurs pour la génération d'images, tels que Normalizing Flows.

Sujets
Intelligence artificielle