| doc_assets | ||
| rasa | ||
| .DS_Store | ||
| .gitignore | ||
| logs.txt | ||
| parsingDemo.py | ||
| README.md | ||
| requirements.txt | ||
Information générale
Description du PoC
Ce projet se concentre sur la mise en place d'un PoC visant à déclencher des actions concrètes à partir d'un NLP/LLM, afin d'exécuter des tâches spécifiques en fonction de l'intention par déclenchement (scripts python).
Une deuxième partie du PoC se concentre sur la présentation d'un modèle pour analyser des données non structurées source par un LLM et les convertir en un format JSON pour du parsing.
Objectif du projet (première partie)
L'objectif est de communiquer avec un chatbot sous l'environnement Rasa, permettant :
- La communication avec le LLM Llama3 (installé en local au travers de Ollama) lors d'une communication générale.
- Le déclenchement d'actions Python (scripts) lorsque les intentions suivantes sont reconnues :
- Intention de connaître les informations d'une ville suisse depuis le NPA, déclenchant l'accès à une API afin de récupérer ces informations.
- Intention de connaître la signification d'un prénom, interrogeant les connaissances du LLM llama3 avec une demande de prompt personnalisé afin de donner la signification ainsi que trois personnes historiquement célèbre ayant porté ce nom.
- Intention de générer un profil d'une personne aléatoirement, en interrogeant une API.
En fonction des intentions détectées par le NLU, les différentes actions sont routées et jouées.
Réalisation
- Installer et configurer Ollama
- Créer et configurer l'environnement Rasa
- Créer les intentions, les stories, les règles et leur liaison aux actions.
- Créer les actions déclenchées en Python.
- Entraîner le modèle sur les intentions dans Rasa.
- Monter l'infrastructure.
- Interagir avec le chatbot et tester la bonne exécution des actions.
Réalisation du PoC
Prérequis
Les technologies utilisées sont accessibles librement ou gratuitement (API, technologies).
Les programmes suivants doivent être installés :
- Python 3.10 doit être installé sur la machine.
Installation d'Ollama
Ollama est une plateforme conçue pour faciliter l'utilisation et le déploiement de modèles de langage de type LLM (Large Language Models) localement sur des machines. Ollama propose une interface simple pour interagir avec différents modèles de langage.
L'installation d'Ollama va nous permettre d'utiliser localement un LLM. Ce concept étant fort intéressant pour la création d'un privacy LLM.
-
Installer Ollama depuis cet https://ollama.com/.
-
Téléchargez le modèle Llama 3.2 (par défaut, le modèle contenant 3,2 milliards de paramètres est téléchargé).
ollama pull llama3.2 -
Essayer d'exécuter et de converser avec le modèle.
ollama run llama3.2 >>> Hello, comment ça va ? 'Bonjour ! Je vais bien, merci pour ta question. C est un plaisir de discuter avec toi en français ! Comment puis-je t aider aujourd hui ?'
Ollama offre l'accès à sont API sur http://localhost:11434/api/generate
Créer le projet rasa
Rasa est une plateforme open source de développement de chatbots et d'assistants virtuels qui utilise le traitement du langage naturel (NLP) pour comprendre les intentions des utilisateurs et gérer les dialogues. Elle permet de créer des modèles personnalisés et d'exécuter des actions en réponse aux demandes des utilisateurs, tout en offrant des fonctionnalités avancées comme la gestion des dialogues contextuels et l'intégration avec diverses API.
Créer un environnement virtuel python
python3.10 -m venv ./venv
source ./venv/bin/activate
Dans cet exemple, j'utilise la version 3.10 de Python, car c'est celle qui est le mieux supportée.
Installer les dépendances
pip insatll -r requirements.txt
Création d'un nouveau projet rasa
mkdir rasa && cd rasa
rasa init
.
├── actions
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-38.pyc
│ │ └── actions.cpython-38.pyc
│ └── actions.py
├── config.yml
├── credentials.yml
├── data
│ ├── nlu.yml
│ ├── rules.yml
│ └── stories.yml
├── domain.yml
├── endpoints.yml
├── models
│ └── 20241008-123922-metal-event.tar.gz
└── tests
└── test_stories.yml
Construire le projet
nlu.yml
Le fichier nlu.ymlpermet de spécifier les intentions qui seront entraîner par le modèle NLU (Natural Language Processing) :
Nous avons donc 4 intentions :
- Générer un profil utilisateur par défaut (API)
- Discuter de manière générale avec le LLM
- Demander au LLM la signification d'un prénom
- Récupérer les informations d'une ville Suisse depuis un NPA (API)
version: "3.1"
nlu:
- intent: intent_randomuser
examples: |
- Génère moi un profil utilisateur
- Crée un profil d'utilisateur
- Peux-tu me donner un profil utilisateur aléatoire ?
- J'ai besoin d'un profil utilisateur
- Donne-moi un exemple de profil utilisateur
- Fais-moi un profil utilisateur
- Génère un profil utilisateur au hasard
- Crée un utilisateur aléatoire pour moi
- Est-ce que tu peux créer un profil utilisateur ?
- intent: intent_ask_llama
examples: |
- Qu'est-ce que tu sais sur les modèles de langage ?
- Comment fonctionne un ordinateur ?
- Quelle est la capitale de la France ?
- intent: intent_firstname_signification_by_llama
examples: |
- Que signifie mon prénom [Guillaume](firstname) ?
- Peux-tu me dire ce que signifie le prénom [Juliette](firstname) ?
- Quelle est la signification de [Emma](firstname) ?
- Explique-moi la signification du prénom [Lucas](firstname).
- Que veut dire le prénom [Sophie](firstname) ?
- Quelle est l'origine du prénom [Maxime](firstname) ?
- Dis-moi la signification de [Chloé](firstname).
- Que représente le prénom [Thomas](firstname) ?
- Je voudrais savoir ce que signifie le prénom [Camille](firstname).
- Que signifie le prénom [Alice](firstname) ?
- intent: intent_swiss_zipcode
examples: |
- Quel est le code postal en Suisse de ce numéro [1977](zipcode)
- Donne-moi le code postal de [1977](zipcode)
- Quel est le code postal pour [1977](zipcode) ?
À noter que dans des expressions telle que
[1977](zipcode), le modèle NLU sera capable de reconnaître que 1977 représente une valeur variable, ce qui lui permettra d'attribuer les valeurs de code postal fournies à la variablezipcode.
stories.yml
Le fichier stories.yml permet de définir les scénarios d'interaction en spécifiant les séquences d'actions et d'intentions que le modèle doit apprendre pour simuler un dialogue.
Nous sommes face à des stories très simple, soit :
- Reconnaître l'intention
- Exécuter l'action associée
version: "3.1"
stories:
- story: request_randomuser
steps:
- intent: intent_randomuser
- action: action_randomuser
- story: request_ask_llama
steps:
- intent: intent_ask_llama
- action: action_ask_llama
- story: request_firstname_signification_by_llama
steps:
- intent: intent_firstname_signification_by_llama
- action: action_firstname_signification_by_llama
- story: request_swiss_zipcode
steps:
- intent: intent_swiss_zipcode
- action: action_swiss_zipcode
Il est tout à fait possible de complexifier les stories comme :
- Rajouter des réponses dans le scénario de conversation
rules.yml
Le fichier rules.yml permet de spécifier les règles qui guideront le comportement du modèle, en définissant des séquences d'actions et de conditions à suivre lors des interactions avec les utilisateurs.:
Nous avons donc une séquence, qui dans l'ordre va repérer les intentions pour :
- Générer un profil utilisateur par défaut (API)
- Discuter de manière générale avec le LLM
- Demander au LLM la signification d'un prénom
- Récupérer les informations d'une ville Suisse depuis un NPA (API)
version: "3.1"
rules:
- rule: rule__randomuser
steps:
- intent: intent_randomuser
- action: action_randomuser
- rule: rule_swiss_zipcode
steps:
- intent: intent_swiss_zipcode
- action: action_swiss_zipcode
- rule: rule_firstname_signification_by_llama
steps:
- intent: intent_firstname_signification_by_llama
- action: action_firstname_signification_by_llama
- rule: General question redirect to LLM
steps:
- intent: intent_ask_llama
- action: action_ask_llama
Il est tout à fait possible de complexifier les rules comme :
- Créer des boucles (remplissage de formulaires, input
- Rajouter des conditions
domain.yml
Le fichier domain.ym définit les éléments essentiels de l'application Rasa, y compris les intentions, les entités, les actions, les réponses et les configurations de dialogue, permettant ainsi au modèle de gérer les interactions avec les utilisateurs.
Il faut renseigner les éléments dans le fichier domain.ym.
version: "3.1"
intents:
- intent_randomuser
- intent_ask_llama
- intent_swiss_zipcode
- intent_firstname_signification_by_llama
actions:
- action_randomuser
- action_ask_llama
- action_swiss_zipcode
- action_firstname_signification_by_llama
actions.py
Le fichier actions.py contient les actions personnalisées que le modèle Rasa peut exécuter en réponse à des requêtes utilisateur. Ce fichier permet de définir des fonctions qui réalisent des tâches spécifiques, comme l'appel à des API, le traitement de données ou l'interaction avec des bases de données.
On retrouve nos fonctions :
-
L'appel à
action_ask_llamapour les questions générales# Action to ask to the Llama model class ActionAskLlama(Action): def name(self): return "action_ask_llama" def run(self, dispatcher, tracker, domain): user_input = tracker.latest_message.get('text') # Call API (Streaming) url = "http://localhost:11434/api/generate" payload = { "model": "llama3.1", "prompt": user_input } try: response = requests.post(url, json=payload, stream=True) if response.status_code == 200: llm_response = "" # Read the response line by line for line in response.iter_lines(): if line: json_line = line.decode('utf-8') json_data = json.loads(json_line) # Done flag for defining the end of the response if json_data.get("done"): break llm_response += json_data.get("response", "") dispatcher.utter_message(text=llm_response.strip()) else: dispatcher.utter_message(text=f"Erreur lors de l'appel à Ollama: {response.status_code} - {response.text}") except Exception as e: dispatcher.utter_message(text=f"Une exception est survenue : {str(e)}") return [] -
L'appel à
action_randomuserpour générer un profil aléatoire (API)class ActionRandomuser(Action): def name(self): return "action_randomuser" ... -
L'appel à
action_swiss_zipcodepour récupérer les information d'une ville Suisse depuis un NPAclass ActionGetZipcode(Action): def name(self) -> str: return "action_swiss_zipcode" def run(self, dispatcher, tracker, domain): zipcode = next(tracker.get_latest_entity_values("zipcode"), None) with open('../logs.txt', 'a') as f: f.write(zipcode + '\n') if zipcode: url = f"https://api.zippopotam.us/ch/{zipcode}" response = requests.get(url) if response.status_code == 200: data = response.json() places = data.get("places", []) if places: place_info = places[0] city = place_info.get("place name") state = place_info.get("state") message = f"Le code postal {zipcode} correspond à {city}, {state}." else: message = f"Aucune information trouvée pour le code postal {zipcode}." else: message = f"Erreur lors de l'appel à l'API : {response.status_code}." else: message = "Je n'ai pas pu extraire le code postal." dispatcher.utter_message(text=message) return [] -
L'appel à
action_firstname_signification_by_llamapour connaître la signification d'un prénom.class ActionFirstnameSignificationLlama(Action): def name(self): return "action_firstname_signification_by_llama"
Entraîner le modèle rasa
Pour entraîner le modèle Rasa, utilisez la commande suivante :
rasa train
Tester le chatbot
Lancer le chatbot
Pour teser le projet, exécuter la commande suivantes :
rasa run actions & rasa shell
Cette commande :
- Démarre le serveur des actions
- Exécuter un shell interractif
Tester le chabot
À noter qu'une des fonctionnalités d'un NLU est l'automatisation et la transparence de la langue. C'est pourquoi la question en anglais est comprise, même si l'intention est en français.
Objectif du projet (deuxième partie)
Cette deuxième partie se concentre sur un PoC de parsing de données non structurées en JSON à l'aide du LLM. Les informations sur les cours, présentées sous forme de texte naturel, doivent être comprises et mises en relation avec un modèle JSON fourni en prompt, accompagné d'un guide expliquant ce que doit faire le LLM. Le LLM doit alors générer uniquement un JSON en sortie.
Code Python
import openai
# API OpenAI
client = openai.Client(api_key='XXXXXXXXX')
# Texte à convertir en JSON
text = 'Le cours "Python ML Avancé" est un programme dédié à l\'apprentissage du Machine Learning et de la régression en Python, proposé chaque lundi. Il est recommandé d\'avoir une bonne maîtrise des bases du Python et du Machine Learning débutant. Le tarif du cours est de 1000 euros.'
# Modèle JSON
model = '''
{
"name": "Data Science avec Python",
"description": "Cours introductif sur l'analyse de données et les bases du machine learning avec Python",
"day": "Mercredi",
"prerequest": "Aucun prérequis nécessaire",
"price": 800
}
'''
# Appel de l'API OpenAI
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "system",
"content": f"Convert this text {text} according to this JSON model: {model}",
},
{
"role": "system",
"content": "Give only the output without text or explanation, I will use it in a JSON parser.",
}
],
max_tokens=2000,
)
# Affichage de la réponse
print(response.choices[0].message.content)
Pour teser le projet, exécuter la commande suivantes :
python parsingDemo.py
Après exécution par le LLM, la sortie générle est la suivante :
{
"name": "Python ML Avancé",
"description": "Cours dédié à l'apprentissage du Machine Learning et de la régression en Python",
"day": "Lundi",
"prerequest": "Bonne maîtrise des bases du Python et du Machine Learning débutant recommandée",
"price": 1000
}
Il est crucial de bien guider le prompt afin d'éviter toute interférence lors du parsing.
