Article
· 15 hr il y a 7m de lecture

Les modèles LLM et les applications RAG étape par étape - Partie ІІ - Création du contexte

Nous poursuivons cette série d'articles sur les applications LLM et RAG et dans cet article nous traiterons de la partie encadrée en rouge du diagramme ci-dessous:

Lors de la création d'une application RAG, il est tout aussi important de choisir un modèle LLM qui réponde à vos besoins (formation dans le domaine correspondant, coût, rapidité, etc.) que de définir clairement le contexte que vous souhaitez lui fournir. Commençons par définir le terme afin d'être clair sur ce que nous entendons par contexte.

Qu'est-ce que le contexte?

Le contexte fait référence à des informations supplémentaires obtenues à partir d'une source externe, telle qu'une base de données ou un système de recherche, afin de compléter ou d'améliorer les réponses générées par un modèle linguistique. Le modèle linguistique utilise ces informations externes pertinentes pour générer des réponses plus précises et plus détaillées plutôt que de s'appuyer uniquement sur ce qu'il a appris au cours de sa formation. Le contexte permet d'actualiser les réponses et de les aligner sur le sujet spécifique de la requête.

Ce contexte peut provenir d'informations stockées dans une base de données avec un outil similaire à celui montré par notre cher membre de la communauté @José Pereira вйты суе article ou d'informations non structurées sous la forme de fichiers texte que nous alimenterons avec le LLM, ce qui sera le cas que nous allons discuter ici.

Comment générer le contexte de notre application RAG?

Tout d'abord, la chose la plus indispensable est évidemment de disposer de toutes les informations que nous considérons comme pertinentes pour les éventuelles requêtes qui seront formulées à l'encontre de notre demande. Une fois ces informations organisées de manière à être accessibles depuis notre application, nous devons être en mesure d'identifier, parmi tous les documents disponibles dans notre contexte, ceux qui se rapportent à la question spécifique posée par l'utilisateur. Dans notre exemple, nous disposons d'une série de documents PDF (notices de médicaments) que nous voulons utiliser comme contexte possible pour les questions posées par les utilisateurs de notre application.

Cet aspect est essentiel au succès d'une application RAG ; il est tout aussi mauvais pour la confiance d'un utilisateur de répondre par des généralisations et des affirmations vagues typiques d'un LLM que de répondre avec un contexte complètement erroné. C'est là qu'interviennent nos précieuses bases de données vectorielles.

Bases de données vectorielles

Vous avez probablement entendu parler des "bases de données vectorielles" comme s'il s'agissait d'un nouveau type de base de données, telles que les bases de données relationnelles ou documentaires, mais rien n'est plus faux. Les bases de données vectorielles sont des bases de données qui supportent les types de données vectorielles et les opérations qui leur sont liées. Voyons dans le projet associé à l'article comment ce type de données sera représenté:

Voyons maintenant à quoi ressemble un enregistrement:

Bases de données vectorielles... Pourquoi faire?

Comme nous l'avons expliqué dans l'article précédent sur les LLM, l'utilisation des vecteurs est essentielle dans les modèles de langage, car ils permettent de représenter les concepts et les relations entre eux dans un espace multidimensionnel. Dans notre cas, cette représentation multidimensionnelle sera la clé pour identifier les documents de notre contexte qui seront pertinents pour la question posée.

Parfait, nous avons notre base de données vectorielle et les documents qui fourniront le contexte, il ne nous reste plus qu'à enregistrer le contenu de ces documents dans notre base de données, mais.... Avec quels critères?

Modèles pour la vectorisation

Eh bien... il n'est pas nécessaire d'ennuyer notre LLM pour vectoriser nos informations contextuelles, nous pouvons utiliser des modèles de langage plus petits qui conviennent mieux à nos besoins pour cette tâche, tels que les modèles entraînés pour détecter les similarités entre les phrases. Vous pouvez en trouver une myriade dans Hugging Face,  chacun étant entraîné avec un ensemble de données spécifique qui nous permettra d'améliorer la vectorisation de nos données.

Et si cela ne vous convainc pas d'utiliser l'un de ces modèles pour la vectorisation, sachez qu'en général ce type de modèles...

Voyons dans notre exemple comment nous invoquons le modèle choisi pour ces vectorisations:

if not os.path.isdir('/app/data/model/'):
    model = sentence_transformers.SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')            
    model.save('/app/data/model/')

Ici, nous téléchargeons le modèle choisi pour notre cas sur notre ordinateur local. Ce mini-LM est multi-langues, nous pourrons donc vectoriser en espagnol et en anglais sans aucun problème.

Chunking

Si vous avez déjà joué avec des modèles de langue, vous avez probablement déjà été confronté au défi du découpage en morceaux - ou "chunking". Qu'est-ce que chunking ? Il s'agit tout simplement de la division d'un texte en fragments plus petits susceptibles de contenir un sens pertinent. Grâce à ce découpage de notre contexte, nous pouvons effectuer des requêtes sur notre base de données vectorielle afin d'extraire les documents de notre contexte qui peuvent être pertinents pour la question posée.

Quels sont les critères de ce découpage ? Il n'y a pas vraiment de critère magique qui nous permette de savoir quelle doit être la longueur de nos morceaux pour qu'ils soient aussi précis que possible. Dans notre exemple, nous utilisons une bibliothèque Python fournie par langchain pour effectuer ce découpage, bien que toute autre méthode ou bibliothèque puisse être utilisée:

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 700,
    chunk_overlap  = 50,
)
path = "/app/data"
loader = PyPDFDirectoryLoader(path)
docs_before_split = loader.load()
docs_after_split = text_splitter.split_documents(docs_before_split)

Comme vous pouvez le constater, la taille choisie est de 700 caractères, avec un chevauchement de 50 pour éviter de couper des mots. Ce sont ces fragments extraits de nos documents que nous allons vectoriser et insérer dans notre base de données.

Ce processus de découpage peut être optimisé à volonté au moyen de la « lemmatisation », qui permet de transformer les mots en leur lemme correspondant (sans les temps des verbes, les pluriels, le genre, etc.) et d'éliminer ainsi une partie du bruit pour la génération du vecteur, mais nous n'allons pas nous étendre sur ce point, vous pouvez voir une explication plus détaillée sur cette page .

Vectorisation des fragments

Très bien, nous avons extrait nos fragments de chacun de nos documents, il est temps de les vectoriser et de les insérer dans notre base de données, jetons un coup d'œil au code pour comprendre comment nous pourrions le faire.

for doc in docs_after_split:
    embeddings = model.encode(doc.page_content, normalize_embeddings=True)
    array = np.array(embeddings)
    formatted_array = np.vectorize('{:.12f}'.format)(array)
    parameters = []
    parameters.append(doc.metadata['source'])
    parameters.append(str(doc.page_content))
    parameters.append(str(','.join(formatted_array)))
    cursorIRIS.execute("INSERT INTO LLMRAG.DOCUMENTCHUNK (Document, Phrase, VectorizedPhrase) VALUES (?, ?, TO_VECTOR(?,DECIMAL))", parameters)
connectionIRIS.commit()

Comme vous pouvez le constater, nous allons suivre les étapes suivantes: 

  1. Nous parcourons la liste de tous les fragments obtenus à partir de tous les documents qui vont former notre contexte.
  2. Pour chaque fragment, nous vectorisons le texte (en utilisant la bibliothèque sentence_transformers). 
  3. Nous créons un tableau à l'aide de la bibliothèque numpy avec le vecteur formaté et le transformons en chaîne de caractères.
  4. Nous enregistrons les informations du document avec son vecteur associé dans notre base de données. Comme vous pouvez le voir, nous exécutons la commande TO_VECTOR qui transformera la chaîne du vecteur que nous avons passé au format approprié.

Conclusion

Dans cet article nous avons vu la nécessité d'avoir une base de données vectorielle pour la création du contexte nécessaire dans notre application RAG, nous avons aussi vu comment découper et vectoriser l'information de notre contexte pour son enregistrement dans cette base de données.

Dans le prochain article, nous verrons comment interroger notre base de données vectorielles à partir de la question que l'utilisateur envoie au modèle LLM et comment, à l'aide d'une recherche de similarité, nous assemblerons le contexte que nous transmettrons au modèle. Ne manquez pas cet article!

Discussion (0)0
Connectez-vous ou inscrivez-vous pour continuer