Prompt engineering
Optimera LLM med DSPy: En steg-för-steg-guide för att bygga, optimera och utvärdera AI-system
Allteftersom förmågan hos stora språkmodeller (LLM) fortsätter att expandera, har utvecklingen av robusta AI-system som utnyttjar deras potential blivit alltmer komplex. Traditionella metoder involverar ofta invecklade prompt-tekniker, datagenerering för finjustering och manuell vägledning för att säkerställa att de följer domänspecifika begränsningar. Detta kan dock vara ett tidskrävande, felbenäget och tungt beroende av mänskligt ingripande.
Här kommer DSPy, ett revolutionerande ramverk designat för att förenkla utvecklingen av AI-system som drivs av LLM. DSPy introducerar en systematisk metod för att optimera LM-prompt och vikter, vilket möjliggör för utvecklare att bygga avancerade applikationer med minimal manuell ansträngning.
I denna omfattande guide kommer vi att utforska DSPys kärnprinciper, dess modulära arkitektur och den mängd kraftfulla funktioner det erbjuder. Vi kommer också att dyka in i praktiska exempel, som visar hur DSPy kan förändra sättet du utvecklar AI-system med LLM.
Vad är DSPy, och varför behöver du det?
DSPy är ett ramverk som separerar programflödet (moduler) från parametrarna (LM-prompt och vikter) för varje steg. Denna separation möjliggör systematisk optimering av LM-prompt och vikter, vilket gör det möjligt för dig att bygga komplexa AI-system med större tillförlitlighet, förutsägbarhet och förenlighet med domänspecifika begränsningar.
Traditionellt har utvecklingen av AI-system med LLM involverat en mödosam process med att bryta ned problemet i steg, skapa invecklade prompt för varje steg, generera syntetiska exempel för finjustering och manuell vägledning för att säkerställa att LLM följer specifika begränsningar. Detta tillvägagångssätt var inte bara tidskrävande utan också benäget för fel, eftersom även små förändringar i pipelinen, LM eller data kunde kräva omfattande omarbete av prompt och finjusteringssteg.
DSPy möter dessa utmaningar genom att introducera en ny paradigm: optimerare. Dessa LM-drivna algoritmer kan justera prompt och vikter för dina LM-anrop, givet en metric du vill maximera. Genom att automatisera optimeringsprocessen, ger DSPy utvecklare möjlighet att bygga robusta AI-system med minimal manuell inblandning, vilket förbättrar tillförlitligheten och förutsägbarheten hos LM-utdata.
DSPys modulära arkitektur
I hjärtat av DSPy ligger en modulär arkitektur som underlättar kompositionen av komplexa AI-system. Ramverket tillhandahåller en uppsättning inbyggda moduler som abstraherar olika prompt-tekniker, såsom dspy.ChainOfThought och dspy.ReAct. Dessa moduler kan kombineras och sammansättas till större program, vilket tillåter utvecklare att bygga invecklade pipelines anpassade till deras specifika krav.
Varje modul inkapslar lärande parametrar, inklusive instruktioner, few-shot-exempel och LM-vikter. När en modul anropas, kan DSPys optimerare finjustera dessa parametrar för att maximera den önskade metriken, säkerställande att LM-utdata följer de specificerade begränsningarna och kraven.
Optimering med DSPy
DSPy introducerar en rad kraftfulla optimerare designade för att förbättra prestanda och tillförlitlighet hos dina AI-system. Dessa optimerare använder LM-drivna algoritmer för att justera prompt och vikter för dina LM-anrop, maximera den specificerade metriken samtidigt som de följer domänspecifika begränsningar.
Några av de viktigaste optimerarna som finns tillgängliga i DSPy inkluderar:
- BootstrapFewShot: Denna optimerare utökar signaturen genom att automatiskt generera och inkludera optimerade exempel inom prompten som skickas till modellen, vilket implementerar few-shot-lärande.
- BootstrapFewShotWithRandomSearch: Tillämpar
BootstrapFewShotflera gånger med slumpmässig sökning över genererade demonstrationer, väljande det bästa programmet över optimeringen. - MIPRO: Genererar instruktioner och few-shot-exempel i varje steg, med instruktionsgenerering som är data-medveten och demonstrations-medveten. Det använder Bayesian Optimization för att effektivt söka över utrymmet av generations-instruktioner och demonstrationer över dina moduler.
- BootstrapFinetune: Destillerar en prompt-baserad DSPy-program till vikt-uppdateringar för mindre LM, vilket tillåter dig att finjustera den underliggande LLM för förbättrad effektivitet.
Genom att utnyttja dessa optimerare kan utvecklare systematiskt optimera sina AI-system, säkerställande högkvalitativa utdata samtidigt som de följer domänspecifika begränsningar och krav.
Komma igång med DSPy
För att illustrera kraften i DSPy, låt oss gå igenom ett praktiskt exempel på att bygga ett retrieval-augmenterat generationssystem (RAG) för frågesvar.
Steg 1: Konfigurera språkmodellen och återställningsmodellen
Det första steget innebär att konfigurera språkmodellen (LM) och återställningsmodellen (RM) inom DSPy.
För att installera DSPy, kör:
pip install dspy-ai
DSPy stöder flera LM- och RM-API:er, samt lokal modellvärd, vilket gör det enkelt att integrera dina föredragna modeller.
import dspy <p># Konfigurera LM och 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>
Steg 2: Ladda datasetet
Nästa steg är att ladda HotPotQA-datasetet, som innehåller en samling komplexa fråga-svar-par som vanligtvis besvaras på ett multi-hop-sätt.
from dspy.datasets import HotPotQA
<p># Ladda datasetet
dataset = HotPotQA(train_seed=1, train_size=20, eval_seed=2023, dev_size=50, test_size=0)</p>
<p># Ange 'fråga'-fältet som indata
trainset = [x.with_inputs('fråga') for x in dataset.train]
devset = [x.with_inputs('fråga') for x in dataset.dev]</p>
Steg 3: Bygga signaturer
DSPy använder signaturer för att definiera beteendet hos moduler. I detta exempel kommer vi att definiera en signatur för uppgiften att generera svar, som specificerar indatafälten (kontext och fråga) och utdatafältet (svar).
<p>class GenerateAnswer(dspy.Signature): """Svara på frågor med korta faktoid-svar.""" kontext = dspy.InputField(desc="kan innehålla relevanta fakta") fråga = dspy.InputField() svar = dspy.OutputField(desc="ofta mellan 1 och 5 ord")
Steg 4: Bygga pipelinen
Vi kommer att bygga vår RAG-pipeline som en DSPy-modul, som består av en initieringsmetod (__init__) för att deklarera undermodulerna (dspy.Retrieve och dspy.ChainOfThought) och en framåtriktad metod (forward) för att beskriva kontrollflödet för att svara på frågan med hjälp av dessa moduler.
<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, fråga): kontext = self.retrieve(fråga).passages prediktion = self.generate_answer(kontext=kontext, fråga=fråga) return dspy.Prediction(kontext=kontext, svar=prediktion.svar)
Steg 5: Optimera pipelinen
Med pipelinen definierad kan vi nu optimera den med hjälp av DSPys optimerare. I detta exempel kommer vi att använda BootstrapFewShot-optimera, som genererar och väljer effektiva prompt för våra moduler baserat på en träningsuppsättning och en metric för validering.
<p>from dspy.teleprompt import BootstrapFewShot</p> <p># Valideringsmetric def validera_kontext_och_svar(exempel, pred, spår=None): svar_EM = dspy.evaluate.svar_exakt_match(exempel, pred) svar_PM = dspy.evaluate.svar_passage_match(exempel, pred) return svar_EM and svar_PM</p> <p># Konfigurera optimeraren teleprompter = BootstrapFewShot(metric=validera_kontext_och_svar)</p> <p># Kompilera programmet kompilerad_rag = teleprompter.compile(RAG(), trainset=trainset)</p>
Steg 6: Utvärdera pipelinen
Efter att ha kompilerat programmet är det viktigt att utvärdera dess prestanda på en utvecklingsuppsättning för att säkerställa att det uppfyller de önskade kraven på noggrannhet och tillförlitlighet.
from dspy.evaluate import Evaluate
<p># Konfigurera utvärderaren
utvärdering = Evaluate(devset=devset, metric=validera_kontext_och_svar, num_threads=4, display_progress=True, display_table=0)</p>
<p># Utvärdera det kompilerade RAG-programmet
utvärderingsresultat = utvärdering(kompilerad_rag)</p>
<p>print(f"Utvärderingsresultat: {utvärderingsresultat}")</p>
Steg 7: Inspektera modellens historia
För en djupare förståelse av modellens interaktioner kan du granska de senaste generationerna genom att inspektera modellens historia.
<p># Inspektera modellens historia turbo.inspect_history(n=1)</p>
Steg 8: Gör förutsägelser
Med pipelinen optimerad och utvärderad kan du nu använda den för att göra förutsägelser på nya frågor.
<p># Exempelfråga
fråga = "Vilket pris fick Gary Zukavs första bok?"</p>
<p># Gör en förutsägelse med det kompilerade RAG-programmet
förutsägelse = kompilerad_rag(fråga)</p>
<p>print(f"Fråga: {fråga}")
print(f"Svar: {förutsägelse.svar}")
print(f"Återställda kontexter: {förutsägelse.kontext}")</p>
Minimalt fungerande exempel med DSPy
Låt oss gå igenom ett annat minimalt fungerande exempel med hjälp av GSM8K-datasetet och OpenAI GPT-3.5-turbo-modellen för att simulera prompt-uppgifter inom DSPy.
Konfigurera
Först måste du säkerställa att din miljö är korrekt konfigurerad:
<p>import dspy from dspy.datasets.gsm8k import GSM8K, gsm8k_metric</p> <p># Konfigurera LM turbo = dspy.OpenAI(model='gpt-3.5-turbo-instruct', max_tokens=250) dspy.settings.configure(lm=turbo)</p> <p># Ladda matematikfrågor från GSM8K-datasetet gsm8k = GSM8K() gsm8k_trainset, gsm8k_devset = gsm8k.train[:10], gsm8k.dev[:10]</p> print(gsm8k_trainset)
Definiera modulen
Nästa steg är att definiera en anpassad program med hjälp av ChainOfThought-modulen för steg-för-steg-resonemang:
<p>class CoT(dspy.Module):
def __init__(self):
super().__init__()
self.prog = dspy.ChainOfThought("fråga -> svar")
def forward(self, fråga):
return self.prog(fråga=fråga)</p>
Kompilera och utvärdera modellen
Nu kan du kompilerar det med BootstrapFewShot-teleprompter:
<p>from dspy.teleprompt import BootstrapFewShot</p> <p># Konfigurera optimeraren config = dict(max_bootstrapped_demos=4, max_labeled_demos=4)</p> <p># Optimera med gsm8k-metric teleprompter = BootstrapFewShot(metric=gsm8k_metric, **config) optimerad_cot = teleprompter.compile(CoT(), trainset=gsm8k_trainset)</p> <p># Konfigurera utvärderaren from dspy.evaluate import Evaluate</p> <p>utvärdering = Evaluate(devset=gsm8k_devset, metric=gsm8k_metric, num_threads=4, display_progress=True, display_table=0) utvärdering(optimerad_cot)</p> <p># Inspektera modellens historia turbo.inspect_history(n=1)</p>
Detta exempel visar hur du kan konfigurera din miljö, definiera en anpassad modul, kompilerar en modell och rigoröst utvärdera dess prestanda med hjälp av det tillhandahållna datasetet och teleprompt-konfigurationer.
Datahantering i DSPy
DSPy opererar med tränings-, utvecklings- och testuppsättningar. För varje exempel i din data har du vanligtvis tre typer av värden: indata, mellanliggande etiketter och slutliga etiketter. Medan mellanliggande eller slutliga etiketter är valfria, är det viktigt att ha några exempelindata.
Skapa exempelobjekt
Exempelobjekt i DSPy liknar Python-ordlistor men kommer med användbara verktyg:
<p>qa_par = dspy.Example(fråga="Detta är en fråga?", svar="Detta är ett svar.")</p> <p>print(qa_par) print(qa_par.fråga) print(qa_par.svar)</p>
Utdata:
<p>Exempel({'fråga': 'Detta är en fråga?', 'svar': 'Detta är ett svar.'}) (input_keys=None)
Detta är en fråga?
Detta är ett svar.</p>
Specificera indata-nycklar
I DSPy har exempelobjekt en with_inputs()-metod för att markera specifika fält som indata:
<p>print(qa_par.with_inputs("fråga"))
print(qa_par.with_inputs("fråga", "svar"))</p>
Värden kan åtkommas med punktoperatören, och metoder som inputs() och labels() returnerar nya exempelobjekt som innehåller endast indata eller icke-indata-nycklar.
Optimerare i DSPy
En DSPy-optimerare justerar parametrarna för ett DSPy-program (dvs. prompt och/eller LM-vikter) för att maximera specificerade metriker. DSPy erbjuder flera inbyggda optimerare, var och en med olika strategier.
Tillgängliga optimerare
- BootstrapFewShot: Genererar few-shot-exempel med hjälp av tillhandahållna märkta indata- och utdata-punkter.
- BootstrapFewShotWithRandomSearch: Tillämpar BootstrapFewShot flera gånger med slumpmässig sökning över genererade demonstrationer.
- COPRO: Genererar och förfinar nya instruktioner för varje steg, optimerar dem med koordinat-stigning.
- MIPRO: Optimerar instruktioner och few-shot-exempel med hjälp av Bayesian Optimization.
Välja en optimerare
Om du är osäker på var du ska börja, använd BootstrapFewShotWithRandomSearch:
För mycket lite data (10 exempel), använd BootstrapFewShot.
För något mer data (50 exempel), använd BootstrapFewShotWithRandomSearch.
För större dataset (300+ exempel), använd MIPRO.
Här är hur du använder 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) optimerad_program = teleprompter.compile(YOUR_PROGRAM_HERE, trainset=YOUR_TRAINSET_HERE)</p>
Spara och ladda optimerade program
Efter att ha kört ett program genom en optimerare kan du spara det för framtida användning:
optimerad_program.save(YOUR_SAVE_PATH)
Ladda ett sparad program:
<p>laddad_program = YOUR_PROGRAM_CLASS() laddad_program.load(path=YOUR_SAVE_PATH)</p>
Avancerade funktioner: DSPy-påståenden
DSPy-påståenden automatiserar tillämpningen av beräkningsbegränsningar på LMs, förbättrar tillförlitligheten, förutsägbarheten och korrektheten hos LM-utdata.
Använda påståenden
Definiera valideringsfunktioner och deklarera påståenden efter respektive modellgenerering. Till exempel:
<p>dspy.Suggest(
len(query) <= 100,
"Frågan bör vara kort och mindre än 100 tecken",
)</p>
<p>dspy.Suggest(
validera_fråga_distinktion_local(prev_frågor, fråga),
"Frågan bör vara distinkt från: " + "; ".join(f"{i+1}) {q}" for i, q in enumerate(prev_frågor)),
)</p>
Transformera program med påståenden
<p>from dspy.primitives.assertions import assert_transform_module, backtrack_handler</p> <p>baleen_med_påståenden = assert_transform_module(SimplifiedBaleenAssertions(), backtrack_handler)</p>
Alternativt kan du aktivera påståenden direkt på programmet:
<p>baleen_med_påståenden = SimplifiedBaleenAssertions().activate_assertions()</p>
Påstående-drivna optimeringar
DSPy-påståenden fungerar med DSPy-optimeringar, särskilt med BootstrapFewShotWithRandomSearch, inklusive inställningar som:
- Kompilering med påståenden
- Kompilering + inferens med påståenden
Slutsats
DSPy erbjuder en kraftfull och systematisk metod för att optimera språkmodeller och deras prompt. Genom att följa stegen i dessa exempel kan du bygga, optimera och utvärdera komplexa AI-system med lätthet. DSPys modulära design och avancerade optimerare möjliggör effektiv och effektiv integration av olika språkmodeller, vilket gör det till ett värdefullt verktyg för alla som arbetar inom området NLP och AI.
Oavsett om du bygger ett enkelt frågesvars-system eller en mer komplex pipeline, erbjuder DSPy den flexibilitet och robusthet som behövs för att uppnå hög prestanda och tillförlitlighet.












