Ingegneria rapida
Ottimizza LLM con DSPy: una guida passo passo per creare, ottimizzare e valutare i sistemi di intelligenza artificiale
Poiché le capacità dei modelli linguistici di grandi dimensioni (LLM) continuano ad espandersi, lo sviluppo di robusti sistemi di intelligenza artificiale che sfruttano il loro potenziale è diventato sempre più complesso. Gli approcci convenzionali spesso implicano complesse tecniche di suggerimento, generazione di dati per la messa a punto e guida manuale per garantire il rispetto dei vincoli specifici del dominio. Tuttavia, questo processo può essere noioso, soggetto a errori e fortemente dipendente dall’intervento umano.
entra DSPy, un framework rivoluzionario progettato per semplificare lo sviluppo di sistemi di intelligenza artificiale basati su LLM. DSPy introduce un approccio sistematico all'ottimizzazione dei prompt e dei pesi LM, consentendo agli sviluppatori di creare applicazioni sofisticate con il minimo sforzo manuale.
In questa guida completa, esploreremo i principi fondamentali di DSPy, la sua architettura modulare e la gamma di potenti funzionalità che offre. Ci immergeremo anche in esempi pratici, dimostrando come DSPy possa trasformare il modo in cui si sviluppano sistemi di intelligenza artificiale con LLM.
Cos'è DSPy e perché ne hai bisogno?
DSPy è un framework che separa il flusso del tuo programma (modules) dai parametri (prompt e pesi LM) di ogni passaggio. Questa separazione consente l'ottimizzazione sistematica dei prompt e dei pesi LM, consentendo di creare sistemi di intelligenza artificiale complessi con maggiore affidabilità , prevedibilità e aderenza ai vincoli specifici del dominio.
Tradizionalmente, lo sviluppo di sistemi di intelligenza artificiale con LLM comportava un laborioso processo di scomposizione del problema in passaggi, creazione di suggerimenti complessi per ogni passaggio, generazione di esempi sintetici per la messa a punto e guida manuale dei LM affinché aderissero a vincoli specifici. Questo approccio non solo richiedeva molto tempo ma era anche soggetto a errori, poiché anche piccole modifiche alla pipeline, al LM o ai dati potevano richiedere un'ampia rielaborazione dei prompt e delle fasi di messa a punto.
DSPy affronta queste sfide introducendo un nuovo paradigma: ottimizzatori. Questi algoritmi basati su LM possono ottimizzare i suggerimenti e i pesi delle chiamate LM, in base a una metrica che desideri massimizzare. Automatizzando il processo di ottimizzazione, DSPy consente agli sviluppatori di creare robusti sistemi di intelligenza artificiale con un intervento manuale minimo, migliorando l'affidabilità e la prevedibilità degli output LM.
Architettura modulare di DSPy
Al centro di DSPy c’è un’architettura modulare che facilita la composizione di sistemi IA complessi. Il framework fornisce una serie di moduli integrati che astraggono varie tecniche di prompt, come dspy.ChainOfThought e dspy.ReAct. Questi moduli possono essere combinati e composti in programmi più ampi, consentendo agli sviluppatori di creare pipeline complesse su misura per le loro esigenze specifiche.
Ogni modulo incapsula parametri apprendibili, tra cui istruzioni, esempi di pochi scatti e pesi LM. Quando un modulo viene richiamato, gli ottimizzatori di DSPy possono ottimizzare questi parametri per massimizzare la metrica desiderata, garantendo che gli output del LM rispettino i vincoli e i requisiti specificati.
Ottimizzazione con DSPy
DSPy introduce una gamma di potenti ottimizzatori progettati per migliorare le prestazioni e l'affidabilità dei tuoi sistemi IA. Questi ottimizzatori sfruttano algoritmi basati su LM per ottimizzare i prompt e i pesi delle chiamate LM, massimizzando la metrica specificata e rispettando i vincoli specifici del dominio.
Alcuni degli ottimizzatori chiave disponibili in DSPy includono:
- BootstrapFewShot: questo ottimizzatore estende la firma generando e includendo automaticamente esempi ottimizzati all'interno del prompt inviato al modello, implementando l'apprendimento a pochi scatti.
- BootstrapFewShotWithRandomSearch: Si applica
BootstrapFewShotpiù volte con ricerca casuale sulle dimostrazioni generate, selezionando il programma migliore rispetto all'ottimizzazione. - MIPRO: genera istruzioni ed esempi di poche riprese in ogni passaggio, con la generazione di istruzioni in grado di riconoscere i dati e la dimostrazione. Utilizza l'ottimizzazione bayesiana per effettuare ricerche efficaci nello spazio delle istruzioni e delle dimostrazioni di generazione dei moduli.
- BootstrapFinetune: distilla un programma DSPy basato su prompt in aggiornamenti del peso per LM più piccoli, consentendo di ottimizzare gli LLM sottostanti per una maggiore efficienza.
Sfruttando questi ottimizzatori, gli sviluppatori possono ottimizzare sistematicamente i propri sistemi di intelligenza artificiale, garantendo risultati di alta qualità nel rispetto dei vincoli e dei requisiti specifici del dominio.
Iniziare con DSPy
Per illustrare la potenza di DSPy, esaminiamo un esempio pratico di creazione di un sistema di generazione aumentata dal recupero (RAG) per le risposte alle domande.
Passaggio 1: impostazione del modello linguistico e del modello di recupero
Il primo passaggio prevede la configurazione del modello linguistico (LM) e del modello di recupero (RM) all'interno di DSPy.
Per installare DSPy eseguire:
pip install dspy-ai
DSPy supporta più API LM e RM, nonché l'hosting di modelli locali, semplificando l'integrazione dei tuoi modelli preferiti.
import dspy # Configure the LM and 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)
Passaggio 2: caricamento del set di dati
Successivamente, caricheremo il dataset HotPotQA, che contiene una raccolta di coppie complesse di domande e risposte, a cui in genere si risponde in modalità multi-hop.
from dspy.datasets import HotPotQA
# Load the dataset
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)
# Specify the 'question' field as the input
trainset = [x.with_inputs('question') for x in dataset.train]
devset = [x.with_inputs('question') for x in dataset.dev]
Passaggio 3: creazione di firme
DSPy utilizza le firme per definire il comportamento dei moduli. In questo esempio, definiremo una firma per l'attività di generazione delle risposte, specificando i campi di input (contesto e domanda) e il campo di output (risposta).
class GenerateAnswer(dspy.Signature): """Answer questions with short factoid answers.""" context = dspy.InputField(desc="may contain relevant facts") question = dspy.InputField() answer = dspy.OutputField(desc="often between 1 and 5 words")
Passaggio 4: costruzione della pipeline
Costruiremo 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.
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)
Passaggio 5: ottimizzazione della pipeline
Una volta definita la pipeline, possiamo ottimizzarla utilizzando gli ottimizzatori di DSPy. In questo esempio, utilizzeremo l'ottimizzatore BootstrapFewShot, che genera e seleziona prompt efficaci per i nostri moduli in base a un set di training e a una metrica per la convalida.
from dspy.teleprompt import BootstrapFewShot # Validation metric 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 # Set up the optimizer teleprompter = BootstrapFewShot(metric=validate_context_and_answer) # Compile the program compiled_rag = teleprompter.compile(RAG(), trainset=trainset)
Passaggio 6: valutazione della pipeline
Dopo aver compilato il programma, è essenziale valutarne le prestazioni su un set di sviluppo per garantire che soddisfi la precisione e l'affidabilità desiderate.
from dspy.evaluate import Evaluate
# Set up the evaluator
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)
# Evaluate the compiled RAG program
evaluation_result = evaluate(compiled_rag)
print(f"Evaluation Result: {evaluation_result}")
Passaggio 7: ispezione della cronologia del modello
Per una comprensione più approfondita delle interazioni del modello, è possibile esaminare le generazioni più recenti esaminando la cronologia del modello.
# Inspect the model's history turbo.inspect_history(n=1)
Passaggio 8: fare previsioni
Con la pipeline ottimizzata e valutata, ora puoi utilizzarla per fare previsioni su nuove domande.
# Example question
question = "Which award did Gary Zukav's first book receive?"
# Make a prediction using the compiled RAG program
prediction = compiled_rag(question)
print(f"Question: {question}")
print(f"Answer: {prediction.answer}")
print(f"Retrieved Contexts: {prediction.context}")
Esempio di lavoro minimo con DSPy
Ora, esaminiamo un altro esempio minimo funzionante utilizzando il Set di dati GSM8K e il modello OpenAI GPT-3.5-turbo per simulare attività di prompt all'interno di DSPy.
Impostare
Innanzitutto, assicurati che il tuo ambiente sia configurato correttamente:
import dspy from dspy.datasets.gsm8k import GSM8K, gsm8k_metric # Set up the LM turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250) dspy.settings.configure(lm=turbo) # Load math questions from the GSM8K dataset gsm8k = GSM8K() gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10] print(gsm8k_trainset)
. gsm8k_treno e gsm8k_devset i set di dati contengono un elenco di esempi in cui ciascun esempio ha un campo di domanda e risposta.
Definire il modulo
Successivamente, definisci un programma personalizzato utilizzando il modulo ChainOfThought per il ragionamento passo passo:
class CoT(dspy.Module): def __init__(self): super().__init__() self.prog = dspy.ChainOfThought("question -> answer") def forward(self, question): return self.prog(question=question)
Compilare e valutare il modello
Ora compilalo con il file BootstrapFewShot teleprompter:
from dspy.teleprompt import BootstrapFewShot # Set up the optimizer config = dict(max_bootstrapped_demos=4, max_labeled_demos=4) # Optimize using the gsm8k_metric teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config) optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset) # Set up the evaluator 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) # Inspect the model's history turbo.inspect_history(n=1)
Questo esempio dimostra come impostare l'ambiente, definire un modulo personalizzato, compilare un modello e valutarne rigorosamente le prestazioni utilizzando il set di dati fornito e le configurazioni del teleprompter.
Gestione dei dati in DSPy
DSPy opera con set di formazione, sviluppo e test. Per ogni esempio nei tuoi dati, in genere hai tre tipi di valori: input, etichette intermedie ed etichette finali. Sebbene le etichette intermedie o finali siano facoltative, è essenziale disporre di alcuni input di esempio.
Creazione di oggetti di esempio
Gli oggetti di esempio in DSPy sono simili ai dizionari Python ma sono dotati di utili utilità :
qa_pair = dspy.Example(question="This is a question?", answer="This is an answer.") print(qa_pair) print(qa_pair.question) print(qa_pair.answer)
Produzione:
Example({'question': 'This is a question?', 'answer': 'This is an answer.'}) (input_keys=None)
This is a question?
This is an answer.
Specifica dei tasti di input
In DSPy, gli oggetti Esempio hanno un metodo with_inputs() per contrassegnare campi specifici come input:
print(qa_pair.with_inputs("question")) print(qa_pair.with_inputs("question", "answer"))
È possibile accedere ai valori utilizzando l'operatore punto e metodi come input() e label() restituiscono nuovi oggetti Esempio contenenti rispettivamente solo chiavi di input o non di input.
Ottimizzatori in DSPy
Un ottimizzatore DSPy ottimizza i parametri di un programma DSPy (ad esempio, prompt e/o pesi LM) per massimizzare le metriche specificate. DSPy offre vari ottimizzatori integrati, ciascuno dei quali utilizza strategie diverse.
Ottimizzatori disponibili
- BootstrapFewShot: genera esempi di pochi scatti utilizzando i punti dati di input e output etichettati forniti.
- BootstrapFewShotWithRandomSearch: applica BootstrapFewShot più volte con ricerca casuale sulle dimostrazioni generate.
- COPRO: Genera e perfeziona nuove istruzioni per ogni passaggio, ottimizzandole con la salita delle coordinate.
- MIPRO: ottimizza le istruzioni e gli esempi con poche riprese utilizzando l'ottimizzazione bayesiana.
Scelta di un ottimizzatore
Se non sai da dove iniziare, usa BootstrapFewShotWithRandomSearch:
Per pochissimi dati (10 esempi), utilizzare BootstrapFewShot.
Per un numero leggermente maggiore di dati (50 esempi), utilizzare BootstrapFewShotWithRandomSearch.
Per set di dati più grandi (oltre 300 esempi), utilizza MIPRO.
Ecco come utilizzare BootstrapFewShotWithRandomSearch:
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=YOUR_METRIC_HERE, **config) optimized_program = teleprompter.compile(YOUR_PROGRAM_HERE, trainset=YOUR_TRAINSET_HERE)
Salvataggio e caricamento di programmi ottimizzati
Dopo aver eseguito un programma tramite un ottimizzatore, salvalo per un uso futuro:
programma_ottimizzato.save(IL TUO_SAVE_PATH)
Caricare un programma salvato:
loaded_program = YOUR_PROGRAM_CLASS() loaded_program.load(path=YOUR_SAVE_PATH)
Funzionalità avanzate: Asserzioni DSPy
Le asserzioni DSPy automatizzano l'applicazione dei vincoli computazionali sui LM, migliorando l'affidabilità , la prevedibilità e la correttezza degli output LM.
Utilizzo delle asserzioni
Definire le funzioni di validazione e dichiarare le asserzioni dopo la rispettiva generazione del modello. Per esempio:
dspy.Suggest(
len(query) <= 100,
"Query should be short and less than 100 characters",
)
dspy.Suggest(
validate_query_distinction_local(prev_queries, query),
"Query should be distinct from: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(prev_queries)),
)
Trasformare i programmi con le asserzioni
from dspy.primitives.assertions import assert_transform_module, backtrack_handler baleen_with_assertions = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler)
In alternativa, attiva le asserzioni direttamente sul programma:
baleen_with_assertions = SimplifiedBaleenAssertions().activate_assertions()
Ottimizzazioni basate sulle asserzioni
Le asserzioni DSPy funzionano con le ottimizzazioni DSPy, in particolare con BootstrapFewShotWithRandomSearch, incluse impostazioni come:
- Compilazione con asserzioni
- Compilazione + Inferenza con asserzioni
Conclusione
DSPy offre un approccio potente e sistematico all'ottimizzazione dei modelli linguistici e dei relativi prompt. Seguendo i passaggi descritti in questi esempi, è possibile costruire, ottimizzare e valutare sistemi di intelligenza artificiale complessi con facilità . Il design modulare e gli ottimizzatori avanzati di DSPy consentono un'integrazione efficiente ed efficace di diversi modelli linguistici, rendendolo uno strumento prezioso per chiunque lavori nel campo dell'elaborazione del linguaggio naturale e dell'intelligenza artificiale.
Che si tratti di realizzare un semplice sistema di domande e risposte o una pipeline più complessa, DSPy offre la flessibilità e la robustezza necessarie per ottenere elevate prestazioni e affidabilità .












