Veröffentlicht am

Chatbot-Antworten optimieren: Chunking, Fine-Tuning und hybrides Retrieval für RAG

Chatbot optimieren

Chatbots sollen Fragen wahrheitsgetreu beantworten. Spezialisierte Chatbots basieren auf Retrieval Augmented Generation (RAG). Dazu beziehen sie Kontext aus einer Vektordatenbank. Befassen wir uns näher mit dem Retrieval in Vektordatenbanken. 

Vektordatenbanken ermöglichen eine semantische Suche – Ergebnis der Suche sind also Texte, die sinngemäß in Zusammenhang mit der in natürlicher Sprache verfassten Benutzerfrage stehen.

Vektordatenbanken vs. Klassische Suchmaschinen

Im Gegensatz zu Vektordatenbanken erfolgt die Suche in einer klassischen Suchmaschine mit Stichworten und nicht mit ganzen Sätzen.
Die Benutzer erwarten als Antwort eine Trefferliste von Dokumenten, in denen die Stichworte enthalten sind.

Gut getunte Suchmaschinen…

  • finden zielgenau passende Dokumente aufgrund der Stichworte in der User-Query,
  • berücksichtigen auch Dokumente, die Begriffe enthalten, die semantisch mit den Suchbegriffen verwandt sind,
    behandelt Deklination und Konjugation, und findet auch diejenigen Texte, in denen die Suchbegriffe in morphologisch veränderter Form stehen.

Beispiel: Der User sucht nach Haus.
Die Suchmaschine findet auch Dokumente in denen Begriffe stehen wie: Häuser, Gebäude, Hütte etc.

Optimierte Suchmaschinen können auch …

  • mit Tippfehlern umgehen,
  • Umlaute behandeln,
  • sie können ganze Phrasen finden,
  • verschiedene natürliche Sprachen unterscheiden.
  • Sie können das Suchergebnis analysieren – wer kennt sie nicht, diese praktischen Aufschlüsselungen nach Sachgebieten in spezialisierten Suchmaschinen – die so genannte Facettierung.

Die besten Suchmaschinen bilden auch implizite Knowledge-Graphen, um inhaltlich verwandte Dokumente zur Lektüre vorzuschlagen.

Gut getunte Suchmaschinen sind Retrieval-Meister – die Treffer enthalten immer Begriffe oder Konzepte, die mit den Suchbegriffen inhaltlich verwandt sind.

Ranking und Dokumentationseinheiten

Die Dokumentationseinheit (DE) bildet die semantische Grundlage jeder klassischen Suchmaschine.
Jeder Treffer in der Trefferliste ist eine Dokumentationseinheit. Beim Design einer Suchmaschine ist die Definition der DE ein wichtiger Aspekt.

Wir sind uns gewohnt, dass die Suchmaschine das ‘beste’ Dokument zuoberst in der Trefferliste liefert. Das Verfahren heißt ‘Ranking’:

  1. Zuerst werden Dokumente gesucht, die in Bezug auf die Suchfrage relevant sind.
  2. Dann wird jedem Dokument ein Score zugeordnet. Je höher der Score, umso relevanter ist das Dokument in Bezug auf die Suchfrage.
  3. Okapi BM25 ist ein gängiges Scoring-Verfahren – ein statistisches Verfahren, das mit Worthäufigkeiten arbeitet.
  4. Danach werden die Dokumente absteigend nach Score sortiert und dem User als Ergebnis präsentiert.

Vektordatenbanken im RAG

Vektordatenbanken funktionieren anders als klassische Suchmaschinen und sie haben ein anderes Ziel.

  1. Die Userfrage sind nicht Stichworte sondern ganze Sätze.
  2. Die Userfrage wird in einen Vektor umgewandelt.
  3. Danach wird mit dem Vektor in der Vektordatenbank nach benachbarten Vektoren gesucht, die semantisch ähnlicheDokumente repräsentieren. Dabei spiel die Wahl der Abstandsmetrik eine wichtige Rolle.
  4. Diese Vektoren werden sortiert nach Distanz aufsteigend, also der nächste Vektor führt die Liste an und dieser repräsentiert, das Dokument mit der höchsten semantischen Ähnlichkeit zur Suchfrage.
    Jetzt haben die Vektoren ihren Dienst getan. Die Trefferliste sind nicht Vektoren, sondern die Texte, die durch die jeweiligen Vektoren repräsentiert werden.

Diese Texte werden zum Kontext im RAG-Prozess.
Das LLM (Large Language Model) ist für  Generierung der definitiven Antwort auf die Userfrage auf möglichst kurze und präzise Kontexte angewiesen. Der Artikel Retrieval Augmented Generation – Proof of Concept befasst sich mit der Prompt Augmentation – dabei wird der Prompt durch den Kontext angereichert.

Chunks als Grundlage für Vektordatenbanken

Soll der Kontext zur Textgenerierung präzise sein, dann werden in der Vektordatenbank nicht die Vektoren ganzer Dokumente, sondern die Vektoren kleinerer Stücke hinterlegt. Diese Textstücke heißen Chunks.

Die optimale Chunking-Strategie hängt von verschiedenen Faktoren ab, wie der Aufgabe des Chatbots, den Dokumenten und der Größe des Prompt-Fensters des Sprachmodells..

Es gibt keine goldene Regel zur Wahl der Chunking-Strategie. Man wird verschiedene Strategien ausprobieren müssen, um zur besten Chunk-Größe und Chunk-Strategie zu finden.

Chunking-Strategien im Überblick

Zeichenbasiertes Chunking:

Man wählt eine Anzahl Zeichen, z.B. 500 Zeichen pro Chunk.
Idealerweise wird man dabei nicht mitten im Satz schneiden.
Oft wird auch eine Überlappung gewählt – ein Chunk überlappt mit dem folgenden Chunk mit beispielsweise 30 Zeichen.

Tokenbasiertes Chunking:

Statt Zeichen wählt man die Anzahl Token.

Satzbasiertes Chunking:

Statt Zeichen wählt man Sätze und fasst immer eine gewisse Anzahl Sätze zu einem Chunk zusammen

Absatzbasiertes Chunking:

Einzelne Absätze oder mehrere Absätze werden zu einem Chunk zusammengefasst.

Semantisches Chunking:

Es wird versucht, sinngemäß zusammengehörende Sätze zu einem Chunk zusammenzufassen.

Hybrides Chunking:

Verschiedene Strategien werden kombiniert, um die ideale ‘Chunkingstragegie’ zu finden.

Embedding-Modell fine-tunen für besseres Vektorretrieval

Untersucht man die Ergebnisse der Vektorsuche, dann wundert man sich oft, ob und inwiefern diese überhaupt im Zusammenhang mit der Suchfrage stehen sollen.
Der Einfluss des verwendeten Embeddingmodell ist oft so dominant, dass die Ergebnisse auch mit dem besten Chunking-Verfahren nicht nachvollziehbar sind.
Man wird nicht umhin kommen, verschiedene Embedding Modelle auszuprobieren und das beste durch Fine Tuning zu verbessern.

Vektordatenbanken und hybride Retrieval-Verfahren

Manche Vektordatenbanken bieten auch hybride Retrieval-Verfahren an. Dabei wird die Vektorsuche ergänzt mit einer klassischen Suche.
Schaut man den jeweiligen Source-Code genauer an, dann stellt man folgendes fest:

  • Das Retrieval beruht auf einem ganz naiven Algorithmus, der Strings beim Leerzeichen in ‘Wörter’ teilt, und String-Matching mit den einzelnen Wörtern in der Suchfrage vornimmt.
  • Diese Art der Suche ist überhaupt nicht optimiert . Es erstaunt nicht weiter, dass ein derart naives Verfahren keine befriedigenden Ergebnisse liefert.
  • Das Ranking wird mit dem BM25 Algorithmus durchgeführt, ebenfalls ohne weitere Optimierung.

Da ist noch viel Luft nach oben!
Das klassische Retrieval-Verfahren könnte gerade bei der Suche nach Fakten glänzen.

Die wenigsten Vektordatenbanken unterstützen eine ausgereifte Kombination beider Retrieval-Verfahren.
Lucene-Basierte Suchmaschinen wie Apache Solr und das kommerzielle ElasticSearch bieten beides von Haus aus. Eine ausgereifte Enterprise-Search bildet einen idealen Ausgangspunkt für eine hybride Vektorsuche.

Fazit:

  • Vektordatenbanken ermöglichen semantische Suche und liefern relevante Textpassagen für Chatbot-Antworten.
  • Die Wahl der Chunking-Strategie beeinflusst die Qualität der Antworten in RAG-basierten Chatbots.
  • Die Wahl des Embedding-Modells und gezieltes Fine Tuning beeinflussen das Retrieval-Ergebnis.
  • Die Wahl der Abstandsmetrik beeinflusst das Ergebnis des Retrievals.
  • Hybride Verfahren, die Vektor- und Keyword-Suche kombinieren, sind vielversprechend, aber oft noch nicht ausgereift.
  • Vektordatenbanken werden klassische Suchmaschinen nicht ersetzen sondern ergänzen.
  • Webinar:

    So baust du LLMs in deine Anwendungen ein

    Erfahre in diesem exklusiven Webinar, wie du LLMs in deine Anwendungen einbaust.

    Mehr Infos zum Webinar findest du in der ausführlichen Beschreibung.

    Das kostenlose Webinar findet statt am Montag, 8. Juli um 13:00-13:45 MEZ via ZOOM.

    Trage dich in die Liste ein und du erhältst den Zugangslink und später den Link zur Aufzeichnung.

  • Chatbot als Lernassistent
  • Prompt Engineering Personas und Wiederholungen
  • AI-Engineering-Fachglossar
  • EBook Tutorial: Cluster aus virtuellen Maschinen
  • Ebook: Apache ZooKeeper
  • Ebook: Realtime Streaming Pipelines
  • LSM-Trees: Log Structured Merge Trees
  • Aufbau einer Enterprise Search
  • Zeit Stream Analytics
  • B-Tree-Index in Datenbanken
  • Ordering Guarantee in Apache Kafka
  • CAP Theorem
  • MapReduce Funktionale Programmierung
  • Konzepte des HDFS
  • Optimistisches Concurrency Control
Veröffentlicht am

Retrieval Augmented Generation – Proof of Concept

Proof-of-Concept-für-RAG

Das Wissen von Large Language Models (LLM) reicht nicht über die Daten hinaus, auf denen sie trainiert wurden. Mit Retrieval Augmented Generation (RAG) können wir LLMs für einen erweiterten Kontext einsetzen. Das ist ganz besonders nützlich, wenn wir die Power der großen Sprachmodelle in unsere Apps einbauen wollen, und zwar auch dann, wenn das verwendete Modell den Kontext unserer App ursprünglich nicht versteht.

Beispiel: Eine App soll Sachbearbeiter dabei unterstützen, Fakten zu sammeln und zu bewerten. Dazu darf weder ChatGPT noch Gemini oder anderer Cloud-Service eingesetzt werden, weil die Daten vertraulich sind und das Haus nicht verlassen dürfen.

Wir sind also auf ein Open-Source-Sprachmodell angewiesen, das aber den spezifischen Kontext unseres Unternehmens nicht versteht.

Der Artikel zeigt mit einem kleinen Experiment, dass auch die großen Modelle vor Irrtum nicht gefeit sind. Als Proof of Concept sehen wir Beispiel von drei Open Source Modellen, dass RAG Abhilfe schaffen kann.

Halluzination in LLMs – ChatGPT und Gemini

Die großen Modelle werden immer besser und damit für uns als Enduser immer zuverläßiger. Schade nur, können wir sie nicht unternehmensintern nutzen, gerade dann nicht, wenn keine vertraulichen Informationen in die Cloud geschickt werden dürfen. Doch auch die großen Modelle können sich irren.

Eine ganz einfache Frage zeigt die Grenzen:

Wann wurde der Bärengraben in Bern ursprünglich gebaut?

ChatGPT und Gemini – die Grenzen

Fragen wir zuerst OpenAI’s Flaggschiff ChatGPT 4o:

OpenAI 4o Hallunzination

Das tönt überzeugend, kann aber nicht sein: Wie in Bern jedes Kind weiß, hat Napoleon seinerzeit die Bären entführt und der kam vor 1857 vorbei. Auch die älteren OpenAI Modelle – 4 und 3.5 – wissen es nicht besser. 4o ist diesbezüglich also nicht gescheiter geworden.

Stellen wir wir Google’s Gemini dieselbe Frage:

Gemini-Hallunzination

Gemini meint 1441 sei das richtige Jahr und untermauert gleich noch mit Fakten. Schön bei Gemini: wir erhalten auch einen Link präsentiert. Folgen wir diesem, dann erfahren wir auf den ersten Blick und aus erster Hand, nämlich den Bärengraben-Betreibern: 1513 wurden die Bären als Kriegsbeute heimgebracht und im Stadtgraben gehalten.

Interessant, dass Gemini die Links nicht konsultiert, die es uns selbst präsentiert.

Betrachten wir als nächstes drei Open-Source-Modelle, die wir vielleicht in unsere Unternehmens-Apps einbauen wollen.

Open-Source-Modelle und ihre Grenzen

Wir betrachten drei Modelle: Llama3, Mistral und Phi3. Alle drei können wir herunterladen und lokal auf dem Laptop laufen lassen.

Diese Modelle sind interessant, weil wir die Daten nicht aus der Hand geben müssen und dennoch die Power von generativen Modellen nutzen können. Zusammen mit RAG, sogar mit Erfolg. Doch erkunden wir zuerst die Grenzen:

Llama3 und seine Grenzen

Llama3 stammt aus dem Hause Meta und wird freundlicherweise Open Source zur Verfügung gestellt. Es sei heute das fähigste offen verfügbare Modell.

Wir verwenden das Meta-Llama-3-8B Modell mit Release Datum 18. April 2024.

Llama3-Hallunzination

Pure Erfindung: da soll ein Tunnel von 1.2km Länge unter der Stadt Bern verlaufen und es gäbe schon Spuren davon aus der Römerzeit. Llama3 antwortet auf die in deutscher Sprache gestellte Frage mit Halluzinationen in englischer Sprache.

Mistral und die Grenzen

Wir verwenden das 7B Modell Version 0.3 von Mistral. Mistral AI ist ein französisches Unternehmen, das sich auf das Training vertrauenswürdiger KI-Modelle spezialisiert hat. Stellen wir auch diesem Modell die Bärengraben-Frage:

Mistral-Beispiel

Et voilà: Anders als die Meta-Ingenieure, haben die französischen Spezialisten bei Mistral AI auch Daten zum Berner Bärengraben im Training verwendet. Das Modell antwortet korrekt und in deutscher Sprache. Das eine Experiment macht keine Aussage über die allgmeine Zuverlässigkeit von Mistral – dazu würden wir weit mehr Beispiele verwenden.

Bevor wir zu RAG übergehen, untersuchen wir noch ein drittes Modell:

Phi3 und seine Grenzen

Phi3 ist das kleinste der drei untersuchten Open-Source-Modelle. Wir verwenden das 3.8B-Mini-Modell – es stammt  von Microsoft.

Phi3-Hallunzination

Sehr kreativ! Ich messe auf der Karte nach und finde heraus, dass die kürzeste Distanz zwischen Bern und Limmat in Luftlinie mehr als 100km beträgt. Und da soll bereits im 14. Jahrhundert ein Tunnel errichtet worden sein, der Bärengraben heißen soll? Microsoft hat sich beim Training seines Phi3-Modells offensichtlich nicht mit der Berner Stadtgeschichte abgegeben.

Retrieval Augmented Generation in a Nutshell

Mit RAG können wir den Wissenslücken der Modelle Abhilfe verschaffen. Untersuchen wir RAG an Phi3 – einerseits weil es das kleinste Modell ist und andererseits weil es – gleich wie das größere Llama3 – so kreativ geantwortet hat.

Die Graphik verdeutlicht die Idee von RAG:

RAG in a Nutshell

Der Prompt des Users wird nicht direkt ans generative Modell geschickt. Vielmehr wird er zu einem Vorverarbeitungsschritt herangezogen:

R = Retrieval: Mit Hilfe des User-Prompts wird nach kontextspezifischem Wissen gesucht. Gerne werden heute dazu Vektordatenbanken und Embedding-Modelle herangezogen. Gut geeignet ist auch klassische Key-Word-Suche oder auch eine hybride Suche, die die klassische Suche mit der Vektorsuche vereint.

A = Augmentation: Die Ergebnisse des Retrievals also der Suche, werden herangezogen, um den User-Prompt mit Kontext anzureichern. So ‘lernt’ das generative Modell, mit ihm bisher unbekannten Fakten umzugehen.

G = Generation: Den verbesserten Prompt präsentieren wir dem generativen Modell. Mit Hilfe des zusätzlichen Kontext sollte es die User-Frage korrekt beantworten können.

RAG funktioniert!

Natürlich reicht ein einziger Prompt nicht aus, um sicher zu sein, ob unser Modell der Wahl funktioniert. Mistral halluziniert bei anderen Fragen, bei denen Llama3 korrekt antwortet. Phi3 Mini als kleinstes der betrachteten Modelle, müssen wir noch besser untersuchen.

Bei unserem Beispiel haben auch die großen Modelle von OpenAI und Google versagt. RAG verbessert selbst das kleinste untersuchte Modell.

Neben der Wahl des Modells, dem Austesten des Prompts spielt das Retrieval eine zentrale Rolle bei RAG – je besser der Kontext desto besser das RAG.

RAG – Prompt Augmentation

In unserem Experiment zeigen wir den Effekt von RAG.

Das Retrieval erledigen wir von Hand: Wir suchen den geeigneten Kontext. Gemini hat uns ja mit einem Link über den Bärengraben in Bern versorgt. Klicken wir auf der Seite etwas weiter, dann finden wir eine schöne grafische Darstellung der historischen Entwicklung des Bärengrabens. Dort kopieren wir den Abschnitt zur Schaffung des Bärengrabens und verwenden diesen Chunk, so der Fachbegriff, um den Prompt anzureichern.

Genau so würde der zum User-Prompt passende Kontext automatisch in einer LLM-gestützten App gesucht und gefunden.

Jetzt reichern wir den Prompt an (augment the prompt) – der Screenshot zeigt das Ergebnis mit dem Phi3-Modell:

RAG-Prompt
  1. Der ursprüngliche Prompt des Users wird angereichert mit
  2. einer Anweisung, was zu tun ist und
  3. dem Kontext aus dem Retrieval-Schritt.
  4. Damit antworte das generative Modell korrekt.

Der Beweis ist erbracht – selbst das kleinste Modell, das wir verwendet haben, antwortet korrekt dank RAG.

Das Prompt-Pattern sehen wir in Schritt 2 – Phi3 ist in der Lage, dieses zu verstehen und umzusetzen.

Interessant dabei ist die Anweisung mit ‘ich weiss nicht’ zu antworten. Testen wir das aus und ersetzen das Wort ‘Bärengraben’ durch ‘Rosengarten’ – ebenfalls ein sehenswerter Ort in Bern. Hier das Ergebnis ebenfalls mit Phi3:

RAG Prompt Test

Phi3 enttäuscht uns nicht und antwortet wie erwartet.

Übrigens auch alle anderen Modelle liefern korrekte Antwort – alle in deutscher Sprache. Auf Screenshots verzichten wir.

  • Webinar:

    So baust du LLMs in deine Anwendungen ein

    Erfahre in diesem exklusiven Webinar, wie du LLMs in deine Anwendungen einbaust.

    Mehr Infos zum Webinar findest du in der ausführlichen Beschreibung.

    Das kostenlose Webinar findet statt am Montag, 8. Juli um 13:00-13:45 MEZ via ZOOM.

    Trage dich in die Liste ein und du erhältst den Zugangslink und später den Link zur Aufzeichnung.

  • Chatbot als Lernassistent
  • Prompt Engineering Personas und Wiederholungen
  • AI-Engineering-Fachglossar
  • EBook Tutorial: Cluster aus virtuellen Maschinen
  • Ebook: Apache ZooKeeper
  • Ebook: Realtime Streaming Pipelines
  • LSM-Trees: Log Structured Merge Trees
  • Aufbau einer Enterprise Search
  • Zeit Stream Analytics
  • B-Tree-Index in Datenbanken
  • Ordering Guarantee in Apache Kafka
  • CAP Theorem
  • MapReduce Funktionale Programmierung
  • Konzepte des HDFS
  • Optimistisches Concurrency Control
Veröffentlicht am

LLM-LangChain-Texte-zusammenfassen

Zusammenfassungen mit LLM und LangChain

Automatisch Texte zusammenfassen, selbst in deutscher Sprache, dank der Large Language Models und APIs wie LangChain ist das einfacher denn je. Der Artikel zeigt ein konkretes Codebeispiel, das dank der Map-Reduce-Technik auch für lange Texte funktioniert.

Dienste wie ChatGPT und Gemini bietet zwar eine einfache Möglichkeit, Dokumente zusammenfassen zu lassen, jedoch stellt sich bei vertraulichen Inhalten die Frage nach Datenschutz und Datensicherheit. Es ist unklar, wie die Daten während der Übertragung und Verarbeitung geschützt werden und ob sie möglicherweise für andere Zwecke verwendet werden könnten.

Wir können ein Large Language Model auch in-house deployen und in unsere Anwendungsprogramme integrieren. Mit einer geeigneten Bibliothek wie LangChain gelingt auch das. Der Artikel zeigt wie’s geht am Beispiel der Textzusammenfassung.

Attention Windows beschränken die Möglichkeiten

Wollen wir mit einem API wie beispielsweise LangChain mit längeren Texten arbeiten, dann lernen wir sehr schnell die Beschränkungen kennen, die das Attention Window auferlegt. Einem LLM können wir nur beschränkt viele Token übergeben. Die Anzahl dieser Tokens, heißt Attention Window.

Ein Token ist ein Wort oder ein Subwort, je nach eingesetzter natürlicher Sprache und je nach Modell.

Beim Programmieren mit LLMs brauchen wir uns nicht so sehr um Tokens zu kümmern, wir treffen jedoch immer wieder auf sie. Spätestens bei der Abrechnung, wenn wir ein LLM as a Service verwenden, denn diese erfolgt aufgrund der Anzahl verarbeiteter Tokens.

Attention Windows sind nicht allzu groß – 2048 Tokens sind nicht unüblich.

Wollen wir einen längeren Text zusammenfassen, dann sind 2048 Wörter eher bescheiden. Für die deutsche Sprache mit ihren oft langen Wörtern, dürften 2048 Tokens deutlich weniger Wörter sein. Und doch gibt es eine Möglichkeit, trotz beschränktem Attention Window auch längere Texte automatisch zusammenzufassen.

Map Reduce für Textzusammenfassung

Das MapReduce Konzept kennen wir aus der Analyse großer Datenmengen und wir begegnen ihm hier wieder. Die Idee ist bestechend einfach:

  • Wir zerlegen den Text in kleinere Fragmente, oder Textbausteine.
  • Dann fassen wir die Bausteine zusammen – das entspricht dem Map-Schritt.
  • Danach vereinen wir einige der Zusammenfassungen zu einem neuen etwas größeren Textbaustein.
  • Und diesen fassen wir wieder zusammen.
  • Das wiederholen wir, bis wir eine einzige Zusammenfassung erhalten.

Die folgende Animation verdeutlicht das Prinzip:

Map Reduce Textzusammenfassung mit LangChain

LangChain und Textzusammenfassungen

LangChain bringt eine ganze Reihe nützlicher Funktionen mit, so auch mehrere Varianten, um Texte zusammenzufassen.

Imports

from langchain.chains.summarize import load_summarize_chain
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate

Falls wir nicht ein OpenAI-Modell verwenden, importieren wir die entsprechende LangChain-Klasse.

Konstanten und Keys

Die Variable file enthält den Pfad zum Dokument, das wir zusammenfassen wollen.

Das Beispiel funktioniert mit einen OpenAI-Modell. Dazu benötigen wir einen OpenAI API Key. Wer an anderes Modell nutzt, braucht einen anderen API-Key oder kommt möglicherweise auch ohne API-Key aus, beispielsweise, wenn das Modell in-house deployed ist.

Mit load_dotenv laden wir den OPENAI_API_KEY, den wir sicher im .env-Verzeichnis untergebracht haben.

file = 'test.pdf'
from dotenv import load_dotenv
load_dotenv()

Das Modell initialisieren

Die Klasse für das Modell haben wir ja schon importiert.

Jetzt initialisieren wir das Modell. Das Beispiel funktioniert mit OpenAI’s gpt-3.5-turbo-Modell. Dies ersetzen wir, falls wir ein anderes Modell verwenden wollen.

OpenAI-Modelle erlauben, mit Hilfe der Temperatur-Angabe zu steuern, wie viel Probabilität bei der Erzeugung der Zusammenfassung im Spiel sein darf. Mit 0.0 schalten wir die Probabilität weitgehend aus.

Wir verwenden max_tokens von 2048 – das Attention-Window soll also nicht größer als diese Anzahl Tokens sein.

openai_chat_model = ChatOpenAI(model='gpt-3.5-turbo',
  temperature=0.0,
  max_tokens=2048,
)

Text laden und splitten

Im folgenden Code-Snippet laden wir die PDF-Datei und zerhacken sie in Chunks (Textbausteine).

loader = PyPDFLoader(file)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
texts = text_splitter.split_documents(documents)

Die Zusammenfassung erstellen

Jetzt führen wir die Zusammenfassung durch und lassen das Ergebnis anzeigen.

Die Variable openai_chat_model ersetzen wir, falls wir ein anderes Modell einsetzen.

chain=load_summarize_chain(openai_chat_model,chain_type='map_reduce')
summary = chain.invoke(texts)['output_text']
summary

Die Erstellung der Zusammenfassung kann auch mehrere Minuten dauern, ganz abhängig von der Größe der PDF-Datei und derjenigen der Chunks, die wir gewählt haben.

Deutschsprachige Texte

Der Code ist verblüffend einfach und leistungsfähig. Doch es gibt einen Haken an der Geschichte – jedenfalls zum Zeitpunkt des Verfassens dieses Artikels: Die Zusammenfassung deutscher Texte ist english.

Um dem Abhilfe zu verschaffen, müssen wir die Prompts, die im Code von load_summarize_chain hinterlegt sind, ebenfalls in deutscher Sprache verfassen.

Das nächste Code-Snippet zeigt, wie es geht:

Deutschsprachige Prompts ergänzen

Bevor wir die Chain aufrufen, bauen wir zwei deutschsprachige Prompts ein, einen für Map und einen für Reduce. Diese geben wir beim Aufruf der Chain mit. Das Ergebnis ist eine Zusammenfassung in deutscher Sprache.

# Map Prompt Template
map_prompt_template = """Fasse den folgenden Textbaustein zusammen:

{text}

TEXTBAUSTEIN ZUSAMMENFASSUNG:"""

map_prompt = PromptTemplate(template=map_prompt_template, input_variables=["text"])

# Reduce Prompt Template
reduce_prompt_template = """Vereine diese Zusammenfassungen zu einer einzigen, präzisen Zusammenfassung:

{text}

PRÄZISE ZUSAMMENFASSUNG:"""

reduce_prompt = PromptTemplate(template=reduce_prompt_template, input_variables=["text"])

chain = load_summarize_chain(
    openai_chat_model,
    chain_type="map_reduce",
    map_prompt=map_prompt,
    combine_prompt=reduce_prompt# For LangChain versions < 0.0.147
    )

summary = chain.invoke(texts)['output_text']
summary

Stellschrauben

Die Code-Snippets zeigen die Mächtigkeit von LangChain an einem einfachen Beispiel. Das Snippet setzt das Modell gpt-3.5-turbo ein. Wir könnten dieses durch ein anderes Modell ersetzen, das trainiert oder fine-tuned wurde, um einerseits Texte zusammenzufassen und andererseits mit deutschsprachigen Texten zu arbeiten.

Wir könnten dieses Modell auch selbst hosten oder weiter auf unsere Bedürfnisse anpassen.

Wir können experimentieren mit der Chunk-Größe und der Überlappung und auch mit der Temperatur des Modells und damit die erzeugten Zusammenfassungen weiter beeinflussen.

Fazit

Jahrzehnte lang forschte man nach Möglichkeiten, Texte automatisch zusammenzufassen. Noch nie war das so einfach. Ob wirklich die relevantesten Inhalte in die Zusammenfassung aufgenommen werden, das müssen wir im Detail untersuchen.

  • Webinar:

    So baust du LLMs in deine Anwendungen ein

    Erfahre in diesem exklusiven Webinar, wie du LLMs in deine Anwendungen einbaust.

    Mehr Infos zum Webinar findest du in der ausführlichen Beschreibung.

    Das kostenlose Webinar findet statt am Montag, 8. Juli um 13:00-13:45 MEZ via ZOOM.

    Trage dich in die Liste ein und du erhältst den Zugangslink und später den Link zur Aufzeichnung.

  • Chatbot als Lernassistent
  • Prompt Engineering Personas und Wiederholungen
  • AI-Engineering-Fachglossar
  • EBook Tutorial: Cluster aus virtuellen Maschinen
  • Ebook: Apache ZooKeeper
  • Ebook: Realtime Streaming Pipelines
  • LSM-Trees: Log Structured Merge Trees
  • Aufbau einer Enterprise Search
  • Zeit Stream Analytics
  • B-Tree-Index in Datenbanken
  • Ordering Guarantee in Apache Kafka
  • CAP Theorem
  • MapReduce Funktionale Programmierung
  • Konzepte des HDFS
  • Optimistisches Concurrency Control
Veröffentlicht am

Chain-of-Though-Prompt-Pattern

Chain-of-Thought Prompt Pattern

Chain of Thought Prompts (CoT) sind ein einfaches Hilfsmittel, um einen Einblick in die ‘Gedankengänge’ des Modells zu erhalten.

Chain of Thought ist eines von vielen wichtigen Prompt Patterns – andere Beispiele sind In-Context-Learning und Persona-Pattern.

Ein Modell ‘weiss’ ja nicht wirklich und ‘Gedankengänge’ hat es schon gar nicht. Wir verwenden die Ausdrücke dennoch, weil wir keine besseren haben. Also:

Was sind Chain of Thought Prompts und warum sind sie wichtig?

Einfach ausgedrückt, Chain of Thought Prompts (CoT) sind eine Methode, um KI-Modelle dazu zu bringen, ihre Entscheidungsprozesse in klaren, nachvollziehbaren Schritten darzustellen.

Anstatt direkt eine Antwort zu geben, führt die KI durch eine Kette von Überlegungen, die zu dieser Antwort führen.

Das ist besonders nützlich in komplexen Situationen, in denen der Entscheidungsweg entscheidend ist.

Die Idee hinter Chain of Thought Prompts ist es, die Transparenz und Nachvollziehbarkeit von KI-Systemen zu erhöhen. Dies hat mehrere Vorteile:

  • Erklärung und Vertrauen: Wenn eine KI ihre Schritte offenlegt, wird es einfacher, ihre Entscheidungen zu verstehen und zu vertrauen.
  • Fehlererkennung: Ein klarer Gedankengang hilft, mögliche Fehler im Prozess zu identifizieren und durch verbesserte Prompts zu korrigieren.
  • Lernmöglichkeit: Für Entwickler und Nutzer ist es lehrreich, zu sehen, wie die KI zu ihren Schlussfolgerungen kommt. Das baut bis zu einem gewissen Grad Vertrauen auf.

Formulieren eines Chain-of-Thought Prompts

Eigentlich ist es ganz einfach, einen CoT-Prompt zu formulieren.

  1. Sorgfältig sein: Ermutige das Modell, seine Gedankengänge zu erklären. Verwende Formulierungen wie “Zeige mir, wie du das lösen würdest” oder “Erkläre deine Überlegungen”.
  2. Geduldig sein: Manchmal braucht das Modell etwas Zeit, um seine Antwort zu entwickeln. Gib ihm die Möglichkeit, seine Gedanken zu ordnen.
  3. Experimentierfreudig sein: Probiere verschiedene Arten von Fragen und Aufgaben aus, um zu sehen, wie das Modell reagiert.

Beispiel eines Chain of Thought Prompts

Der folgende Screenshot zeigt einen Prompt in OpenAI’s ChatGpt 3.5 ohne CoT. Wir erhalten ein schönes Antwortsätzchen mit dem Ergebnis.

ChatGPT 3.5 ohne CoT

Jetzt wenden wir das Chain-of-Thougt-Pattern an. Dazu ergänzen wir den Prompt. ChaGPT 3.5 erläutert sofort viel ausführlicher, wie auf dem folgenden Screenshot zu sehen ist.

ChatGPT 3.5 mit Chain of Thought

ChatGPT 4 und 4o, sowie Google’s Gemini kommen von Haus aus mit eingeschaltetem Chain-of-Thought. So erklären sich auch die ausführlichen Antworten, die wir dort erhalten. Einen Screenshot erstelle ich dazu nicht extra.

Wir können bei diesen Modellen das Verhalten ausschalten – mit einer Art ‘inversem’ Chain-of-Thought:

ChatGPT 4o ausgeschaltetes CoT

Grenzen des Chain-of-Thought-Patterns

Das Pattern kann dazu beitragen, dass die generierten Ergebnisse sogar besser werden. Siehe dazu auch die erste Veröffentlichung  zu CoT: Wei et al, Chain-of-Thought Prompting Elicits Reasoning in Large Language Models, NeurIPS 2022, hier abrufbar https://arxiv.org/abs/2201.11903. 

Untersuchen wir das, nachdem etwa eineinhalb Jahre verstrichen sind. Diesmal verwenden wir nicht die ganz großen LLM, wie ChatGPT 4 oder Gemini, sondern das kleinere Mistral 7B Instruct Version 02, von Mistral AI. Es ist klein genug, um es mit Ollama auch lokal auf dem Laptop laufen zu lassen.

Es ist für einige Überraschungen gut, wie der folgende Screenshot zeigt:

Mistral und rechnen

Mistral versucht ebenfalls, gleich von Anfang an, ein Chain-of-Thought-Verhalten an den Tag zu legen. Doch plötzlich ist das Ergebnis 60 und nicht mehr 70, wie wir im vorherigen Beispiel korrekterweise gesehen haben.  Da schwindet doch gleich das Vertrauen, nicht wahr?

Versuchen wir es mit explizitem Chain-of-Thought:

Mistral rechnen mit CoT

Mit dem Ergebnis 66 ist eine ‘Korrektur nach oben’ zu verzeichnen – doch das Ergebnis ist noch immer falsch.

Konfrontieren wir Mistral doch mit dem korrekten Ergebnis:

Mistral mit Entschuldigung

Interessant: das Sprachmodell entschuldigt sich und rechnet dann gleich nochmals vor. Diesmal mit einer noch ausführlicheren Erklärung. Es kann zwar die arithmetischen Regeln wiedergeben, doch anwenden kann es sie nicht. Am Schluss entschuldigt das Modell sich nochmals ganz höflich und insistiert auf dem falschen Ergebnis.

Warum kann Mistral nicht rechnen?

Dass Mistral beim Rechnen so kläglich versagt, kann nicht auf seine weiteren Eigenschaften übertragen werden. Wie genau und auf welchen Daten Mistral trainiert wurde, konnte ich nicht herausfinden – die Hersteller halten sich diesbezüglich bedeckt. Rechenkünste haben sie dem Modell offensichtlich nicht beigebracht.

Wenn wir happy sind mit den vielen guten Eigenschaften, die Mistral mitbringt, dann können wir es für das korrekte Lösen von Rechenaufgaben fine-tunen. Das dürfte allerdings in einigen Aufwand ausarten und es könnte sich lohnen, nach einem Modell Ausschau zu halten, das Rechnen kann. Dieses wird andere Schwächen haben.

Fazit

Chain of Thought Prompts sind ein nützliches Werkzeug, das uns Einblick bringt, mit welchen Schritten, das KI-Modell zur Schlussfolgerung gelangt.

Auch Laien, die ChatBots einsetzen, können daraus nutzen ziehen.

Wer als AI Engineer, KI-Modelle in seine Anwendungen einbauen will, kommt nicht um Chain-of-Thought herum.

  • Webinar:

    So baust du LLMs in deine Anwendungen ein

    Erfahre in diesem exklusiven Webinar, wie du LLMs in deine Anwendungen einbaust.

    Mehr Infos zum Webinar findest du in der ausführlichen Beschreibung.

    Das kostenlose Webinar findet statt am Montag, 8. Juli um 13:00-13:45 MEZ via ZOOM.

    Trage dich in die Liste ein und du erhältst den Zugangslink und später den Link zur Aufzeichnung.

  • Chatbot als Lernassistent
  • Prompt Engineering Personas und Wiederholungen
  • AI-Engineering-Fachglossar
  • EBook Tutorial: Cluster aus virtuellen Maschinen
  • Ebook: Apache ZooKeeper
  • Ebook: Realtime Streaming Pipelines
  • LSM-Trees: Log Structured Merge Trees
  • Aufbau einer Enterprise Search
  • Zeit Stream Analytics
  • B-Tree-Index in Datenbanken
  • Ordering Guarantee in Apache Kafka
  • CAP Theorem
  • MapReduce Funktionale Programmierung
  • Konzepte des HDFS
  • Optimistisches Concurrency Control
Veröffentlicht am

Semantische Suche und Abstandsmetriken

Distanzmetriken und Semantische Suche mit Vektor-Embeddings

Die semantische Suche ist ein wichtiger Bestandteil in LLM-gestützten Anwendung. Durch Anwendung des RAG-Patterns (Retrieval Augmented Generation) können wir dank semantischer Suche, die Antworten eines LLMs durch eigene Inhalte anreichern. Im Herzen der semantischen Suche liegt der Vergleich von Vektoren. Der Artikel untersucht verschiedene Methoden und zeigt deren Grenzen. 

Vektoren und Embedding Modelle

Embedding Modelle berechnen für semantisch ähnliche Textstelle benachbarte Vektoren. Warum das so ist, ergibt sich aus der Art und Weise, wie die Embedding Modelle erstellt werden.

Dass es so gut funktioniert, erstaunt noch immer auch die Experten.

Es gibt verschiedene Embedding Modelle. Wir untersuchen in diesem Artikel Word Embeddings. Denkbar ist auch der Einsatz von Sentence Embeddings, Paragraph-Embeddings – je nachdem, wie das Modell trainiert wurde. Das Tutorial Sentence Embeddings für Vektordatenbanken zeigt, wie ein Index für eine Vektordatenbank aufgebaut werden kann.

Das Konzept der Suche ist für jede Art Embedding identisch. Wir widmen uns Word-Embeddings.

Motivation Vektoren in Embeddings

Das Bild verdeutlicht den Ansatz – vereinfacht im zweidimensionalen Raum: Der Vektor für das Konzept ‘Prince’ liegt näher an den Vektoren für die Konzepte ‘King’ und ‘Queen’ als an Vektoren für die Konzepten ‘Man’ und ‘Woman’. Das ist eine fundamentale Eigenschaft der Word-Embeddings.

Wir nutzen diese Eigenschaft bei der semantischen Suche. Bei der Keyword-Suche helfen Vektoren wenig.

Keyword-Suche kennen wir beispielsweise von Google: Wir tippen Schlüsselwörter ein und erhalten als Suchergebnisse Dokumente gezeigt, in denen die Schlüsselwörter auftauchen.

Semantische Suche funktioniert anders: Hier tippen wir einen ganzen Satz ein oder sogar mehrere Sätze. Das Ergebnis sind Textfragmente  oder auch ganze Dokumente, die inhaltlich zu unseren Suchsätzen passen. Und hier glänzt die Vektorsuche.

  • Zur Inexierungszeit werden Textfragmente in Vektoren umgewandelt. Die Wahl der Grösse eines Textfragments ist eine Designentscheidung.
  • Zur Suchzeit wird unsere Suchfrage zu Vektoren umgewandelt.
  • Die Treffer der semantischen Suche entsprechen denjenigen Textfragmenten, deren Vektoren nahe an den Vektoren der Suchfrage liegen. Sie weisen einen Inhaltlichen Zusammenhang mit der Suchfrage auf ohne, dass die Wörter aus der Suchfrage mit denjenigen aus dem Textfragment übereinstimmen.

Was bedeutet ‘nahe’ in diesem Zusammenhang?

Hier kommen Metriken, also Abstandsfunktionen, zum Zuge.

In der Mathematik ist eine Metrik eine Funktion, die den Abstand zwischen zwei Punkten misst.

Formale Definition einer Metrik (Abstandsfunktion)

Eine Metrik (auch Abstandsfunktion) auf einer Menge M ist eine Funktion d: M x M → ℝ, die die folgenden Eigenschaften erfüllt:

  1. Nichtnegativität: Für alle x, y ∈ M gilt: d(x, y) ≥ 0
  2. Identität: Für alle x ∈ M gilt: d(x, x) = 0
  3. Symmetrie: Für alle x, y ∈ M gilt: d(x, y) = d(y, x)
  4. Dreiecksungleichung: Für alle x, y, z ∈ M gilt: d(x, z) ≤ d(x, y) + d(y, z)

Erläuterung:

  1. Nichtnegativität: Der Abstand zwischen zwei Punkten kann niemals negativ sein.
  2. Identität: Der Abstand eines Punktes zu sich selbst ist immer 0.
  3. Symmetrie: Der Abstand zwischen zwei Punkten ist gleich dem Abstand in umgekehrter Richtung.
  4. Dreiecksungleichung: Intuitiv besagt dies, dass der kürzeste Weg zwischen zwei Punkten niemals länger sein kann als die Summe der Entfernungen über einen Zwischenpunkt.

Beispiele für Metriken in der Vektorsuche

Euklidische Metrik

Die euklidische Metrik fällt uns zuerst ein. Sie misst die Luftlinie zwischen zwei Punkten im Raum. Das Bild verdeutlicht die Metrik.

Veranschulichung der euklidischen Metrik bei der Vektorsuche

Das Codefragment berechnet die Euklidische Metrik (oder Norm) in Python:

import math

v1 = [1, 2, 3] # Vektor 1
v2 = [4, 5, 6] # Vektor 2
quadratischer_abstand = sum((a - b)**2 for a, b in zip(v1, v2))
abstand = math.sqrt(quadratischer_abstand)

oder einfacher mit numpy

import numpy as np

v1 = np.array([1, 2, 3]) # Vektor 1 als NumPy-Array
v2 = np.array([4, 5, 6]) # Vektor 2 als NumPy-Array

abstand = np.linalg.norm(v1 - v2) # Euklidische Distanz berechnen

Die Manhattan Distanz

Die Manhattan Distanz oder auch City-Block-Distanz erfüllt die Definition einer Metrik.
Sie misst den Abstand zwischen zwei Punkten in einem gitterförmigen Raum und zwar so ähnlich, wie wenn wir in den Strassenschluchen in Manhattan ausrechnen, wie viele Block-Längen wir laufen müssen, um von A nach B zu gelangen.
Das Bild verdeutlicht das Konzept: Wir ‘laufen’ den Achsen entlang – im zweidimensionalen Raum beachten wir die zwei Achsen, Word-Embeddings finden in hochdimensionalen Räumen statt und entsprechend viele Achsen sind dann zu berücksichtigen.

Manhattan Distanz für Word Embeddings

Hier der Python Code (ohne Ausnahmebehandlung)

v1 = [1, 2, 3]
v2 = [4, 5, 6]
abstand = 0
for i in range(len(v1)):
    abstand += abs(v1[i] - v2[i])

Wie auch die Euklidische Distanz erfüllt die Manhattan Distanz die Anforderungen der Definition einer Distanzmetrik.

Als nächsten untersuchen wir zwei sehr beliebte Funktionen, die in Vektordatenbanken gerne eingesetzt werden:

Cosinus-Ähnlichkeit (cosinus similarity)

Diese Ähnlichkeitsfunktion misst den Winkel zwischen zwei Vektoren. Das Bild zeigt die Heuristik: Je kleiner der Winkel, umso ähnlicher sind die Konzepte. Na ja, relativ ähnlich, so wie das Bild zeigt. Der Winkel zwischen den Vektoren die Prince und King sowie Prince und Queen zugeordnet sind, sind deutlich kleiner als die Winkel zwischen den Vektoren für das Prince-Woman respektive das Prince-Man-Paar.

Cosinus-Ähnlichkeit für Word-Embeddings

Hier der Python Code:

Zuerst stellen wir sicher, dass wir nicht durch 0 dividieren werden.

Danach berechnen wir das Skalar-Produkt der beiden Vektoren (englisch: dot-Produkt) und dividieren durch die Länge, also Norm, der beiden Vektoren.

import numpy as np

v1 = np.array([1, 2, 3])  # Vektor 1 als NumPy-Array
v2 = np.array([4, 5, 6])  # Vektor 2 als NumPy-Array


v1_norm = np.linalg.norm(v1)
  v2_norm = np.linalg.norm(v2)
  if v1_norm == 0 or v2_norm == 0:
    abstand = 0
  else:
    abstand = np.dot(v1, v2) / (v1_norm * v2_norm)

Das Skalarprodukt können wir auch ohne numpy berechnen und zwar:

sum(a * b for a, b in zip(v1, v2))

Oder ganz ohne Python-Funktionen

v1 = [1, 2, 3]  # Vektor 1 als Liste
v2 = [4, 5, 6]  # Vektor 2 als Liste
abstand = 0
  for i in range(len(v1)):
    abstand += v1[i] * v2[i]

Skalarprodukt

Auch das Skalarprodukt wird oft zur Vektorsuche verwendet. Ein größeres Skalarprodukt bedeutet, dass ein Vektor mehr auf den anderen projiziert, was auf mehr gemeinsame Informationen oder Merkmale hinweist.

Das Skalarprodukt der Einheitsvektoren entspricht dem Cosinus der beiden Vektoren. In dem Fall fällt in Bezug auf die Formel zur Cosinus-Ähnlichkeit die Division durch das Produkt der beiden Normen weg.

Zur Bildung der Norm wird ja der verallgemeinerte Satz von Pythagoras verwendet, was ziemlich rechenintensiv ist. Da geht es einfacher, nur das Skalarprodukt zu nehmen – dieses ist präzise genug und erst noch einfacher zu berechnen.

Die Cosinus-Ähnlichkeit ist keine Metrik

Schauen wir genau hin, dann erfüllen weder die Cosinusähnlichkeit noch das Skalarprodukt die Anforderungen an einer Metrik:

Die Cosinusähnlichkeit verletzt unter anderem die Identität: Eine Abstandsfunktion muss für alle Punktepaare d(x, y) > 0 sein, außer wenn x und y identisch sind (d(x, x) = 0). Die Cosinusähnlichkeit und auch das Skalarprodukt, kann jedoch auch für unterschiedliche Punkte 1 ergeben (z.B. wenn die Vektoren die gleiche Richtung haben).

Das Bild zeigt, was passieren kann:

Unschärfen und Grenzen der Cosinus-Ähnlichkeit

Der Winkel zwischen ‘Whiteboard’ und ‘Price’ ist in diesem hypothetischen und stark vereinfachten Bild gleich Null.
Das bedeutet: Für die Vektorsuche stimmen die Konzepte ‘Whiteboard’ und ‘Prince’ semantisch überein. Das ist nicht im Sinne der semantischen Suche.

Für das Skalarprodukt liesse sich ein analoges Beispiel konstruieren.

Fazit

Für die semantische Suche in Vektordatenbanken ist die Ausführungsgeschwindigkeit wichtiger als mathematischen Präzision. Und deshalb lohnt es sich, verschiedene Metriken bei der Vektorsuche zu testen.

Welche Abstandsfunktion für unsere Anwendungsfälle die beste ist, werden wir empirisch herausfinden müssen.

Die Qualität der semantischen Suche ist nicht unerheblich, wenn es um RAG, also Retrieval Augmented Generation geht – denn seit es generative KI gibt, ist der Bedarf nach semantischen Suchsystemen erheblich gestiegen.

  • Webinar:

    So baust du LLMs in deine Anwendungen ein

    Erfahre in diesem exklusiven Webinar, wie du LLMs in deine Anwendungen einbaust.

    Mehr Infos zum Webinar findest du in der ausführlichen Beschreibung.

    Das kostenlose Webinar findet statt am Montag, 8. Juli um 13:00-13:45 MEZ via ZOOM.

    Trage dich in die Liste ein und du erhältst den Zugangslink und später den Link zur Aufzeichnung.

  • Chatbot als Lernassistent
  • Prompt Engineering Personas und Wiederholungen
  • AI-Engineering-Fachglossar
  • EBook Tutorial: Cluster aus virtuellen Maschinen
  • Ebook: Apache ZooKeeper
  • Ebook: Realtime Streaming Pipelines
  • LSM-Trees: Log Structured Merge Trees
  • Aufbau einer Enterprise Search
  • Zeit Stream Analytics
  • B-Tree-Index in Datenbanken
  • Ordering Guarantee in Apache Kafka
  • CAP Theorem
  • MapReduce Funktionale Programmierung
  • Konzepte des HDFS
  • Optimistisches Concurrency Control