Prompt engineering

Optimer LLM med DSPy: En trinnvis guide til å bygge, optimere og evaluere AI-systemer

mm
DSPy is a framework for algorithmically optimizing LM prompts and weights

Ettersom evnene til store språkmodeller (LLM) fortsetter å utvides, har utvikling av robuste AI-systemer som utnytter deres potensiale blitt stadig mer kompleks. Konvensjonelle metoder innebærer ofte intrikate prompt-teknikker, datagenerering for finjustering og manuell veiledning for å sikre overholdelse av domenespesifikke begrensninger. Dette prosessen kan være tidskrevende, feilfølsom og sterkt avhengig av menneskelig inngripen.

DSPy er et revolusjonerende rammeverk designet for å forenkle utviklingen av AI-systemer drevet av LLM. DSPy innfører en systematisk tilnærming til å optimere LM-prompter og vekter, som muliggjør utviklere å bygge sofistikerte applikasjoner med minimal manuell innsats.

I denne omfattende guiden vil vi utforske de grunnleggende prinsippene i DSPy, dens modulære arkitektur og de kraftfulle funksjonene det tilbyr. Vi vil også dykke ned i praktiske eksempler som demonstrerer hvordan DSPy kan transformere måten du utvikler AI-systemer med LLM.

Hva er DSPy, og hvorfor trenger du det?

DSPy er et rammeverk som skiller programstrømmen fra parameterne (LM-prompter og vekter) for hver enkelt trinn. Denne skille muliggjør en systematisk optimalisering av LM-prompter og vekter, som gjør det mulig å bygge komplekse AI-systemer med større pålitelighet, forutsigbarhet og overholdelse av domenespesifikke begrensninger.

Tradisjonelt har utvikling av AI-systemer med LLM innebærer en tidskrevende prosess med å bryte ned problemet i trinn, lage intrikate prompter for hvert trinn, generere syntetiske eksempler for finjustering og manuell veiledning for å sikre overholdelse av bestemte begrensninger. Denne tilnærmingen var ikke bare tidskrevende, men også feilfølsom, da selv små endringer i røret, LM eller data kunne nødvendiggjøre omfattende omarbeidelse av prompter og finjusteringstrinn.

DSPy møter disse utfordringene ved å innføre en ny paradigme: optimalisatorer. Disse LM-drevne algoritmene kan finjustere promptene og vektene for LM-kall, gitt en metode du ønsker å maksimere. Ved å automatisere optimaliseringsprosessen, gir DSPy utviklere mulighet til å bygge robuste AI-systemer med minimal manuell inngripen, og forbedrer påliteligheten og forutsigbarheten av LM-utdata.

DSPy’s modulære arkitektur

I hjertet av DSPy ligger en modulær arkitektur som muliggjør komposisjon av komplekse AI-systemer. Rammeverket tilbyr en rekke innebygde moduler som abstraherer ulike prompt-teknikker, som dspy.ChainOfThought og dspy.ReAct. Disse modulene kan kombineres og komponeres til større programmer, som muliggjør utviklere å bygge intrikate rør tilpasset deres spesifikke krav.

Hver modul inkapslerer lærbare parametre, inkludert instruksjoner, få-shot-eksempler og LM-vektorer. Når en modul aktiveres, kan DSPy’s optimalisatorer finjustere disse parameterne for å maksimere den ønskede metoden, og sikre at LM-utdataene overholder de spesifiserte begrensningene og kravene.

Optimere med DSPy

DSPy innfører en rekke kraftfulle optimalisatorer designet for å forbedre ytelsen og påliteligheten av dine AI-systemer. Disse optimalisatorene utnytter LM-drevne algoritmer for å finjustere promptene og vektene for LM-kall, og maksimere den spesifiserte metoden mens de overholder domenespesifikke begrensninger.

Noen av de viktigste optimalisatorene som er tilgjengelige i DSPy inkluderer:

  1. BootstrapFewShot: Denne optimalisatoren utvider signaturer ved å automatisk generere og inkludere optimerte eksempler i prompten som sendes til modellen, og implementerer få-shot-læring.
  2. BootstrapFewShotWithRandomSearch: Denne optimalisatoren anvender BootstrapFewShot flere ganger med tilfeldig søk over genererte demonstrasjoner, og velger det beste programmet over optimaliseringen.
  3. MIPRO: Denne optimalisatoren genererer instruksjoner og få-shot-eksempler i hvert trinn, med instruksjonsgenerering som er data- og demonstrasjonsbevisst. Den bruker Bayesian-Optimizing for å effektivt søke over rommet av genereringsinstruksjoner og demonstrasjoner over modulene.
  4. BootstrapFinetune: Denne optimalisatoren destillerer en prompt-basert DSPy-program til vektoppdateringer for mindre LM, og muliggjør finjustering av underliggende LLM for bedre effisiens.

Ved å utnytte disse optimalisatorene, kan utviklere systematisk optimere sine AI-systemer, og sikre høykvalitetsutdata mens de overholder domenespesifikke begrensninger og krav.

Komme i gang med DSPy

For å illustrere kraften til DSPy, la oss gå gjennom et praktisk eksempel på å bygge et retrieval-augmentert genereringsystem (RAG) for spørsmål-svar.

Trinn 1: Konfigurere språkmodellen og hentingmodellen

Det første trinnet innebærer å konfigurere språkmodellen (LM) og hentingmodellen (RM) i DSPy.

For å installere DSPy, kjør:


pip install dspy-ai

DSPy støtter flere LM- og RM-API-er, samt lokale modellhåndtering, og gjør det enkelt å 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>

Trinn 2: Last inn datasettet

Neste trinn er å laste inn HotPotQA-datasettet, som inneholder en samling komplekse spørsmål-svar-par som vanligvis besvares på en multi-hop-måte.


from dspy.datasets import HotPotQA

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

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

Trinn 3: Bygge signaturer

DSPy bruker signaturer for å definere oppførselen til moduler. I dette eksemplet vil vi definere en signatur for oppgaven å generere svar, og spesifisere inndatafeltene (kontekst og spørsmål) og utdatafeltet (svar).


<p>class GenerateAnswer(dspy.Signature):
"""Besvar spørsmål med korte faktoid-svar."""

kontekst = dspy.InputField(desc="kan inneholde relevante fakta")
spørsmål = dspy.InputField()
svar = dspy.OutputField(desc="ofte mellom 1 og 5 ord")

Trinn 4: Bygge røret

Vi vil bygge vårt RAG-rør som en DSPy-modul, som består av en init-metode for å erklære undermoduler (dspy.Retrieve og dspy.ChainOfThought) og en forward-metode for å beskrive kontrollflyten for å besvare spørsmålet ved hjelp av disse modulene.


<p>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, spørsmål):
kontekst = self.retrieve(spørsmål).passages
prediksjon = self.generate_answer(kontekst=kontekst, spørsmål=spørsmål)
return dspy.Prediction(kontekst=kontekst, svar=prediksjon.svar)

Trinn 5: Optimere røret

Med røret definert, kan vi nå optimere det ved hjelp av DSPy’s optimalisatorer. I dette eksemplet vil vi bruke BootstrapFewShot-optimatisatoren, som genererer og velger effektive prompter for våre moduler basert på et treningssett og en metode for validering.


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

<p># Valideringsmetode
def valider_kontekst_og_svar(eksempel, pred, spor=None):
svar_EM = dspy.evaluate.svar_nøyaktig_treffe(eksempel, pred)
svar_PM = dspy.evaluate.svar_passasje_treffe(eksempel, pred)
return svar_EM and svar_PM</p>

<p># Sett opp optimalisatoren
teleprompter = BootstrapFewShot(metric=valider_kontekst_og_svar)</p>

<p># Kompilér programmet
kompilert_rag = teleprompter.compile(RAG(), trainset=trainset)</p>

Trinn 6: Evaluere røret

Etter å ha kompilert programmet, er det viktig å evaluere dets ytelse på et utviklingssett for å sikre at det møter de ønskede kravene til nøyaktighet og pålitelighet.


from dspy.evaluate import Evaluate

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

<p># Evaluér det kompilerte RAG-programmet
evalueringsresultat = evaluate(kompilert_rag)</p>

<p>print(f"Evaluering Resultat: {evalueringsresultat}")</p>

Trinn 7: Inspectere modellhistorikk

For en dypere forståelse av modellens interaksjoner, kan du se på de siste genereringene ved å inspisere modellens historikk.


<p># Inspecter modellens historikk
turbo.inspect_history(n=1)</p>

Trinn 8: Gjøre prediksjoner

Med røret optimert og evaluert, kan du nå bruke det til å gjøre prediksjoner på nye spørsmål.


<p># Eksempel-spørsmål
spørsmål = "Hva er tittelen på Gary Zukavs første bok?"</p>

<p># Gjør en prediksjon ved hjelp av det kompilerte RAG-programmet
prediksjon = kompilertrag(spørsmål)</p>

<p>print(f"Spørsmål: {spørsmål}")
print(f"Svar: {prediksjon.svar}")
print(f"Hentede kontekster: {prediksjon.kontekst}")</p>

Minimalt arbeids eksempel med DSPy

La oss nå gå gjennom et annet minimalt arbeids eksempel som bruker GSM8K-datasettet og OpenAI GPT-3.5-turbo-modellen for å simulere prompt-oppdrag i DSPy.

Oppsett

Først må du sikre at din miljø er korrekt konfigurert:


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

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

<p># Last inn matematikk-spørsmål fra GSM8K-datasettet
gsm8k = GSM8K()
gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]</p>

print(gsm8k_trainset)

Definere modulen

Neste trinn er å definere en egen program som bruker ChainOfThought-modulen for stegvis resonnering:


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

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

Kompilér og evaluér modellen

Nå kan du kompilere det med BootstrapFewShot-teleprompteren:


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

<p># Sett opp optimalisatoren
config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)</p>

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

<p># Sett opp 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(optimalt_cot)</p>

<p># Inspecter modellens historikk
turbo.inspect_history(n=1)</p>

Dette eksemplet demonstrerer hvordan du kan sette opp din miljø, definere en egen modul, kompilere en modell og grundig evaluere dens ytelse ved hjelp av det tilgjengelige datasettet og teleprompt-konfigurasjonene.

Datahåndtering i DSPy

DSPy opererer med trenings-, utviklings- og testsett. For hvert eksempel i dine data, har du vanligvis tre typer verdier: inndata, mellomliggende etiketter og endelige etiketter. Mens mellomliggende eller endelige etiketter er valgfrie, er det viktig å ha noen få eksempel-inndata.

Opprette eksempel-objekter

Eksempel-objekter i DSPy er lignende Python-ordbøker, men kommer med nyttige verktøy:


<p>qa_par = dspy.Example(spørsmål="Dette er et spørsmål?", svar="Dette er et svar.")</p>

<p>print(qa_par)
print(qa_par.spørsmål)
print(qa_par.svar)</p>

Utdata:


<p>Eksempel({'spørsmål': 'Dette er et spørsmål?', 'svar': 'Dette er et svar.'}) (inndata_nøkler=None)
Dette er et spørsmål?
Dette er et svar.</p>

Spesifisere inndata-nøkler

I DSPy har eksempel-objekter en metode for å markere bestemte felt som inndata:


<p>print(qa_par.with_inputs("spørsmål"))
print(qa_par.with_inputs("spørsmål", "svar"))</p>

Verdier kan aksesseres ved hjelp av punkt-operatoren, og metoder som inputs() og labels() returnerer nye eksempel-objekter som inneholder bare inndata eller ikke-inndata-nøkler.

Optimalisatorer i DSPy

En DSPy-optimalisator finjusterer parameterne til et DSPy-program (dvs. prompter og/eller LM-vektorer) for å maksimere spesifiserte metrikker. DSPy tilbyr flere innebygde optimalisatorer, hver med ulike strategier.

Tilgjengelige optimalisatorer

  • BootstrapFewShot: Genererer få-shot-eksempler ved hjelp av labeled inndata og utdata-punkter.
  • BootstrapFewShotWithRandomSearch: Anvender BootstrapFewShot flere ganger med tilfeldig søk over genererte demonstrasjoner.
  • COPRO: Genererer og finjusterer nye instruksjoner for hvert trinn, og optimaliserer dem med koordinat-stigning.
  • MIPRO: Optimerer instruksjoner og få-shot-eksempler ved hjelp av Bayesian-Optimizing.

Velge en optimalisator

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

For svært lite data (10 eksempler), bruk BootstrapFewShot.
For litt mer data (50 eksempler), bruk BootstrapFewShotWithRandomSearch.
For større datasett (300+ eksempler), bruk MIPRO.

Her er hvordan du kan bruke 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_METRIKK_HER, **config)
optimalt_program = teleprompter.compile(DITT_PROGRAM_HER, trainset=DITT_TRENINGSSETT_HER)</p>

Lagre og last inn optimaliserte programmer

Etter å ha kjørt et program gjennom en optimalisator, kan du lagre det for fremtidig bruk:

optimalt_program.save(DITT_LAGRINGSSTI)

Last inn et lagret program:


<p>lastet_inn_program = DITT_PROGRAMKLASS()
lastet_inn_program.load(path=DITT_LAGRINGSSTI)</p>

Avanserte funksjoner: DSPy-påstander

DSPy-påstander automatiserer håndhevingen av beregningsbegrensninger på LM, og forbedrer påliteligheten, forutsigbarheten og riktigheten av LM-utdata.

Bruke påstander

Definér valideringsfunksjoner og erklær påstander etter modellgenereringen. For eksempel:


<p>dspy.Suggest(
len(spørsmål) &lt;= 100,
&quot;Spørsmål skal være kort og mindre enn 100 tegn&quot;,
)</p>

<p>dspy.Suggest(
valider_spørsmål_distinksjon_local(forrige_spørsmål, spørsmål),
"Spørsmål skal være distinkt fra: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(forrige_spørsmål)),
)</p>

Transformere programmer med påstander


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

<p>baleen_med_påstander = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler)</p>

Alternativt kan du aktivere påstander direkte på programmet:


<p>baleen_med_påstander = SimplifiedBaleenAssertions().activate_assertions()</p>

Påstand-drevne optimaliseringer

DSPy-påstander fungerer med DSPy-optimaliseringer, spesielt med BootstrapFewShotWithRandomSearch, inkludert innstillinger som:

  • Kompilering med påstander
  • Kompilering + inferens med påstander

Konklusjon

DSPy tilbyr en kraftfull og systematisk tilnærming til å optimere språkmodeller og deres prompter. Ved å følge trinnene i disse eksemplene, kan du bygge, optimere og evaluere komplekse AI-systemer med lettighet. DSPy’s modulære design og avanserte optimalisatorer muliggjør effektiv og effektiv integrering av ulike språkmodeller, og gjør det til et verdifullt verktøy for alle som arbeider i feltet NLP og AI.

Uansett om du bygger et enkelt spørsmål-svar-system eller et mer komplekst rør, tilbyr DSPy fleksibilitet og robusthet for å oppnå høy ytelse og pålitelighet.

Jeg har brukt de siste fem årene på å dykke ned i den fasiniserende verden av Maskinlæring og Dypt Læring. Min lidenskap og ekspertise har ledet meg til å bidra til over 50 ulike programvareprosjekter, med særlig fokus på AI/ML. Min pågående nysgjørhet har også trukket meg mot Naturlig Språkbehandling, et felt jeg er ivrig etter å utforske videre.