⚠ Brouillon — en attente de relecture
langchain v1.3.13

Output Parsers dans LangChain : structurer les réponses du LLM

Les Output Parsers transforment le texte brut du LLM en données structurées. Depuis LangChain 0.3, with_structured_output est la méthode recommandée — elle utilise le function calling natif du modèle.

⚠️ Point d'attention

Ne pas mélanger with_structured_output et StrOutputParser dans la même chaîne : le premier renvoie un objet Pydantic, le second attend un AIMessage.

Output Parsers dans LangChain

Le problème

Un LLM renvoie du texte. Votre application a besoin de données structurées — un objet Python, un dictionnaire, une liste. Le parseur de sortie transforme le texte brut du modèle en structure exploitable.

LangChain propose plusieurs parseurs, du plus simple au plus robuste. Depuis LangChain 0.3, la méthode recommandée pour la plupart des cas est with_structured_output, mais les parseurs classiques restent utiles dans certains contextes.

StrOutputParser : extraire le texte brut

Le parseur le plus simple. Il extrait la chaîne de caractères du message de réponse.

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

prompt = ChatPromptTemplate.from_template("Résume en une phrase : {texte}")
model = ChatOpenAI(model="gpt-4o-mini")
parser = StrOutputParser()

chain = prompt | model | parser
result = chain.invoke({"texte": "LangChain est un framework..."})
# result est une str, pas un AIMessage
print(type(result))  # <class 'str'>

Sans StrOutputParser, la chaîne renvoie un objet AIMessage. Avec, elle renvoie directement le contenu texte. Presque toutes les chaînes LCEL l’utilisent en dernier maillon.

JsonOutputParser : extraire du JSON

Quand le modèle doit renvoyer un objet JSON :

from langchain_core.output_parsers import JsonOutputParser

parser = JsonOutputParser()

prompt = ChatPromptTemplate.from_template(
    """Extrais les informations suivantes du texte.
Réponds UNIQUEMENT avec un objet JSON valide, sans texte autour.

Champs attendus : nom, age, ville

Texte : {texte}

{format_instructions}"""
)

# Injecter les instructions de format dans le prompt
prompt_with_format = prompt.partial(
    format_instructions=parser.get_format_instructions()
)

chain = prompt_with_format | model | parser
result = chain.invoke({"texte": "Marie, 28 ans, habite à Lyon."})
print(result)  # {"nom": "Marie", "age": 28, "ville": "Lyon"}
print(type(result))  # <class 'dict'>

get_format_instructions() génère un texte qui indique au modèle le format attendu. Le parseur tente ensuite d’extraire le JSON de la réponse, même si le modèle ajoute du texte autour.

PydanticOutputParser : validation avec un schéma

Pour une validation stricte avec un modèle Pydantic :

from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

class PersonneInfo(BaseModel):
    nom: str = Field(description="Le nom complet de la personne")
    age: int = Field(description="L'âge en années")
    ville: str = Field(description="La ville de résidence")

parser = PydanticOutputParser(pydantic_object=PersonneInfo)

prompt = ChatPromptTemplate.from_template(
    """Extrais les informations de la personne mentionnée dans le texte.

{format_instructions}

Texte : {texte}"""
)

chain = prompt.partial(
    format_instructions=parser.get_format_instructions()
) | model | parser

result = chain.invoke({"texte": "Pierre Dupont, 35 ans, vit à Bordeaux."})
print(result.nom)   # Pierre Dupont
print(result.age)   # 35
print(type(result)) # <class 'PersonneInfo'>

Avantage par rapport au JsonOutputParser : Pydantic valide les types (un age qui n’est pas un entier lève une erreur), fournit des valeurs par défaut, et documente le schéma via les descriptions de champs.

with_structured_output : la méthode recommandée

Depuis LangChain 0.3, la méthode with_structured_output sur les modèles de chat est le moyen recommandé pour obtenir des sorties structurées. Elle utilise les fonctionnalités natives du modèle (function calling, tool use) au lieu de demander au LLM de formater du JSON dans sa réponse textuelle.

from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI

class Analyse(BaseModel):
    sentiment: str = Field(description="positif, négatif ou neutre")
    score: float = Field(description="Score de confiance entre 0 et 1")
    mots_cles: list[str] = Field(description="3 mots-clés principaux")

model = ChatOpenAI(model="gpt-4o-mini")
model_structure = model.with_structured_output(Analyse)

prompt = ChatPromptTemplate.from_template(
    "Analyse le sentiment de ce texte : {texte}"
)

chain = prompt | model_structure
result = chain.invoke({"texte": "Ce produit est excellent, je le recommande !"})
print(result.sentiment)  # positif
print(result.score)      # 0.95
print(result.mots_cles)  # ["excellent", "recommande", "produit"]

Pourquoi préférer with_structured_output :

  • Plus fiable — le modèle utilise son mécanisme natif de function calling, pas du formatage texte.
  • Pas besoin de format_instructions — le schéma Pydantic est transmis directement au modèle.
  • Pas de parseur séparé — le modèle renvoie directement l’objet Pydantic.
  • Streaming supporté — les champs arrivent au fur et à mesure.

Quand utiliser quoi

Situation Outil recommandé
Texte brut en sortie StrOutputParser
JSON structuré, modèle récent (GPT-4, Claude, Gemini) with_structured_output
JSON structuré, modèle sans function calling PydanticOutputParser
JSON sans schéma strict JsonOutputParser
Listes simples CommaSeparatedListOutputParser

Gestion des erreurs de parsing

Les modèles ne produisent pas toujours un JSON valide. OutputFixingParser tente de corriger les erreurs en renvoyant la sortie malformée au modèle :

from langchain.output_parsers import OutputFixingParser

# Encapsule un parseur existant avec auto-correction
fixing_parser = OutputFixingParser.from_llm(
    parser=PydanticOutputParser(pydantic_object=PersonneInfo),
    llm=model
)

# Si le premier parsing échoue, le modèle est rappelé
# avec le JSON malformé + l'erreur pour correction
chain = prompt | model | fixing_parser

Le coût : un appel LLM supplémentaire en cas d’échec. En production, surveillez le taux de corrections — s’il est élevé, améliorez le prompt plutôt que de compter sur le fixing.

Points d’attention

with_structured_output ne fonctionne pas avec tous les modèles. Il nécessite le support du function calling ou tool use. Les modèles OpenAI (GPT-4, GPT-4o), Anthropic (Claude 3+), et Google (Gemini) le supportent. Les modèles locaux via Ollama ne le supportent pas toujours — vérifiez avec model.with_structured_output et gérez le NotImplementedError.

Ne pas mélanger with_structured_output et StrOutputParser. Le premier renvoie un objet Pydantic, le second attend un AIMessage. Les deux dans la même chaîne lèvent une erreur de type.

Les descriptions des champs Pydantic comptent. Le modèle les utilise pour comprendre quoi extraire. score: float est ambigu. score: float = Field(description="Score de confiance entre 0 et 1") est clair.