En 2024, les applications basées sur le LLM ne manquent pas. De grandes entreprises technologiques comme Microsoft et Google proposent des versions toujours plus puissantes de leurs modèles phares ChatGPT et Gemini, et des acteurs spécialisés comme Anthropic proposent des offres concurrentes avec des intégrations supplémentaires. Dans le monde du LLM appliqué, les entreprises et même les gouvernements expérimentent des applications de chat pour une variété de contextes.
Malgré l'énorme énergie entrepreneuriale investie dans les LLM, la plupart des applications de haut niveau sont encore limitées par leur concentration sur des interfaces de type chat qui acceptent et renvoient du texte lisible par l'homme. C'est compréhensible : après tout, l'un des développements les plus passionnants des LLM est la capacité de comprendre et de générer un langage humain, permettant ainsi une interface utilisateur conversationnelle. Cependant, les interfaces de chat négligent un autre cas d’utilisation très important des LLM : le traitement de texte en tant qu’étape intermédiaire dans un pipeline de données plus vaste.
Aujourd'hui, nous allons explorer ce cas d'utilisation et voir comment les LLM peuvent être utiles dans le cadre d'un pipeline de données, et pas seulement en tant que générateur de langage naturel.
Afin d'utiliser les LLM dans le cadre d'un pipeline de données, nous devons modifier le format de sortie du LLM : au lieu de générer des paragraphes que les humains peuvent lire, le modèle doit générer quelque chose que les ordinateurs peuvent lire. Habituellement, cela signifie une sortie structurée dans un format de données tel que JSON ou des instructions dans un langage de programmation tel que Python ou SQL. Ces formats de sortie sont beaucoup moins indulgents que le langage naturel, car un guillemet ou un crochet manquant peut faire planter l'ensemble du pipeline. Par conséquent, nous devrons nous appuyer sur des méthodes et fonctionnalités spécialisées qui ont été développées pour prendre en charge ce cas d’utilisation. Ces fonctionnalités sont collectivement appelées appels de fonctions, car la sortie a tendance à appeler des fonctions ou à être consommée dans des appels de fonctions.
Avant d'aborder ces méthodes, explorons d'abord un peu plus en profondeur pourquoi les fonctionnalités d'appel de fonctions ont été développées en premier lieu.
Connexion à des services externes
Le cas d’utilisation original et le plus simple de l’appel de fonction consiste à se connecter à des services externes. Lorsque OpenAI a initialement publié GPT-4, il a également mis à jour l'API avec une fonctionnalité permettant à l'utilisateur de fournir au modèle un ensemble de fonctions de style python que le modèle pourrait appeler pour atteindre ses objectifs. On pourrait par exemple dire au modèle qu'il peut appeler une fonction externe pour calculer le prix d'un titre complexe. Grâce à ces informations, le modèle serait capable d'écrire un code qui calcule la valeur d'un portefeuille composé de ces titres, sans avoir à posséder des connaissances spécialisées en matière de tarification des titres.
L’appel de fonctions de style python n’est que la pointe de l’iceberg. Une fois que l'importance des appels de fonctions a été prouvée sur le marché, OpenAI et d'autres fournisseurs LLM ont commencé à prendre en charge d'autres formats de sortie, tels que JSON ou SQL. L’important était que ces modèles produisaient des résultats lisibles par machine, qui pouvaient être lus de manière fiable par d’autres processus.
Les lecteurs avisés reconnaîtront peut-être que nous avons fait quelque chose de similaire dans les articles précédents, en utilisant LLM pour générer des données de formation , SQL ou JSON . Dans ces articles , nous avons accompli cela en utilisant une ingénierie rapide et une vérification des résultats, mais maintenant que l'appel de fonction est une fonctionnalité largement prise en charge, nous pouvons le faire plus facilement en nous appuyant sur ces fonctionnalités au niveau du modèle.
Enchaînement des LLM
Les appels de fonctions ont créé de nouvelles possibilités pour les applications multi-LLM, et bientôt les développeurs ont expérimenté le chaînage des LLM pour créer des systèmes sophistiqués. Certains de ces systèmes sont devenus connus sous le nom d' agents , capables de rechercher indépendamment sur le Web, de collecter de nouvelles données et d'appeler un autre LLM avec les nouvelles informations. Ces pipelines sont capables d'une autonomie surprenante et sont capables de résoudre des problèmes sophistiqués avec très peu d'interventions, même s'il existe encore des limitations, telles que les coûts des API et les garanties comportementales, qui empêchent les agents d'être largement adoptés.
Utilisation du LLM comme entrée et traitement intermédiaire
Un autre cas d’utilisation des LLM appelant des fonctions est le traitement des données d’entrée et intermédiaires. Les LLM peuvent être utilisés pour analyser des entrées non structurées en données structurées pouvant être utilisées pour le traitement en aval. Bien que bon nombre de ces tâches aient tendance à être reléguées aux technologies NLP « traditionnelles », la nature flexible des modèles basés sur des transformateurs signifie qu'un modèle spécifiquement formé peut être bien plus performant sur ces tâches que les autres technologies NLP. En conséquence, de nombreux développeurs tentent d’exploiter ces modèles spécialisés dans leurs pipelines de données.
Maintenant que nous connaissons la théorie derrière les appels de fonctions, regardons l’application que nous allons construire aujourd’hui.
Dans un article précédent , j'ai créé une application RAG simple pour répondre aux questions en langage naturel sur la newsletter populaire CB Insights. Dans l'article d'aujourd'hui, nous allons créer une application de questions-réponses similaire, mais au lieu de nous appuyer sur l'intégration de la recherche et de GPT3.5, nous utiliserons la reconnaissance d'entités comme méthode d'indexation principale. De plus, nous utiliserons DRAGON comme moteur de synthèse afin de pouvoir exécuter l'intégralité de l'application sur notre ordinateur portable, sans nécessiter de services cloud.
Pourquoi utiliser la reconnaissance d'entités ?
Avant d'aborder la mise en œuvre, explorons d'abord les avantages de l'utilisation de NER comme technologie de récupération au lieu d'intégrer la recherche. Alors qu'en production, nous souhaitons utiliser chaque technique en fonction des exigences de la situation spécifique, NER offre plusieurs avantages par rapport à un système qui repose sur la recherche intégrée.
Débogabilité : la reconnaissance d'entités étant une tâche facilement vérifiable, l'ensemble du pipeline est beaucoup plus déboguable. Il est facile de vérifier si le modèle identifie correctement toutes les entités, et il est facile de construire et d'améliorer un algorithme de correspondance basé sur ces entités. En comparaison, il est beaucoup plus difficile de vérifier que l’algorithme d’intégration identifie correctement les similitudes et les différences dans les passages.
Flexibilité : en séparant la reconnaissance et le filtrage, nous rendons le pipeline beaucoup plus flexible qu'un algorithme de recherche basé sur l'intégration. Nous pouvons ajouter des métadonnées supplémentaires, modifier les algorithmes de recherche en fonction du type d'entité et même utiliser des algorithmes d'intégration au-dessus des résultats de recherche basés sur NER. Cela permet de développer des fonctionnalités beaucoup plus puissantes sur la base de combinaisons de technologies.
Par exemple, un pipeline basé sur NER peut utiliser la recherche basée sur les entités pour affiner un ensemble de documents, puis utiliser un algorithme d'intégration pour affiner davantage l'espace de recherche. Cela tend à rendre la recherche beaucoup plus rapide et plus efficace.
Pouvoir d'identification : en raison du niveau de contrôle manuel possible, les pipelines NER sont beaucoup plus adaptés à certaines tâches de recherche et de récupération. Les recherches d'intégration sont basées sur la proximité des passages au sein des données d'entraînement, qui calcule la probabilité que deux documents proviennent du même document plus volumineux. Dans certains cas d'utilisation, la recherche intégrée manquera des documents importants.
Maintenant que nous comprenons les avantages de l'utilisation de NER dans un pipeline RAG, examinons de plus près les technologies spécifiques que nous utilisons dans notre application.
Reconnaissance d'entité LLM
Entity Recognition est une technologie NLP « traditionnelle » permettant d’extraire des données structurées à partir de données linguistiques non structurées. Les données extraites peuvent ensuite être utilisées dans le traitement en aval ou comme métadonnées pour le passage analysé.
Historiquement, cela était accompli à l'aide de petits algorithmes d'apprentissage automatique spécialement conçus qui balisaient d'abord les parties du discours, suivis d'une seconde passe qui déterminait si les noms propres identifiés sont des entités nommées.
Avec les LLM appelant des fonctions, nous pouvons accomplir la même tâche, avec plusieurs avantages supplémentaires.
Étant donné que l'architecture du transformateur est capable de mieux comprendre la structure du langage que les modèles NLP plus petits, les performances seront probablement plus robustes, par exemple dans les cas où le passage est mal formaté.
Étant donné que les LLM sont mis à jour avec les données de formation les plus récentes, le système de reconnaissance d'entités restera probablement plus à jour que les autres modèles de reconnaissance d'entités open source.
Des techniques d'ingénierie rapides peuvent être utilisées pour intégrer des données supplémentaires et donner des instructions supplémentaires, permettant un comportement plus flexible, même dans les modèles disponibles dans le commerce.
DRAGON Nous avons abordé Dragon dans un article précédent dans lequel nous avons souligné ses performances impressionnantes dans la synthèse de données en langage naturel. Nous utiliserons Dragon pour effectuer la dernière étape de l'analyse, où nous résumerons tous les articles pertinents pour les entités sélectionnées.
SLIM Les SLIM sont une nouvelle famille de modèles miniaturisés et exécutables localement de LLMWare - ce n'est un secret pour personne, je suis fan de leur travail de miniaturisation - spécialisés dans l'appel de fonctions. Ces modèles ont été affinés spécifiquement pour générer des sorties pouvant être interprétées par des machines, permettant aux utilisateurs de profiter des développements récents en matière d'architecture d'appel de fonctions sans avoir à s'appuyer sur des API externes.
Aujourd'hui, nous utiliserons le modèle SLIMs-NER, qui effectuera la reconnaissance d'entités nommées sur les articles de la newsletter. En plus du NER, il existe également des modèles SLIM pour l'analyse des sentiments, la génération SQL et les agents multi-étapes.
Maintenant que nous comprenons la technologie, implémentons l'application !
Commençons par télécharger les articles CB Insights. Importons les dépendances :
import requests from bs4 import BeautifulSoup import os import pandas as pd import json import re
Et maintenant le code pour télécharger les archives de la newsletter :
res = requests.get('https://www.cbinsights.com/newsletter/') soup = BeautifulSoup(res.text) article_links = [[i.text, i['href']] for i in soup.find_all('a') if 'campaign-archive' in i['href'] ] article_soups = [BeautifulSoup(requests.get(link).text) for title, link in article_links]
Maintenant que nous avons téléchargé l'archive de la newsletter, traitons-la au format JSON
result_json = {} for soup_meta, soup_art in zip(article_links, article_soups): article_tables = [] cur_article = [] for table in soup_art.find_all('table'): if table.attrs.get('mc:variant') == 'Section_Divider': article_tables.append(get_deduped_article_tables(cur_article)) cur_article = [] else: cur_article.append(table.text) article_tables.append(get_deduped_article_tables(cur_article)) result_json[soup_meta[0]] = article_tables articles_with_meta = [] for name, tables in result_json.items(): print(name, pd.to_datetime(tables[0][1].strip())) articles_with_meta.append({ 'name': name, 'date': pd.to_datetime(tables[0][1].strip()).strftime('%Y-%m-%d'), 'tables': tables }) df = pd.DataFrame(articles_with_meta)
Nous en sommes maintenant au même endroit que dans l’article précédent. Au lieu de passer directement à la construction du RAG en créant des intégrations, nous exécuterons plutôt une étape de reconnaissance d'entité.
Tout d'abord, importons les dépendances pour exécuter les SLIM, un nouvel ensemble de modèles de LLMWare qui nous permet d'effectuer la reconnaissance d'entités localement sur notre machine :
from llmware.agents import LLMfx from llmware.parsers import WikiParser from collections import defaultdict # define a function for identifying all the named entities def run_ner(text): agent = LLMfx() agent.load_work(text) agent.load_tool("ner") named_entities = agent.ner() ner_dict= named_entities["llm_response"] return ner_dict
Nous pouvons désormais exécuter la reconnaissance des entités nommées sur tous les articles :
date_entities = defaultdict(dict) for _, row in df.iterrows(): for idx, t in enumerate(row['tables'][1:]): if 'Start Your Free Trial' in t: t = t[:t.index('Start Your Free Trial')] date_entities[row['date']][idx] = run_ner('\n'.join(t))
L'achèvement du pipeline NER peut prendre quelques minutes, mais c'est tout ce dont vous avez besoin pour reconnaître les entités à l'aide d'un LLM miniaturisé de pointe.
Vous pouvez consulter le dictionnaire date_entities en imprimant certains éléments de test. Par exemple, le code :
date_entities[list(date_entities.keys())[0]]
Devrait produire le résultat ci-dessous :
{0: {'people': ['Yahoo!'], 'place': [], 'company': ['Databricks', 'MosaicML'], 'misc': []}, 1: {'people': [], 'place': ['New York'], 'company': ['CB Insights'], 'misc': []}}
Ce qui montre toutes les différentes entités détectées par le modèle SLIM.
Maintenant que les entités ont été détectées, créons un workflow de questions-réponses qui démontre la puissance de cette technique. Pour notre exemple, nous utiliserons la question test : Quel rôle OpenAI joue-t-il dans la stratégie d'IA de Microsoft ?
Commençons par importer les packages appropriés pour exécuter DRAGON :
from llmware.prompts import Prompt query = "What role does OpenAI play in Microsoft's AI strategy?" model_name = "llmware/dragon-llama-7b-gguf" prompter = Prompt().load_model(model_name)
Maintenant, nous pouvons créer la fonction qui répond à la question en utilisant la reconnaissance d'entité. Afin d'exploiter nos données NER, nous souhaiterons mettre en œuvre le flux de travail suivant :
Voici à quoi ressemble le workflow sous forme de code :
def answer_question_with_ner(query): ner_results = run_ner(query) # run NER on the user query search_entities = [] for ent_type, ent_list in ner_results.items(): search_entities.extend(ent_list) # create a list of entities to search for search_entities = list(set(search_entities)) # now perform a lookup for articles that mention the identified entities, using set arithmetic. articles = set(entity_to_place_map[search_entities[0]]) for se in search_entities: articles &= set(entity_to_place_map[se]) # now process the corpus into a prompt and feed it to the question-answering LLM. article_content = [] for article in articles: article_content.extend(df[df['date'] == article[0]].iloc[0]['tables'][article[1]+1]) response = prompter.prompt_main(query, context='\n'.join(article_content), prompt_name="default_with_context", temperature=0.3) return response # return the response.
Exécutez la fonction, avec la requête du premier bloc de code, et vous devriez voir le résultat suivant :
Microsoft has poured billions of dollars into ChatGPT developer OpenAI. However, it's also placed a number of bets on other GenAI startups across computing, mapping, and gaming.
Vous pouvez également voir dans la section « preuves » de l'objet de réponse qu'en effet les deux articles de l'archive CB Insights qui mentionnent Microsoft et OpenAI ont été récupérés, et que la réponse du LLM se base directement sur les preuves.
Notez que parce que nous effectuons une reconnaissance d'entité explicite, le processus de récupération est extrêmement transparent et déboguable. Si jamais la question se pose de savoir pourquoi le modèle a récupéré ces informations spécifiques du corpus, il suffit d'une simple déclaration d'impression pour voir que le modèle a choisi l'article parce que la requête mentionne « Microsoft » et « OpenAI », et le deux sections de newsletter récupérées sont les seules sections qui mentionnent les deux entités.
De plus, par rapport à la recherche vectorielle basée sur l'intégration, la méthode de recherche NER fournit des réponses beaucoup plus précises. Lors de mes tests, les articles sélectionnés figuraient dans le top 10 des articles les plus pertinents classés par l'algorithme ada d'OpenAI, mais n'étaient pas ceux identifiés comme étant les plus proches de la question posée. Par conséquent, il est possible qu’une application utilisant la recherche intégrée n’ait pas du tout répondu correctement à la question, et le manque de débogage ne ferait que contribuer à la confusion.
Et avec cela, nous avons construit une application de questions-réponses utilisant les recherches NER, améliorant ainsi la qualité du pipeline !
Aujourd'hui, nous avons créé une application utilisant l'appel de fonction, une nouvelle fonctionnalité intéressante du LLM. Les modèles d’appel de fonctions miniaturisés et exécutables localement constituent un développement révolutionnaire qui ouvre la voie à une nouvelle classe d’applications d’IA, et nous n’assistons qu’à la première itération de ces technologies. Il sera passionnant de voir quelles applications les développeurs créeront avec ces technologies dans les mois à venir.
Si vous avez une idée dans le domaine de l'IA que vous souhaitez voir mise en œuvre ou si vous souhaitez simplement discuter de technologie, n'hésitez pas à nous contacter sur Github ou LinkedIn .
Si vous souhaitez en savoir plus sur LLMWare, la société derrière SLIM et DRAGON, vous pouvez les trouver sur HugginFace ou Github .