Créer un moteur de recherche avec GPT-3
Si vous avez été en ligne récemment, vous avez probablement vu l’enthousiasme suscité par le nouveau modèle de langage d’OpenAI, ChatGPT. ChatGPT est étonnamment bon dans de nombreux domaines, y compris le débogage de code et la réécriture de texte dans le style que vous lui demandez. En tant que dérivé de GPT-3.5, un grand modèle de langage (LLM) avec des milliards de paramètres, ChatGPT doit son impressionnante quantité de connaissances au fait qu’il a vu une grande partie d’Internet pendant la formation – sous la forme du corpus Common Crawl et d’autres données.
Après des décennies de chatbots qui ne pouvaient même pas se souvenir de ce qu’ils disaient il y a un instant, il est compréhensible que les gens soient enthousiasmés par un modèle de langage capable de tenir une conversation et de créer un solide semblant d’intelligence. Mais lorsqu’il s’agit de la validité des réponses générées par ces énormes modèles, nous devons rester critiques. Les LLM sont particulièrement sujets aux hallucinations : produire un texte qui semble sensé au premier abord mais qui ne résiste pas à un examen plus approfondi, et présenter des choses comme des faits entièrement inventés.
Les moteurs de recherche sémantique – notre spécialité chez deepset – sont souvent alimentés par des modèles de questions-réponses extractives. Ces modèles renvoient des extraits de la base de connaissances textuellement, plutôt que de générer du texte à partir de zéro comme le fait ChatGPT. Cependant, de nombreuses applications peuvent bénéficier des capacités des LLM génératifs. C’est pourquoi Haystack , le framework open source de deepset pour le traitement appliqué du langage naturel (TAL), vous permet d’exploiter plusieurs modèles GPT dans votre pipeline. Avec cette approche, vous pouvez créer un moteur de recherche sémantique alimenté par GPT qui utilise vos propres données comme vérité de terrain et fonde ses réponses en langage naturel sur les informations qu’il contient.
Vous pouvez considérer Haystack comme une boîte à outils complète et très flexible dont l’objectif principal est de rendre la création de différentes saveurs de systèmes NLP facile et rapide, mais transparente. En plus de fournir un point d’entrée confortable à l’ API OpenAI , Haystack offre tous les autres composants dont vous avez besoin pour implémenter avec succès un système NLP de bout en bout avec GPT : une base de données vectorielle, un module de récupération et le pipeline qui combine tous ces éléments. dans un système interrogeable.
Dans cet article, nous allons montrer comment créer un système de questions-réponses génératif qui utilise le modèle GPT-3 « davinci-00 3 » pour présenter les résultats dans un langage naturel convaincant.
L’avènement des grands modèles de langage
Tous les modèles de langage moderne ne sont-ils pas grands ? C’est vrai – depuis que le Transformer a été introduit en tant qu’architecture de référence pour toutes sortes de tâches NLP, les modèles ont pris de l’ampleur. Mais alors que le plus grand modèle BERT a 336 millions de paramètres, le plus grand modèle GPT-3.5 d’OpenAI – sur lequel ChatGPT est basé – en a 520 fois plus.
Alors, que fait GPT avec toute sa capacité supplémentaire ? D’après l’observation, nous pouvons dire que GPT est exceptionnellement doué pour comprendre l’implication et l’intention. Il peut se souvenir de ce qui a été discuté plus tôt dans la conversation, y compris comprendre à quoi vous faites référence avec des mots comme « il » ou « avant cela », et il peut vous dire quand votre question n’a pas de sens. Toutes ces propriétés expliquent le sens accru de l’intelligence réelle. Il doit également générer un langage à partir de zéro, une tâche beaucoup plus difficile que de renvoyer la bonne section d’un corpus. Mais il a également été démontré que GPT utilise un grand nombre de ses paramètres pour stocker des faits – des informations réelles, qu’il utilise ensuite pour des tâches telles que le débogage de code et la réponse à des questions de connaissances générales.
Mais voici le problème : GPT peut encore faire des erreurs massives, et celles-ci sont plus difficiles à détecter car il est si bon pour converser et faire en sorte que ses réponses et ses exemples de code soient corrects. Début décembre, le forum de questions-réponses sur la programmation Stack Overflow a temporairement interdit les solutions générées par ChatGPT . Pendant ce temps, les hallucinations dans les grands modèles de langage ont donné naissance à un nouveau domaine de recherche .
Cependant, il existe un moyen d’utiliser les modèles GPT de manière plus sûre et génératrice de valeur. En connectant le modèle génératif à une base de données textuelle avec un contenu organisé et spécifique à un domaine – par exemple, un corpus de critiques de produits, une collection de rapports financiers ou une base de données avec des documents de recherche – vous pouvez combiner l’exactitude factuelle avec les prouesses conversationnelles de GPT. Avec Haystack, vous pouvez configurer un tel moteur de recherche basé sur GPT en un rien de temps. Le moteur de recherche est placé au-dessus de votre base de données textuelle et renvoie des réponses en langage naturel en réponse à une requête d’entrée.
Différents types de moteurs de recherche
Les moteurs de recherche sémantique se déclinent en différentes variétés et peuvent être grossièrement distingués par le type de réponse qu’ils renvoient. Les réponses peuvent consister en des documents correspondants (dans la recherche de documents), des étendues de réponses (en AQ extractive) ou des réponses nouvellement générées (en AQ générative).
The GenerativeQAPipeline : composant de Haystack pour un moteur de recherche génératif
Pour chacun de ces paradigmes de recherche, Haystack propose des pipelines prêts à l’emploi : des configurations de moteur de recherche avec des espaces réservés pour les modèles de langage pour une efficacité maximale. Dans ce tutoriel, nous utilisons le GenerativeQAPipeline. Il se compose d’un récupérateur (pour trouver les documents pertinents) et d’un générateur (pour écrire du texte), enchaînés. Le récupérateur se connecte à la base de données. Comme le générateur, il est souvent (mais pas nécessairement) basé sur un modèle Transformer. Sa tâche est de récupérer les documents de la base de données qui sont les plus susceptibles de contenir des informations précieuses, en fonction de la requête d’entrée d’un utilisateur. Notre modèle génératif utilise ensuite ces documents comme base factuelle pour écrire sa réponse.
Comment créer un moteur de recherche avec GPT-3
Avant de commencer, parlons rapidement des outils dont vous avez besoin pour suivre.
Conditions préalables
- Vous devez installer Haystack. Nous utilisons la version 1.13.
- Pour utiliser l’ API OpenAI , vous devez créer un compte et générer une clé API . Notez que si les premières requêtes sont gratuites, vous devez payer une fois que vous atteignez une certaine limite. (OpenAI vous accorde un budget initial de 18 $, ce qui est plus que suffisant pour terminer ce didacticiel et jouer avec le pipeline.)
- Ici, nous utilisons un petit ensemble de données de 18 articles Wikipédia sur Berlin, la capitale de l’Allemagne. Vous pouvez, bien sûr, utiliser votre propre jeu de données.
- Étant donné que nos intégrations et nos réponses sont fournies via l’API OpenAI, il n’est pas nécessaire d’utiliser des GPU pour ce guide. Cependant, si vous souhaitez expérimenter différents modèles, nous vous recommandons de travailler dans un notebook Colab et d’activer le GPU (sous « Runtime -> Change runtime type »).
Conversion et prétraitement
Avant de pouvoir configurer le pipeline, vous devez prétraiter vos données et les ajouter au magasin de documents ou à la base de données. Il existe de nombreuses options pour les magasins de documents dans Haystack. Ce tutoriel utilise FAISS, qui est une base de données vectorielle.
Avant de pouvoir introduire des données dans le magasin de documents, vous devez les mettre au bon format. Le DocumentStore s’attend à ce que les données soient fournies sous la forme d’un type de données Haystack appelé Document – un type de données de dictionnaire qui stocke les informations sous la forme d’un ensemble de champs associés (tels que le texte du document et ses métadonnées). La fonction convert_files_to_docs récupère vos fichiers à partir d’un répertoire et les convertit en documents Haystack. Si vous travaillez avec des articles de Wikipédia, vous pouvez utiliser la fonction de nettoyage clean_wiki_text qui supprime certains passe-partout spécifiques à Wikipédia.
de haystack.utils importer convert_files_to_docs, clean_wiki_text
docs = convert_files_to_docs(dir_path=DOC_DIR, clean_func=clean_wiki_text, split_paragraphs= True )
Selon le format de vos propres données, vous devrez peut-être suivre une procédure légèrement différente pour le prétraitement. Avec Haystack, vous pouvez extraire des données de sites Web ou convertir différents formats de fichiers tels que des fichiers pdf, txt ou docx. Consultez notre didacticiel de prétraitement et la page de documentation de FileConverter pour en savoir plus.
De nombreux documents, y compris des articles de Wikipédia sur des sujets populaires, peuvent être très longs. Vous devez vous assurer que les documents de votre base de données sont suffisamment courts pour que le modèle d’intégration capture correctement leur signification. Pour ce faire, vous pouvez utiliser le préprocesseur pour les diviser en extraits de texte plus courts. Nous suggérons une longueur fractionnée de 100 jetons par extrait et un chevauchement de trois jetons, pour nous assurer qu’aucune information ne soit perdue.
from haystack.nodes import PreProcessor preprocessor
= PreProcessor(
clean_empty_lines= True ,
clean_whitespace= True ,
clean_header_footer= False ,
split_by=”word”,
split_length= 100 ,
split_overlap= 3 ,
split_respect_sentence_boundary= False ,
)
processor_docs = preprocessor.process(docs)
A quoi ressemblent ces documents traités ? Jetons un œil à l’un d’eux :
documents_traités[ 0 ]
<Document : {'content' : 'Le U-Bahn de Berlin (en allemand : [ˈuː baːn] ; abréviation de Untergrundbahn, "chemin de fer souterrain") est un système de transport en commun rapide à Berlin, la capitale et la plus grande ville d'Allemagne, et un important partie du système de transport public de la ville. Avec le S-Bahn, un réseau de lignes de trains de banlieue et un réseau de tramway qui dessert principalement les parties orientales de la ville, il sert de principal moyen de transport dans la capitale.\nOuvert en 1902, le U-Bahn dessert 175 stations[1] réparties sur neuf lignes, avec une longueur totale de voie de 155,4 kilomètres (96 miles 45 chaînes),[3] dont environ 80 % sont souterrains.[4] Trains run',
'content_type': 'text',
'score' : Aucun,
'meta' : {'name' : 'Berlin U-Bahn.txt', '_split_id' :
'identifiant' : 'd2bf58a531b2500250650b43b1cce290'}>
Chaque document a été transformé en un objet de la classe Document, qui est un dictionnaire qui contient non seulement le texte du document, mais aussi des métadonnées générées automatiquement, comme le fichier d’où provient le texte.
Initialisation du DocumentStore
Il est temps de configurer le magasin de documents – par exemple, la base de données FAISS optimisée pour les vecteurs. Lorsque vous initialisez le magasin de documents, vous devez connaître la longueur des incorporations vectorielles de documents de votre récupérateur – ses représentations internes qu’il produira pour chaque document. Étant donné que vous allez travailler avec le modèle text-embedding-ada-002 de grande dimension d’OpenAI, vous devez définir l’embedding_dim des vecteurs sur 1536.
depuis haystack.document_stores import FAISSDocumentStore
document_store = FAISSDocumentStore(faiss_index_factory_str=”Flat”, embedding_dim= 1536 )
Maintenant, supprimez tous les documents existants dans la base de données et ajoutez les documents prétraités que vous avez générés précédemment.
document_store.delete_documents()
document_store.write_documents(processed_docs)
Notez que jusqu’à présent, la base de données ne contient que les documents en texte brut. Pour ajouter les représentations vectorielles vectorielles en grande dimension – les représentations de chaque document qui ont un sens pour le modèle de langage et qu’il peut utiliser pour la recherche sémantique – vous devez configurer le modèle pour la récupération.
Retriever
Le récupérateur est le module qui associe votre requête aux documents de la base de données et récupère ceux qu’il juge les plus susceptibles de contenir la réponse. Les récupérateurs peuvent être basés sur des mots clés (comme tf-idf et BM25), ou ils peuvent coder la similarité sémantique grâce à l’utilisation de vecteurs de texte générés par Transformer. Dans ce dernier cas, le récupérateur est également utilisé pour indexer les documents de votre base de données, c’est-à-dire les transformer en incorporations de grande dimension que le récupérateur peut ensuite rechercher.
Vous travaillerez avec le modèle de récupération le plus récent d’OpenAI , text-embedding-ada-002. Pour l’initialiser dans Haystack, vous devez fournir votre clé API OpenAI.
depuis haystack.nodes import EmbeddingRetriever
retriever = EmbeddingRetriever(
document_store=document_store,
embedding_model=”text-embedding-ada-002 ",
batch_size = 32,
api_key=MY_API_KEY,
max_seq_len = 1024
)
Lorsque vous configurez le récupérateur, vous le connectez directement à votre magasin de documents. Vous pouvez désormais utiliser la méthode update_embeddings pour transformer les documents bruts du magasin de documents en vecteurs de grande dimension que le modèle de récupération peut rechercher et comparer.
document_store.update_embeddings(récupérateur)
Générateur
Vous êtes maintenant prêt à initialiser le modèle GPT qui générera du texte pour vous. Le nœud OpenAIAnswerGenerator peut utiliser quatre modèles GPT différents. Vous pouvez utiliser le modèle GPT-3.5 le plus performant, text-davinci-003.
à partir de haystack.nodes , importez le générateur OpenAIAnswerGenerator
= OpenAIAnswerGenerator(api_key=MY_API_KEY, model='text-davinci-003 ', temperature=.5, max_tokens=30)
Nous vous recommandons d’augmenter le paramètre max_tokens de la valeur par défaut de 13 à 30, afin que le modèle GPT puisse produire des séquences plus longues. Nous vous suggérons également de régler la température sur 0,5 (la valeur par défaut est 0,2), ce qui donne au modèle un peu plus de liberté pour générer ses réponses. Plus la température est basse, plus le modèle reste fidèle aux textes sources sous-jacents.
Pipeline
Maintenant que tous les éléments individuels de votre moteur de recherche GPT sont configurés, il est temps de les transmettre à votre pipeline QA génératif.
from haystack.pipelines import GenerativeQAPipeline
gpt_search_engine = GenerativeQAPipeline(generator=generator, retriever=retriever)
Et c’est tout! Votre moteur de recherche alimenté par GPT est prêt à être interrogé.
Interroger le pipeline
Vous pouvez maintenant poser à votre système des questions générales sur Berlin (ou tout autre sujet sur lequel porte votre jeu de données). En plus de la requête elle-même, vous pouvez passer quelques paramètres au moteur de recherche, comme le nombre de documents que le récupérateur doit livrer au générateur et le nombre de réponses qui doivent être générées (tous deux désignés « top_k »).
query = 'Pour quoi Berlin est- elle connue ? '
params = {"Récupérateur": {"top_k": 5 }, "Générateur": {"top_k": 1 }}
réponse = gpt_search_engine.run(query=query, params=params)
Pour imprimer la réponse générée par votre pipeline, importez la fonction pratique print_answers de Haystack. Il vous permet de déterminer la quantité de détails que vous souhaitez voir lors de l’impression de la réponse. Le régler au minimum n’imprimera que la chaîne de réponse. Alors, quelle est la réponse du moteur de recherche à la question ci-dessus ?
depuis haystack.utils import print_answers
print_answers(answer, details=”minimum”)
>>> Question : Pourquoi Berlin est- elle connue ?
Réponses :
[ { 'réponse' : ' Berlin est connue pour sa culture diversifiée, sa vie nocturne, '
' ses arts contemporains et sa qualité de vie élevée.'}]
Notez que cette réponse est générée à partir de zéro : il ne s’agit pas d’une citation d’aucun des articles de Wikipédia, mais a été rédigée en fonction de leur contenu.
Les réponses générées dépendent du contexte
Rappelez-vous comment nous disions plus tôt que le modèle GPT-3 génère ses réponses sur la base des documents qu’il reçoit ? Vous pouvez maintenant tester cela en exécutant le générateur de manière isolée, sans le récupérateur. Cependant, vous ne pouvez pas l’exécuter sans aucun document, vous devez donc lui transmettre un seul extrait. Voici ce qui se passe si vous utilisez l’extrait sur le U-Bahn qui a été imprimé ci-dessus.
generator.predict("Pourquoi Berlin est- elle connue ?", documents=[processed_docs[ 0 ]])
>>> Question : Pourquoi Berlin est- elle connue ?
Réponses :
[ { 'answer' : ' Le U-Bahn de Berlin.'}]
Le système répond que Berlin est bien connue pour son métro, car c’est toute la connaissance qu’il a de ce seul document.
Maintenant, revenez à la version complète du moteur de recherche – celle qui a ingéré l’ensemble de vos données (par exemple, les 18 articles de Wikipédia sur Berlin) – et posez-lui quelques questions supplémentaires, pour avoir une meilleure idée de la façon dont votre moteur de recherche fonctionne.
Exemple 1
Question : Quelle est la meilleure période pour visiter Berlin ?
Réponses :
[ { 'answer': ' Berlin est une ville formidable à visiter toute l' année , mais le meilleur '
' moment pour visiter est pendant les mois d'été, de juin à '
' août.'}]
Exemple 2
Question : Les habitants de Berlin ont-ils un dialecte ?
Réponses :
[ { 'answer': ' Oui, les habitants de Berlin ont un dialecte, qui est une variante '
'du dialecte brandebourgeois.'}]
Exemple 3
Question : Parlez-moi de quelques bâtiments intéressants à Berlin.
Réponses :
[ { 'réponse' : ' La tour de télévision de Berlin est une tour de télévision à Berlin, en Allemagne. C'est la structure la plus
haute de Berlin , à une hauteur de 1 207 pieds . “}]
Exemple 4
Question : Comment la tour de télévision a-t-elle été construite ?
Réponses :
[ { 'answer': ' La tour de télévision a été construite par une équipe d'architectes entre '
' 1965 et 1969. La tour a été construite en un temps record de '
' seulement 53 mois,'}]
Un fait intéressant à propos de GPT est qu’il ne renvoie pas toujours les mêmes réponses. Lorsqu’il est invité plusieurs fois avec la même requête, il essaiera de trouver des réponses différentes. Lorsque nous avons travaillé nous-mêmes sur ce didacticiel, notre modèle a eu une hallucination majeure, après avoir reçu la même question plusieurs fois. Jetez un oeil à cette réponse:
Question : Comment la tour de télévision a-t-elle été construite ?
Réponses :
[ { 'answer': ' La tour de télévision a été construite par les troupes soviétiques en mettant le '
' contenu en feu et en transformant la tour en une '
' cheminée de fortune.'}]
Cette réponse – qui a été classée plus bas que la bonne réponse – est tellement absurde que c’est drôle. Mais cela devrait rappeler que la sortie d’un modèle génératif, même lorsqu’elle ressemble à une réponse bien formée, peut être entièrement hallucinée et doit être vérifiée.
Exemple 5
Question : Berlin est-il un bon endroit pour sortir en boîte ?
Réponses :
[ { 'answer': ' Oui, Berlin est un bon endroit pour sortir en boîte. Il existe de nombreuses '
'boîtes de nuit, dont le Watergate, le Tresor et le Berghain.}]
Comparaison de l’AQ générative à l’AQ extractive
Comme ce pipeline génératif, un moteur de recherche basé sur l’assurance qualité extractive renvoie des réponses sur un corpus de documents en réponse à une requête en langage naturel. Mais comme le système d’assurance qualité extractif extrait ses réponses textuellement du texte du document lui-même, il présente certaines restrictions par rapport au moteur de recherche GPT.
Un modèle d’AQ extractif est incapable de produire le type d’éléments conversationnels que vous pouvez voir dans les exemples ci-dessus, comme répondre « Oui » ou répéter des parties de la question dans sa réponse. Plus important encore, il ne peut pas répondre aux questions de manière aussi complète que le modèle GPT, car il n’est pas capable d’agréger les informations de différents textes.
Dans le dernier exemple, GPT a affirmé que Berlin est un bon endroit pour le clubbing, avant de citer quelques exemples de boîtes de nuit célèbres.
Mais lorsqu’un modèle d’AQ extractif se voit poser la même question, il ne peut répondre à la question que de manière implicite, en extrayant les portions de texte qu’il juge les plus pertinentes pour la requête. Voici deux réponses renvoyées par un tel moteur de recherche QA extractif, y compris la section (« contexte ») à partir de laquelle elles ont été extraites :
Question : Berlin est-il un bon endroit pour sortir en boîte ?
Réponses :
[ { 'réponse' : 'Les fêtards en Allemagne portent souvent un toast au Nouvel An avec un verre '
'de vin mousseux',
'contexte' : 'ke place dans toute la ville. En Allemagne, les fêtards ' ' toastent
souvent le Nouvel An avec un verre de vin mousseux.\n'
'Berlin abrite 44 théâtres et '}, { 'answer' : "La scène des clubs de Berlin est un lieu
de vie nocturne de premier ordre",
'contexte' : 'particulièrement celles d' Europe occidentale et centrale, faites '
« La scène des clubs de Berlin est un lieu de vie nocturne de premier ordre. Après la «
'chute du mur de Berlin en 1989 , beaucoup de salut'}]
Devez-vous utiliser l’assurance qualité générative ou extractive ?
Les avantages de l’AQ générative par rapport à l’AQ extractive sont clairs : elle a de meilleures compétences conversationnelles, produit des phrases bien formées en langage naturel et peut agréger des connaissances provenant de plusieurs sources en une seule réponse. Mais, comme nous l’avons vu, il a aussi quelques inconvénients. Vous devriez envisager d’utiliser l’assurance qualité extractive plutôt que générative dans les cas suivants :
- Lorsque vous souhaitez travailler avec des modèles open source plus petits. Comme nous l’avons vu, les modèles GPT sont énormes, et une fois que vous avez atteint une certaine limite de requêtes, vous devez payer pour utiliser l’API. Le hub de modèles Hugging Face , quant à lui, héberge des milliers de modèles open source pré-formés que vous pouvez télécharger gratuitement.
- Lorsque vous voulez de la transparence sur la provenance des informations du modèle. Les modèles extractifs n’hallucinent pas. Naturellement, ces modèles peuvent également renvoyer de mauvaises réponses. Mais ceux-ci sont beaucoup plus faciles à détecter en vérifiant le contexte dont ils ont été extraits.
- Lorsque vous souhaitez utiliser les réponses dans une tâche en aval. L’une des applications les plus populaires pour la réponse aux questions extractive est dans les systèmes d’extraction d’informations . De tels systèmes n’ont aucune utilité pour les capacités conversationnelles d’un moteur de recherche génératif. Au contraire, ils nécessitent une fonctionnalité de recherche capable d’extraire rapidement et de manière fiable des informations factuelles à partir de grands corpus.
Haystack : le cadre principal pour la création de moteurs de recherche
QA générative, QA extractive, traduction, résumé et bien plus encore : avec Haystack, vous pouvez créer le système le mieux adapté pour résoudre votre problème spécifique, en utilisant les nouvelles architectures les plus récentes.
Notre approche du TAL axée sur les applications vous fournit les blocs de construction modulaires pour configurer votre propre système dans les plus brefs délais. Consultez le référentiel Haystack pour en savoir plus ou consultez notre documentation .