Metoda .with_structured_output() și Pydantic în LangChain & LangGraph

Face modelul să răspundă cu date în forma unei scheme (Pydantic, TypedDict sau JSON Schema) în loc de text liber.

Sintaxă & invocare Python
from pydantic import BaseModel, Field

class Recenzie(BaseModel):
    scor: int = Field(description="Nota de la 1 la 10")
    sentiment: str = Field(description="pozitiv, neutru sau negativ")

extractor = model.with_structured_output(Recenzie)
rez = extractor.invoke("Telefonul are o baterie excelentă, îi dau 9 din 10!")

model.with_structured_output(Schema) întoarce un Runnable care răspunde cu date în forma schemei. Schema poate fi o clasă Pydantic (primești o instanță validată), un TypedDict sau un JSON Schema (primești un dicționar). Documentația precizează că doar modelele Pydantic validează automat; la TypedDict și JSON Schema validarea e manuală.

Parametrul method alege mecanismul, după ce suportă furnizorul: "json_schema" folosește funcția de structured output a furnizorului, "function_calling" forțează un apel de unealtă cu schema dată, iar "json_mode" cere doar JSON valid, cu schema descrisă în prompt. Cu include_raw=True primești un dicționar cu raw (mesajul brut, de exemplu pentru usage_metadata), parsed și parsing_error.

Descrierile din Field(description=...) și docstring-ul clasei ajung în schema trimisă modelului. La agenți, echivalentul este parametrul response_format din create_agent, cu strategiile ToolStrategy (apel de unealtă) și ProviderStrategy (structured output nativ); rezultatul apare în cheia structured_response.

Concepte cheie și caracteristici

Concept / Parametru Descriere practică
schema Clasă Pydantic, TypedDict sau dicționar JSON Schema.
method="json_schema" Folosește structured output-ul nativ al furnizorului.
method="function_calling" Forțează un apel de unealtă care urmează schema.
method="json_mode" JSON valid, dar schema trebuie descrisă în prompt.
include_raw=True Întoarce {"raw": ..., "parsed": ..., "parsing_error": ...}.
response_format (create_agent) Varianta pentru agenți: schemă, ToolStrategy(Schema) sau ProviderStrategy(Schema).

Exemple practice și scenarii reale

Exemplul 1: Extragere într-o clasă Pydantic

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model

class Recenzie(BaseModel):
    """Analiza unei recenzii de produs."""
    scor: int = Field(description="Nota de la 1 la 10")
    sentiment: str = Field(description="pozitiv, neutru sau negativ")

model = init_chat_model("gpt-6-astra")
rez = model.with_structured_output(Recenzie).invoke(
    "Telefonul are o baterie excelentă, îi dau 9 din 10!"
)
print(rez.scor, rez.sentiment)

Exemplul 2: În lanț, cu mesajul brut

from langchain_core.prompts import ChatPromptTemplate

class Factura(BaseModel):
    furnizor: str
    total_ron: float
    produse: list[str]

prompt = ChatPromptTemplate.from_messages([
    ("system", "Extragi datele facturii din text."),
    ("human", "{text}"),
])
extractor = prompt | model.with_structured_output(Factura, include_raw=True)
rez = extractor.invoke({"text": text_factura})
print(rez["parsed"], rez["raw"].usage_metadata)

Greșeli frecvente și capcane

  • Să crezi că orice schemă e validată. Validarea automată există doar pentru Pydantic; cu TypedDict sau JSON Schema verifici tu datele primite.
  • Să lași câmpurile fără descriere. Descrierile din Field și docstring-ul fac parte din schema pe care o vede modelul.
  • Să ceri JSON doar prin prompt la un agent. În v1, varianta „prompted output” din response_format a fost eliminată pentru că nu s-a dovedit fiabilă; folosește ToolStrategy sau ProviderStrategy.

Noțiuni și module înrudite