Dans cet article nous allons voir comment :
- Utiliser de grands modèles de langage (LLM) open source pour ingérer des informations à partir de documents.
- Générer des réponses IA aux questions posées sur le contenu texte.
Mon objectif étant d’évaluer la faisabilité d’un développement d’un système automatisé pour ingérer de la documentation et fournir des réponses générées par l’IA aux questions posées et basées sur les dernières informations disponibles.
Pour ce faire nous créerons un outil d’extraction et d’analyse de données (RAG) utilisant le framework Python LlamaIndex avec le modèle LMM Vigogne. Ainsi ce RAG, ou Retrieval Augmented Generation, nous permettra d’utiliser la puissance d’un agent conversationnel IA avec l’utilisation de nos propres documentations.
Création de l’application RAG
Dans le cadre de cet article, nous utiliserons Google Colaboratory (Colab). En effet cet outil permet de développer des applications d’l’Intelligence Artificielle (IA) en permettant l’accès à un processeur graphique GPU gratuitement. Des informations détaillées sont disponibles sur la page FAQ de Colab.
Alors comment créer un RAG à partir d’une liste de documents ? Un RAG est constitué des étapes suivantes :
- La création de chunks (la division du corpus de textes en sous-parties).
- La création d’embeddings (la transformation de ces sous-parties de textes en vecteurs de valeurs numériques).
- La création d’une base de données vectorielles (le stockage des vecteurs dans une base de données adaptée).
- La recherche d’informations ou information retrieval (la recherche des chunks sémantiquement proches de la question posée).
Installation des dépendances/packages requis
Nous avons besoin des packages suivants :
%%bash # https://github.com/run-llama/llama_index pip install -q llama-index # https://github.com/UKPLab/sentence-transformers pip install -q sentence-transformers
Il est aussi nécessaire d’installer le package Python llama-cpp-python qui fournit une interface Python à la bibliothèque C++ Llama CPP
sans avoir à écrire du code C++ ou à gérer des API C++ de bas niveau.
Si vous avez positionné le type d’exécution du Notebook avec l’accélérateur matériel T4 GPU, pour profiter de la GPU vous devez installer llama-cpp-python
de la manière suivante :
# GPU !CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install llama-cpp-python
Sinon pour une exécution standard (càd avec l’accélérateur matériel CPU), l’installation doit se faire de la manière suivante :
# CPU !CMAKE_ARGS="-DLLAMA_CUBLAS=off" pip install llama-cpp-python
Préparation des documents textes
J’ai créé ces 2 fichiers au format texte brut contenant des informations à des fins de test. Les informations dans ces fichiers sont suffisamment précises et assez absurdes afin d’être sûrs que l’IA fait référence à ces informations pour constituer les réponses aux questions posées.
Info1.txt
MrTuto est un développeur de logiciel Open Source. Il est l'auteur principal de TutoPlot, TutoNGram et de plusieurs autres packages Python open source. La couleur préférée de MrTuto est le bleu foncé malgré le fait qu'il soit daltonien. Le plaidoyer de MrTuto en faveur des personnes souffrant d’un déficit de vision des couleurs l’amène à recommander des palettes de couleurs adaptées aux daltoniens pour rendre les graphiques plus accessibles.
Info2.txt
« JupyterTutoGoCrash » est le nom d'un package Python permettant de créer des notebooks Jupyter non maintenables. Ce package n'est plus activement développé et est désormais considéré comme obsolète. En effet les développeurs se sont rendu compte que les exigences de sécurité des environnements Jupyter empêchais ce package de fonctionner.
Chargement des données texte
Nous utilisons L’API LlamaIndex SimpleDirectoryReader comme connecteur de données permettant de lire des fichiers à partir d’un répertoire d’entrée ou d’une liste de fichiers. SimpleDirectoryReader
sélectionne automatiquement le meilleur lecteur de fichiers en fonction des extensions de fichiers. Il peut être configuré avec plusieurs arguments, tels que le répertoire d’entrée et la liste de fichiers à lire.
Ici nous chargeons les 2 fichiers Info1.txt
& Info2.txt
à partir d’un répertoire Google Drive.
from llama_index import SimpleDirectoryReader print("Chargement des documents 'Info1.txt' & 'Info2.txt'") documents = SimpleDirectoryReader( input_files=[ '/content/drive/MyDrive/Colab Notebooks/LlamaIndex-Vigogne QA/Data/Info1.txt', '/content/drive/MyDrive/Colab Notebooks/LlamaIndex-Vigogne QA/Data/Info2.txt', ] ).load_data()
Création des chunks
Ensuite, nous divisons le document en morceaux de texte (chunks), appelés « nœuds » (nodes) dans LlamaIndex, où nous définissons la taille du chunk à 500 caractères.
from llama_index.node_parser import SimpleNodeParser from llama_index.schema import IndexNode node_parser = SimpleNodeParser.from_defaults(chunk_size=500) base_nodes = node_parser.get_nodes_from_documents(documents)
Les embeddings et la base de données vecteurs
Cette troisième étape consiste à transformer nos morceaux de textes en représentations vectorielles, appelées embeddings. Ces embeddings nous permettront de calculer une similarité pour affiner le contexte transmis au modèle de langue. Afin de ne pas recalculer ces embeddings, ils seront stockés dans une base de données vectorielles.
LlamaIndex propose de nombreuses intégrations de modèles d’embeddings et de bases de données vectorielles. Nous utilisons le modèle embedding dangvantuan/sentence-camembert-base qui est un modèle d’embeddings de référence pour les phrases en français. Et nous prenons le modèle de langage LLM bofenghuang/vigogne-2-7b-chat qui est un modèle de Chat LLM basé sur Llama-2 pour générer des réponses basées sur la requête et le contexte récupéré.
LlamaIndex stocke les données en mémoire, et ces données peuvent être explicitement conservées via le code Python suivant :
storage_context.persist(persist_dir="<persist_dir>")
Cela conservera les données sur le disque, sous le répertoire persist_dir
spécifié (ou ./storage
par défaut).
Embeddings
# Name or path to sentence-transformers embedding model. # - Multilingual: paraphrase-multilingual-mpnet-base-v2, paraphrase-multilingual-MiniLM-L12-v2 # - French: dangvantuan/sentence-camembert-base, dangvantuan/sentence-camembert-large EMBEDDING_MODEL_NAME = 'dangvantuan/sentence-camembert-base' from langchain.embeddings.huggingface import HuggingFaceEmbeddings from llama_index import LangchainEmbedding print(f"Chargement du modéle Embedding: {EMBEDDING_MODEL_NAME} ...") embedding_model = LangchainEmbedding(HuggingFaceEmbeddings( model_name=EMBEDDING_MODEL_NAME, encode_kwargs = {"normalize_embeddings": False} ) )
LLM
# https://huggingface.co/TheBloke/Vigogne-2-7B-Chat-GGUF LLM_MODEL_NAME = "https://huggingface.co/TheBloke/Vigogne-2-7B-Chat-GGUF/resolve/main/vigogne-2-7b-chat.Q5_K_M.gguf" from llama_index.llms import LlamaCPP from llama_index.llms.llama_utils import messages_to_prompt, completion_to_prompt print(f"Chargement du modéle LLM: {LLM_MODEL_NAME} ...") llm = LlamaCPP( # You can pass in the URL to a GGML/GGUF model to download it automatically model_url=LLM_MODEL_NAME, # optionally, you can set the path to a pre-downloaded model instead of mo-del_url model_path=None, temperature=0.1, max_new_tokens=1024, generate_kwargs={}, model_kwargs={ "low_cpu_mem_usage": True, }, messages_to_prompt=messages_to_prompt, completion_to_prompt=completion_to_prompt, verbose=True, )
Vector store index
from llama_index import ServiceContext from llama_index import VectorStoreIndex service_context=ServiceContext.from_defaults( llm=llm, embed_model=embedding_model ) vectorstore_index = VectorStoreIndex( nodes=base_nodes, service_context=service_context ) print("Sauvegarde de la base de données vectorielle") vectorstore_index.storage_context.persist(persist_dir='llama_index')
Voilà la structure de données de type Vector Store Index est créée. Le Vector Store Index prend les morceaux de texte/nœuds, puis crée des intégrations vectorielles du texte de chaque nœud, prêtes à être interrogées par un LLM.
Le Vector Store Index permettra de récupérer rapidement des informations pertinentes pour une requête utilisateur à partir de documents externes.
Questions et réponses sur les documents
Dans cette dernière partie, nous allons créer une chaîne nous permettant de mettre en place notre processus de question/réponse.
Tout d’abord, il faut créer le modèle de prompt adéquat qui aidera le modèle de langue (LLM) à raisonner. Puis le retriever as_query_engine() permettant de poser des questions sur des informations spécifiques (chunks) contenues dans la base vectorielle et de recevoir une réponse correspondante à l’aide du modèle LLM configuré.
from llama_index.prompts import PromptTemplate from llama_index import ServiceContext text_qa_template_str = ( "<|system|>: Vous êtes un assistant IA qui répond à la question posée à la fin en utilisant le contexte suivant. Si vous ne connaissez pas la réponse, dites simplement que vous ne savez pas, n'essayez pas d'inventer une réponse. Veuillez répondre exclusivement en français.\n" "<|user|>: {context_str}\n" "Question: {query_str}\n" "<|assistant|>:" ) text_qa_template = PromptTemplate(text_qa_template_str) query_engine = vectorstore_index.as_query_engine( text_qa_template=text_qa_template, service_context=ServiceContext.from_defaults( llm=llm, embed_model=embedding_model, chunk_size=500, ), )
Ainsi les étapes suivantes sont mises en place :
- Créer l’embedding de la question
- Trouver les contenus similaires de la question dans la base vectorielle
- Créer le prompt adéquat
- Récupérer la réponse de notre modèle de langue
Nous pouvons désormais effectuer une requête.
rom IPython.display import Markdown response = query_engine.query("Qui est l’auteur de TutoPlot ? Quelle est sa couleur préférée ?") print("Question: Qui est l’auteur de TutoPlot ? Quelle est sa couleur préférée ?") display(Markdown(f"Reponse: <i>{response}</i>"))
Question: Qui est l’auteur de TutoPlot ? Quelle est sa couleur préférée ?
Reponse: L'auteur de TutoPlot est MrTuto, qui est également l'auteur principal de plusieurs autres packages Python open source. Sa couleur préférée est le bleu foncé malgré le fait qu'il soit daltonien.
response = query_engine.query("Pourquoi JupyterTutoGoCrash est-il obsolète ?") print("Question: Pourquoi JupyterTutoGoCrash est-il obsolète ?") display(Markdown(f"Reponse: <i>{response}</i>"))
Question: Pourquoi JupyterTutoGoCrash est-il obsolète ?
Reponse: il est obsolète en raison du manque de développement et des exigences de sécurité des environnements Jupyter qui empêchent ce package de fonctionner.
Comme nous pouvons le constater, le modèle LLM Vigogne a répondu avec précision à la requête. Il a effectué une recherche dans l’index et a trouvé les informations pertinentes.
Conclusion
LlamaIndex fournit une boîte à outils puissante pour créer des systèmes de génération augmentée RAG combinant les atouts des grands modèles de langage avec des bases de connaissances personnalisées. Nous avons ainsi vu comment créer une base de données vectorielles indexé de données spécifiques à un domaine et l’exploiter lors de l’inférence pour fournir un contexte pertinent au LLM afin de générer des réponses de haute qualité.
Il est à noter qu’une approche RAG est constitué à partir des deux modèles suivants:
- du modèle d’embeddings et de la base de données vectorielles.
- du modèle de langage LLM.
Il convient donc de faire attention à la qualité de ces deux composants. Le premier composant dépend principalement du choix de l’embedding et de la métrique de similarité. Le second composant dépend du choix du modèle de langage utilisé et de la qualité du prompt.
Code Python du Notebook Colab: LlamaIndex-Vigogne QA.ipynb
Super tuto!
J’essaie de faire fonctionner vigogne sur privateGPT, mais je n’y arrive pas (je me demande si ce n’est pas a cause du prompt spécial que tu utilises).
Serais-tu intéressé pour faire fonctionner Vigogne sur privateGPT et faire une contribution open source au projet?
La page GitHub du projet: https://github.com/imartinez/privateGPT
Tu peux y trouver le lien vers notre serveur discord: https://discord.gg/bK6mRVpErU
N’hesite pas me ping sur discord (pseudo `lopagela`)
A bientot!
Je ne connais pas privateGPT.
Cependant, si je peux aider en contribuant au projet, pourquoi pas !
Je te contacte sur Discord.
Bonjour
Avez vous ce message :
Chargement du modéle Embedding: dangvantuan/sentence-camembert-large …
No sentence-transformers model found with name /home/*******/.cache/torch/sentence_transformers/dangvantuan_sentence-camembert-large. Creating a new one with MEAN pooling.
Il semblerait que le téléchargement du modèle d’embeddings (`EMBEDDING_MODEL_NAME`) se soit mal déroulé.
Bonjour,
Merci pour le tuto !!
Est-il possible de créer une base de données avec des documents pdf et pourquoi pas des vidéos avec un système qui utiliserait les retranscriptions ?
(Je suis débutant en informatique et je serais ravi de pouvoir échanger sur le sujet)
Merci d’avance !!
Thomas