Înapoi la catalog
Season 2 15 Episoade 58 min 2026

Learning DSPy (v3.1 - 2026 Edition)

O programă cuprinzătoare, pas cu pas, pentru învățarea DSPy, trecând de la prompturi fragile bazate pe șiruri de caractere către programare modulară, structurată și optimizare automată.

Framework-uri AI/ML Prompt Engineering
Learning DSPy (v3.1 - 2026 Edition)
Se redă acum
Click play to start
0:00
0:00
1
Programare, nu Prompting
Acest episod acoperă filozofia fundamentală a DSPy: trecerea de la prompturi fragile bazate pe șiruri de caractere către o programare modulară și structurată. Ascultătorii vor învăța de ce separarea arhitecturii sistemului de instrucțiunile modelului de limbaj creează aplicații AI mai robuste.
3m 37s
2
Configurarea modelelor de limbaj
Învață cum să configurezi și să gestionezi modelele de limbaj în DSPy. Acest episod acoperă setarea modelelor implicite, gestionarea cache-ului, suprascrierea setărilor de generare și accesarea diferiților furnizori de modele prin LiteLLM.
4m 04s
3
Prompting declarativ cu Signatures
Descoperă cum DSPy Signatures înlocuiesc prompting-ul tradițional. Acest episod explică modul de definire declarativă a comportamentului de intrare și ieșire al unui modul, folosind atât șiruri de caractere inline, cât și definiții bazate pe clase cu strict typing.
4m 11s
4
Componente de bază folosind Modules
Explorează DSPy Modules, componentele de bază pentru programele modelelor de limbaj. Acest episod acoperă dspy.Predict, dspy.ChainOfThought și modul de compunere a mai multor module într-un pipeline mai mare și coerent.
4m 25s
5
Conectarea modelelor cu Adapters
Înțelege rolul Adapters în DSPy. Acest episod explică modul în care ChatAdapter și JSONAdapter reduc decalajul dintre semnăturile abstracte DSPy și mesajele reale multi-turn trimise către API-urile modelelor de limbaj.
4m 05s
6
Gestionarea datelor cu Examples
Învață cum gestionează DSPy seturile de date pentru machine learning. Acest episod acoperă obiectul dspy.Example, făcând distincția între cheile de intrare (input keys) și etichete (labels), și pregătirea datelor pentru evaluare și optimizare.
3m 45s
7
Definirea succesului prin metrici
Descoperă cum să evaluezi programele DSPy folosind metrici. Acest episod te învață cum să scrii funcții Python personalizate pentru a puncta ieșirile, cum să folosești argumentul trace și chiar cum să valorifici AI-as-a-judge pentru evaluări de tip long-form.
4m 10s
8
O introducere în Optimizers
Pătrunde în magia de bază a DSPy: Optimizers. Acest episod oferă o privire de ansamblu asupra a ceea ce fac optimizatorii, ciclul iterativ de optimizare și strategia neobișnuită de împărțire a datelor 20/80 pentru optimizarea prompturilor.
3m 58s
9
Few-Shot Learning automat
Învață cum automatizează DSPy prompting-ul few-shot. Acest episod se concentrează pe BootstrapFewShot și BootstrapFewShotWithRandomSearch, explicând modul în care acestea sintetizează, filtrează și injectează exemple de înaltă calitate în prompturile tale.
3m 41s
10
Optimizarea instrucțiunilor cu MIPROv2
Aprofundează ajustarea automată a instrucțiunilor (instruction tuning). Acest episod explorează MIPROv2 și COPRO, arătând cum DSPy folosește Bayesian Optimization și coordinate ascent pentru a descoperi instrucțiuni de prompt superioare, contra-intuitive.
4m 02s
11
Finetuning cu BootstrapFinetune
Descoperă cum să distilezi modele de limbaj masive în unele mai mici și eficiente. Acest episod acoperă BootstrapFinetune, explicând cum să convertești un program DSPy bazat pe prompturi într-un model personalizat, cu ponderi actualizate (weight-updated).
3m 38s
12
Utilizarea automată a instrumentelor cu ReAct
Învață cum să oferi modelelor de limbaj acces la instrumente externe. Acest episod acoperă modulul dspy.ReAct, demonstrând cum să construiești agenți autonomi care raționează și interacționează dinamic cu API-urile.
3m 46s
13
Gestionarea manuală a instrumentelor pentru control
Preia controlul complet asupra execuției instrumentelor. Acest episod acoperă gestionarea manuală a instrumentelor în DSPy folosind dspy.Tool, dspy.ToolCalls și native function calling pentru aplicații sensibile la latență.
3m 30s
14
Integrarea instrumentelor cu MCP
Conectează-ți agenții la servere universale de instrumente. Acest episod explică modul de utilizare a Model Context Protocol (MCP) în DSPy pentru a valorifica instrumente standardizate în diferite framework-uri cu o configurare minimă.
3m 51s
15
Ensembles și Meta-Optimizare
Împinge DSPy la limitele sale. Ultimul episod acoperă transformările de programe prin dspy.Ensemble și meta-optimizatorul experimental BetterTogether, care combină prompt tuning cu weight finetuning pentru performanță maximă.
3m 55s

Episoade

1

Programare, nu Prompting

3m 37s

Acest episod acoperă filozofia fundamentală a DSPy: trecerea de la prompturi fragile bazate pe șiruri de caractere către o programare modulară și structurată. Ascultătorii vor învăța de ce separarea arhitecturii sistemului de instrucțiunile modelului de limbaj creează aplicații AI mai robuste.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învăț DSPy, episodul 1 din 15. Petreci trei ore construind perfect un prompt, astfel încât modelul tău de limbaj să genereze output-urile corecte. Apoi, un provider lansează un model nou, schimbi cheia de API și tot pipeline-ul tău se face praf. Rămâi blocat menținând strings fragile în loc să construiești software. Asta e problema pe care o rezolvă o filozofie numită Programming, Not Prompting. Oamenii aud des de DSPy și presupun că e doar un alt tool de prompt templating pentru inserarea variabilelor în blocuri de text. Nu este. DSPy este un framework pentru compilarea și optimizarea de control flow. Ia un setup standard pentru un sistem care citește documente și generează un raport cu citări. Într-o abordare tradițională, scrii un bloc masiv de text. Explici task-ul, injectezi documentele, adaugi instrucțiuni manuale precum think step by step și specifici exact cum trebuie să arate citările. Abordarea asta cuplează strâns arhitectura sistemului tău de niște alegeri incidentale. Arhitectura ta este logica de bază. Asta înseamnă extragerea informațiilor, redactarea unui rezumat și adăugarea citărilor. Alegerile incidentale sunt cuvintele specifice pe care le-ai folosit pentru a convinge un anumit model de limbaj să te asculte. Exact acele cuvinte nu vor funcționa optim pe un model diferit, sau chiar pe o versiune diferită a aceluiași model. Când datele se modifică puțin, prompt-ul crapă. DSPy separă arhitectura sistemului tău de acele alegeri incidentale de prompt. Nu mai scrii strings lungi cu instrucțiuni. În schimb, îți definești task-ul pur și simplu în termeni de inputs și outputs. Pentru generatorul de rapoarte, declari că input-ul este o listă de fragmente de text, iar output-ul este un text redactat și un set de referințe pentru citări. Odată ce aceste inputs și outputs sunt definite, le conectezi între ele folosind cod standard. Creezi o componentă de extragere, îi pasezi documentele și colectezi informațiile. Apoi pasezi acele informații într-o componentă de redactare. În cele din urmă, ai putea folosi un loop simplu pentru a verifica draft-ul cu informațiile originale. Nu mai există strings manuale care să implore modelul să-și formateze corect output-ul. Există doar logică structurată. Iată ideea cheie. Pentru că arhitectura ta este definită sub formă de cod modular, un compilator poate traduce automat acea structură în prompt-urile reale necesare pentru orice model de limbaj pe care îl folosești. DSPy tratează instrucțiunile modelului, pașii de raționament și exemplele few-shot ca parametri interni. Acestea sunt variabile care urmează să fie optimizate de framework, în loc de text static pe care îl scrii manual. Tu construiești pipeline-ul, definești forma datelor și scrii pașii de execuție în Python standard. Framework-ul se ocupă de task-ul imprevizibil de a descoperi cea mai bună modalitate de a cere modelului de limbaj să execute acei pași într-un mod fiabil. Asta schimbă fundamental experiența de developer. Îți petreci timpul făcând debugging la logica aplicației tale, nu ghicind ce adjectiv va face modelul să fie atent la sfârșitul unei propoziții. Arhitectura sistemului tău ar trebui să supraviețuiască particularităților oricărui model de limbaj către care rutezi request-uri astăzi. Mulțumesc pentru ascultare, happy coding tuturor!
2

Configurarea modelelor de limbaj

4m 04s

Învață cum să configurezi și să gestionezi modelele de limbaj în DSPy. Acest episod acoperă setarea modelelor implicite, gestionarea cache-ului, suprascrierea setărilor de generare și accesarea diferiților furnizori de modele prin LiteLLM.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învăț DSPy, episodul 2 din 15. E ușor să faci un singur API call către un language model. Dar gestionarea mai multor provideri, stocarea în cache a răspunsurilor și urmărirea istoricului de prompturi te obligă de obicei să construiești și să menții un custom wrapper. Configurarea de language models în DSPy elimină toată această muncă de rutină. Ai putea presupune că ai nevoie de SDK-ul OpenAI pentru modelele GPT, de SDK-ul Anthropic pentru Claude și de o librărie separată pentru modelele locale. Nu e nevoie. DSPy gestionează asta uniform printr-o singură clasă LM, propulsată de LiteLLM under the hood. Ca să folosești un model, instanțiezi un obiect LM din DSPy și îi pasezi un string care conține numele providerului, un slash și numele modelului. De exemplu, pasezi open ai slash gpt-4o-mini. Când creezi acest obiect, poți să pasezi și parametri standard, cum ar fi temperature sau max tokens. Datorită backend-ului unificat, numele acestor parametri rămân consistente indiferent de providerul pe care îl apelezi de fapt. Poți interacționa direct cu acest obiect LM. Apelează-l ca pe o funcție Python normală, pasând fie un simplu text string, fie o listă de chat dictionaries. Procesează inputul și returnează o listă de stringuri generate. By default, returnează un singur string în acea listă, dar poți cere mai multe completions. Această utilizare directă e simplă, dar să pasezi manual un obiect model către fiecare funcție dintr-un codebase mare devine rapid o bătaie de cap. Pentru a rezolva asta, DSPy folosește un sistem global de configurare. Îți definești language model-ul default o singură dată apelând dspy dot configure, atribuind obiectul LM instanțiat ca target. Fiecare operațiune DSPy ulterioară este rutată automat prin acel model. Dar ce faci dacă vrei să compari outputurile între provideri? Să zicem că vrei să testezi cum gestionează Claude 3.5 Sonnet o funcție specifică în comparație cu modelul tău GPT default. În loc să suprascrii state-ul global, folosești dspy dot context. Asta creează un scope temporar. Deschizi un with block în Python folosind dspy dot context, îl atribui pe Claude ca default local și îți execuți codul. Când block-ul se termină, DSPy revine automat la modelul tău global GPT-4o-mini. Asta acoperă rutarea requesturilor. Dar cum rămâne cu performanța? DSPy salvează în cache fiecare generare a modelului by default, ca să economisească timp și costuri API. Dacă rulezi exact același prompt cu exact aceiași parametri, îți servește instant răspunsul din cache. Aici e ideea cheie. Uneori ai nevoie de o generare fresh fără să schimbi promptul sau să ajustezi temperature. Pentru asta, DSPy folosește un parametru numit rollout id. Când pasezi un nou rollout id, cum ar fi un integer unic, DSPy îl tratează ca pe un request distinct și face bypass la cache. Asta forțează modelul să genereze o nouă secvență, oferindu-ți control asupra diversității generării, în timp ce păstrezi inputurile de bază statice. În final, când experimentezi, trebuie să vezi exact ce s-a trimis over the wire. Fiecare obiect LM își menține propriul log de interacțiuni. Poți accesa datele raw prin atributul history de pe obiectul model. Pentru un rezumat human readable, apelezi metoda inspect history. Aceasta dă print la promptul exact trimis către provider și la răspunsul exact primit. Adevărata valoare a acestui layer de configurare e că detașează complet logica aplicației de ciudățeniile providerilor, transformând selecția modelului și caching-ul în simple switch-uri declarative. Mersi de audiție, happy coding tuturor!
3

Prompting declarativ cu Signatures

4m 11s

Descoperă cum DSPy Signatures înlocuiesc prompting-ul tradițional. Acest episod explică modul de definire declarativă a comportamentului de intrare și ieșire al unui modul, folosind atât șiruri de caractere inline, cât și definiții bazate pe clase cu strict typing.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 3 din 15. Semnăturile standard ale funcțiilor Python îi spun codului tău la ce tipuri de date să se aștepte. Dar cum ar fi dacă o semnătură ar putea dicta însăși logica funcției, fără ca tu să scrii explicit instrucțiunile? Asta este premisa pentru Declarative Prompting cu semnături. E normal să confunzi o semnătură DSPy cu o semnătură standard de funcție Python. Arată similar, dar rolurile lor sunt fundamental diferite. O semnătură standard Python definește o interfață strictă de date. O semnătură DSPy declară și inițializează, de fapt, comportamentul modelului de limbaj. Tu nu scrii un prompt. Scrii o specificație declarativă a ceea ce trebuie să se întâmple. Framework-ul ia această specificație, se uită la așteptările de input și output, și construiește promptul din spate pentru tine. Cel mai simplu mod de a defini o semnătură este inline, folosind un string scurt. Specifici variabilele de input, scrii o săgeată direcțională și specifici variabilele de output. De exemplu, string-ul „question săgeată answer” îi spune lui DSPy că modelul va primi o întrebare și trebuie să genereze un răspuns. Poți pasa mai multe input-uri, cum ar fi „context virgulă question săgeată answer”. Aici devine interesant. Numele variabilelor pe care le alegi au o greutate semantică reală. DSPy folosește exact acele nume de string-uri pentru a atribui roluri în prompt. Dacă numești un input „context”, modelul îl interpretează ca informații de fundal. Nu face over-engineering la aceste nume și nu încerca să dai hack la keywords cu trucuri inteligente de prompt. Folosește cuvinte în engleză, clare și descriptive, pentru a defini rolurile. Când string-urile inline nu sunt suficient de expresive, treci la semnături bazate pe clase. Creezi o clasă nouă care moștenește din clasa de bază DSPy Signature. În interiorul acestei clase, îți definești input-urile și output-urile ca atribute. Atribui aceste atribute folosind funcțiile Input Field și Output Field oferite de DSPy. Abordarea asta îți oferă un control fin asupra comportamentului modelului. Docstring-ul clasei în sine devine instrucțiunea principală pentru modelul de limbaj, definind task-ul general. Ia în considerare un scenariu de clasificare multi-modală de imagini. Vrei să pasezi o imagine și o întrebare text către un model de vision, și să extragi rasa specifică a unui câine. Creezi o clasă numită ClassifyDogBreed. În partea de sus a clasei, scrii un docstring care spune: Identifică rasa câinelui pe baza imaginii și a întrebării furnizate. Apoi, îți definești input-urile. Creezi un atribut numit „image” și îl atribui ca un Input Field. Creezi un al doilea atribut numit „question” și îl atribui ca un Input Field. În cele din urmă, definești un atribut numit „breed” și îl atribui ca un Output Field. În interiorul acelui Output Field, poți pasa un argument de tip description care să precizeze: Numele exact al rasei de câine, fără text suplimentar. Semnăturile bazate pe clase gestionează, de asemenea, type resolution. Poți specifica type hints standard din Python pentru field-urile tale. Dacă pui un type hint de boolean pe output field, DSPy înțelege că modelul trebuie să returneze o valoare true sau false. Framework-ul procesează aceste type annotations și injectează automat constrângeri în structura promptului, ghidând modelul către formatul corect de output. Structura datelor tale și numele variabilelor tale sunt instrucțiunile propriu-zise. Un field denumit clar și un docstring precis într-o semnătură declarativă vor dicta comportamentul modelului mult mai fiabil decât paragraf după paragraf de prompt engineering făcut manual. Mulțumesc pentru audiție, spor la codat tuturor!
4

Componente de bază folosind Modules

4m 25s

Explorează DSPy Modules, componentele de bază pentru programele modelelor de limbaj. Acest episod acoperă dspy.Predict, dspy.ChainOfThought și modul de compunere a mai multor module într-un pipeline mai mare și coerent.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 4 din 15. De obicei, atunci când vrei ca un language model să raționeze pentru a rezolva o problemă, recurgi la a lipi string-uri între ele, adăugând la întâmplare expresii precum think step by step la promptul tău. Îți amesteci logica aplicației cu instrucțiuni text fragile. În DSPy, tehnicile de prompting nu sunt string-uri. Sunt componente structurate, interschimbabile, numite Module. Este ușor să confundi modulele cu semnăturile. Gândește-te la o semnătură ca la un contract. Definește acel ce, mapând câmpuri specifice de input la câmpuri specifice de output. Un modul definește acel cum. Este un obiect parametrizat, callable, care îți preia semnătura și aplică o strategie specifică de prompting pentru a îndeplini acel contract. Cel mai de bază modul este modulul Predict. Îl inițializezi pasând semnătura ta ca argument. Dacă semnătura ta cere transformarea unui document într-un rezumat, modulul Predict se ocupă de formatarea promptului și apelează language model-ul. Dar poate că task-ul este complex și necesită o logică intermediară. Poți schimba ușor Predict cu modulul Chain of Thought. Nu îți schimbi semnătura. Pur și simplu o pasezi modulului Chain of Thought în schimb. În spate, acest modul modifică automat arhitectura promptului. Instruiește language model-ul să genereze un reasoning trace pas cu pas înainte de a produce câmpurile de output finale pe care le-ai definit. Când apelezi modulul Chain of Thought cu datele tale de input, acesta returnează un obiect care conține output-urile solicitate. Pentru că ai folosit Chain of Thought, acel obiect include și un câmp nou care conține raționamentul modelului. Poți inspecta exact cum a ajuns language model-ul la răspunsul său, separat complet de valoarea finală extrasă. Aici este ideea principală. Poți să faci nest la aceste module built-in pentru a crea programe complexe, la fel cum ai stivui layere de rețele neuronale în PyTorch. Putem construi un pipeline de retrieval multi-hop pentru a vedea asta în acțiune. Începi prin a defini o clasă custom. În faza ei de inițializare, declari modulele mai mici de care vei avea nevoie. Pentru o arhitectură multi-hop, ai putea declara un modul de query generator folosind Chain of Thought, și un modul de answer synthesis folosind Predict standard. Apoi, definești o metodă forward pentru a ruta datele între ele. Metoda forward preia o întrebare inițială a utilizatorului. Pasează acea întrebare modulului tău de query generator, care dă ca output un search query. Execuți acel search pe baza ta de date pentru a extrage un document. Dacă ai nevoie de un al doilea hop, pasezi documentul extras și întrebarea originală înapoi în modulul de query generator pentru a produce un search query mai rafinat. În cele din urmă, pasezi toate documentele extrase și întrebarea utilizatorului în modulul de answer synthesis pentru a genera răspunsul final. Tocmai ai construit un graf custom, executabil, din componente modulare. Când faci chain la mai multe apeluri în acest fel, este crucial să vezi exact ce este trimis către model în spate. DSPy urmărește utilizarea language model-ului tău la nivel global. Poți apela comanda inspect history pe obiectul tău de language model pentru a printa cele mai recente interacțiuni. Asta randează string-ul exact pe care l-a primit modelul și string-ul exact pe care l-a generat, asigurându-te că pipeline-ul tău compus asamblează corect contextul. Prin separarea definiției task-ului în semnături și a strategiei de execuție în module parametrizate, transformi prompting-ul dintr-o corvoadă de editare de text într-o decizie arhitecturală, permițându-ți să faci upgrade la capacitatea de reasoning a pipeline-ului tău pur și simplu prin schimbarea unui nume de clasă. Mulțumesc pentru audiție, happy coding tuturor!
5

Conectarea modelelor cu Adapters

4m 05s

Înțelege rolul Adapters în DSPy. Acest episod explică modul în care ChatAdapter și JSONAdapter reduc decalajul dintre semnăturile abstracte DSPy și mesajele reale multi-turn trimise către API-urile modelelor de limbaj.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 5 din 15. Scrii o signature curată, strongly-typed, în codul tău, o transmiți unui model de limbaj și, cumva, primești înapoi un obiect Python perfect structurat. Între codul tău curat și API-ul de raw text al modelului se află un strat haotic de traducere. Acest strat ascuns este conceptul de conectare a modelelor cu Adapters. Înainte să vedem cum funcționează, hai să clarificăm o confuzie comună. S-ar putea să confundi Adapters cu Modules. Modules gestionează strategia de raționament. Ele decid dacă modelul ar trebui să folosească Chain of Thought sau să se bazeze pe tool-uri externe. Adapters nu țin cont de strategie. Un adapter este pur și simplu stratul de traducere. El gestionează raw string-ul și serializarea JSON care sunt trimise efectiv pe rețea către API-ul modelului. Modelele de limbaj nu înțeleg signatures declarative. Ele se așteaptă la arrays de mesaje multi-turn care conțin roluri specifice și blocuri de text. Adapter-ul face această legătură. Tool-ul default pentru asta în DSPy este ChatAdapter. Când invoci un module, ChatAdapter îți interceptează signature-ul și îl formatează într-un chat history standard. Instrucțiunea principală din signature este mapată direct în system prompt. Câmpurile tale de input sunt colectate și plasate în user message. Iată ideea principală. ChatAdapter folosește text markers specifici pentru a-ți menține inputurile strict organizate. Încadrează fiecare nume de câmp în paranteze pătrate duble și două simboluri hash. Dacă câmpul tău de input este denumit context, modelul de limbaj vede un marker cu paranteze și hash-uri care înconjoară cuvântul context, urmat imediat de datele efective din context. Această limită vizuală împiedică modelul să confunde accidental system instructions cu textul de user input. Repetă acest pattern pentru câmpurile de output așteptate, cerând modelului să genereze exact aceiași markeri în răspunsul său. Ia în considerare un scenariu în care extragi știri științifice. Inputul tău este un articol raw text, iar outputul tău trebuie să se potrivească cu o clasă Pydantic cu câmpuri specifice pentru titlu și descoperirea științifică principală. Când transmiți această cerință prin ChatAdapter, acesta inspectează clasa Pydantic, generează o JSON schema completă și injectează acea schemă direct în system prompt. Acesta îi spune explicit modelului de limbaj cum să își formateze răspunsul text. Când modelul răspunde în cele din urmă, ChatAdapter prinde raw text string-ul. Caută markerii de output așteptați, extrage blocul de text dintre ei și parsează acele date înapoi în obiectele Python exacte de care are nevoie aplicația ta. Asta acoperă inputurile și parsarea pentru interacțiunile bazate pe text. Dar modelele de limbaj moderne au adesea suport nativ pentru structured output. Aici intervine JSONAdapter. În loc să modifice masiv system prompt-ul și să se bazeze pe text markers, JSONAdapter adoptă o rută mai directă. Deleagă constrângerile de formatare către JSON mode-ul nativ al providerului de model sau către API-ul de structured outputs. Modelul este forțat la nivel de protocol să returneze un obiect JSON valid care conține toate câmpurile de output solicitate. Deoarece API-ul modelului gestionează structura nativ, elimină necesitatea ca adapter-ul să caute string markers prin raw text. Dacă modelul tău țintă acceptă această capacitate, schimbarea pipeline-ului pentru a folosi JSONAdapter are ca rezultat, de obicei, o latență mai mică și o parsare semnificativ mai fiabilă. Adapter-ul este granița rigidă dintre logica deterministă a aplicației tale și generarea de text nestructurat a modelului de limbaj. Controlând exact modul în care inputurile sunt serializate și outputurile sunt parsate, adapters se asigură că pipeline-ul tău nu se strică niciodată din cauza unui string formatat greșit. Mulțumesc pentru audiție, happy coding tuturor!
6

Gestionarea datelor cu Examples

3m 45s

Învață cum gestionează DSPy seturile de date pentru machine learning. Acest episod acoperă obiectul dspy.Example, făcând distincția între cheile de intrare (input keys) și etichete (labels), și pregătirea datelor pentru evaluare și optimizare.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 6 din 15. Rulezi un optimizer pentru a-ți îmbunătăți pipeline-ul de language models, dar obține un scor perfect chiar din prima încercare. Te uiți mai atent și realizezi că ai introdus accidental răspunsurile target direct în prompt. Pentru a trata aceste language models ca pe niște componente tradiționale de machine learning, ai nevoie de o metodă sigură prin care să-ți gestionezi seturile de training, dev și test, fără să faci leak la răspunsuri. Gestionarea datelor cu Examples în DSPy rezolvă exact această problemă. În DSPy, structura de date fundamentală este obiectul Example. Îl folosești pentru a-ți construi toate dataset-urile. La prima vedere, se comportă foarte mult ca un dictionary standard din Python. Creezi unul pasând perechi key-value care îți reprezintă datele. Să luăm ca exemplu un task de summarization. Creezi un nou obiect Example și îi dai două field-uri. Atribui un string lung unui field numit report, și un string scurt unui field numit summary. Poți citi aceste valori înapoi oricând folosind dot notation standard, cerând field-ul report sau field-ul summary direct din obiect. E ceva obișnuit să tratezi obiectul Example doar ca pe un dictionary wrapper, dar folosirea unui dictionary simplu va strica procesul de compilare. Când pasezi un dataset către un optimizer DSPy, compiler-ul trebuie să separe ce intră în pipeline de ce este folosit pentru a da un scor acelui pipeline. Are nevoie de granițe explicite între datele de input și răspunsurile așteptate. Aici devine interesant. Obiectul Example controlează aceste granițe folosind o metodă specifică numită with_inputs. Când instanțiezi obiectul Example care conține acel report și summary, faci chain la metoda with_inputs chiar la final. Îi pasezi string-ul report. Asta etichetează explicit field-ul report ca date de input. Orice field pe care nu îl specifici în această metodă devine automat un label. Optimizer-ul știe acum că trebuie să trimită doar acel report către pipeline-ul tău. Acel summary rămâne complet ascuns în timpul etapei de inference. Odată ce ai configurat un singur exemplu, grupezi mai multe exemple în liste standard din Python pentru a-ți forma seturile de training, dev și test. Pentru că DSPy tratează prompt engineering-ul ca pe o problemă de optimizare de machine learning, să ai aceste dataset-uri clar partiționate este o cerință strictă. Când acel optimizer îți rulează pipeline-ul peste setul de training, procesează câte un Example pe rând. Elimină acele labels, pasează acele inputs mai departe, capturează acel output generat, și apoi evaluează rezultatul. Când scrii metrici de evaluare custom, va trebui să accesezi aceste field-uri separate. Obiectul Example oferă două metode pentru această extragere. Apelarea metodei inputs returnează un dictionary care conține doar datele pe care le-ai marcat ca inputs. Apelarea metodei labels returnează un dictionary care conține datele target ascunse. Funcția ta de evaluare apelează metoda labels pentru a recupera acel target summary, îl compară cu textul generat, și atribuie un scor în funcție de cât de bine se potrivesc. Configurarea corectă a obiectelor Example garantează că pipeline-ul tău învață efectiv să mapeze acele inputs la outputs. Separarea strictă dintre inputs și labels previne acel data leakage în timpul optimizării, asigurându-te că sistemul tău se îmbunătățește, în loc să memoreze pur și simplu răspunsurile furnizate. Mersi pentru audiție, happy coding tuturor!
7

Definirea succesului prin metrici

4m 10s

Descoperă cum să evaluezi programele DSPy folosind metrici. Acest episod te învață cum să scrii funcții Python personalizate pentru a puncta ieșirile, cum să folosești argumentul trace și chiar cum să valorifici AI-as-a-judge pentru evaluări de tip long-form.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 7 din 15. Nu poți îmbunătăți constant ceea ce nu poți măsura, iar atunci când lucrezi cu language models, să te bazezi pe intuiția umană pentru a măsura calitatea output-ului pur și simplu nu scalează. Pentru a-ți rescrie automat prompt-urile sau pentru a-ți face tune la sistem, compilatorul are nevoie de un reper matematic, iar asta este exact ceea ce îți oferă definirea succesului prin metrici. În DSPy, o metrică este o funcție Python standard. Ea primește două argumente principale. Primul este un example, care reprezintă input-ul ideal și output-ul așteptat din dataset-ul tău. Al doilea este un prediction, adică răspunsul efectiv generat de programul tău DSPy. Funcția metrică compară acel prediction cu acel example și returnează un scor. Acest scor este de obicei un float, un integer sau o simplă valoare boolean, cum ar fi true sau false. Pentru task-uri de clasificare de bază, metrica ta ar putea fi o simplă logică de Python. Ai putea scrie o funcție de exact match care verifică dacă acel string prezis este perfect egal cu acel string așteptat. Pentru a executa această măsurătoare în mod sistematic pe toate datele tale, DSPy oferă un utilitar built-in numit Evaluate. Îi pasezi acestui utilitar dataset-ul tău de development, funcția metrică și parametrii de execuție, cum ar fi numărul de thread-uri paralele. Utilitarul Evaluate rulează metrica peste fiecare prediction, agregă rezultatele și returnează un singur scor numeric care reprezintă performanța generală a sistemului tău. Totuși, un exact match este aproape mereu prea rigid pentru task-uri de limbaj generativ. Aici faci tranziția de la simple verificări de string-uri la utilizarea de feedback AI, un pattern cunoscut de obicei sub numele de LLM-as-a-judge. Deoarece modulele DSPy sunt doar cod Python, funcția ta metrică poate instanția și apela un program DSPy mai mic, separat, pentru a evalua output-uri semantice complexe. Gândește-te la un scenariu concret. Construiești un sistem care generează un tweet promoțional pentru a răspunde la întrebarea unui user. O metrică de exact match eșuează complet aici, deoarece un tweet bun poate fi formulat în nenumărate moduri valide. În schimb, funcția ta metrică ar trebui să evalueze mai multe dimensiuni ale output-ului. În primul rând, folosește un length check de bază din Python pentru a se asigura că textul generat are sub două sute optzeci de caractere. În al doilea rând, verifică dacă textul conține răspunsul factual cerut de acel example. În cele din urmă, pasează textul generat către o signature DSPy specializată, care îi cere unui language model mai mic să evalueze dacă tweet-ul este captivant. Funcția ta metrică combină apoi acel length check, acel fact check și scorul de engagement al acelui language model într-o singură valoare matematică finală. Când vei începe, în cele din urmă, să compilezi și să optimizezi aceste programe, funcția ta metrică trebuie să accepte un al treilea argument, opțional. Acesta se numește trace. Ascultătorii confundă adesea argumentul trace cu un debugging log care printează erori în consolă sau istoricul execuției. Dar nu este deloc asta. Argumentul trace este un obiect specific, folosit de compilatorul DSPy în timpul optimizării pentru a valida pașii intermediari de reasoning. Dacă programul tău face chain la mai multe apeluri de language model, acel trace conține calea specifică de reasoning pe care a parcurs-o modelul pentru a ajunge la final. Accesând acel trace din interiorul metricii tale, funcția ta poate verifica nu doar dacă tweet-ul final a fost bun, ci și dacă pașii intermediari folosiți pentru a-l redacta au fost corecți din punct de vedere logic. Asta este partea care contează. Metrica ta definește strict cum arată succesul, iar compilatorul DSPy îți va optimiza sistemul fără milă pentru a maximiza acel scor specific. Dacă metrica ta este greșită, programul tău compilat va fi greșit în exact același mod. Mulțumesc pentru audiție, happy coding tuturor!
8

O introducere în Optimizers

3m 58s

Pătrunde în magia de bază a DSPy: Optimizers. Acest episod oferă o privire de ansamblu asupra a ceea ce fac optimizatorii, ciclul iterativ de optimizare și strategia neobișnuită de împărțire a datelor 20/80 pentru optimizarea prompturilor.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 8 din 15. Să presupunem că scrii un software și, în loc să-i modifici manual logica internă pentru a trece de teste, un compilator rescrie automat instrucțiunile, astfel încât programul să performeze mai bine singur. Nu te atingi de cod. Oferi doar setul de teste. Exact asta face DSPy printr-un concept numit optimizers. Acești optimizers, care în versiunile mai vechi ale framework-ului se numeau teleprompters, sunt algoritmi care ajustează parametrii programului tău. În machine learning tradițional, parametrii înseamnă weights dintr-o rețea neuronală. În DSPy, parametrii înseamnă în principal acele prompt strings și instrucțiunile trimise către language model, deși pot include și weights. Treaba unui optimizer este să ajusteze acești parametri pentru a maximiza o metrică pe care ai definit-o deja. Acest proces are loc înainte să dai deploy la aplicație. Este pur compute de pre-inference. Consumi putere de procesare în avans pentru a găsi cele mai bune instrucțiuni, astfel încât aplicația ta să ruleze cu precizie mai târziu. Când auzi cuvântul optimizer, s-ar putea să presupui că ai nevoie de datasets masive, așa cum ai avea nevoie pentru fine-tuning pe un model tradițional. Nu e cazul. Acești prompt optimizers sunt extrem de eficienți. De obicei, necesită doar între treizeci și trei sute de exemple. Pentru că acest dataset este atât de mic, DSPy recomandă o abordare neobișnuită pentru a face split la date. În loc de acel split standard de optzeci-douăzeci, unde majoritatea datelor merg la training, tu inversezi proporția. Folosești douăzeci la sută pentru training și optzeci la sută pentru validation. Dacă ai cincizeci de exemple, îi dai zece acelui optimizer pentru a construi acele prompts și folosești restul de patruzeci pentru a evalua dacă acele prompts chiar generalizează. Acest reverse split împiedică acel optimizer să facă overfitting pe acele prompts generate, pe un set minuscul de inputs. Iată ideea cheie. Ciclul iterativ de development în DSPy se învârte în jurul rulării acestui optimization loop. Hai să trecem printr-un scenariu concret. Construiești un bot simplu de question answering. Mai întâi, îți definești programul DSPy și metrica. Apoi, îți aduni un dataset de cincizeci de întrebări unlabelled. Faci split la aceste date, pasând porțiunea mică de training către un obiect optimizer. Îi spui acelui optimizer să compileze programul folosind datele tale de training și metrica. Acest optimizer rulează, experimentând cu diferite structuri de prompt under the hood. Verifică acele outputs în raport cu metrica ta, învață ce funcționează și rafinează acele prompts. Când acest optimizer termină, returnează o nouă versiune compilată a programului tău. Acest program compilat conține parametrii proaspăt ajustați. Nu trebuie să rulezi acest pas de optimizare de fiecare dată când pornește aplicația ta. În schimb, apelezi metoda save pe programul compilat, oferind un file path. Asta scrie toate acele prompts și configurații optimizate într-un fișier JSON standard. Când dai deploy la aplicație în producție, codul tău pur și simplu instanțiază programul de bază și apelează metoda load, indicând exact către acel fișier JSON. Botul tău este imediat gata să răspundă la întrebări folosind instrucțiunile optimizate. Adevărata putere a acestor optimizers din DSPy constă în faptul că decuplează logica aplicației tale de formularea exactă a acelor prompts, lăsând partea de compute să găsească cele mai bune cuvinte pentru tine. Mulțumesc pentru audiție, happy coding tuturor!
9

Few-Shot Learning automat

3m 41s

Învață cum automatizează DSPy prompting-ul few-shot. Acest episod se concentrează pe BootstrapFewShot și BootstrapFewShotWithRandomSearch, explicând modul în care acestea sintetizează, filtrează și injectează exemple de înaltă calitate în prompturile tale.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 9 din 15. Alegerea manuală a celor mai bune exemple pentru a le pune într-un prompt este o treabă migăloasă și predispusă la bias. Ghicești ce exemple contează, le dai hardcode în string-urile tale și speri că modelul este atent. DSPy sintetizează, testează și selectează activ demonstrațiile perfecte pentru tine. Acest proces este automatic few-shot learning, iar DSPy îl gestionează prin trei optimizatori specifici. Cea mai simplă abordare este LabeledFewShot. Oferi un set de exemple de training etichetate. Optimizatorul selectează random un subset din aceste perechi de input și output și le inserează direct în prompt-urile tale ca demonstrații. Îi oferă modelului un pattern de bază de urmat. Asta funcționează bine dacă datele tale de training se potrivesc exact cu pașii intermediari de care are nevoie programul tău. De obicei, nu e cazul. Asta ne aduce la BootstrapFewShot. O concepție greșită comună este că BootstrapFewShot doar alege random exemple din setul tău de training. Nu face asta. Generează activ pași intermediari de reasoning care nu au existat niciodată în datele tale raw. Iată cum decurge procesul de bootstrapping. Optimizatorul are nevoie de un program teacher. By default, asta este doar versiunea neoptimizată, zero-shot, a propriului tău program. Teacher-ul parcurge exemplele tale de training. Pentru fiecare exemplu, încearcă să genereze un răspuns. DSPy dă apoi acel răspuns mai departe către metrica ta de evaluare. Dacă metrica spune că output-ul este corect, DSPy salvează întregul trace al acelei execuții de succes. Acest trace include input-ul, output-ul și, foarte important, orice muncă intermediară pe care a făcut-o programul pentru a ajunge acolo. Gândește-te la un sentiment classifier. Dataset-ul tău raw conține doar review-uri de la clienți și un label pozitiv sau negativ. Programul tău DSPy îi cere modelului de limbaj să folosească chain-of-thought reasoning înainte de a genera sentimentul. În timpul bootstrapping-ului, teacher-ul citește un review și scrie un paragraf de reasoning înainte să ghicească sentimentul. Dacă ghicirea finală se potrivește cu label-ul corect, acel reasoning generat este considerat un succes. Optimizatorul colectează aceste trace-uri de succes. Ia patru dintre ele și le injectează în prompt-uri viitoare. Classifier-ul tău zero-shot este acum un classifier expert four-shot, completat cu pași de reasoning sintetizați. BootstrapFewShot se oprește odată ce găsește suficiente trace-uri de succes. Dar primele trace-uri de succes nu sunt mereu cele mai bune. Aici e ideea cheie. BootstrapFewShotWithRandomSearch rezolvă asta rulând întregul proces de bootstrap de mai multe ori. De fiecare dată, extrage un sub-sample random din datele tale de training. Asta creează mai multe seturi candidate diferite de demonstrații few-shot. Optimizatorul ia apoi toate aceste seturi candidate și le evaluează pe datele tale de validare. Testează care combinație specifică de demonstrații obține cel mai mare scor general. Aruncă seturile slabe și păstrează câștigătorul matematic. Adevărata putere a automatic few-shot learning nu este doar că îți salvează timp la scrierea de prompt-uri, ci și că descoperă căi intermediare de reasoning de succes pe care dataset-ul tău nu le-a conținut niciodată explicit. Mersi de ascultare, happy coding tuturor!
10

Optimizarea instrucțiunilor cu MIPROv2

4m 02s

Aprofundează ajustarea automată a instrucțiunilor (instruction tuning). Acest episod explorează MIPROv2 și COPRO, arătând cum DSPy folosește Bayesian Optimization și coordinate ascent pentru a descoperi instrucțiuni de prompt superioare, contra-intuitive.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 10 din 15. Uneori, cea mai eficientă instrucțiune pentru un language model pare complet lipsită de sens pentru un om. Petreci ore întregi construind meticulos formularea perfectă, doar ca să descoperi că un prompt generat automat, ușor incoerent, îți depășește complet munca. De aceea ar trebui să lași algoritmii să-ți scrie prompturile. Astăzi vorbim despre Instruction Optimization cu MIPROv2. Mai întâi, uită de prompt templating. Nu este vorba despre înlocuirea variabilelor într-un string static. Instruction Optimization rescrie, de fapt, instrucțiunile de sistem care îți guvernează pipeline-ul. Algoritmii mai vechi, precum COPRO și SIMBA, au abordat asta generând variații pas cu pas ale prompturilor și rafinându-le în timp. MIPROv2 duce acest concept mult mai departe, tratând instrucțiunile și exemplele few-shot ca un unified search space. MIPROv2 funcționează în trei etape distincte. Prima etapă este bootstrapping-ul. Optimizatorul rulează programul tău neoptimizat pe datele de training pentru a construi un set de execution traces. Aceste traces conțin inputurile reale, pașii intermediari și outputurile care trec prin sistemul tău. A doua etapă este grounded proposal. Optimizatorul nu ghicește orbește instrucțiuni noi. Folosește un language model separat, numit prompter, pentru a analiza acele traces generate. Analizând unde a avut succes și unde a eșuat pipeline-ul tău, prompter-ul redactează un set de noi instrucțiuni candidate. Acești candidați sunt direct ancorați în comportamentul real al programului tău, nu în template-uri generice. A treia etapă este discrete search. MIPROv2 evaluează noile instrucțiuni alături de diferite combinații de few-shot traces. Pentru a face asta eficient, se bazează pe Bayesian Optimization. În loc să facă brute-force pe fiecare combinație posibilă, MIPROv2 construiește un surrogate model. Acest surrogate model acționează ca un proxy lightweight. El prezice ce combinații de instrucțiuni și traces vor obține cel mai mare scor pe metrica ta specifică de evaluare. Bayesian Optimization permite acelui surrogate model să mapeze spațiul de prompturi și demonstrații. Calculează îmbunătățirea așteptată atunci când testează o nouă combinație. Asta echilibrează sistematic explorarea instrucțiunilor netestate cu exploatarea combinațiilor care obțin deja scoruri bune. Optimizatorul găsește configurația optimă fără să execute mii de network calls redundante. Ia în considerare un scenariu concret. Construiești un agent ReAct pentru a răspunde la query-uri complexe. Inițial, acuratețea lui este de 24 la sută. Treci acest agent prin MIPROv2, îl configurezi să ruleze în light mode și îi oferi un dataset de 500 de întrebări. Optimizatorul face bootstrap la traces, propune grounded instructions și caută prin spațiu folosind acel surrogate model. Când termină, acuratețea agentului tău sare de la 24 la sută la 51 la sută. Promptul final care generează acest salt de performanță va conține, cel mai probabil, instrucțiuni și selecții de traces pe care un om nu le-ar fi conceput niciodată. Iată ideea cheie. MIPROv2 elimină bottleneck-ul intuiției umane. Tratează instrucțiunile în limbaj natural exact ca pe niște weights ajustabile într-un model matematic, transformând crearea de prompturi dintr-o formă de artă imprevizibilă într-o problemă de optimizare deterministă. Mersi de ascultare, happy coding tuturor!
11

Finetuning cu BootstrapFinetune

3m 38s

Descoperă cum să distilezi modele de limbaj masive în unele mai mici și eficiente. Acest episod acoperă BootstrapFinetune, explicând cum să convertești un program DSPy bazat pe prompturi într-un model personalizat, cu ponderi actualizate (weight-updated).

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 11 din 15. Prompting-ul modelelor masive este excelent pentru a porni un prototip. Dar când această logică ajunge în producție, latența și costul unui model cu șaptezeci de miliarde de parametri devin rapid o problemă. Ai nevoie de puterea de raționament a modelului mare, dar de viteza și prețul unui model de opt miliarde de parametri. Exact de asta se ocupă BootstrapFinetune. BootstrapFinetune compilează programul tău DSPy într-un model fine-tuned. Este optimizarea supremă pentru eficiență. Actualizează weights-urile reale ale unui model target mai mic pentru a imita exact comportamentul pipeline-ului tău complex. O concepție greșită des întâlnită este că, pentru a da fine-tune unui model, trebuie să aduni manual mii de exemple, să le formatezi în fișiere JSONL plictisitoare și să supraveghezi un training loop. BootstrapFinetune automatizează complet acest lucru. Se ocupă de generarea dataset-ului, de formatare și de actualizarea weights-urilor, în întregime prin trace-urile de execuție ale programului tău. Să luăm un scenariu concret cu un clasificator de intenții bancare. Programul preia un mesaj haotic de la un client și îl clasifică. Inițial, construiești un modul DSPy folosind un model foarte capabil, cum ar fi GPT-4o-mini, configurat să folosească un raționament de tip chain-of-thought. Modelul gândește pas cu pas prin formularea clientului înainte de a genera intenția ca output. Obține răspunsurile corecte, dar este prea lent și scump pentru un chat în timp real. Pentru a optimiza asta, inițializezi BootstrapFinetune. Îi dai metrica de evaluare pentru a măsura succesul și specifici modelul target mai mic și mai ieftin căruia vrei să-i dai deploy. Apoi compilezi programul. Când dai compile, DSPy rulează programul tău neoptimizat pe datele de training. Folosește modelul teacher complex pentru a genera output-uri. Optimizatorul urmărește această execuție. De fiecare dată când modelul teacher obține răspunsul corect conform metricii tale, BootstrapFinetune capturează trace-ul. Înregistrează input-urile, raționamentul pas cu pas și output-ul final. Mapează logica internă a modelului masiv într-un format pe care modelul target mic îl poate procesa. Odată ce sunt colectate suficiente trace-uri de succes, BootstrapFinetune le structurează automat într-un dataset de training. Apoi declanșează procesul de fine-tuning pe modelul tău target. Modelul mic este antrenat direct pe reasoning paths de înaltă calitate generate de modelul mare. Iată ideea cheie. Modelul mai mic învață distribuția specifică a task-ului și stilul de raționament necesar pentru a-l rezolva, fără a rula acel chain-of-thought complex la inference time. În exemplul nostru cu clasificatorul bancar, un model mic standard ar putea atinge doar o acuratețe de șaizeci și șase la sută out of the box. Dar după compilarea cu BootstrapFinetune, același model mic sare la o acuratețe de optzeci și șapte la sută. Fine-tuning-ul nu mai este un proiect de infrastructură separat; este pur și simplu un alt pas de compilare care transformă un reasoning pipeline scump într-un asset de producție rapid și ieftin. Mulțumesc pentru ascultare, happy coding tuturor!
12

Utilizarea automată a instrumentelor cu ReAct

3m 46s

Învață cum să oferi modelelor de limbaj acces la instrumente externe. Acest episod acoperă modulul dspy.ReAct, demonstrând cum să construiești agenți autonomi care raționează și interacționează dinamic cu API-urile.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 12 din 15. Să oferi unui LLM acces la API-uri externe îl face incredibil de capabil, dar să scrii un loop care să-i gestioneze raționamentul, să facă parse la outputs și să-și revină din erorile de execuție este o mare bătaie de cap. Soluția este folosirea complet automatizată de tools cu modulul DSPy ReAct. Lumea confundă adesea ReAct cu un basic function calling. Function calling este doar mecanismul de API care îi permite unui language model să-și formateze output-ul ca un request de date structurate. ReAct este o paradigmă comportamentală specifică. Vine de la Reason și Act. Este un execution loop în care modelul trece prin trei pași distincți: un Thought, un Action și un Observation. Modulul DSPy ReAct gestionează complet această orchestrare pentru tine. Nu scrii tu acel execution loop. Nu faci catch manual la excepțiile de API. ReAct face wrap peste o signature DSPy și o listă de tools, transformând un prompt static într-un agent autonom. Ca să-l folosești, mai întâi îți definești acele tools. În DSPy, tools sunt pur și simplu funcții standard Python. Scrii o funcție, îi definești parametrii de input și oferi un docstring clar. Acel docstring este critic. DSPy extrage numele funcției și docstring-ul, pasându-le către language model ca să știe exact ce face acel tool și când să-i dea deploy. Imaginează-ți un scenariu în care construiești un agent de bază pentru vreme și căutare. Scrii o funcție Python numită get weather care acceptă numele unui oraș ca string și face un query către un API pentru a returna temperatura curentă. Faci instantiate la modulul dspy dot ReAct, pasându-i o signature standard de question and answer, împreună cu o listă care conține funcția ta get weather. Când întrebi modulul cum e vremea în Tokyo, începe acel loop ReAct. Mai întâi, modelul generează un Thought. Deduce că are nevoie de date meteorologice curente pentru Tokyo. Apoi, generează un Action. Decide să apeleze acel tool get weather, pasând Tokyo ca argument. Aici e ideea cheie. Nu execuți tu acea funcție. Modulul DSPy ReAct interceptează acel Action al modelului, execută funcția ta Python în fundal și capturează output-ul. Dacă funcția are succes, DSPy trimite datele de temperatură înapoi la model ca un Observation. Dacă modelul halucinează un parametru sau funcția aruncă o eroare Python, DSPy face catch la acea eroare și trimite mesajul de eroare înapoi ca Observation. Modelul citește eroarea, generează un nou Thought pentru a-și corecta greșeala și încearcă un nou Action. Odată ce modelul observă datele corecte de temperatură, recunoaște că și-a atins obiectivul. Iese din loop și formatează răspunsul final pentru user. Pentru a preveni execuțiile necontrolate, acest ciclu este strict limitat de un parametru numit max iters, care vine de la maximum iterations. Acest parametru dictează câte cicluri de Thought, Action și Observation are voie să efectueze modulul. Dacă modelul se chinuie să găsească datele corecte și atinge limita de iterații, ReAct îl forțează să oprească căutarea și să genereze un răspuns final folosind doar informațiile pe care le-a colectat cu succes. Adevărata putere a acestui modul este că face abstractizare la acel control flow fragil și predispus la erori al agent loops, permițându-ți să tratezi raționamentul complex augmentat de tools ca pe o altă componentă previzibilă din pipeline-ul tău. Mulțumesc că m-ai ascultat, happy coding tuturor!
13

Gestionarea manuală a instrumentelor pentru control

3m 30s

Preia controlul complet asupra execuției instrumentelor. Acest episod acoperă gestionarea manuală a instrumentelor în DSPy folosind dspy.Tool, dspy.ToolCalls și native function calling pentru aplicații sensibile la latență.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Learning DSPy, episodul 13 din 15. Agenții automatizați sunt excelenți atunci când ai un task flexibil, open-ended. Dar când ai nevoie de control absolut, determinist asupra modului exact în care, când și dacă o funcție externă este executată, e prea riscant să lași volanul complet în seama modelului de limbaj. Trebuie să ridici capota și să gestionezi execuția tu însuți. Exact aici intervine manual tool handling pentru control. Folosirea unui agent loop automatizat abstractizează layer-ul de execuție, ceea ce poate cauza o latență imprevizibilă sau poate ascunde runtime errors. Gestionarea manuală este alternativa pentru power-users. Îți redă controlul asupra error recovery-ului, limitelor de timeout și ordinii exacte de execuție. Ca să construiești asta în DSPy, începi prin a face wrap unei funcții Python standard folosind clasa dspy.Tool. Imaginează-ți că ai o funcție Python care acționează ca un calculator pentru a înmulți două numere. Pasezi această funcție în dspy.Tool. Dacă funcția ta gestionează query-uri de baze de date sau network requests, poți să faci wrap și la funcții asincrone, iar clasa tool va gestiona execuția async în mod nativ. Odată ce tool-ul tău calculator este gata, trebuie să-l expui modelului de limbaj. Faci asta pasând o listă care conține tool-ul tău direct într-un modul DSPy Predict. Definești un parametru numit tools în apelul tău Predict. Când modelul procesează input-ul, evaluează prompt-ul și decide dacă are nevoie de calculator pentru a genera răspunsul final. Când modelul decide să folosească tool-ul tău, se bazează pe un mecanism subiacent numit Adapter. By default, DSPy folosește un JSONAdapter. Acest adapter traduce automat tool-ul tău Python în formatul nativ de function calling cerut de API-ul specific modelului de limbaj pe care îl folosești. Asta asigură că modelul generează un JSON fiabil și structurat atunci când solicită un tool. Fii atent la partea asta. E ușor să presupui că folosirea de native tool calling produce automat output-uri de o calitate mai bună. Documentația DSPy avertizează explicit că asta e o concepție greșită. Native tool calling oferă o fiabilitate mai bună pentru sintaxa request-ului, dar nu garantează o calitate mai bună a raționamentului decât un parsing standard bazat pe text. Modelul nu e brusc mai inteligent doar pentru că formatează JSON. Pentru că gestionezi acest proces manual, modelul nu rulează de fapt calculatorul. El se oprește și returnează un response care conține intenția sa. Accesezi această intenție inspectând response outputs punct tool calls. Această proprietate returnează un obiect dspy.ToolCalls, care se comportă ca o listă de instrucțiuni. Fiecare element din această listă specifică ce tool vrea să folosească modelul și argumentele exacte pe care le-a generat, cum ar fi cinci și zece pentru calculator. Apoi, scrii un loop Python standard pentru a itera prin aceste tool calls solicitate. Pentru fiecare call, invoci manual metoda sa execute. Invocarea metodei execute îți declanșează codul Python propriu-zis folosind argumentele generate de model și returnează rezultatul. Dacă argumentele sunt invalide sau dacă calculatorul aruncă o eroare, loop-ul tău Python o prinde. Gestionezi eroarea în termenii tăi, în loc să speri că un loop automatizat își va face recover singur. Manual tool handling separă clar decizia modelului de a solicita o acțiune de execuția fizică a acelei acțiuni, oferind aplicației tale fiabilitatea deterministă pe care o cer mediile de producție. Mulțumesc pentru audiție, happy coding tuturor!
14

Integrarea instrumentelor cu MCP

3m 51s

Conectează-ți agenții la servere universale de instrumente. Acest episod explică modul de utilizare a Model Context Protocol (MCP) în DSPy pentru a valorifica instrumente standardizate în diferite framework-uri cu o configurare minimă.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 14 din 15. De fiecare dată când adopți un nou framework de AI, de obicei ajungi să rescrii aceleași wrapper-e Python custom pentru query-urile de database, căutările web și file readere. În loc să menții la nesfârșit wrapper-e de API duplicate, cum ar fi dacă agenții tăi s-ar putea conecta instant la tool servere universale și standardizate? Asta este promisiunea Model Context Protocol, iar astăzi ne uităm la integrarea tool-urilor cu MCP. Model Context Protocol este un open standard introdus de Anthropic. El oferă o metodă universală de a conecta modelele de AI la surse de date și tool-uri externe. Adoptând acest standard, developerii scriu un tool o singură dată, îi fac host pe un server MCP și îl folosesc în orice framework compatibil. DSPy suportă asta nativ. Nu trebuie să scrii clase adaptor complexe pentru a aduce aceste tool-uri externe în programele tale DSPy. O concepție greșită comună este că DSPy gestionează singur conexiunile de server subiacente către aceste tool-uri. Nu o face. DSPy se bazează în întregime pe package-ul oficial Python mcp pentru a gestiona partea de networking și a stabili conexiunea. DSPy intervine doar la final, pentru a converti obiectul tool-ului MCP activ într-un format de tool nativ DSPy. Ca să vezi cum funcționează asta, hai să trecem prin conectarea unui tool server local la un agent DSPy. Mai întâi, ai nevoie de un server MCP care rulează. În scriptul tău Python, imporți clasa de parametri ai serverului din package-ul MCP. Dacă rulezi un proces local, definești parametrii de server standard IO și îl direcționezi către executabilul serverului tău. Alternativ, dacă tool-urile tale se află pe un server remote, configurezi o conexiune de client HTTP. Ambele metode stabilesc felul în care aplicația ta va comunica cu providerul de tool-uri. Apoi, folosești librăria MCP pentru a deschide o sesiune de client. În acest context de sesiune, inițializezi conexiunea. În acest moment, DSPy este încă complet scos din peisaj. Ceri sesiunii MCP active să listeze tool-urile disponibile. Serverul răspunde cu o listă de obiecte de tip tool. Fiecare obiect conține numele tool-ului, o descriere a ceea ce face și argumentele de input așteptate. Acum faci legătura. Aici devine interesant. Pentru fiecare tool returnat de server, apelezi metoda from mcp tool pe clasa de bază DSPy Tool. Trimiți acestei metode două argumente specifice: obiectul raw al tool-ului și sesiunea de client activă. Această singură comandă citește schema oferită de serverul MCP și îi face instant un wrap într-o interfață compatibilă. Acum ai o listă gata de utilizare cu tool-uri native DSPy. În cele din urmă, dai acea listă de tool-uri nou convertită unui agent. Inițializezi un modul ReAct și pasezi array-ul tău de tool-uri DSPy. Când rulezi agentul, acesta poate acum să apeleze fără probleme tool-urile MCP externe. Argumentele circulă de la modulul ReAct, prin wrapper-ul DSPy convertit, prin sesiunea de client MCP către server, iar rezultatul se întoarce pentru a informa următorul pas de reasoning. Adevărata putere a acestei integrări este decuplarea. Modulele tale DSPy pot accesa în siguranță database-uri enterprise sau file system-uri locale cu zero cod de wrapper custom, asigurându-te în același timp că exact același tool server rămâne complet utilizabil de către framework-uri complet diferite. Mersi de ascultare, happy coding tuturor!
15

Ensembles și Meta-Optimizare

3m 55s

Împinge DSPy la limitele sale. Ultimul episod acoperă transformările de programe prin dspy.Ensemble și meta-optimizatorul experimental BetterTogether, care combină prompt tuning cu weight finetuning pentru performanță maximă.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. Învățăm DSPy, episodul 15 din 15. Ce se întâmplă când combini Bayesian prompt optimization cu weight fine-tuning din deep learning? Nu mai tratezi prompt engineering-ul și antrenarea modelelor ca pe niște pași izolați, ci începi să le tratezi ca pe un pipeline continuu. Aici ajungi la cel mai înalt nivel de AI engineering automatizat, bazându-te pe Ensembles și Meta-Optimization. Trebuie să clarificăm imediat un lucru. Când auzi cuvântul ensemble, probabil te gândești la a face query pe cinci foundation models diferite în același timp. În DSPy, un ensemble este cu totul altceva. Un ensemble aici înseamnă rularea mai multor programe optimizate pe același language model de bază. Combină diferite structuri de prompt și diferite reasoning traces pentru a le agrega output-urile. Logica de aici este simplă. În timpul unei rulări de optimizare complexe, diferite configurații descoperă adesea reasoning paths distincte, dar la fel de valide, pentru a ajunge la răspunsul corect. Să zicem că tocmai ai rulat optimizatorul MIPROv2. Acesta evaluează sute de configurații și păstrează un istoric cu cele mai performante. În loc să alegi un singur program cu cel mai mare scor și să le ignori pe restul, extragi primele cinci programe candidate. Le pasezi în transformarea DSPy Ensemble. Când vine un nou input, ensemble-ul execută toate cele cinci programe. Le agregă output-urile, de obicei prin majority voting, și returnează un răspuns final, extrem de robust. Practic, îți scalezi compute-ul la inference time pentru a garanta un rezultat de o calitate mult mai bună. Rularea unui ensemble de cinci programe pe un foundation model masiv îți oferă o acuratețe incredibilă, dar este scumpă și lentă. Aici intervin acești meta-optimizers. Un meta-optimizer gestionează execuția altor optimizatori, secvențiindu-i pentru a le cumula beneficiile. Cel mai bun exemplu în DSPy este BetterTogether. BetterTogether aplică îmbunătățirile în straturi, în mod sistematic. Îți permite să iei capacitatea masivă de reasoning a ensemble-ului tău și să o distilezi într-un model rapid, cu fine-tuning. Mai întâi, configurezi BetterTogether să folosească prompt optimization pentru a genera reasoning traces de o calitate extrem de înaltă din ensemble-ul tău greoi. Apoi, pasează automat aceste traces într-un weight optimizer. Acest weight optimizer folosește acele date pentru a face fine-tuning pe parametrii unui student model mult mai mic și mai ieftin. În cele din urmă, BetterTogether poate rula o a doua rundă de prompt optimization, de data aceasta adaptând instrucțiunile special pentru weights-urile recent actualizate ale student model-ului. Treci de la prompt optimization, la weight optimization, și înapoi la prompt optimization. Output-ul este un model rapid și extrem de specializat, care a capturat diversele reasoning paths ale ensemble-ului original, fără costul masiv de inference. Aplicarea secvențială în straturi a tehnicilor de optimizare este modul prin care reduci decalajul dintre reasoning-ul complex și costisitor și inference-ul rapid, production-ready. Asta ne aduce la finalul seriei. Te încurajez cu tărie să explorezi documentația oficială DSPy, să încerci să construiești aceste pipeline-uri hands-on, sau să vizitezi devstories dot eu pentru a sugera subiecte pe care vrei să le vezi abordate în continuare. Mulțumesc pentru audiție, spor la codat tuturor!