Prompt engineering

Ottimizza LLM con DSPy: Una Guida Passo-Passo per Costruire, Ottimizzare e Valutare Sistemi AI

mm
Aggiungi Unite.AI alle tue fonti preferite su Google
DSPy is a framework for algorithmically optimizing LM prompts and weights

Man mano che le capacità dei modelli linguistici di grandi dimensioni (LLM) continuano ad espandersi, lo sviluppo di sistemi AI robusti che sfruttano il loro potenziale è diventato sempre più complesso. Gli approcci convenzionali spesso implicano tecniche di prompt intricate, generazione di dati per il fine-tuning e guida manuale per assicurarsi che si aderisca a vincoli specifici del dominio. Tuttavia, questo processo può essere tedioso, soggetto a errori e fortemente dipendente dall’intervento umano.

Entra DSPy, una piattaforma rivoluzionaria progettata per semplificare lo sviluppo di sistemi AI alimentati da LLM. DSPy introduce un approccio sistematico all’ottimizzazione dei prompt e dei pesi dei modelli, consentendo agli sviluppatori di costruire applicazioni sofisticate con uno sforzo manuale minimo.

In questa guida completa, esploreremo i principi fondamentali di DSPy, la sua architettura modulare e la gamma di funzionalità potenti che offre. Esamineremo anche esempi pratici, dimostrando come DSPy possa trasformare il modo in cui si sviluppano sistemi AI con LLM.

Cosa è DSPy e Perché Ne Hai Bisogno?

DSPy è una piattaforma che separa il flusso del tuo programma (moduli) dai parametri (prompt dei modelli e pesi) di ogni passaggio. Questa separazione consente l’ottimizzazione sistematica dei prompt e dei pesi dei modelli, permettendoti di costruire sistemi AI complessi con maggiore affidabilità, prevedibilità e aderenza a vincoli specifici del dominio.

Tradizionalmente, lo sviluppo di sistemi AI con LLM ha comportato un processo laborioso di suddivisione del problema in passaggi, creazione di prompt intricati per ogni passaggio, generazione di esempi sintetici per il fine-tuning e guida manuale dei modelli per aderire a vincoli specifici. Questo approccio non era solo tempo-dipendente, ma anche soggetto a errori, poiché anche piccoli cambiamenti nella pipeline, nel modello o nei dati potevano richiedere un’estesa rielaborazione dei prompt e dei passaggi di fine-tuning.

DSPy affronta queste sfide introducendo un nuovo paradigma: ottimizzatori. Questi algoritmi guidati dai modelli possono regolare i prompt e i pesi delle chiamate ai modelli, dati una metrica da massimizzare. Automatizzando il processo di ottimizzazione, DSPy consente agli sviluppatori di costruire sistemi AI robusti con un minimo intervento manuale, migliorando l’affidabilità e la prevedibilità delle uscite dei modelli.

Architettura Modulare di DSPy

Al cuore di DSPy si trova un’architettura modulare che facilita la composizione di sistemi AI complessi. La piattaforma fornisce un set di moduli predefiniti che astraggono varie tecniche di prompt, come dspy.ChainOfThought e dspy.ReAct. Questi moduli possono essere combinati e composti in programmi più grandi, permettendo agli sviluppatori di costruire pipeline intricate personalizzate in base alle loro esigenze specifiche.

Ogni modulo incapsula parametri apprendibili, inclusi le istruzioni, gli esempi a pochi shot e i pesi del modello. Quando un modulo viene invocato, gli ottimizzatori di DSPy possono regolare questi parametri per massimizzare la metrica desiderata, assicurando che le uscite del modello aderiscano ai vincoli e ai requisiti specificati.

Ottimizzazione con DSPy

DSPy introduce una gamma di ottimizzatori potenti progettati per migliorare le prestazioni e l’affidabilità dei tuoi sistemi AI. Questi ottimizzatori sfruttano algoritmi guidati dai modelli per regolare i prompt e i pesi delle chiamate ai modelli, massimizzando la metrica specificata e aderendo a vincoli specifici del dominio.

Alcuni degli ottimizzatori chiave disponibili in DSPy includono:

  1. BootstrapFewShot: Questo ottimizzatore estende la firma generando e includendo automaticamente esempi ottimizzati all’interno del prompt inviato al modello, implementando l’apprendimento a pochi esempi.
  2. BootstrapFewShotWithRandomSearch: Applica BootstrapFewShot più volte con ricerca casuale su dimostrazioni generate, selezionando il miglior programma sull’ottimizzazione.
  3. MIPRO: Genera istruzioni e esempi a pochi shot in ogni passaggio, con la generazione delle istruzioni che è consapevole dei dati e delle dimostrazioni. Utilizza l’ottimizzazione bayesiana per cercare efficacemente nello spazio di generazione delle istruzioni e delle dimostrazioni attraverso i tuoi moduli.
  4. BootstrapFinetune: Distilla un programma DSPy basato su prompt in aggiornamenti di peso per modelli più piccoli, consentendoti di fine-tuning il modello sottostante per una maggiore efficienza.

Sfruttando questi ottimizzatori, gli sviluppatori possono ottimizzare sistematicamente i loro sistemi AI, assicurando uscite di alta qualità e aderendo a vincoli specifici del dominio e ai requisiti.

Iniziare con DSPy

Per illustrare il potere di DSPy, esaminiamo un esempio pratico di costruzione di un sistema di generazione aumentata di recupero (RAG) per la risposta alle domande.

Passo 1: Configurazione del Modello Linguistico e del Modello di Recupero

Il primo passo consiste nel configurare il modello linguistico (LM) e il modello di recupero (RM) all’interno di DSPy.

Per installare DSPy, esegui:


pip install dspy-ai

DSPy supporta più API di LM e RM, nonché l’hosting di modelli locali, rendendolo facile integrare i modelli preferiti.


import dspy

<p># Configura il LM e il 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>

Passo 2: Caricamento del Dataset

Successivamente, carichiamo il dataset HotPotQA, che contiene una raccolta di coppie di domande e risposte complesse tipicamente risposte in modo multi-hop.


from dspy.datasets import HotPotQA

<p># Carica il dataset
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)</p>

<p># Specifica il campo 'domanda' come input
trainset = [x.with_inputs('domanda') for x in dataset.train]
devset = [x.with_inputs('domanda') for x in dataset.dev]</p>

Passo 3: Creazione delle Firme

DSPy utilizza le firme per definire il comportamento dei moduli. In questo esempio, definiamo una firma per il compito di generazione della risposta, specificando i campi di input (contesto e domanda) e il campo di output (risposta).


<p>class GenerateAnswer(dspy.Signature):
"""Rispondi alle domande con risposte brevi e fattoidi."""

contesto = dspy.InputField(desc="può contenere fatti rilevanti")
domanda = dspy.InputField()
risposta = dspy.OutputField(desc="spesso tra 1 e 5 parole")

Passo 4: Creazione della Pipeline

Costruiamo la nostra pipeline RAG come un modulo DSPy, che consiste in un metodo di inizializzazione (__init__) per dichiarare i sottomoduli (dspy.Retrieve e dspy.ChainOfThought) e un metodo forward (forward) per descrivere il flusso di controllo della risposta alla domanda utilizzando questi moduli.


<p>class RAG(dspy.Module):
def __init__(self, num_passaggi=3):
super().__init__()

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

def forward(self, domanda):
contesto = self.retrieve(domanda).passaggi
previsione = self.generate_answer(contesto=contesto, domanda=domanda)
return dspy.Prediction(contesto=contesto, risposta=previsione.risposta)

Passo 5: Ottimizzazione della Pipeline

Con la pipeline definita, possiamo ora ottimizzarla utilizzando gli ottimizzatori di DSPy. In questo esempio, utilizziamo l’ottimizzatore BootstrapFewShot, che genera e seleziona prompt efficaci per i nostri moduli in base a un set di training e a una metrica di convalida.


<p>from dspy.teleprompt import BootstrapFewShot</p>

<p># Metrica di convalida
def validate_contesto_e_risposta(esempio, previsione, traccia=None):
risposta_EM = dspy.evaluate.risposta_esatta(esempio, previsione)
risposta_PM = dspy.evaluate.risposta_passaggio(esempio, previsione)
return risposta_EM and risposta_PM

<p># Configura l'ottimizzatore
teleprompter = BootstrapFewShot(metric=validate_contesto_e_risposta)

<p># Compila il programma
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

Passo 6: Valutazione della Pipeline

Dopo la compilazione del programma, è essenziale valutarne le prestazioni su un set di sviluppo per assicurarsi che raggiunga la precisione e l’affidabilità desiderate.


from dspy.evaluate import Evaluate

<p># Configura il valutatore
evaluate = Evaluate(devset=devset, metric=validate_contesto_e_risposta, num_threads=4, display_progress=True, display_table=0)

<p># Valuta il programma RAG compilato
evaluation_result = evaluate(compiled_rag)

<p>print(f"Risultato della valutazione: {evaluation_result}")

Passo 7: Ispezione della Storia del Modello

Per una comprensione più approfondita delle interazioni del modello, è possibile esaminare le generazioni più recenti ispezionando la storia del modello.


<p># Ispeziona la storia del modello
turbo.inspect_history(n=1)

Passo 8: Effettuare Previsioni

Con la pipeline ottimizzata e valutata, è possibile utilizzarla per effettuare previsioni su nuove domande.


<p># Esempio di domanda
domanda = "Quale premio ha ricevuto il primo libro di Gary Zukav?"

<p># Effettua una previsione utilizzando il programma RAG compilato
previsione = compiled_rag(domanda)

<p>print(f"Domanda: {domanda}")
print(f"Risposta: {previsione.risposta}")
print(f"Contesti recuperati: {previsione.contesto}")

Esempio Minimo Funzionante con DSPy

Ora, esaminiamo un altro esempio minimo funzionante utilizzando il dataset GSM8K e il modello OpenAI GPT-3.5-turbo per simulare compiti di prompt all’interno di DSPy.

Configurazione

Assicurati che il tuo ambiente sia configurato correttamente:


<p>import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric</p>

<p># Configura il modello linguistico
turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250)
dspy.settings.configure(lm=turbo)

<p># Carica le domande matematiche dal dataset GSM8K
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]

print(gsm8k_trainset)

Il gsm8k_trainset e il gsm8k_devset contengono un elenco di esempi con ogni esempio che ha un campo domanda e un campo risposta.

Definisci il Modulo

Definisci un programma personalizzato utilizzando il modulo ChainOfThought per il ragionamento passo-passo:


<p>class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought("domanda -&gt; risposta")

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

Compila e Valuta il Modello

Ora compila il modello con il teleprompter BootstrapFewShot:


<p>from dspy.teleprompt import BootstrapFewShot</p>

<p># Configura l'ottimizzatore
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)

<p># Ottimizza utilizzando la metrica gsm8k
teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config)
optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)

<p># Configura il valutatore
from dspy.evaluate import Evaluate</p>

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

<p># Ispeziona la storia del modello
turbo.inspect_history(n=1)

Questo esempio dimostra come configurare l’ambiente, definire un modulo personalizzato, compilare un modello e valutarne le prestazioni utilizzando il dataset e la configurazione del teleprompter forniti.

Gestione dei Dati in DSPy

DSPy opera con set di training, sviluppo e test. Per ogni esempio nei tuoi dati, di solito hai tre tipi di valori: input, etichette intermedie e etichette finali. Mentre le etichette intermedie o finali sono opzionali, avere alcuni esempi di input è essenziale.

Creazione di Oggetti Esempio

Gli oggetti esempio in DSPy sono simili ai dizionari Python, ma vengono forniti con utili utility:


<p>qa_pair = dspy.Example(domanda="Questa è una domanda?", risposta="Questa è una risposta.")

<p>print(qa_pair)
print(qa_pair.domanda)
print(qa_pair.risposta)

Output:


<p>Example({'domanda': 'Questa è una domanda?', 'risposta': 'Questa è una risposta.'}) (input_keys=None)
Questa è una domanda?
Questa è una risposta.

Specificare le Chiavi di Input

In DSPy, gli oggetti Example hanno un metodo with_inputs() per marcare campi specifici come input:


<p>print(qa_pair.with_inputs("domanda"))
print(qa_pair.with_inputs("domanda", "risposta"))

I valori possono essere acceduti utilizzando l’operatore di punto, e i metodi come inputs() e labels() restituiscono nuovi oggetti Example che contengono solo chiavi di input o non-input, rispettivamente.

Ottimizzatori in DSPy

Un ottimizzatore DSPy regola i parametri di un programma DSPy (cioè prompt e/o pesi del modello) per massimizzare metriche specificate. DSPy offre vari ottimizzatori predefiniti, ognuno dei quali utilizza strategie diverse.

Ottimizzatori Disponibili

  • BootstrapFewShot: Genera esempi a pochi shot utilizzando dati di input e output etichettati.
  • BootstrapFewShotWithRandomSearch: Applica BootstrapFewShot più volte con ricerca casuale su dimostrazioni generate.
  • COPRO: Genera e raffina nuove istruzioni per ogni passaggio, ottimizzandole con ascesa coordinata.
  • MIPRO: Ottimizza istruzioni ed esempi a pochi shot utilizzando l’ottimizzazione bayesiana.

Scegliere un Ottimizzatore

Se non si è sicuri di dove iniziare, utilizzare BootstrapFewShotWithRandomSearch:

Per pochi dati (10 esempi), utilizzare BootstrapFewShot.
Per dati leggermente più grandi (50 esempi), utilizzare BootstrapFewShotWithRandomSearch.
Per set di dati più grandi (300+ esempi), utilizzare MIPRO.

Ecco come utilizzare 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)

Salvare e Caricare Programmi Ottimizzati

Dopo aver eseguito un programma attraverso un ottimizzatore, salvarlo per un uso futuro:

optimized_program.save(YOUR_SAVE_PATH)

Caricare un programma salvato:


<p>loaded_program = YOUR_PROGRAM_CLASS()
loaded_program.load(path=YOUR_SAVE_PATH)

Funzionalità Avanzate: Affermazioni DSPy

Le affermazioni DSPy automatizzano l’applicazione di vincoli computazionali sui modelli linguistici, migliorando l’affidabilità, la prevedibilità e la correttezza delle uscite del modello.

Utilizzare le Affermazioni

Definisci funzioni di convalida e dichiara affermazioni in seguito alla generazione del modello. Ad esempio:


<p>dspy.Suggest(
len(query) &lt;= 100,
&quot;La query dovrebbe essere breve e meno di 100 caratteri&quot;,
)

<p>dspy.Suggest(
validate_query_distinction_local(prev_queries, query),
"La query dovrebbe essere distinta da: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(prev_queries)),
)

Trasformare Programmi con Affermazioni


<p>from dspy.primitives.assertions import assert_transform_module, backtrack_handler</p>

<p>baleen_with_assertions = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler)

Alternativamente, attiva le affermazioni direttamente sul programma:


<p>baleen_with_assertions = SimplifiedBaleenAssertions().activate_assertions()

Ottimizzazioni Guidate dalle Affermazioni

Le affermazioni DSPy funzionano con le ottimizzazioni DSPy, in particolare con BootstrapFewShotWithRandomSearch, inclusi impostazioni come:

  • Compilazione con affermazioni
  • Compilazione + inferenza con affermazioni

Conclusione

DSPy offre un approccio potente e sistematico all’ottimizzazione dei modelli linguistici e dei loro prompt. Seguendo i passaggi descritti in questi esempi, puoi costruire, ottimizzare e valutare sistemi AI complessi con facilità. La progettazione modulare di DSPy e gli ottimizzatori avanzati consentono un’integrazione efficiente e efficace di vari modelli linguistici, rendendolo uno strumento prezioso per chiunque lavori nel campo del NLP e dell’AI.

Indipendentemente dal fatto che tu stia costruendo un semplice sistema di risposta alle domande o una pipeline più complessa, DSPy fornisce la flessibilità e la robustezza necessarie per raggiungere prestazioni elevate e affidabilità.

Ho trascorso gli ultimi cinque anni immergendomi nel mondo affascinante del Machine Learning e del Deep Learning. La mia passione e la mia esperienza mi hanno portato a contribuire a oltre 50 progetti di ingegneria del software diversi, con un focus particolare su AI/ML. La mia curiosità in corso mi ha anche portato verso l'elaborazione del linguaggio naturale, un campo che sono ansioso di esplorare ulteriormente.