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 (LLM) weiter expandieren, ist die Entwicklung robuster KI-Systeme, die ihr Potenzial nutzen, immer komplexer geworden. Herkömmliche Ansätze erfordern oft komplexe Prompting-Techniken, Daten 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.
Hier kommt DSPy ins Spiel, ein revolutionäres Framework, das die Entwicklung von KI-Systemen auf Basis von LLM vereinfacht. DSPy bietet einen systematischen Ansatz zur Optimierung von LM-Prompts und Gewichten, sodass Entwickler komplexe Anwendungen mit minimalem manuellem Aufwand erstellen können.
In diesem umfassenden Leitfaden werden wir die Kernprinzipien von DSPy, seine modulare Architektur und die Vielzahl leistungsstarker Funktionen erkunden. Wir werden auch praktische Beispiele vorstellen, um zu demonstrieren, wie DSPy die Entwicklung von KI-Systemen mit LLM revolutionieren kann.
Was ist DSPy und warum benötigen Sie es?
DSPy ist ein Framework, das den Fluss Ihres Programms (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 erforderte die Entwicklung von KI-Systemen mit LLM einen mühsamen Prozess, bei dem das Problem in Schritte aufgeteilt, komplexe Prompts für jeden Schritt erstellt und synthetische Beispiele für Feinabstimmung generiert wurden. Dieser Ansatz war nicht nur zeitaufwändig, sondern auch fehleranfällig, da sogar kleine Änderungen an der Pipeline, dem LM oder den Daten eine umfangreiche Überarbeitung von Prompts und Feinabstimmungsschritten erfordern konnten.
DSPy adressiert diese Herausforderungen, indem es ein neues Paradigma einführt: Optimizer. Diese LM-gesteuerten Algorithmen können die Prompts und Gewichte von LM-Aufrufen anpassen, basierend auf einer Metrik, die maximiert werden soll. Durch die Automatisierung des Optimierungsprozesses ermöglicht DSPy es Entwicklern, robuste KI-Systeme mit minimalem manuellem Eingreifen zu erstellen, was die Zuverlässigkeit und Vorhersehbarkeit von LM-Ausgaben verbessert.
DSPys modulare Architektur
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 abstrahieren, wie z.B. dspy.ChainOfThought und dspy.ReAct. Diese Module können kombiniert und zu größeren Programmen zusammengesetzt werden, um Entwicklern die Erstellung von komplexen Pipelines zu ermöglichen, die ihren spezifischen Anforderungen entsprechen.
Jedes Modul kapselt lernbare Parameter, einschließlich Anweisungen, Few-Shot-Beispiele und LM-Gewichte. Wenn ein Modul aufgerufen wird, können DSPys Optimizer diese Parameter anpassen, um die gewünschte Metrik zu maximieren, sodass die LM-Ausgaben den spezifizierten Einschränkungen und Anforderungen entsprechen.
Optimieren mit DSPy
DSPy bietet eine Reihe leistungsstarker Optimierer, die die Leistung und Zuverlässigkeit von KI-Systemen verbessern. Diese Optimierer nutzen LM-gesteuerte Algorithmen, um die Prompts und Gewichte von LM-Aufrufen anzupassen, um die spezifizierte Metrik zu maximieren, während sie domänen-spezifischen Einschränkungen entsprechen.
Einige der verfügbaren Optimierer in DSPy sind:
- BootstrapFewShot: Dieser Optimierer erweitert die Signatur, indem er automatisch optimierte Beispiele innerhalb des Prompts generiert und einschließt, der an das Modell gesendet wird, und Few-Shot-Lernen implementiert.
- BootstrapFewShotWithRandomSearch: Wendet BootstrapFewShot mehrmals 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 zu suchen.
- BootstrapFinetune: Destilliert ein prompt-basiertes DSPy-Programm in Gewichtsaktualisierungen für kleinere LMs, sodass Sie die zugrunde liegenden LLM(s) für eine verbesserte Effizienz feinabstimmen können.
Durch die Nutzung dieser Optimierer können Entwickler ihre KI-Systeme systematisch optimieren, um hochwertige Ausgaben zu gewährleisten, während sie domänen-spezifischen Einschränkungen und Anforderungen entsprechen.
Erste Schritte mit DSPy
Um die Leistungsfähigkeit von DSPy zu veranschaulichen, gehen wir durch ein praktisches Beispiel, um ein Retrieval-augmentiertes Generierungssystem (RAG) für Frage-Antwort-Systeme zu 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 den folgenden Befehl aus:
pip install dspy-ai
DSPy unterstützt mehrere LM- und RM-APIs sowie lokale Modell-Hosting, was es einfach macht, Ihre bevorzugten Modelle zu integrieren.
import dspy <p># Konfigurieren des LM und RM turbo = dspy.OpenAI(model='gpt-3.5-turbo') colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')</p> <p>dspy.settings.configure(lm=turbo, rm=colbertv2_wiki17_abstracts)</p>
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 Fashion beantwortet werden.
from dspy.datasets import HotPotQA
<p># Laden des Datensatzes
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)</p>
<p># 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]</p>
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) spezifizieren.
<p>class GenerateAnswer(dspy.Signature): """Beantworten von Fragen mit kurzen faktoiden Antworten."""</p> <p>context = dspy.InputField(desc="Kontext, der möglicherweise relevante Fakten enthält") question = dspy.InputField() answer = dspy.OutputField(desc="Antwort, oft zwischen 1 und 5 Wörtern")</p>
Schritt 4: Erstellen der Pipeline
Wir erstellen unsere RAG-Pipeline als DSPy-Modul, das aus einer Initialisierungsmethode (__init__) besteht, um die Sub-Module (dspy.Retrieve und dspy.ChainOfThought) zu deklarieren, und einer Forward-Methode (forward), um den Kontrollfluss der Beantwortung der Frage mithilfe dieser Module zu beschreiben.
<p>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 Pipeline definiert, können wir sie jetzt mithilfe von DSPys Optimierern optimieren. In diesem Beispiel verwenden wir den BootstrapFewShot-Optimizer, der effektive Prompts für unsere Module basierend auf einem Trainingsset und einer Metrik für die Validierung generiert und auswählt.
<p>from dspy.teleprompt import BootstrapFewShot</p> <p># 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 <p># Einrichten des Optimierers teleprompter = BootstrapFewShot(metric=validate_context_and_answer) <p># 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
<p># Einrichten des Evaluators
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)
<p># Auswerten des kompilierten RAG-Programms
evaluation_result = evaluate(compiled_rag)
<p>print(f"Auswertungsergebnis: {evaluation_result}")
Schritt 7: Inspektion der Modellhistorie
Um ein tieferes Verständnis der Modellinteraktionen zu erhalten, können Sie die jüngsten Generationen durch Inspektion der Modellhistorie überprüfen.
<p># Inspektion der Modellhistorie turbo.inspect_history(n=1)
Schritt 8: Vorhersagen treffen
Mit der Pipeline optimiert und ausgewertet, können Sie sie jetzt verwenden, um Vorhersagen für neue Fragen zu treffen.
<p># Beispiel-Frage
question = "Welchen Award erhielt Gary Zukavs erstes Buch?"
<p># Vorhersage mit dem kompilierten RAG-Programm
prediction = compiled_rag(question)
<p>print(f"Frage: {question}")
print(f"Antwort: {prediction.answer}")
print(f"Abgerufene Kontexte: {prediction.context}")
Minimales Arbeitsbeispiel mit DSPy
Jetzt gehen wir durch ein weiteres minimales Arbeitsbeispiel, das den GSM8K-Datensatz und das OpenAI-GPT-3.5-Turbo-Modell verwendet, um Prompting-Aufgaben innerhalb von DSPy zu simulieren.
Einrichtung
Stellen Sie sicher, dass Ihre Umgebung ordnungsgemäß konfiguriert ist:
<p>import dspy from dspy.datasets.gsm8k import GSM8K, gsm8k_metric</p> <p># Einrichten des LM turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250) dspy.settings.configure(lm=turbo) <p># Laden von Math-Fragen 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 Antwortfeld hat.
Definieren des Moduls
Definieren Sie als nächstes ein benutzerdefiniertes Programm, das das ChainOfThought-Modul für schrittweises Reasoning verwendet:
<p>class CoT(dspy.Module): def __init__(self): super().__init__() self.prog = dspy.ChainOfThought("Frage -> Antwort") def forward(self, question): return self.prog(question=question)
Kompilieren und Auswerten des Modells
Kompilieren Sie es jetzt mit dem BootstrapFewShot-Teleprompter:
<p>from dspy.teleprompt import BootstrapFewShot</p> <p># Einrichten des Optimierers config = dict(max_bootstrapped_demos=4, max_labeled_demos=4) <p># Optimieren mit der gsm8k-Metrik teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config) optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset) <p># Einrichten des Evaluators from dspy.evaluate import Evaluate <p>evaluate = Evaluate(devset=gsm8k_devset, metric=gsm8k_metric, num_threads=4, display_progress=True, display_table=0) evaluate(optimized_cot) <p># Inspektion 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 mit den bereitgestellten Datensatz und Teleprompter-Konfigurationen auswerten können.
Datamanagement in DSPy
DSPy arbeitet mit Trainings-, Entwicklungs- und Testsets. Für jedes Beispiel in Ihren Daten haben Sie normalerweise drei Arten von Werten: Eingaben, Zwischenlabels und Endlabels. Während Zwischen- oder Endlabels optional sind, ist es wichtig, einige Beispiel-Eingaben zu haben.
Erstellen von Beispiel-Objekten
Beispiel-Objekte in DSPy sind ähnlich wie Python-Dictionarys, aber sie bieten nützliche Hilfsmittel:
<p>qa_pair = dspy.Example(question="Dies ist eine Frage?", answer="Dies ist eine Antwort.") <p>print(qa_pair) print(qa_pair.question) print(qa_pair.answer)
Ausgabe:
<p>Example({"question": "Dies ist eine Frage?", "answer": "Dies ist eine Antwort."}) (input_keys=None)
Dies ist eine Frage?
Dies ist eine Antwort.
Spezifizieren von Eingabeschlüsseln
In DSPy haben Beispiel-Objekte eine with_inputs()-Methode, um bestimmte Felder als Eingaben zu markieren:
<p>print(qa_pair.with_inputs("question")) print(qa_pair.with_inputs("question", "answer"))
Werte können mithilfe des Punktoperators zugreifen, und Methoden wie inputs() und labels() geben neue Beispiel-Objekte zurück, die nur Eingabeschlüssel oder Nicht-Eingabeschlüssel enthalten.
Optimizer in DSPy
Ein DSPy-Optimizer passt die Parameter eines DSPy-Programms (d. h. Prompts und/oder LM-Gewichte) an, um bestimmte Metriken zu maximieren. DSPy bietet verschiedene integrierte Optimierer, von denen jeder unterschiedliche Strategien verwendet.
Verfügbare Optimierer
- BootstrapFewShot: Generiert Few-Shot-Beispiele mithilfe von bereitgestellten markierten Eingabe- und Ausgabedaten.
- BootstrapFewShotWithRandomSearch: Wendet BootstrapFewShot mehrmals mit zufälliger Suche über generierte Demonstrationen an.
- COPRO: Generiert und verfeinert neue Anweisungen für jeden Schritt, indem es diese mit koordiniertem Anstieg optimiert.
- MIPRO: Optimiert Anweisungen und Few-Shot-Beispiele mithilfe von Bayesian-Optimierung.
Auswahl eines Optimierers
Wenn Sie unsicher sind, wo Sie beginnen 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.
So verwenden Sie BootstrapFewShotWithRandomSearch:
<p>from dspy.teleprompt import BootstrapFewShotWithRandomSearch</p> <p>config = dict(max_bootstrapped_demos=4, max_labeled_demos=4, num_candidate_programs=10, num_threads=4) teleprompter = BootstrapFewShotWithRandomSearch(metric=YOUR_METRIC_HERE, **config) optimized_program = teleprompter.compile(YOUR_PROGRAM_HERE, trainset=YOUR_TRAINSET_HERE)
Speichern und Laden optimierter Programme
Nachdem Sie ein Programm durch einen Optimierer geführt haben, können Sie es für die spätere Verwendung speichern:
optimized_program.save(YOUR_SAVE_PATH)
Laden Sie ein gespeichertes Programm:
<p>loaded_program = YOUR_PROGRAM_CLASS() loaded_program.load(path=YOUR_SAVE_PATH)
Erweiterte Funktionen: DSPy-Asserts
DSPy-Asserts automatisieren die Durchsetzung von Berechnungseinschränkungen auf LMs, was die Zuverlässigkeit, Vorhersehbarkeit und Richtigkeit von LM-Ausgaben verbessert.
Verwenden von Asserts
Definieren Sie Validierungsfunktionen und erklären Sie Asserts nach der jeweiligen Modellgenerierung. Zum Beispiel:
<p>dspy.Suggest(
len(query) <= 100,
"Abfrage sollte kurz und weniger als 100 Zeichen lang sein",
)
<p>dspy.Suggest(
validate_query_distinction_local(prev_queries, query),
"Abfrage sollte unterschiedlich sein von: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(prev_queries)),
)
Transformieren von Programmen mit Asserts
<p>from dspy.primitives.assertions import assert_transform_module, backtrack_handler</p> <p>baleen_with_assertions = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler) <p>Alternativ können Sie Asserts direkt auf dem Programm aktivieren:</p> [code language="Python"] <p>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. Durch die Befolgung der in diesen Beispielen beschriebenen Schritte können Sie komplexe KI-Systeme mit Leichtigkeit erstellen, optimieren und auswerten. DSPys modulares Design und leistungsstarke Optimierer ermöglichen eine effiziente und effektive Integration verschiedener Sprachmodelle, was es zu einem wertvollen Werkzeug für jeden macht, der im Bereich von NLP und KI tätig ist.
Ob Sie ein einfaches Frage-Antwort-System oder eine komplexere Pipeline erstellen, DSPy bietet die Flexibilität und Robustheit, die erforderlich ist, um hohe Leistung und Zuverlässigkeit zu erzielen.












