Prompt engineering

Optimer LLM med DSPy: En trin-for-trin guide til at bygge, optimere og evaluere AI-systemer

mm
Føj Unite.AI til dine foretrukne kilder på Google
DSPy is a framework for algorithmically optimizing LM prompts and weights

Da mulighederne for store sprogmodeller (LLM’er) fortsætter med at udvide sig, er det blevet mere komplekst at udvikle robuste AI-systemer, der udnytter deres potentiale. Traditionelle metoder indebærer ofte intrikerede prompt-teknikker, data-generering til finjustering og manuel vejledning for at sikre overholdelse af domænespecifikke begrænsninger. Dette proces kan være tidskrævende, fejlbehæftet og stærkt afhængig af menneskelig indgriben.

Indtast DSPy, et revolutionerende framework designet til at strømline udviklingen af AI-systemer drevet af LLM’er. DSPy introducerer en systematisk tilgang til at optimere LM-prompts og vægte, hvilket giver udviklere mulighed for at bygge avancerede applikationer med minimal manuel indsats.

I denne omfattende guide vil vi udforske DSPy’s kerneprincipper, dets modulære arkitektur og det bredt udvalg af kraftfulde funktioner, det tilbyder. Vi vil også dykke ned i praktiske eksempler, der demonstrerer, hvordan DSPy kan transformere måden, du udvikler AI-systemer med LLM’er på.

Hvad er DSPy, og hvorfor har du brug for det?

DSPy er et framework, der adskiller programfladen (moduler) fra parametrene (LM-prompts og vægte) for hvert trin. Denne adskillelse giver mulighed for en systematisk optimering af LM-prompts og vægte, hvilket giver dig mulighed for at bygge komplekse AI-systemer med større pålidelighed, forudsigelighed og overholdelse af domænespecifikke begrænsninger.

Traditionelt set indebærer udvikling af AI-systemer med LLM’er en møjsom proces med at bryde problemet ned i trin, fremstille intrikerede prompts for hvert trin, generere syntetiske eksempler til finjustering og manuel vejledning for at sikre, at LLM’erne overholder bestemte begrænsninger. Denne tilgang var ikke kun tidskrævende, men også fejlbehæftet, da selv mindre ændringer af pipeline, LM eller data kunne kræve omfattende omarbejdning af prompts og finjusterings-trin.

DSPy løser disse udfordringer ved at introducere en ny paradigm: optimeringsalgoritmer. Disse LM-drevne algoritmer kan justere prompts og vægte for dine LM-kald, givet en metrik, du ønsker at maksimere. Ved at automatisere optimeringsprocessen giver DSPy udviklere mulighed for at bygge robuste AI-systemer med minimal manuel indsats, hvilket forbedrer pålideligheden og forudsigeligheden af LM-udgang.

DSPy’s modulære arkitektur

I hjertet af DSPy ligger en modulær arkitektur, der faciliterer kompositionen af komplekse AI-systemer. Frameworket tilbyder en række indbyggede moduler, der abstraherer forskellige prompt-teknikker, såsom dspy.ChainOfThought og dspy.ReAct. Disse moduler kan kombineres og komponeres til større programmer, hvilket giver udviklere mulighed for at bygge intrikerede pipelines tilpasset deres specifikke krav.

Hver modul indeholder lærbare parametre, herunder instruktioner, few-shot-eksempler og LM-vægte. Når en modul aktiveres, kan DSPy’s optimeringsalgoritmer finjustere disse parametre for at maksimere den ønskede metrik, hvilket sikrer, at LM-udgangen overholder de specifikke begrænsninger og krav.

Optimering med DSPy

DSPy introducerer en række kraftfulde optimeringsalgoritmer designet til at forbedre ydeevnen og pålideligheden af dine AI-systemer. Disse optimeringsalgoritmer udnytter LM-drevne algoritmer til at justere prompts og vægte for dine LM-kald, maksimerer den specifikke metrik, mens de overholder domænespecifikke begrænsninger.

Nogle af de nøgleoptimeringsalgoritmer, der er tilgængelige i DSPy, omfatter:

  1. BootstrapFewShot: Denne optimeringsalgoritme udvider signaturerne ved automatisk at generere og inkludere optimerede eksempler i prompten, der sendes til modellen, og implementerer few-shot-læring.
  2. BootstrapFewShotWithRandomSearch: Denne optimeringsalgoritme anvender BootstrapFewShot flere gange med tilfældig søgning over genererede demonstrationer og vælger det bedste program over optimeringen.
  3. MIPRO: Denne optimeringsalgoritme genererer instruktioner og few-shot-eksempler i hvert trin, hvor instruktionsgenereringen er data- og demonstrationssensitiv. Den anvender Bayesian-optimering til at effektivt søge over rummet af generationsinstruktioner og demonstrationer over dine moduler.
  4. BootstrapFinetune: Denne optimeringsalgoritme destillerer en prompt-baseret DSPy-program til vægt-opdateringer for mindre LM’er, hvilket giver dig mulighed for at finjustere den underliggende LLM til forbedret effektivitet.

Ved at udnytte disse optimeringsalgoritmer kan udviklere systematisk optimere deres AI-systemer, hvilket sikrer højkvalitets-udgang, mens de overholder domænespecifikke begrænsninger og krav.

Introduktion til DSPy

For at illustrere DSPy’s kraft, skal vi gå igennem et praktisk eksempel på at bygge et retrieval-augmenteret generationssystem (RAG) til spørgsmål-svar.

Trin 1: Konfiguration af sprogmodellen og retrieval-modellen

Det første trin indebærer konfiguration af sprogmodellen (LM) og retrieval-modellen (RM) i DSPy.

For at installere DSPy, skal du køre:


pip install dspy-ai

DSPy understøtter multiple LM- og RM-API’er, samt lokal model-vært, hvilket gør det let at integrere dine foretrukne modeller.


import dspy

<p># Konfigurer LM og 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>

Trin 2: Indlæsning af datasettet

Herefter skal vi indlæse HotPotQA-datasettet, der indeholder en samling af komplekse spørgsmål-svar-par, der typisk besvares på en multi-hop-måde.


from dspy.datasets import HotPotQA

<p># Indlæs datasettet
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)</p>

<p># Specificer 'spørgsmål'-feltet som input
trainset = [x.with_inputs('spørgsmål') for x in dataset.train]
devset = [x.with_inputs('spørgsmål') for x in dataset.dev]</p>

Trin 3: Bygning af signaturer

DSPy anvender signaturer til at definere modulernes adfærd. I dette eksempel vil vi definere en signatur for opgaven med at generere svar, hvor vi specificerer input-felterne (kontekst og spørgsmål) og output-feltet (svar).


<p>class GenerateAnswer(dspy.Signature):
&quot;&quot;&quot;Besvar spørgsmål med korte faktiske svar.&quot;&quot;&quot;</p>

<p>kontekst = dspy.InputField(desc=&quot;kan indeholde relevante fakta&quot;)
spørgsmål = dspy.InputField()
svar = dspy.OutputField(desc=&quot;ofte mellem 1 og 5 ord&quot;)</p>

Trin 4: Bygning af pipeline

Vi skal bygge vores RAG-pipeline som en DSPy-modul, der består af en initialiseringsmetode (__init__) til at erklære undermodulerne (dspy.Retrieve og dspy.ChainOfThought) og en forward-metode (forward) til at beskrive kontrollfladen for at besvare spørgsmålet ved hjælp af disse moduler.


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

<p>self.retrieve = dspy.Retrieve(k=num_passages)
self.generate_answer = dspy.ChainOfThought(GenerateAnswer)</p>

<p>def forward(self, spørgsmål):
kontekst = self.retrieve(spørgsmål).passages
prediction = self.generate_answer(kontekst=kontekst, spørgsmål=spørgsmål)
return dspy.Prediction(kontekst=kontekst, svar=prediction.svar)</p>

Trin 5: Optimering af pipeline

Med pipeline-definieret kan vi nu optimere den ved hjælp af DSPy’s optimeringsalgoritmer. I dette eksempel vil vi anvende BootstrapFewShot-optimeringsalgoritmen, der genererer og vælger effektive prompts for vores moduler baseret på et træningsset og en valideringsmetrik.


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

<p># Valideringsmetrik
def validate_context_and_answer(eksempel, pred, trace=None):
answer_EM = dspy.evaluate.answer_exact_match(eksempel, pred)
answer_PM = dspy.evaluate.answer_passage_match(eksempel, pred)
return answer_EM and answer_PM</p>

<p># Konfigurer optimeringsalgoritmen
teleprompter = BootstrapFewShot(metric=validate_context_and_answer)</p>

<p># Kompiler programmet
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)</p>

Trin 6: Evaluering af pipeline

Efter at have kompilert programmet er det vigtigt at evaluere dets ydeevne på et udviklingssæt for at sikre, at det opfylder de ønskede krav til nøjagtighed og pålidelighed.


from dspy.evaluate import Evaluate

<p># Konfigurer evaluator
evaluate = Evaluate(devset=devset, metric=validate_context_and_answer, num_threads=4, display_progress=True, display_table=0)</p>

<p># Evaluér det kompilerede RAG-program
evaluation_result = evaluate(compiled_rag)</p>

<p>print(f&amp;EVALUATION_RESULT: {evaluation_result})</p>

Trin 7: Inspektion af modellens historik

For en dybere forståelse af modellens interaktioner kan du se på de seneste generationer ved at inspicere modellens historik.


<p># Inspect modellens historik
turbo.inspect_history(n=1)</p>

Trin 8: Foretagelse af forudsigelser

Med pipeline-optimeret og evalueret kan du nu anvende den til at foretage forudsigelser på nye spørgsmål.


<p># Eksempel-spørgsmål
spørgsmål = &quot;Hvilken pris modtog Gary Zukavs første bog?&quot;</p>

<p># Foretag en forudsigelse ved hjælp af det kompilerede RAG-program
prediction = compiled_rag(spørgsmål)</p>

<p>print(f&amp;SPØRGSMÅL: {spørgsmål})
print(f&amp;SVAR: {prediction.svar})
print(f&amp;INDHENTET KONTEKST: {prediction.kontekst})</p>

Minimalt fungerende eksempel med DSPy

Lad os gå igennem et andet minimalt fungerende eksempel, der anvender GSM8K-datasettet og OpenAI GPT-3.5-turbo-modellen til at simulere prompt-opgaver i DSPy.

Konfiguration

Først skal du sikre, at din miljø er korrekt konfigureret:


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

<p># Konfigurer LM
turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250)
dspy.settings.configure(lm=turbo)</p>

<p># Indlæs matematiske spørgsmål fra GSM8K-datasettet
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]</p>

print(gsm8k_trainset)

Definér modulen

Herefter skal du definere en brugerdefineret program, der anvender ChainOfThought-modulen til trin-for-trin-reasonering:


<p>class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought(&quot;spørgsmål -&gt; svar&quot;)</p>

<p>def forward(self, spørgsmål):
return self.prog(spørgsmål=spørgsmål)</p>

Kompiler og evaluér modellen

Nu skal du kompilere det med BootstrapFewShot-teleprompteren:


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

<p># Konfigurer optimeringsalgoritmen
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)</p>

<p># Optimér med gsm8k-metrik
teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config)
optimized_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)</p>

<p># Konfigurer evaluator
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>

<p># Inspect modellens historik
turbo.inspect_history(n=1)</p>

Dette eksempel demonstrerer, hvordan du kan konfigurere din miljø, definere en brugerdefineret modul, kompilere en model og rigorøst evaluere dens ydeevne ved hjælp af det tilgængelige dataset og teleprompt-konfigurationer.

Datastyring i DSPy

DSPy opererer med trænings-, udviklings- og test-sæt. For hvert eksempel i dine data har du typisk tre typer værdier: input, mellem-læbel og slut-læbel. Mens mellem- eller slut-læbel er valgfrit, er det vigtigt at have få eksempel-input-værdier.

Oprettelse af eksempel-objekter

Eksempel-objekter i DSPy ligner Python-dictionaries, men kommer med nyttige værktøjer:


<p>qa_pair = dspy.Example(spørgsmål=&quot;Dette er et spørgsmål?&quot;, svar=&quot;Dette er et svar.&quot;)</p>

<p>print(qa_pair)
print(qa_pair.spørgsmål)
print(qa_pair.svar)</p>

Udskrift:


<p>Example({&quot;spørgsmål&quot;: &quot;Dette er et spørgsmål?&quot;, &quot;svar&quot;: &quot;Dette er et svar.&quot;}) (input_keys=None)
Dette er et spørgsmål?
Dette er et svar.</p>

Specificering af input-nøgle

I DSPy har eksempel-objekter en with_inputs()-metode til at markere bestemte felter som input:


<p>print(qa_pair.with_inputs(&quot;spørgsmål&quot;))
print(qa_pair.with_inputs(&quot;spørgsmål&quot;, &quot;svar&quot;))</p>

Værdier kan tilgås ved hjælp af punkt-operatoren, og metoder som inputs() og labels() returnerer nye eksempel-objekter, der indeholder kun input- eller non-input-nøgle-værdier.

Optimeringsalgoritmer i DSPy

En DSPy-optimeringsalgoritme justerer parametrene for en DSPy-program (dvs. prompts og/eller LM-vægte) for at maksimere specifikke metrikker. DSPy tilbyder forskellige indbyggede optimeringsalgoritmer, hver med forskellige strategier.

Tilgængelige optimeringsalgoritmer

  • BootstrapFewShot: Genererer few-shot-eksempler ved hjælp af labeled input- og output-data.
  • BootstrapFewShotWithRandomSearch: Anvender BootstrapFewShot flere gange med tilfældig søgning over genererede demonstrationer.
  • COPRO: Genererer og forbedrer nye instruktioner for hvert trin, optimerer dem med koordinat-ascent.
  • MIPRO: Optimerer instruktioner og few-shot-eksempler ved hjælp af Bayesian-optimering.

Valg af optimeringsalgoritme

Hvis du er usikker på, hvor du skal starte, anvend BootstrapFewShotWithRandomSearch:

For meget lidt data (10 eksempler), anvend BootstrapFewShot.
For lidt mere data (50 eksempler), anvend BootstrapFewShotWithRandomSearch.
For større dataset (300+ eksempler), anvend MIPRO.

Her er, hvordan du anvender 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=DIN_METRIK_HER, **config)
optimized_program = teleprompter.compile(DIT_PROGRAM_HER, trainset=DIT_TRAINSET_HER)</p>

Gemme og indlæsning af optimerede programmer

Efter at have kørt et program gennem en optimeringsalgoritme kan du gemme det til fremtidig brug:

optimized_program.save(DIN_GEMME_STI)

Indlæs et gemt program:


<p>loaded_program = DIT_PROGRAM_KLASS()
loaded_program.load(path=DIN_INDLÆSNING_STI)</p>

Avancerede funktioner: DSPy-assertioner

DSPy-assertioner automatiserer gennemtvingelsen af beregningsbegrænsninger på LM’er, hvilket forbedrer pålideligheden, forudsigeligheden og korrektheden af LM-udgang.

Brug af assertioner

Definér valideringsfunktioner og erklær assertioner efter modellens generation. For eksempel:


<p>dspy.Suggest(
len(query) &amp;lt;= 100,
&quot;Spørgsmålet skal være kort og mindre end 100 tegn&quot;,
)</p>

<p>dspy.Suggest(
validate_query_distinction_local(prev_queries, query),
&quot;Spørgsmålet skal være forskelligt fra: &quot; + &quot;; &quot;.join(f&quot;{i+1}) {q}&quot; for i, q in enumerate(prev_queries)),
)</p>

Transformation af programmer med assertioner


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

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

Alternativt kan du aktivere assertioner direkte på programmet:


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

Assertion-drevne optimeringer

DSPy-assertioner arbejder med DSPy-optimeringer, især med BootstrapFewShotWithRandomSearch, herunder indstillinger som:

  • Kompilering med assertioner
  • Kompilering + inferens med assertioner

Konklusion

DSPy tilbyder en kraftfuld og systematisk tilgang til at optimere sprogmodeller og deres prompts. Ved at følge de trin, der er beskrevet i disse eksempler, kan du bygge, optimere og evaluere komplekse AI-systemer med letthed. DSPy’s modulære design og avancerede optimeringsalgoritmer giver mulighed for effektiv og effektiv integration af forskellige sprogmodeller, hvilket gør det til et værdifuldt værktøj for alle, der arbejder med NLP og AI.

Uanset om du bygger et simpelt spørgsmål-svar-system eller en mere kompleks pipeline, giver DSPy dig den fleksibilitet og robusthed, der er nødvendig for at opnå høj ydeevne og pålidelighed.

Jeg har brugt de sidste fem år på at dykke ned i den fascinerende verden af Machine Learning og Deep Learning. Min passion og ekspertise har ført mig til at bidrage til over 50 forskellige software-ingeniørprojekter, med en særlig fokus på AI/ML. Min fortsatte nysgerrighed har også ført mig mod Natural Language Processing, et felt jeg er ivrig efter at udforske yderligere.