In der Entwicklung von Anwendungen mit Large Language Models (LLMs) besteht eine Herausforderung darin, die natürlichsprachlichen Ausgaben des Modells in ein maschinenlesbares Format zu überführen. Während LLMs gut darin sind, Texte zu generieren, benötigen nachgelagerte Softwareprozesse (z. B. Datenbanken oder APIs) strukturierte Daten wie XML, JSON oder TOON. DSPy bietet integrierte Mechanismen, die über Prompt Engineering hinausgehen und die Typensicherheit von Python-Bibliotheken wie Pydantic nutzen.
Von Text zu Struktur mit Typisierung
Traditionell wird versucht, LLMs durch Anweisungen im Prompt (z. B. „Antworte nur im JSON-Format“) zur Ausgabe strukturierter Daten zu bewegen. Dieser Ansatz ist leider oft fehleranfällig, da das Modell invaliden Code oder zusätzlichen Konversationstext generieren kann. DSPy abstrahiert diesen Prozess durch die Verwendung von Typed Signatures (typisierten Signaturen). Anstatt das Ausgabeformat manuell im Prompt zu beschreiben, werden Python-Klassen (z.B. Pydantic-Modelle) als Zielformat definiert. DSPy instruiert das zugrunde liegende Modell automatisch, die Ausgabestruktur einzuhalten, und validiert das Ergebnis gegen das definierte Schema. Dies garantiert, dass die Rückgabewerte den erwarteten Datentypen (String, Integer, Listen) entsprechen. Der Vorteil liegt in der deterministischen Weiterverarbeitung: Das extrahierte Objekt kann direkt im Code verwendet werden, ohne dass komplexe Parsing-Logik mit regulären Ausdrücken notwendig ist.
Implementierung der JSON-Extraktion
Die folgende Implementierung zeigt, wie aus unstrukturiertem Text strukturierte Informationen extrahiert werden können.
Definition des Datenmodells
Zunächst muss die gewünschte Ausgabestruktur definiert werden. Hierfür eignet sich die Bibliothek pydantic, die eine strikte Typisierung ermöglicht. Das Ziel ist ein Objekt, das den Produktnamen, den Preis und eine Liste von Merkmalen enthält.
import dspy
from pydantic import BaseModel, Field
from typing import List
# Konfiguration des Language Models (hier als Beispiel OpenAI)
lm = dspy.LM('openai/gpt-4o-mini')
dspy.configure(lm=lm)
# Definition des Ziel-Datenmodells
class ProductSchema(BaseModel):
name: str = Field(..., description="Der genaue Name des Produkts.")
price: float = Field(..., description="Der Preis des Produkts als Zahl.")
features: List[str] = Field(..., description="Eine Liste der wichtigsten technischen Merkmale.")
Erstellung der Signatur
Die Signatur verbindet den Eingabetext mit dem Ausgabemodell. Durch die Verwendung von Type-Hints (: str, : ProductSchema) versteht DSPy die Anforderungen an Ein- und Ausgabe.
class ProductExtraction(dspy.Signature):
"""
Analysiert eine Produktbeschreibung und extrahiert strukturierte Daten
gemäß dem definierten Schema.
"""
description: str = dspy.InputField(desc="Der unstrukturierte Werbetext des Produkts.")
product_data: ProductSchema = dspy.OutputField(desc="Die extrahierten Produktinformationen als Objekt.")
3. Instanziierung des Moduls
Für Aufgaben, die eine strikte Einhaltung von Typen erfordern, wirddspy.Predict mit entsprechender Konfiguration verwendet. Dieser sorgt dafür, dass das LLM das Schema versteht und die Antwort validiert.
# Erstellen des Predictors mit der definierten Signatur
extractor = dspy.Predict(ProductExtraction)
Ausführung und Extraktion
Im nächsten Schritt wird ein beispielhafter Produkttext definiert und das Modul ausgeführt.
# Unstrukturierter Eingabetext (Santa Cruz Skateboard)
raw_text = """
Hol dir das Santa Cruz Classic Dot 80s Cruiser Skateboard für dein nächstes Abenteuer.
Dieses Board kostet aktuell 149,95 Euro und bietet echtes Retro-Feeling.
Es besteht aus 7-lagigem nordamerikanischem Ahorn und ist mit weichen
60mm Slime Balls Rollen ausgestattet, die perfekt für rauen Asphalt sind.
Zudem verfügt es über hochwertige Krux Achsen und das ikonische Logo-Design auf der Unterseite.
"""
# Ausführung der Extraktion
response = extractor(description=raw_text)
# Zugriff auf das extrahierte Pydantic-Objekt
extracted_data = response.product_data
Ergebnisse und Interpretation
Nach der Ausführung liegt das Ergebnis nicht als String, sondern als Instanz der Klasse ProductSchema vor. Dies ermöglicht den direkten programmgesteuerten Zugriff auf die Attribute.
Um das Ergebnis als JSON darzustellen, kann die Methode .model_dump_json() von Pydantic verwendet werden.
# Ausgabe als JSON-String
print(extracted_data.model_dump_json(indent=2))
Erwarteter Output:
{
"name": "Santa Cruz Classic Dot 80s Cruiser Skateboard",
"price": 149.95,
"features": [
"7-lagiges nordamerikanisches Ahorn",
"60mm Slime Balls Rollen",
"Krux Achsen"
]
}
Analyse des Ergebnisses
- Name: Der Produktname wurde korrekt isoliert.
- Preis: Der Preis wurde von einem String („149.95 Euro“) in eine Gleitkommazahl (
149.95) konvertiert. Dies ist entscheidend für Berechnungen. - Merkmale: Die Features ausdem im Text wurde in eine Liste von Strings (
List[str]) überführt.
Das Modell hat die semantische Bedeutung des Textes verstanden und in die syntaktisch korrekte Struktur überführt, die durch das ProductSchema vorgegeben wurde.
Zusammenfassung
Die Nutzung von DSPy in Kombination mit Pydantic ermöglicht eine robuste Extraktion strukturierter Daten aus unstrukturiertem Text. Durch die Definition von Typen in der Signatur entfällt die Notwendigkeit für komplexes Prompt Engineering zur Formatierung der Ausgabe. Dies erhöht die Verlässlichkeit von LLM-Anwendungen, die Daten weiterverarbeiten müssen, erheblich. Am morgigen Tag der Challenge wird dieses Konzept durch die Einführung von dspy.Assert erweitert, um noch spezifischere Bedingungen an die extrahierten Daten zu stellen.
