Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Einführung

In der Welt der Softwareentwicklung verschwinden weniger ideale Innovationen mit weniger idealer Entwicklerakzeptanz und -gemeinschaft in die Bedeutungslosigkeit. In der heutigen hektischen und verwirrenden Welt der generativen KI tauchen täglich bessere „Möglichkeiten, Dinge zu tun“ auf, jede mit ihren Befürwortern, die mit ansteckendem Enthusiasmus ihre Vorzüge gegenüber anderen Innovationen vertreten.

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Ist DSPy, ausgesprochen als „dee-s-pie“, das neue Framework von Stanford NLP für Programmiersprachenmodelle eine weniger als ideale Innovation? Ist es ein Ersatz, wie einige seiner Befürworter behaupten, für Techniken des Prompt-Engineerings? Schließlich ist das Ziel des Frameworks, die kunstvolle und geschickte, aber mühsame und zerbrechliche Konstruktion von Prompts durch systematische, modulare und komponierbare Programme zu ersetzen?

In diesem Artikel untersuche ich, was an DSPy vielversprechend und verwirrend ist, was fehlt und verbessert werden muss und wie es modulare Pipelines erstellen kann, um mit LLMs zu interagieren. Anhand einiger End-to-End-Prompting-Beispiele werde ich etablierte Prompting-Techniken in äquivalente modulare DSPy-Versionen umwandeln und deren Verdienst bewerten. Sie können diese IPython-Notebooks auf Google Colab und Python-Apps auf GitHub durchsuchen.

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

DSPy Programmiermodell

Die ML-Community macht schnell Fortschritte bei Techniken für das Prompting von Sprachmodellen (LMs) und deren Integration in Pipelines zur Bewältigung komplexer Aufgaben. Aktuelle LM-Pipelines verlassen sich jedoch häufig auf harte „Prompt-Vorlagen“, die lang, zerbrechlich, spröde und von Hand erstellte Prompts sind, die durch Versuch und Irrtum entwickelt wurden.

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Dieser Ansatz, obwohl üblich, kann zerbrechlich, spröde und nicht skalierbar sein, ähnlich wie das manuelle Abstimmen von Klassifizierungsgewichten. Außerdem kann ein spezifischer oder elaborierter String-Prompt möglicherweise nicht gut auf verschiedene Pipelines, Sprachmodelle, Datenbereiche oder Eingaben generalisiert werden.

Daher schlagen die Forscher einen deklarativeren, systematischeren und programmatischeren Ansatz zur Interaktion mit Sprachmodellen vor – etwas, an das PyTorch- und Python-Entwickler gewöhnt sind, wenn sie Machine-Learning-Programme (ML) und damit zusammenhängende Konzepte entwickeln.

Das DSPy-Programmiermodell besteht aus drei hochrangigen Abstraktionen: Signaturen, Modulen und Telepromptern (auch als Optimierer bezeichnet). Signaturen abstrahieren und diktieren das Eingabe-/Ausgabeverhalten eines Moduls; Module ersetzen die aktuellen Hand-Prompting-Techniken und können als beliebige Pipelines zusammengesetzt werden; und Teleprompter, durch Kompilierung, optimieren alle Module in der Pipeline, um eine Metrik zu maximieren.

Beginnen wir mit den Signaturen.

Signaturen abstrahieren das Prompting

Eine DSPy-Signatur ist eine natürlichsprachige Funktionsdeklaration mit Typen: eine knappe Spezifikation, die beschreibt, was eine Texttransformation erreichen sollte (z. B. „verarbeite Fragen und liefere Antworten“), anstatt zu detaillieren, wie ein bestimmtes LM aufgefordert werden soll, diese Aufgabe auszuführen.

Als solche haben sie zwei Vorteile gegenüber Prompts. Erstens können sie in selbstverbessernde, pipeline-adaptive Prompts kompiliert oder durch Bootstrapping nützlicher Beispiele für jede Signatur feinabgestimmt werden. Zweitens verwalten sie strukturierte Formatierungs- und Parsing-Logik, wodurch die brüchige Zeichenfolgenmanipulation in Benutzerprogrammen verringert oder idealerweise beseitigt wird.

„Eine Signatur ist eine deklarative Spezifikation des Eingabe-/Ausgabeverhaltens eines DSPy-Moduls. Signaturen ermöglichen es Ihnen, dem LM mitzuteilen, was es tun soll, anstatt anzugeben, wie wir das LM auffordern sollen, es zu tun“, so die Dokumentation.

Sie können beispielsweise eine DSPy-Signatur deklarativ mit einer Kurzschreibung als Argument definieren. Effektiv erklärt diese Signatur nun eine Aufgabe als knappen Prompt: Gegeben eine Frage, liefere eine Antwort. Hier sind einige Beispiele für Kurzschreibungen:

import dspy
sig_1 = dspy.Signature("question -> answer")
sig_2 = dspy.Signature("document -> summary")
sig_3 = dspy.Signature("question, context -> answer")

Abgesehen von der Inline-Kurzschreibung zur Deklaration von Aufgaben können Sie eine klassenbasierte Signatur definieren, die Ihnen mehr Kontrolle über das Format, den Stil und die beschreibende Aufgabenbeschreibung der Eingabe-/Ausgabefelder gibt. Die Aufgabenbeschreibung ist eine Python-Docstring in der Klassendefinition. Und das Format, der Stil oder das Verhalten der Ausgabe kann ein beschreibendes und deklaratives Argument für dspy.OutputField sein, wodurch es einfacher ist, es anzupassen, anstatt Teil eines größeren Prompts zu sein.

class BasicQA(dspy.Signature):
  """Beantworte Fragen mit kurzen, sachlichen Antworten"""
  question = dspy.InputField()
  answer = dspy.OutputField(desc="oft zwischen 1 und 5 Wörtern",
                            prefix="Antwort auf die Frage:")

Intern konvertiert DSPy beide oben genannten deklarativen Formate in einen Prompt für das zugrunde liegende LM, wie in Abbildung 2 gezeigt. Optional können diese Prompts mit DSPy-Telepromptern (Optimierern) kompiliert werden, um iterativ einen optimierten LM-Prompt zu generieren (siehe den Abschnitt unten zu Optimierern), ähnlich wie Sie ein ML-Modell mit Lernoptimierern wie SGD in einem ML-Framework wie PyTorch optimieren würden.

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Die Verwendung der oben genannten klassenbasierten Signatur ist einfach und intuitiv.

generate_response  = dspy.Predict(BasicQA)
pred = generate_response(question="When was the last Solar Eclipse in the United States, and what states were covered in total darkness?"
print(f"Antwort: {pred.answer}")

👎👎👎: Die Verwendung einer Aufgabenbeschreibung als Python-Klassen-Docstring oder Kurzschreibung zur Generierung eines LM-Prompts, ohne einen Prompt von Hand zu erstellen, entspricht einer wesentlichen Behauptung des DSPy-Frameworks. Es fühlt sich an wie Python-Programmierung, nicht wie manuelles Erstellen zerbrechlicher Prompts. Die Umwandlung einiger Prompting-Technik-Beispiele oben in den Abbildungen 1(a) und 1(b) hat mir dieses Gefühl vermittelt und inspiriert.

Während die dspy.Signature-Klasse das grundlegende Bauelement ist, enthält DSPy auch integrierte Module, die sich gut für Prompting-Techniken wie Chain of Thought, ReAct, RAG, Program of Thought und komplexe Reasoning eignen.

Im Mittelpunkt aller dieser Module steht das dspy.Predict-Modul, auf das alle Module, einschließlich Signaturen, über ihre forward()-Funktionsaufrufe verweisen. Intern speichert Predict die Signatur und verwendet sie, um einen Prompt zu erstellen.

Erkunden wir diese Module als Nächstes.

Module erstellen komplexe Pipelines

Laut der DSPy-Dokumentation ist ein DSPy-Modul ein grundlegendes Bauelement zum Erstellen von DSPy-Pipelines oder -programmen, die Sprachmodelle verwenden. Jedes Modul abstrahiert eine Prompting-Technik, wie z. B. Chain of Thought oder ReAct, und ist verallgemeinert, um jede DSPy-Signatur zu behandeln.

Module können lernbare Parameter haben, einschließlich Prompt-Komponenten und LM-Gewichten. Als aufrufbare Klassen können sie mit Eingaben aufgerufen werden und geben Ausgaben zurück. Da sie Bausteine sind, können mehrere Module zu größeren komponierbaren Programmen als Pipelines kombiniert werden. Inspiriert von NN-Modulen in PyTorch sind DSPy-Module für LLM-Programme konzipiert.

Als aufrufbare Klassen können Module mit Eingaben aufgerufen werden und geben Ausgaben zurück. Da sie Bausteine sind, können mehrere Module zu größeren Programmen als Pipelines kombiniert werden. Inspiriert von NN-Modulen in PyTorch sind DSPy-Module für LLM-Programme konzipiert.

Denken Sie an Module als eine intelligente Abkürzung, um komplexe Prompting-Techniken zu vereinfachen. Sie sind wie vorgefertigte Blöcke, die Sie zusammensetzen können, um Ihr Programm zu erstellen. Das Erstellen eigener Module wird ermutigt und ist der Kern, um komplexe Daten-Pipeline-Programme in DSPy zu erstellen. Diese Module können als Standalone oder kombiniert als Pipelines für komplexere Aufgaben verwendet werden und können in verschiedenen Anwendungen eingesetzt werden.

Beispielsweise kann ich ein eigenständiges ChainOfThought-Modul mit einer Kurzschreibung der Signatur-Notation definieren.

class ChainOfThought(dspy.Module):
 def __init__( self, signature):
  super().__init__()
  self.predict = dspy.Signature(signature)
 # Überschreibe die forward-Funktion
 def forward(self, **kwargs):
  return self.predict(**kwargs)
# Erstelle eine Instanz der Klasse mit Kurzschreibung der Signatur-Notation
# als Argument
cot_generate = ChainOfThought("context, question → answer")
# Rufe die Instanz mit den in der Signatur angegebenen Eingabeparametern auf
response = cot_generate("context=....",
   "question=How to compute area of a triangle with height 5 feet and width 3 feet."
print(f"Fläche des Dreiecks: {response.answer}")

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Nehmen wir diese Idee einen Schritt weiter und erstellen eine komponierbare Pipeline mit dem oben definierten Baustein zusammen mit einem integrierten dspy.Retriever-Modul, um ein RAG DSPy-Programm zu veranschaulichen.

class RAGSignature(dspy.Signature):
      """
      Given a context and question, answer the question.
      """
      context = dspy.InputField()
      question = dspy.InputField()
      answer = dspy.OutputField()
class RAG(dspy.Module) :
      def __init__ ( self , num_passages=3) :
          super().__init__()
          # Retrieve will use the user's default retrieval settings
          # unless overridden .
          self.retrieve = dspy.Retrieve(k=num_passages)
          # ChainOfThought with signature that generates
          # answers given retrieval context & question .
          self.generate_answer = dspy.ChainOfThought(RAGSignature)
       def forward (self, question) :
           context = self.retrieve (question).passages
           return self.generate_answer(context=context, question=question)

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Um eine vollständige Implementierung eines naiven RAG mit DSPy-Modulen zu sehen, schauen Sie sich die Links in den Abbildungen 1(a) und 1(b) an.

👎👎👎: DSPy-Module sind Python-Deklarativcode, der Ihre Aufgabenlogik (von was-zu-tun anstelle von wie-zu-tun), Verhalten, Eingabe-/Ausgabeformat, Stil und jeden benutzerdefinierten Code kapselt. Es ist keine Notwendigkeit, einen Roman als elaborierten Prompt zu schreiben, keine Notwendigkeit, sich mit den Prompts mühsam durch Versuch und Irrtum zu bemühen. Stattdessen konstruieren Sie Ihren Workflow als Pipeline komponierbarer Blöcke. Ich bevorzuge es, Python-Code statt Englisch zu schreiben, obwohl ich das Schreiben liebe. Und lassen Sie DSPy die Arbeit erledigen, indem es den Prompt generiert und mit dem Sprachmodell interagiert.

Die integrierten Module, die sich gut für gängige Prompting-Techniken eignen, sind erweiterbar und anpassbar. Zum Zeitpunkt der Erstellung dieses Artikels waren die folgenden DSPy-Module verfügbar:

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Noch besser ist, dass Sie, wie bei ML-Modellen, diese Module mit DSPy-Optimierern durch Kompilierung für die effiziente Prompt-Generierung und Antwortbewertung optimieren können. Schauen wir uns als Nächstes an, wie wir das erreichen können.

Optimierung und Kompilierung von Modulen

Ähnlich wie die PyTorch-Optimierer, wie SGD, zur Minimierung des Verlusts und Maximierung der Genauigkeit in ML, bietet die DSPy-Optimierer-API die Möglichkeit, Trainingsbeispiele und eine Auswertungsmetrik zur Messung der Genauigkeit bereitzustellen. Wenn Sie mit PyTorch vertraut sind, wird Ihnen dieses Konzept vertraut sein.

Optimierer nehmen ein Trainingsset (um mittels Few-Shot-Learning in einem größeren In-Context-Prompt einige ausgewählte Beispiele zu lernen, wie der Prompt generiert werden soll) und eine Metrik (um die Nähe zur oder Übereinstimmung mit der korrekten Antwort zu messen) auf; sie generieren eine Instanz eines optimierten Programms, das verwendet werden kann, um ein DSPy-Programmmodul zu kompilieren. Aktuell unterstützt DSPy eine Reihe von integrierten Optimierern, von denen jeder in unterschiedlichem Maße darauf abzielt, Ihre Metrik zu maximieren.

Am besten veranschaulicht man dies anhand von Beispielcode. Betrachten Sie ein kleines Trainingsset von Beispielen, die Sie verwenden möchten, um ein DSPy-Modul für die Sentimentanalyse zu trainieren. Im Prompt-Engineering entspricht dies einer Few-Shot-Learning-Technik als Teil eines größeren In-Context-Prompts.

Die Antwort des Moduls nach der Interaktion mit dem Ziel-Sprachmodell ist entweder positiv, negativ oder neutral. Ihre Metrik kann dann überprüfen, ob die zurückgegebene Antwort eine dieser Sentiment-Kategorien ist – oder etwas Unsinniges.

Erstellen wir ein kurzes Trainingsset, eine Metrik und ein Modul. Beachten Sie, dass Metriken so einfach sein können, wie eine numerische Punktzahl (z. B. 0 oder 1), eine exakte Übereinstimmung (EM) oder F1 zurückzugeben, sowie ein vollständiges DSPy-Programm, das mehrere Bedenken bei der Vorhersage ausbalanciert und misst.

# Bewerte eine Metrik für die richtige Antwortkategorie
def evaluate_sentiment(example, pred, trace=None)->bool:
  return pred in ["positive", "negative", "neutral"]
def get_examples()-> List[dspy.Example]:
  trainset = [dspy.Example(sentence="""This movie is a true cinematic gem,
                                     blending an engaging plot with superb performances and stunning visuals. A masterpiece that leaves a lasting impression""",
                            sentiment="positive").with_inputs("sentence"),
              dspy.Example(sentence="""Regrettably, the film failed to live
                                     up to expectations, with a convoluted
                                     storyline, lackluster acting, and
                                     uninspiring cinematography.
                                     disappointment overall."""
                             sentiment="negative").with_inputs("sentence")
              dspy.Example(sentence="""The movie had its moments, offering
                                     a decent storyline and average
                                     performances. While not groundbreaking,
                                     it provided an enjoyable viewing
                                     experience.""",
                            sentiment="neutral").with_inputs("sentence")
             ...
           ]
      return trainset
# Definiere unser DSPy-Modul, das du optimieren und kompilieren möchtest
class ClassifyEmotion(dspy.Signature):
  """Klassifiziere die Emotion auf der Grundlage der Eingabesätze und liefere das Sentiment als Ausgabe"""
   sentence = dspy.InputField()
   sentiment = dspy.OutputField(desc="generiere Sentiment als positiv, negativ oder neutral")
from dspy.teleprompt import BootstrapFewShot
# Erstelle einen Optimierer
optimizer = BootstrapFewShot(metric=evaluate_sentiment,
trainset=get_examples())
compiled_classifier = optimizer.compile(ClassifyEmotion(),
trainset=get_examples()
# Verwende unseren kompilierten Klassifizierer, der gelernt hat, durch Bootstrapping einiger Beispiele, wie man die Antwort generiert
response = compiled_classifier(sentence="I can't believe how beautiful the sunset was tonight! The colors were breathtaking and it really made my day"
print(response.sentiment)

Erkundungstour durch DSPy: Ein Framework für Programmiermodelle für Sprachmodelle, nicht für Prompting

Intern erreicht alles oben Genannte Folgendes:

  1. Bootstrappen unseres Trainingssets zum Lernen mit Few-Shot-In-Context-Prompting
  2. Verwenden der Metrik, um zu bewerten, ob die Ausgabe eines der drei Sentiment-Kategorien vorhersagt
  3. Kompilieren des DSPy-Moduls
  4. Generieren von Prompts
  5. Verwenden des kompilierten Klassifizierers, um unsere Sätze mit dem besten Prompt zu klassifizieren

Omar Khattab und Arnav Singhvi et al. beschreiben den oben genannten Optimierungs- und Kompilierungsprozess, der drei Phasen durchläuft:

  1. Kandidatengenerierung: Wählen Sie den Kandidaten-Predictor-Modul aus, wenn mehr als eines vorhanden ist.
  2. Parameteroptimierung: Wählen Sie die Anweisungen oder Demonstrationen in den Prompts der Kandidaten aus und optimieren Sie sie dann mit unterschiedlichen LM-Gewichten für die beste Antwort.
  3. Höherstufige Programmoptimierung: Denken Sie an diese als Sprachcompiler-Codeoptimierung, bei der der Code für eine bessere Ausführung neu angeordnet wird. In DSPy werden komplizierte Pipelines als Ensembles vereinfacht und neu angeordnet, um den Steuerungsfluss zu ändern.

Um zu sehen, wie das DSPy-Framework Ihre Prompts optimiert und abgestimmt hat, drucken Sie einfach die Historie aller generierten Prompts mit diesem Befehl aus, wobei n > 0.

your_model.inpspect_history(n=3)

Dies gibt drei verschiedene optimierte Prompts aus, die für das LM generiert wurden. Um ein vollständiges Beispiel für ein Few-Shot-Beispiel mit Optimierer und Kompilierung zu sehen, schauen Sie sich das Notebook oder die Python-App für ReAct-Aufgaben in den Abbildungen 1(a) und 1(b) an.

Eine weitere Diskussion von Frederick Ros behandelt die Abstimmung und Optimierung von DSPy-Modulen. Schließlich bieten Omar Khattab et al. einige Fallstudien mit empirischen Daten, die darauf hindeuten, dass optimierte und kompilierte Module bei komplexen Reasoning-Aufgaben einen messbaren Effizienz-, Leistungs- und Genauigkeitsvorteil gegenüber nicht optimierten Modulen bieten.

👎👎👎: Das Konzept von Optimierern und Compilern im DSPy-Framework kann schwer zu verstehen sein, wirkt nicht intuitiv und mysteriös wie eine Blackbox. Obwohl sie ihre Ziele erreichen, sind sie in Bezug auf Klarheit und Einfachheit unzureichend: Warum nicht optimieren und kompilieren als einen einzigen API-Aufruf zusammenfassen, anstatt zwei separate Phasen? Außerdem ist die Dokumentation dürftig, ohne explizite Beispiele oder Illustrationen, die Licht ins Dunkel bringen und schärfer fokussieren.

Alle von mir untersuchten Ressourcen – Dokumentation und veröffentlichte Blogs – kommen nicht klar darin zurecht, dieses mächtige Konzept zu erläutern. Denn dieses Konzept ist von zentraler Bedeutung für den Aspekt der Selbstverbesserung und Optimierung des Frameworks. Aufgrund des Fehlens klarer Beispiele und praktischer Anwendungsfälle ist mir dieses Konzept entgangen, um den WOW-Faktor 🤯 in mir auszulösen.

DSPy End-to-End-Beispielprogramme

Programmierframeworks, so schreiben Omar Khattab und Arnav Singhvi et al., können anhand vieler Dimensionen bewertet werden, darunter Rechenleistung, Entwicklereffizienz, Intuitivität von Code und Konzepten usw. Die Autoren bewerten das DSPy-Programmierframework anhand dreier Hypothesen:

  • H1: Mit DSPy können wir handgefertigte Prompt-Strings durch knappe und gut definierte Module ersetzen, ohne die Qualität oder den Ausdrucksreichtum zu beeinträchtigen.
  • H2: Das Parametrisieren der Module und die Behandlung des Promptings als Optimierungsproblem macht DSPy besser geeignet, um sich an verschiedene LMs anzupassen, und es kann Experten-geschriebene Prompts übertreffen.
  • H3: Die daraus resultierende Modularität ermöglicht es, komplexe Pipelines gründlicher zu erforschen, die nützliche Leistungsmerkmale oder passende Metriken aufweisen.

Ich habe das DSPy-Framework verwendet, um alle meine Beispiele aus einem zuvor veröffentlichten Blog zum Prompt Engineering mit expliziten und elaborierten Prompting-Techniken zu konvertieren. Unter Verwendung des lokalen OLama-Sprachmodells und der integrierten Tools von DSPy wie Retrievern konnte ich modulare und komplexe Pipelines für komplexe Reasoning-Aufgaben erstellen.

NLP-Aufgaben

Ich habe DSPy-Signaturen verwendet, um auszudrücken, wie man Code für allgemeine natürliche Sprachverständnisfähigkeiten eines generischen LLM, wie z. B. ChatGPT, OLlama, Mistral und Llama 3-Serie, schreibt:

  • Textgenerierung oder -vervollständigung
  • Textzusammenfassung
  • Textextraktion
  • Textklassifizierung oder Sentimentanalyse
  • Textkategorisierung
  • Texttransformation und -übersetzung
  • Einfache und komplexe Reasoning

Dazu waren die DSPy-Module gewachsen. Der Code ist modular, deklarativ und es ist keine Geschichte mit Prompts erforderlich; keine Notwendigkeit für das CO-STAR-Prompt-Framework, um einen elaborierten Prompt von Hand zu erstellen. Siehe Notebooks und Python-Apps in den Abbildungen 1(a) und 1(b) im GenAI Cookbook GitHub-Repository.

Program of Thought-Aufgabe

Program of Thought (PoT) Prompting für LLMs beinhaltet die Bereitstellung einer Sequenz von Denkschritten im Prompt, um das Modell zur Lösung zu führen. Diese Technik hilft dem Modell, komplexe Probleme zu verarbeiten, indem sie in Zwischenschritte zerlegt werden, ähnlich wie ein Mensch es tun würde. Durch die Nachahmung menschlichen Denkens verbessert PoT-Prompting die Fähigkeit des Modells, Aufgaben zu bewältigen, die Logik, Schlussfolgerung und Programmierung erfordern.

Unter Verwendung des DSPy PoT-Moduls dspy.ProgramOfThought generieren die meisten dieser Beispiele Python-Code, um das Problem zu lösen. Es ist kaum notwendig, elaborierte Prompts anzugeben, nur eine knappe Aufgabenbeschreibung.

Siehe Notebooks und Python-Apps in den Abbildungen 1(a) und 1(b) im GenAI Cookbook GitHub-Repository.

Naives RAG

Erstaunlich einfach und modular können DSPy-Module verkettet oder gestapelt werden, um eine Pipeline zu erstellen. In unserem Fall besteht die Erstellung eines naiven RAG aus der Verwendung von dspy.Signature und dspy.ChainOfThought und der Klasse RAG (siehe Implementierung in dspy_utils).

Standardmäßig unterstützt DSPy eine Reihe von Retriever-Clients. Für dieses Beispiel habe ich das unterstützte Tool dspy.ColBERTv2 verwendet.

Siehe Notebooks und Python-Apps in den Abbildungen 1(a) und 1(b) im GenAI Cookbook GitHub-Repository.

ReAct-Aufgaben

In einem Artikel von Yao et al., 2022 vorgestellt, ist ReAct ein Paradigma für Reasoning und Acting, das LLM dazu anleitet, auf strukturierte Weise auf komplexe Abfragen zu reagieren. Reasoning und Aktionen sind verflochten und fortschreitend, so dass LLM schrittweise von einem Ergebnis zum nächsten fortschreitet, wobei das vorherige Ergebnis verwendet wird.

Die Ergebnisse deuten darauf hin, dass ReAct die Leistung in Sprach- und Entscheidungsaufgaben übertrifft und das menschliche Verständnis und Vertrauen in große Sprachmodelle (LLMs) verbessert. Es ist am besten, wenn es mit Chain-of-Thought (CoT)-Schritten kombiniert wird, die als einzelne Aufgaben mit Ergebnissen verwendet werden, die für den nächsten Schritt verwendet werden, wobei sowohl internes Wissen als auch externe Informationen während des Reasonings genutzt werden.

Diese Aufgabe war eine DSPy-Konvertierung des LLM ReAct-Prompting-Notebooks.

Siehe Notebooks und Python-Apps in den Abbildungen 1(a) und 1(b) im GenAI Cookbook GitHub-Repository.

👎👎👎: In allen oben genannten Prompt-Engineering-Aufgaben scheinen die Hypothesen H1 und H3 der Schöpfer von DSPy zu gelten und meinen Erwartungen zu entsprechen. H2 ist jedoch etwas unklar und unintuitiv, und ich konnte mir keinen Reim darauf machen. In gewisser Weise haben die Zuordnung von DSPy-Modulen zu allgemeinen Prompting-Aufgaben und die Verwendung von DSPy zur Erstellung modularer und deklarativer Programme statt expliziter und elaborierter Prompts die Hypothesen H1 und H2 untermauert.

Schlussfolgerung

In diesem Artikel haben wir das DSPy-Framework und das Programmiermodell behandelt, eine innovative, deklarative, systematische und modulare Methode zur Programmierung und Interaktion mit Sprachmodellen anstelle der Verwendung expliziter und elaborierter Prompts. Anhand umfangreicher Beispiele für Prompt-Engineering-Techniken, die in meinem vorherigen Blog erforscht wurden, habe ich Prompting-Techniken in ihre äquivalenten DSPy-Programme umgewandelt.

Dabei habe ich viele Aspekte von DSPy gelobt, die mir gefallen haben und die auch Python-Entwicklern vertraut sein dürften, die deklarative Methoden der Programmierung bevorzugen. Ich habe auch einige der Mängel von DSPy in Bezug auf Konzepte, dokumentierte Beispiele und fehlende Anwendungsfälle aufgezeigt. Zwei der drei Hypothesen, die in dem ursprünglichen Papier untersucht wurden, haben sich bei meiner programmatischen Bemühung als haltbar erwiesen: die Umwandlung elaborierter und expliziter Prompt-Engineering-Techniken in modulare und deklarative DSPy-Programme.

Ist das neue Framework von Stanford NLP für Programmiersprachenmodelle eine weniger als ideale Innovation? Wird es in die Bedeutungslosigkeit verschwinden?

Ich denke nicht. Obwohl es nicht so populär explodiert ist wie andere LLM-Frameworks wie LangChain und LlamaIndex, hat es eine wachsende Gemeinschaft, eine zunehmende Präsenz auf seinem GitHub (mit 924 Forks, 150 Mitwirkenden und über 12.000 Sternen) und lebhafte Diskussionen auf Reddit und im discord-Forum, daher ist es unwahrscheinlich, dass es in die Bedeutungslosigkeit verschwindet.

Ist es ein Ersatz, wie einige seiner Befürworter behaupten, für Techniken des Prompt-Engineerings? Es ist wahrscheinlich eine optionale Präferenz, wo anwendbar mit greifbaren Anwendungsfällen, die seine Wirksamkeit und Nutzung demonstrieren. Wenn mehr GenAI-, Daten-, KI-Pioniere wie Databricks das DSPy-Framework in ihr Ökosystem integrieren oder ein gut finanziertes Startup-Unternehmen hinter DSPy entsteht, werden wir wahrscheinlich eine weitere Verbreitung sehen.

Eine totale Ersetzung einer technologischen Innovation ist eine hyperbolische Behauptung; eine totale Ersetzung wird nur im Laufe der Zeit erreicht, nicht über Nacht. Es ist unwahrscheinlich, dass DSPy sofort handgefertigte Prompts und Prompt-Vorlagen-Engineering verdrängen oder verdrängen wird.

 

Referenzen und Ressourcen

[1, 2, 3, 4, 11, 13, 14, 15] https://arxiv.org/pdf/2310.03714

[5] https://dspy-docs.vercel.app/docs/building-blocks/signatures

[6] https://dspy-docs.vercel.app/docs/building-blocks/modules

[7, 8] https://www.theaidream.com/post/dspy-a-revolutionary-framework-for-programming-llms

[9] https://dspy-docs.vercel.app/docs/building-blocks/modules#what-other-dspy-modules-are-there-how-can-i-use-them

[10] https://medium.com/@frederick.ros/dspy-essentials-mastering-model-tuning-with-optimizers-32b1db951915

[12] https://towardsdatascience.com/intro-to-dspy-goodbye-prompting-hello-programming-4ca1c6ce3eb9

[16] https://www.databricks.com/blog/optimizing-databricks-llm-pipelines-dspy

[17] https://dspy-docs.vercel.app/docs/tutorials/examples

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert