O semnătură (dspy.Signature) spune ce trebuie să facă modelul: ce câmpuri primește și ce câmpuri produce. Forma scurtă este un șir "intrari -> iesiri", de exemplu "context, intrebare -> raspuns". Câmpurile fără tip sunt str; tipul se poate scrie în șir ("text -> etichete: list[str]"). Documentația insistă pe nume: modelul citește numele câmpurilor și deduce din ele ce se cere.
Forma de clasă adaugă un docstring, folosit ca instrucțiuni ale sarcinii, și câmpuri dspy.InputField / dspy.OutputField cu tipuri și descrieri (desc). Tipurile pot fi Literal, liste, modele Pydantic sau tipuri DSPy (dspy.Image, dspy.History), iar răspunsul este convertit în tipul declarat. Fără docstring, DSPy generează instrucțiunea „Given the fields …, produce the fields …”. Optimizatorii de instrucțiuni rescriu doar docstring-ul; numele și descrierile câmpurilor rămân cum le-ai scris.
Un modul spune cum se execută semnătura. dspy.Predict face un apel; dspy.ChainOfThought adaugă înaintea ieșirilor un câmp reasoning; dspy.ReAct rulează o buclă cu unelte. Programele mai mari moștenesc dspy.Module (asemănător cu torch.nn.Module), își declară submodulele în __init__ și le compun în forward(). Submodulele declarate ca atribute sunt găsite automat de optimizatori și de save(). Rezultatul este un dspy.Prediction, cu câmpurile de ieșire ca atribute.
Concepte cheie și caracteristici
| Concept / Parametru | Descriere practică |
|---|---|
dspy.Signature |
Clasa de bază. Șirul "a, b -> c" și o clasă derivată produc același tip de obiect. Metodele with_instructions(), append(), with_updated_fields() întorc o semnătură nouă. |
dspy.InputField / dspy.OutputField |
Câmpuri construite peste pydantic.Field: desc, prefix și constrângerile Pydantic (gt, min_length …). |
dspy.Predict(semnatura) |
Modulul de bază: un apel la model. |
dspy.ChainOfThought(semnatura) |
Adaugă ieșirea reasoning înaintea câmpurilor declarate; se citește cu rez.reasoning. |
dspy.ReAct(semnatura, tools=[...]) |
Buclă cu unelte; vezi ReAct și unelte. |
dspy.Module |
Clasa de bază pentru programe proprii: submodule în __init__, logica în forward() sau aforward(). |
dspy.Prediction |
Rezultatul unui modul; câmpurile se citesc ca rez.camp sau rez["camp"]. |
Exemple practice și scenarii reale
Exemplul 1: Semnătură ca șir, cu tip
import dspy
dspy.configure(lm=dspy.LM("openai/gpt-6-luna"))
clasifica = dspy.Predict("propozitie -> pozitiva: bool")
rez = clasifica(propozitie="Livrarea a întârziat, dar produsul e foarte bun.")
print(rez.pozitiva)
Exemplul 2: Semnătură ca clasă, executată cu ChainOfThought
from typing import Literal
import dspy
dspy.configure(lm=dspy.LM("anthropic/claude-sonnet-5-5"))
class AnalizaStire(dspy.Signature):
"""Clasifică știrea și scrie un rezumat scurt, în română."""
articol: str = dspy.InputField(desc="textul complet al știrii")
categorie: Literal["Tehnologie", "Economie", "Politică", "Sport"] = dspy.OutputField()
rezumat: str = dspy.OutputField(desc="cel mult două propoziții")
analiza = dspy.ChainOfThought(AnalizaStire)
rez = analiza(articol="...")
print(rez.categorie)
print(rez.rezumat)
print(rez.reasoning) # câmpul adăugat de ChainOfThought
Exemplul 3: Program propriu din doi pași
class RezumatTradus(dspy.Module):
def __init__(self):
super().__init__()
self.rezuma = dspy.ChainOfThought("text -> rezumat")
self.traduce = dspy.Predict("text, limba -> traducere")
def forward(self, text, limba="engleză"):
rezumat = self.rezuma(text=text).rezumat
return self.traduce(text=rezumat, limba=limba)
program = RezumatTradus()
rez = program(text="...") # nu program.forward(...)
print(rez.traducere)
Greșeli frecvente și capcane
- Citești
rez.rationale, ca în tutorialele vechi. În DSPy 3.x câmpul adăugat deChainOfThoughtse numeștereasoning. - Pui reguli lungi în docstring sau în
desc. Documentația recomandă o descriere scurtă a sarcinii; regulile detaliate sunt treaba optimizatorilor. Descrierile și numele câmpurilor nu sunt modificate de optimizatori, deci alege-le clar. - Apelezi
program.forward(...)direct. Ocolești urmărirea consumului și callback-urile, iar DSPy afișează un avertisment de depreciere; apeleazăprogram(...). - Rulezi un modul fără
dspy.configure(lm=...). Modulul caută modelul la apel și se oprește cu eroare dacă nu există unul.