Connect with us

Prompt Engineering

Optimieren Sie LLM mit DSPy: Ein Schritt-für-Schritt-Leitfaden zum Erstellen, Optimieren und Auswerten von KI-Systemen

mm
DSPy is a framework for algorithmically optimizing LM prompts and weights

Da die Fähigkeiten von großen Sprachmodellen (LLMs) weiter expandieren, ist die Entwicklung robuster KI-Systeme, die ihr Potenzial nutzen, zunehmend komplexer geworden. Herkömmliche Ansätze umfassen oft komplexe Prompting-Techniken, Datengenerierung für Feinabstimmung und manuelle Anleitung, um die Einhaltung von domänen-spezifischen Einschränkungen sicherzustellen. Dieser Prozess kann jedoch mühsam, fehleranfällig und stark von menschlicher Intervention abhängig sein.

Treten Sie in DSPy ein, ein revolutionäres Framework, das die Entwicklung von KI-Systemen, die von LLMs angetrieben werden, vereinfacht. DSPy führt einen systematischen Ansatz zur Optimierung von LM-Prompts und -Gewichten ein, sodass Entwickler mit minimalem manuellem Aufwand anspruchsvolle Anwendungen erstellen können.

In diesem umfassenden Leitfaden werden wir die Kernprinzipien von DSPy, seine modulare Architektur und die Vielzahl leistungsstarker Funktionen, die es bietet, erkunden. Wir werden auch in praktische Beispiele eintauchen, um zu demonstrieren, wie DSPy die Art und Weise, wie Sie KI-Systeme mit LLMs entwickeln, verändern kann.

Was ist DSPy und warum benötigen Sie es?

DSPy ist ein Framework, das den Programmfluss (Module) von den Parametern (LM-Prompts und -Gewichten) jedes Schritts trennt. Diese Trennung ermöglicht die systematische Optimierung von LM-Prompts und -Gewichten, sodass Sie komplexe KI-Systeme mit größerer Zuverlässigkeit, Vorhersehbarkeit und Einhaltung von domänen-spezifischen Einschränkungen erstellen können.

Traditionell umfasste die Entwicklung von KI-Systemen mit LLMs einen mühsamen Prozess, bei dem das Problem in Schritte aufgeteilt, komplexe Prompts für jeden Schritt erstellt, synthetische Beispiele für Feinabstimmung generiert und die LMs manuell angeleitet wurden, um bestimmte Einschränkungen einzuhalten. Dieser Ansatz war nicht nur zeitaufwändig, sondern auch fehleranfällig, da selbst kleine Änderungen an der Pipeline, dem LM oder den Daten eine umfassende Überarbeitung von Prompts und Feinabstimmungsschritten erfordern konnten.

DSPy geht auf diese Herausforderungen ein, indem es ein neues Paradigma einführt: Optimierer. Diese LM-gesteuerten Algorithmen können die Prompts und Gewichte der LM-Aufrufe anhand einer Metrik, die maximiert werden soll, anpassen. Durch die Automatisierung des Optimierungsprozesses ermöglicht DSPy Entwicklern, robuste KI-Systeme mit minimalem manuellem Eingreifen zu erstellen, wodurch die Zuverlässigkeit und Vorhersehbarkeit der LM-Ausgaben verbessert werden.

Modulare Architektur von DSPy

Im Herzen von DSPy liegt eine modulare Architektur, die die Zusammensetzung komplexer KI-Systeme erleichtert. Das Framework bietet eine Reihe von integrierten Modulen, die verschiedene Prompting-Techniken wie dspy.ChainOfThought und dspy.ReAct abstrahieren. Diese Module können kombiniert und zu größeren Programmen zusammengesetzt werden, sodass Entwickler komplexe Pipelines nach ihren spezifischen Anforderungen erstellen können.

Jedes Modul kapselt learnbare Parameter, einschließlich Anweisungen, Few-Shot-Beispielen und LM-Gewichten. Wenn ein Modul aufgerufen wird, können die Optimierer von DSPy diese Parameter anpassen, um die gewünschte Metrik zu maximieren und sicherzustellen, dass die LM-Ausgaben den angegebenen Einschränkungen und Anforderungen entsprechen.

Optimieren mit DSPy

DSPy bietet eine Reihe leistungsstarker Optimierer, die zur Verbesserung der Leistung und Zuverlässigkeit Ihrer KI-Systeme konzipiert sind. Diese Optimierer nutzen LM-gesteuerte Algorithmen, um die Prompts und Gewichte der LM-Aufrufe anzupassen, um die angegebene Metrik zu maximieren und die domänen-spezifischen Einschränkungen einzuhalten.

Einige der wichtigsten Optimierer, die in DSPy verfügbar sind:

  1. BootstrapFewShot: Dieser Optimierer erweitert die Signatur, indem er automatisch optimierte Beispiele innerhalb des an das Modell gesendeten Prompts generiert und implementiert, wodurch Few-Shot-Lernen ermöglicht wird.
  2. BootstrapFewShotWithRandomSearch: Wendet BootstrapFewShot mehrmals mit zufälliger Suche über generierte Demonstrationen an und wählt das beste Programm über die Optimierung aus.
  3. MIPRO: Generiert Anweisungen und Few-Shot-Beispiele in jedem Schritt, wobei die Anweisungsgenerierung daten- und demonstrationsbewusst ist. Es verwendet Bayesian-Optimierung, um effektiv im Raum der Generierungsanweisungen und Demonstrationen über Ihre Module zu suchen.
  4. BootstrapFinetune: Destilliert ein promptbasiertes DSPy-Programm in Gewichtsaktualisierungen für kleinere LMs, sodass Sie die zugrunde liegenden LLM(s) für eine verbesserte Effizienz feinabstimmen können.

Indem Sie diese Optimierer nutzen, können Entwickler ihre KI-Systeme systematisch optimieren und sicherstellen, dass die Ausgaben von hoher Qualität sind und den domänen-spezifischen Einschränkungen und Anforderungen entsprechen.

Erste Schritte mit DSPy

Um die Leistungsfähigkeit von DSPy zu demonstrieren, gehen wir durch ein praktisches Beispiel, bei dem wir ein Retrieval-augmentiertes Generierungssystem (RAG) für Fragebeantwortung erstellen.

Schritt 1: Einrichten des Sprachmodells und des Retrieval-Modells

Der erste Schritt umfasst die Konfiguration des Sprachmodells (LM) und des Retrieval-Modells (RM) innerhalb von DSPy.

Um DSPy zu installieren, führen Sie aus:


pip install dspy-ai

DSPy unterstützt mehrere LM- und RM-APIs sowie lokale Modellhosting, was es einfach macht, Ihre bevorzugten Modelle zu integrieren.


import dspy

# Konfigurieren Sie das LM und das RM
turbo = dspy.OpenAI(model='gpt-3.5-turbo')
colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')

dspy.settings.configure(lm=turbo, rm=colbertv2_wiki17_abstracts)

Schritt 2: Laden des Datensatzes

Als Nächstes laden wir den HotPotQA-Datensatz, der eine Sammlung von komplexen Frage-Antwort-Paaren enthält, die normalerweise in einer mehrstufigen Art und Weise beantwortet werden.


from dspy.datasets import HotPotQA

# Laden des Datensatzes
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)

# Spezifizieren des 'question'-Felds als Eingabe
trainset = [x.with_inputs('question') for x in dataset.train]
devset = [x.with_inputs('question') for x in dataset.dev]

Schritt 3: Erstellen von Signaturen

DSPy verwendet Signaturen, um das Verhalten von Modulen zu definieren. In diesem Beispiel definieren wir eine Signatur für die Aufgabe der Antwortgenerierung, wobei wir die Eingabefelder (Kontext und Frage) und das Ausgabefeld (Antwort) angeben.


class GenerateAnswer(dspy.Signature):
"""Beantworten Sie Fragen mit kurzen faktoiden Antworten."""

context = dspy.InputField(desc="kann relevante Fakten enthalten")
question = dspy.InputField()
answer = dspy.OutputField(desc="meist zwischen 1 und 5 Wörtern")

Schritt 4: Erstellen der Pipeline

Wir erstellen unsere RAG-Pipeline als DSPy-Modul, das aus einer Initialisierungsmethode (__init__) besteht, um die Submodule (dspy.Retrieve und dspy.ChainOfThought) zu deklarieren, und einer Forward-Methode (forward), um den Steuerfluss der Beantwortung der Frage mithilfe dieser Module zu beschreiben.


class RAG(dspy.Module):
def __init__(self, num_passages=3):
super().__init__()

self.retrieve = dspy.Retrieve(k=num_passages)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)

def forward(self, question):
context = self.retrieve(question).passages
prediction = self.generate_answer(context=context, question=question)
return dspy.Prediction(context=context, answer=prediction.answer)

Schritt 5: Optimieren der Pipeline

Mit der definierten Pipeline können wir sie jetzt mithilfe der Optimierer von DSPy optimieren. In diesem Beispiel verwenden wir den BootstrapFewShot-Optimierer, der effektive Prompts für unsere Module basierend auf einem Trainingsset und einer Metrik für die Validierung generiert und auswählt.


from dspy.teleprompt import BootstrapFewShot

# Validierungsmetrik
def validate_context_and_answer(example, pred, trace=None):
answer_EM = dspy.evaluate.answer_exact_match(example, pred)
answer_PM = dspy.evaluate.answer_passage_match(example, pred)
return answer_EM and answer_PM

# Einrichten des Optimierers
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)

# Kompilieren des Programms
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

Schritt 6: Auswerten der Pipeline

Nach der Kompilierung des Programms ist es wichtig, seine Leistung auf einem Entwicklungsset zu bewerten, um sicherzustellen, dass es die gewünschte Genauigkeit und Zuverlässigkeit erreicht.


from dspy.evaluate import Evaluate

# Einrichten des Evaluators
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)

# Auswerten des kompilierten RAG-Programms
evaluation_result = evaluate(compiled_rag)

print(f"Evaluierungsergebnis: {evaluation_result}")

Schritt 7: Überprüfen der Modellhistorie

Um ein tieferes Verständnis der Modellinteraktionen zu erhalten, können Sie die jüngsten Generationen durch Überprüfen der Modellhistorie überprüfen.


# Überprüfen der Modellhistorie
turbo.inspect_history(n=1)

Schritt 8: Erstellen von Vorhersagen

Mit der optimierten und ausgewerteten Pipeline können Sie sie jetzt verwenden, um Vorhersagen für neue Fragen zu erstellen.


# Beispiel-Frage
question = "Welchen Preis hat das erste Buch von Gary Zukav erhalten?"

# Erstellen einer Vorhersage mithilfe des kompilierten RAG-Programms
prediction = compiled_rag(question)

print(f"Frage: {question}")
print(f"Antwort: {prediction.answer}")
print(f"Abrufkontexte: {prediction.context}")

Minimales Arbeitsbeispiel mit DSPy

Jetzt gehen wir durch ein weiteres minimales Arbeitsbeispiel, bei dem wir den GSM8K-Datensatz und das OpenAI-GPT-3.5-Turbo-Modell verwenden, um Prompting-Aufgaben innerhalb von DSPy zu simulieren.

Einrichtung

Stellen Sie zunächst sicher, dass Ihre Umgebung ordnungsgemäß konfiguriert ist:


import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric

# Einrichten des LMs
turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250)
dspy.settings.configure(lm=turbo)

# Laden von Mathematikfragen aus dem GSM8K-Datensatz
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]

print(gsm8k_trainset)

Der gsm8k_trainset und gsm8k_devset enthalten eine Liste von Beispielen, von denen jeder ein Frage- und ein Antwortfeld enthält.

Definieren des Moduls

Definieren Sie als Nächstes ein benutzerdefiniertes Programm, das das ChainOfThought-Modul für schrittweises Reasoning nutzt:


class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought("question -> answer")

def forward(self, question):
return self.prog(question=question)

Kompilieren und Auswerten des Modells

Kompilieren Sie es jetzt mit dem BootstrapFewShot-Teleprompter:


from dspy.teleprompt import BootstrapFewShot

# Einrichten des Optimierers
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)

# Optimieren mithilfe der gsm8k_metric
teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config)
optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)

# Einrichten des Evaluators
from dspy.evaluate import Evaluate

evaluate = Evaluate(devset=gsm8k_devset, metric=gsm8k_metric, num_threads=4, display_progress=True, display_table=0)
evaluate(optimized_cot)

# Überprüfen der Modellhistorie
turbo.inspect_history(n=1)

Dieses Beispiel zeigt, wie Sie Ihre Umgebung einrichten, ein benutzerdefiniertes Modul definieren, ein Modell kompilieren und seine Leistung mithilfe des bereitgestellten Datensatzes und der Teleprompter-Konfigurationen rigoros auswerten können.

Datemanagement in DSPy

DSPy arbeitet mit Trainings-, Entwicklungs- und Testsets. Für jedes Beispiel in Ihren Daten haben Sie normalerweise drei Arten von Werten: Eingaben, Zwischenetiketten und Endetiketten. Während Zwischen- oder Endetiketten optional sind, ist es wichtig, einige Beispiel-Eingaben zu haben.

Erstellen von Beispiel-Objekten

Beispiel-Objekte in DSPy sind ähnlich wie Python-Wörterbücher, aber sie verfügen über nützliche Hilfsmittel:


qa_pair = dspy.Example(question="Dies ist eine Frage?", answer="Dies ist eine Antwort.")

print(qa_pair)
print(qa_pair.question)
print(qa_pair.answer)

Ausgabe:


Example({'question': 'Dies ist eine Frage?', 'answer': 'Dies ist eine Antwort.'}) (input_keys=None)
Dies ist eine Frage?
Dies ist eine Antwort.

Angeben von Eingabeschlüsseln


print(qa_pair.with_inputs("question"))
print(qa_pair.with_inputs("question", "answer"))

Werte können mithilfe des Punktoperators abgerufen werden, und Methoden wie inputs() und labels() geben neue Beispiel-Objekte zurück, die nur Eingabe- oder Nicht-Eingabeschlüssel enthalten.

Optimierer in DSPy

Ein DSPy-Optimierer passt die Parameter eines DSPy-Programms (d. h. Prompts und/oder LM-Gewichte) an, um angegebene Metriken zu maximieren. DSPy bietet verschiedene integrierte Optimierer, von denen jeder unterschiedliche Strategien anwendet.

Verfügbare Optimierer

  • BootstrapFewShot: Generiert Few-Shot-Beispiele mithilfe der bereitgestellten beschrifteten Eingabe- und Ausgabedatenpunkte.
  • BootstrapFewShotWithRandomSearch: Wendet BootstrapFewShot mehrmals mit zufälliger Suche über generierte Demonstrationen an.
  • COPRO: Generiert und verfeinert neue Anweisungen für jeden Schritt und optimiert sie mithilfe von koordiniertem Aufstieg.
  • MIPRO: Optimiert Anweisungen und Few-Shot-Beispiele mithilfe der Bayesian-Optimierung.

Auswahl eines Optimierers

Wenn Sie sich unsicher sind, wo Sie anfangen sollen, verwenden Sie BootstrapFewShotWithRandomSearch:

Für sehr wenig Daten (10 Beispiele) verwenden Sie BootstrapFewShot.
Für etwas mehr Daten (50 Beispiele) verwenden Sie BootstrapFewShotWithRandomSearch.
Für größere Datensätze (300+ Beispiele) verwenden Sie MIPRO.

Hier ist, wie Sie BootstrapFewShotWithRandomSearch verwenden:


from dspy.teleprompt import BootstrapFewShotWithRandomSearch

config = dict(max_bootstrapped_demos=4, max_labeled_demos=4, num_candidate_programs=10, num_threads=4)
teleprompter = BootstrapFewShotWithRandomSearch(metric=IHR_METRIK_HIER, **config)
optimized_program = teleprompter.compile(IHR_PROGRAMM_HIER, trainset=IHR_TRAINSET_HIER)

Speichern und Laden optimierter Programme

Nachdem Sie ein Programm durch einen Optimierer geführt haben, speichern Sie es für die zukünftige Verwendung:

optimized_program.save(IHR_SPEICHPFAD)

Laden Sie ein gespeichertes Programm:


loaded_program = YOUR_PROGRAM_CLASS()
loaded_program.load(path=IHR_SPEICHPFAD)

Erweiterte Funktionen: DSPy-Asserts

DSPy-Asserts automatisieren die Durchsetzung von berechnungstechnischen Einschränkungen auf LMs, wodurch die Zuverlässigkeit, Vorhersehbarkeit und Korrektheit der LM-Ausgaben verbessert werden.

Verwenden von Asserts

Definieren Sie Validierungsfunktionen und erklären Sie Asserts nach der jeweiligen Modellgenerierung. Zum Beispiel:


dspy.Suggest(
len(query) <= 100,
"Abfrage sollte kurz und weniger als 100 Zeichen lang sein",
)

dspy.Suggest(
validate_query_distinction_local(prev_queries, query),
"Abfrage sollte sich von unterscheiden: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(prev_queries)),
)

Transformieren von Programmen mit Asserts


from dspy.primitives.assertions import assert_transform_module, backtrack_handler

baleen_with_assertions = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler)

Alternativ können Sie Asserts direkt auf dem Programm aktivieren:


baleen_with_assertions = SimplifiedBaleenAssertions().activate_assertions()

Assert-getriebene Optimierungen

DSPy-Asserts arbeiten mit DSPy-Optimierungen zusammen, insbesondere mit BootstrapFewShotWithRandomSearch, einschließlich Einstellungen wie:

  • Kompilieren mit Asserts
  • Kompilieren + Inferenz mit Asserts

Zusammenfassung

DSPy bietet einen leistungsstarken und systematischen Ansatz zur Optimierung von Sprachmodellen und ihren Prompts. Indem Sie den in diesen Beispielen beschriebenen Schritten folgen, können Sie komplexe KI-Systeme mit Leichtigkeit erstellen, optimieren und auswerten. Die modulare Konstruktion und die erweiterten Optimierer von DSPy ermöglichen eine effiziente und effektive Integration verschiedener Sprachmodelle, wodurch es ein wertvolles Werkzeug für jeden darstellt, der im Bereich NLP und KI tätig ist.

Egal, ob Sie ein einfaches Frage-Antwort-System oder eine komplexere Pipeline erstellen, bietet DSPy die notwendige Flexibilität und Robustheit, um hohe Leistung und Zuverlässigkeit zu erzielen.

Ich habe die letzten fünf Jahre damit verbracht, mich in die faszinierende Welt des Machine Learning und Deep Learning zu vertiefen. Meine Leidenschaft und mein Fachwissen haben mich dazu geführt, an über 50 verschiedenen Software-Entwicklungsprojekten mitzuwirken, mit einem besonderen Fokus auf KI/ML. Meine anhaltende Neugier hat mich auch zum Natural Language Processing hingezogen, ein Feld, das ich weiter erforschen möchte.