Im Jahr 2024 wird es keinen Mangel an LLM-basierten Anwendungen geben. Große Technologieunternehmen wie Microsoft und Google treiben immer leistungsfähigere Versionen ihrer Flaggschiffmodelle ChatGPT und Gemini voran, und Spezialanbieter wie Anthropic treiben konkurrierende Angebote mit zusätzlichen Integrationen voran. In der Welt des angewandten LLM experimentieren Unternehmen und sogar Regierungen mit Chat-Anwendungen für verschiedene Kontexte.
Trotz der enormen unternehmerischen Energie, die in LLMs gesteckt wird, sind die meisten hochkarätigen Anwendungen immer noch durch ihren Fokus auf chatähnliche Schnittstellen eingeschränkt, die für Menschen lesbaren Text aufnehmen und zurückgeben. Das ist verständlich – schließlich ist eine der aufregendsten Entwicklungen von LLMs die Fähigkeit, menschliche Sprache zu verstehen und zu generieren und so eine dialogorientierte Benutzeroberfläche zu ermöglichen. Allerdings übersehen Chat-Schnittstellen einen weiteren sehr wichtigen Anwendungsfall für LLMs – die Textverarbeitung als Zwischenschritt in einer größeren Datenpipeline.
Heute werden wir diesen Anwendungsfall untersuchen und sehen, wie LLMs als Teil einer Datenpipeline und nicht nur als Generator natürlicher Sprache nützlich sein können.
Um LLMs als Teil einer Datenpipeline zu verwenden, müssen wir das Ausgabeformat des LLM ändern – anstatt Absätze zu generieren, die von Menschen gelesen werden können, muss das Modell etwas generieren, das Computer lesen können. Normalerweise bedeutet dies eine strukturierte Ausgabe in einem Datenformat wie JSON oder Anweisungen in einer Programmiersprache wie Python oder SQL. Diese Ausgabeformate sind viel weniger nachsichtig als natürliche Sprache, da ein fehlendes Anführungszeichen oder eine fehlende Klammer die gesamte Pipeline zum Absturz bringen kann. Daher müssen wir uns auf spezielle Methoden und Funktionen verlassen, die zur Unterstützung dieses Anwendungsfalls entwickelt wurden. Diese Funktionen werden zusammenfassend als Funktionsaufrufe bezeichnet, da die Ausgabe dazu neigt, Funktionen aufzurufen oder in Funktionsaufrufen verbraucht zu werden.
Bevor wir uns jedoch mit diesen Methoden befassen, wollen wir zunächst etwas genauer untersuchen, warum Funktionsaufruffunktionen überhaupt entwickelt wurden.
Verbindung zu externen Diensten herstellen
Der ursprüngliche und einfachste Anwendungsfall für Funktionsaufrufe ist die Verbindung mit externen Diensten. Als OpenAI GPT-4 ursprünglich veröffentlichte, aktualisierte es auch die API mit einer Funktion, die es dem Benutzer ermöglichte, dem Modell eine Reihe von Funktionen im Python-Stil bereitzustellen, die das Modell aufrufen konnte, um seine Ziele zu erreichen. Dem Modell könnte beispielsweise mitgeteilt werden, dass es eine externe Funktion aufrufen kann, um den Preis eines komplexen Wertpapiers zu berechnen. Anhand dieser Informationen wäre das Modell in der Lage, Code zu schreiben, der den Wert eines Portfolios aus diesen Wertpapieren berechnet, ohne dass spezielle Kenntnisse über die Preisgestaltung von Wertpapieren erforderlich sind.
Der Aufruf von Funktionen im Python-Stil ist nur die Spitze des Eisbergs. Nachdem sich die Bedeutung des Funktionsaufrufs auf dem Markt gezeigt hatte, begannen OpenAI und andere LLM-Anbieter, andere Ausgabeformate wie JSON oder SQL zu unterstützen. Wichtig war, dass diese Modelle maschinenlesbare Ausgaben lieferten, die von anderen Prozessen zuverlässig gelesen werden konnten.
Aufmerksame Leser werden vielleicht erkennen, dass wir in früheren Artikeln etwas Ähnliches getan haben, indem wir LLM zum Generieren von Trainingsdaten , SQL oder JSON verwendet haben. In diesen Artikeln haben wir dies mithilfe von Prompt Engineering und Ausgabeprüfung erreicht. Da Funktionsaufrufe nun jedoch eine weithin unterstützte Funktion sind, können wir dies einfacher erreichen, indem wir uns auf diese Funktionen auf Modellebene verlassen.
Verkettung von LLMs
Funktionsaufrufe eröffneten neue Möglichkeiten für Multi-LLM-Anwendungen, und bald experimentierten Entwickler mit der Verkettung von LLMs, um anspruchsvolle Systeme zu erstellen. Einige dieser Systeme wurden als Agenten bekannt, die selbstständig das Web durchsuchen, neue Daten sammeln und ein anderes LLM mit den neuen Informationen anrufen konnten. Diese Pipelines verfügen über ein überraschend hohes Maß an Autonomie und sind in der Lage, anspruchsvolle Probleme mit sehr wenig Eingaben zu lösen. Allerdings gibt es immer noch Einschränkungen, wie z. B. API-Kosten und Verhaltensschutzmaßnahmen, die eine breite Akzeptanz von Agenten verhindern.
Verwendung von LLM als Eingabe- und Zwischenverarbeitung
Ein weiterer Anwendungsfall für funktionsaufrufende LLMs ist die Eingabe- und Zwischendatenverarbeitung. LLMs können verwendet werden, um unstrukturierte Eingaben in strukturierte Daten zu analysieren, die für die Weiterverarbeitung verwendet werden können. Während viele dieser Aufgaben tendenziell „traditionellen“ NLP-Technologien vorbehalten sind, bedeutet die Flexibilität transformatorbasierter Modelle, dass ein speziell trainiertes Modell diese Aufgaben viel besser bewältigen kann als andere NLP-Technologien. Aus diesem Grund versuchen viele Entwickler, diese speziellen Modelle in ihren Datenpipelines zu nutzen.
Nachdem wir nun mit der Theorie hinter Funktionsaufrufen vertraut sind, schauen wir uns die Anwendung an, die wir heute erstellen werden.
In einem früheren Artikel habe ich eine einfache RAG-Anwendung erstellt, um Fragen in natürlicher Sprache zum beliebten Newsletter von CB Insights zu beantworten. Im heutigen Artikel werden wir eine ähnliche Frage-Antwort-Anwendung erstellen, aber anstatt uns auf die Einbettung von Suche und GPT3.5 zu verlassen, werden wir die Entitätserkennung als primäre Indexierungsmethode verwenden. Darüber hinaus werden wir DRAGON als Zusammenfassungs-Engine verwenden, sodass wir die gesamte Anwendung auf unserem Laptop ausführen können, ohne dass Cloud-Dienste erforderlich sind.
Warum die Entitätserkennung verwenden?
Bevor wir uns mit der Implementierung befassen, wollen wir zunächst die Vorteile der Verwendung von NER als Abruftechnologie anstelle der eingebetteten Suche untersuchen. Während wir in der Produktion jede Technik entsprechend den Anforderungen der jeweiligen Situation verwenden möchten, bietet NER mehrere Vorteile gegenüber einem System, das auf der eingebetteten Suche basiert.
Debugbarkeit: Da die Entitätserkennung eine leicht überprüfbare Aufgabe ist, ist die gesamte Pipeline viel besser debuggbar. Es lässt sich leicht überprüfen, ob das Modell alle Entitäten korrekt identifiziert, und es ist einfach, einen auf diesen Entitäten basierenden Matching-Algorithmus zu erstellen und zu verbessern. Im Vergleich dazu ist es viel schwieriger zu überprüfen, ob der Einbettungsalgorithmus Ähnlichkeiten und Unterschiede in Passagen richtig erkennt.
Flexibilität: Durch die Trennung von Erkennung und Filterung machen wir die Pipeline wesentlich flexibler als ein einbettungsbasierter Suchalgorithmus. Wir können zusätzliche Metadaten hinzufügen, Suchalgorithmen basierend auf dem Entitätstyp ändern und sogar Einbettungsalgorithmen zusätzlich zu den NER-basierten Suchergebnissen verwenden. Dies ermöglicht die Entwicklung wesentlich leistungsfähigerer Funktionen auf Basis von Technologiekombinationen.
Beispielsweise kann eine NER-basierte Pipeline eine entitätsbasierte Suche verwenden, um eine Reihe von Dokumenten einzugrenzen, und dann einen Einbettungsalgorithmus verwenden, um den Suchraum weiter einzugrenzen. Dadurch wird die Suche tendenziell viel schneller und effizienter.
Identifikationsleistung: Aufgrund der möglichen manuellen Steuerung eignen sich NER-Pipelines viel besser für bestimmte Such- und Abrufaufgaben. Einbettungssuchen basieren auf der Nähe von Passagen innerhalb der Trainingsdaten, wodurch die Wahrscheinlichkeit berechnet wird, dass zwei Dokumente aus demselben größeren Dokument stammen. In einigen Anwendungsfällen führt dies dazu, dass bei der Einbettungssuche wichtige Dokumente übersehen werden.
Nachdem wir nun die Vorteile der Verwendung von NER innerhalb einer RAG-Pipeline verstanden haben, werfen wir einen genaueren Blick auf die spezifischen Technologien, die wir in unserer Anwendung verwenden.
Anerkennung von LLM-Entitäten
Entity Recognition ist eine „traditionelle“ NLP-Technologie zum Extrahieren strukturierter Daten aus unstrukturierten Sprachdaten. Die extrahierten Daten können dann in der Weiterverarbeitung oder als Metadaten für die analysierte Passage verwendet werden.
In der Vergangenheit wurde dies mithilfe kleiner, speziell entwickelter Algorithmen für maschinelles Lernen erreicht, die zunächst die Wortarten markieren und dann in einem zweiten Durchgang feststellen, ob es sich bei den identifizierten Eigennamen um benannte Entitäten handelt.
Mit funktionsaufrufenden LLMs können wir dieselbe Aufgabe erfüllen, mit mehreren zusätzlichen Vorteilen.
Da die Transformer-Architektur die Sprachstruktur besser verstehen kann als kleinere NLP-Modelle, ist die Leistung wahrscheinlich robuster, beispielsweise in Fällen, in denen die Passage falsch formatiert ist.
Da LLMs mit den neuesten Trainingsdaten aktualisiert werden, bleibt das Entitätserkennungssystem wahrscheinlich aktueller als andere Open-Source-Entitätserkennungsmodelle.
Mithilfe von Prompt-Engineering-Techniken können zusätzliche Daten eingebettet und zusätzliche Anweisungen gegeben werden, was ein flexibleres Verhalten auch bei Standardmodellen ermöglicht.
DRAGON Wir haben Dragon in einem früheren Artikel behandelt, in dem wir seine beeindruckende Leistung bei der Zusammenfassung natürlichsprachlicher Daten hervorgehoben haben. Wir werden Dragon verwenden, um den letzten Schritt der Analyse durchzuführen, in dem wir alle Artikel zusammenfassen, die für die ausgewählten Entitäten relevant sind.
SLIMs SLIMs sind eine neue Familie miniaturisierter, lokal ausführbarer Modelle von LLMWare – es ist kein Geheimnis, dass ich ein Fan ihrer Miniaturisierungsarbeit bin – die auf Funktionsaufrufe spezialisiert ist. Diese Modelle wurden speziell darauf abgestimmt, Ausgaben zu generieren, die von Maschinen interpretiert werden können, sodass Benutzer von den jüngsten Entwicklungen in der Funktionsaufrufarchitektur profitieren können, ohne auf externe APIs angewiesen zu sein.
Heute verwenden wir das SLIMs-NER-Modell, das die Named Entity Recognition für die Newsletter-Artikel durchführt. Neben NER gibt es auch SLIMs-Modelle für Stimmungsanalyse, SQL-Generierung und mehrstufige Agenten.
Nachdem wir die Technologie verstanden haben, implementieren wir die Anwendung!
Beginnen wir mit dem Herunterladen der CB Insights-Artikel. Importieren wir die Abhängigkeiten:
import requests from bs4 import BeautifulSoup import os import pandas as pd import json import re
Und jetzt der Code zum Download des Newsletter-Archivs:
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]
Nachdem wir nun das Newsletter-Archiv heruntergeladen haben, verarbeiten wir es im JSON-Format
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)
Jetzt sind wir am selben Punkt wie im vorherigen Artikel. Anstatt jedoch direkt mit der RAG-Konstruktion fortzufahren und Einbettungen zu erstellen, führen wir stattdessen einen Entitätserkennungsschritt aus.
Importieren wir zunächst die Abhängigkeiten für die Ausführung von SLIMs, einem neuen Satz von Modellen von LLMWare, der es uns ermöglicht, die Entitätserkennung lokal auf unserem Computer durchzuführen:
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
Jetzt können wir die Erkennung benannter Entitäten für alle Artikel ausführen:
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))
Es kann einige Minuten dauern, bis die NER-Pipeline fertig ist, aber das ist alles, was Sie brauchen, um Entitäten mithilfe eines hochmodernen miniaturisierten LLM zu erkennen.
Sie können das date_entities-Wörterbuch überprüfen, indem Sie einige Testelemente ausdrucken. Zum Beispiel der Code:
date_entities[list(date_entities.keys())[0]]
Sollte die folgende Ausgabe erzeugen:
{0: {'people': ['Yahoo!'], 'place': [], 'company': ['Databricks', 'MosaicML'], 'misc': []}, 1: {'people': [], 'place': ['New York'], 'company': ['CB Insights'], 'misc': []}}
Hier werden alle verschiedenen Entitäten angezeigt, die vom SLIMs-Modell erkannt wurden.
Nachdem die Entitäten nun erkannt wurden, erstellen wir einen Frage-Antwort-Workflow, der die Leistungsfähigkeit dieser Technik demonstriert. Für unser Beispiel verwenden wir die Testfrage: Welche Rolle spielt OpenAI in der KI-Strategie von Microsoft?
Beginnen wir mit dem Importieren der richtigen Pakete zum Ausführen von 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)
Jetzt können wir die Funktion erstellen, die die Frage mithilfe der Entitätserkennung beantwortet. Um unsere NER-Daten zu nutzen, möchten wir den folgenden Workflow implementieren:
So sieht der Workflow in Codeform aus:
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.
Führen Sie die Funktion mit der Abfrage aus dem ersten Codeblock aus und Sie sollten das folgende Ergebnis sehen:
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.
Sie können auch im Abschnitt „Beweise“ des Antwortobjekts sehen, dass tatsächlich die beiden Artikel aus dem CB Insights-Archiv, in denen Microsoft und OpenAI erwähnt werden, abgerufen wurden und dass die Antwort des LLM direkt auf den Beweisen basiert.
Beachten Sie, dass der Abrufprozess äußerst transparent und debuggbar ist, da wir eine explizite Entitätserkennung durchführen. Sollte sich jemals die Frage stellen, warum das Modell diese spezifischen Informationen aus dem Korpus abgerufen hat, genügt eine einfache Druckanweisung, um zu erkennen, dass das Modell den Artikel ausgewählt hat, weil in der Abfrage „Microsoft“ und „OpenAI“ erwähnt werden Zwei abgerufene Newsletter-Abschnitte sind die einzigen Abschnitte, in denen beide Entitäten erwähnt werden.
Darüber hinaus liefert die NER-Suchmethode im Vergleich zur einbettungsbasierten Vektorsuche wesentlich präzisere Antworten. In meinen Tests befanden sich die ausgewählten Artikel in der Rangliste des ADA-Algorithmus von OpenAI in den Top 10 der relevantesten Artikel, es wurde jedoch nicht festgestellt, dass sie der jeweiligen Frage am nächsten kommen. Daher ist es möglich, dass eine Anwendung, die die eingebettete Suche verwendet, die Frage überhaupt nicht richtig beantwortet hat und die mangelnde Debugbarkeit nur zur Verwirrung beitragen würde.
Und damit haben wir eine Frage-Antwort-Anwendung mithilfe von NER-Suchen erstellt und dabei die Qualität der Pipeline verbessert!
Heute haben wir eine Anwendung mithilfe von Funktionsaufrufen erstellt, einer aufregenden neuen LLM-Funktion. Miniaturisierte, lokal ausführbare Funktionsaufrufmodelle sind eine revolutionäre Entwicklung, die eine neue Klasse von KI-Anwendungen erschließt, und wir sehen erst die erste Iteration dieser Technologien. Es wird spannend sein zu sehen, welche Anwendungsentwickler mit diesen Technologien in den kommenden Monaten erstellen werden.
Wenn Sie eine Idee im KI-Bereich haben, die Sie umgesetzt sehen möchten, oder einfach nur über Technologie chatten möchten, zögern Sie bitte nicht, uns auf Github oder LinkedIn zu kontaktieren.
Wenn Sie mehr über LLMWare, das Unternehmen hinter SLIMs und DRAGON, erfahren möchten, finden Sie diese auf HugginFace oder Github .