Prompt Engineering
Optimieren Sie LLM mit DSPy: Ein Schritt-für-Schritt-Leitfaden zum Erstellen, Optimieren und Auswerten von KI-Systemen
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:
- 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.
- BootstrapFewShotWithRandomSearch: Wendet
BootstrapFewShotmehrmals mit zufälliger Suche über generierte Demonstrationen an und wählt das beste Programm über die Optimierung aus. - 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.
- 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.












