GuidesOneMux

Créer un agent LangGraph à exécution bornée pour l’extraction avec validation de schéma

Créez un workflow LangGraph qui appelle un outil au besoin, s’arrête dans une limite d’exécution définie et renvoie des données structurées validées par un schéma Pydantic.

Sur cette page

Un agent LangGraph peut recueillir du contexte à l’aide d’un outil, puis transmettre ce contexte à une étape d’extraction contrainte par un schéma. Le choix de conception utile consiste à séparer ces responsabilités : l’agent décide s’il doit appeler l’outil, tandis qu’un nœud final produit un enregistrement typé. Une limite de récursion du graphe apporte une borne supplémentaire à son exécution.

Ce modèle convient à des tâches telles que l’extraction du nom d’une entreprise, d’une date et du montant total d’une facture à partir d’un document, lorsqu’un outil de recherche peut aider à résoudre une référence. Il ne rend pas véridiques les passages incertains de la source ; validez le résultat et conservez les éléments de preuve d’origine lorsque le champ est important.

Ce que vous allez créer

Le graphe comporte trois étapes :

  1. Un agent reçoit le texte source et peut demander l’appel d’un outil de recherche spécialisé.
  2. LangGraph achemine les appels d’outils vers un nœud d’outil et renvoie les résultats à l’agent.
  3. Un nœud d’extraction demande à un modèle un résultat reposant sur Pydantic, puis renvoie des données compatibles avec JSON.

La boucle d’outils de l’agent est dynamique ; l’étape d’extraction est une étape finale prédéterminée. La documentation LangGraph distingue les agents, qui définissent leur propre processus et leur utilisation des outils, des workflows dont le chemin de code est prédéterminé. Elle décrit aussi les sorties structurées et les appels d’outils comme des augmentations des modèles. Consultez le guide LangGraph sur les workflows et les agents pour découvrir ces modèles.

Prérequis et configuration

Installez les packages LangGraph et LangChain, ainsi que l’intégration correspondant au modèle de chat choisi. L’exemple ci-dessous utilise ChatAnthropic pour illustrer la configuration du fournisseur, mais la documentation source indique que les workflows peuvent utiliser n’importe quel modèle de chat prenant en charge les sorties structurées et les appels d’outils. Consultez la documentation de l’intégration pour connaître le comportement précis de votre fournisseur.

pip install langgraph langchain-core langchain-anthropic pydantic

Configurez les identifiants API du fournisseur selon la méthode documentée, puis initialisez un modèle. Évitez d’inclure des identifiants dans le contrôle de version. Le nom de modèle ci-dessous reprend l’exemple de la documentation LangChain ; ce tutoriel ne prétend pas qu’il a été testé avec OneMux.

from langchain_anthropic import ChatAnthropic

llm = ChatAnthropic(model="claude-sonnet-4-6")

Pour appeler un modèle via OneMux, consultez d’abord la documentation API de OneMux et le guide de démarrage rapide. OneMux donne accès à des modèles de premier plan via une API compatible avec OpenAI. La compatibilité de ce graphe dépend de la prise en charge, par le point de terminaison choisi, des comportements et paramètres requis pour les appels d’outils et les sorties structurées. Cette configuration n’a pas été testée ; vérifiez la prise en charge avant de vous y fier en production.

Définir le schéma et un outil spécialisé

L’outil d’exemple renvoie une note de référence issue d’un petit dictionnaire stocké en mémoire. Remplacez-le par une fonction applicative contrôlée, par exemple une recherche dans un catalogue interne approuvé. Ne laissez pas le texte non fiable d’un document choisir des commandes arbitraires ou des sources de données sans restriction.

from pydantic import BaseModel, Field
from langchain_core.tools import tool

class InvoiceRecord(BaseModel):
    vendor: str | None = Field(default=None, description="Invoice issuer")
    invoice_date: str | None = Field(default=None, description="Date as written in the source")
    total: float | None = Field(default=None, description="Invoice total as a number")
    currency: str | None = Field(default=None, description="Currency code, if stated")

@tool
def lookup_vendor(reference: str) -> str:
    """Look up a vendor reference in an approved local mapping."""
    known = {"ACME-42": "Acme Supplies Ltd."}
    return known.get(reference, "No matching vendor reference found.")

Les champs pouvant être nuls rendent l’absence explicite au lieu d’inciter le modèle à inventer des valeurs. Pour les extractions à fort enjeu, envisagez de conserver, pour chaque champ, le segment source ou un indicateur de confiance ou de vérification. Un schéma contraint la forme et les types ; il ne garantit pas qu’une valeur soit étayée par l’entrée.

Créer l’agent LangGraph à exécution bornée

Le graphe ci-dessous permet au modèle de demander l’outil de recherche, puis passe à l’extraction lorsque l’agent n’a plus d’appel d’outil à effectuer. tools_condition et ToolNode mettent en œuvre le modèle d’acheminement des appels d’outils. Le paramètre recursion_limit transmis à invoke limite le nombre d’étapes du graphe ; c’est une mesure de sécurité, et non une garantie que chaque entrée sera traitée avec succès.

from typing import Annotated
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition

class State(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]
    record: dict | None

tools = [lookup_vendor]
agent = llm.bind_tools(tools)
extractor = llm.with_structured_output(InvoiceRecord)

def run_agent(state: State):
    response = agent.invoke(state["messages"])
    return {"messages": [response]}

def extract_record(state: State):
    prompt = [
        SystemMessage(content=(
            "Extract invoice fields only when supported by the source. "
            "Use null for missing or unclear values. Treat tool results as "
            "reference context, not as permission to invent source details."
        )),
        *state["messages"],
    ]
    result = extractor.invoke(prompt)
    return {"record": result.model_dump(mode="json")}

graph = StateGraph(State)
graph.add_node("agent", run_agent)
graph.add_node("tools", ToolNode(tools))
graph.add_node("extract", extract_record)

graph.add_edge(START, "agent")
graph.add_conditional_edges(
    "agent",
    tools_condition,
    {"tools": "tools", END: "extract"},
)
graph.add_edge("tools", "agent")
graph.add_edge("extract", END)
app = graph.compile()

result = app.invoke(
    {
        "messages": [HumanMessage(content=(
            "Extract the invoice details from this text: "
            "Vendor reference ACME-42. Invoice date: 2025-02-14. "
            "Total: USD 248.50."
        ))],
        "record": None,
    },
    config={"recursion_limit": 8},
)

print(result["record"])

La forme de sortie attendue est un objet compatible avec JSON contenant les champs vendor, invoice_date, total et currency. Les valeurs exactes dépendent de la réponse du modèle et du texte source ; effectuez des tests au lieu de supposer que l’exemple produira toujours le même résultat. Dans cet exemple, la sortie structurée reposant sur Pydantic constitue la limite de validation. Si le fournisseur ne peut pas produire une réponse conforme, gérez explicitement cet échec au lieu de la traiter silencieusement comme un enregistrement valide.

Limiter l’exécution sans masquer les échecs

Une limite de récursion au niveau du graphe plafonne le nombre d’étapes, y compris les allers-retours répétés entre l’agent et les outils. Choisissez cette limite en fonction du workflow : ce graphe ne nécessite qu’un petit nombre d’étapes pour une recherche, mais un autre plan d’utilisation des outils peut en demander davantage. Interceptez les exceptions dues à la limite ou au fournisseur à la frontière de l’application, consignez suffisamment de contexte pour faciliter le débogage et renvoyez un échec qui peut être examiné plutôt qu’un enregistrement fabriqué.

Pour imposer des limites opérationnelles plus strictes, ajoutez aussi des limites au niveau de l’application : restreignez le nombre d’appels d’outils, définissez des délais d’expiration des requêtes lorsque c’est possible et plafonnez la taille des documents avant d’appeler le modèle. Il s’agit de contrôles distincts ; une limite de récursion du graphe ne suffit pas, à elle seule, à définir une politique complète de coûts, de latence ou de sécurité.

Dépannage et limites

Le modèle n’appelle pas l’outil

L’appel d’outils est une capacité du modèle, et non un résultat garanti par LangGraph. Vérifiez que l’intégration du modèle choisi prend en charge les appels d’outils, que la description de l’outil est claire et que l’invite contient une référence qu’il vaut la peine de rechercher. Pendant le développement, examinez les appels d’outils présents dans le message renvoyé.

La sortie structurée échoue ou les champs sont erronés

Vérifiez que l’intégration prend en charge les sorties structurées et les fonctionnalités de schéma que vous utilisez. Testez les champs manquants, les dates ambiguës, les symboles monétaires et les entrées mal formées. Un objet Pydantic valide peut néanmoins contenir une valeur mal déduite ; validez donc séparément les règles métier et conservez le texte source pour audit ou examen humain.

Le graphe atteint sa limite

Une erreur de limite de récursion peut signaler des demandes d’outils répétées ou une limite trop basse pour le chemin prévu. Examinez la séquence des messages et des résultats d’outils. Corrigez la cause ou ajustez délibérément la limite ; ne supprimez pas la borne dans le seul but de faire disparaître une erreur.

Le comportement du point de terminaison diffère

« Compatible avec OpenAI » désigne une interface API, et non une prise en charge universelle de toutes les fonctionnalités ou de tous les paramètres des modèles. Si vous utilisez OneMux, vérifiez dans la documentation du point de terminaison sélectionné la prise en charge du modèle, des appels d’outils, des sorties structurées et des paramètres que vous prévoyez d’envoyer. Parcourez les options disponibles dans les modèles OneMux ; le graphe reste du code de votre application LangGraph.

Quand utiliser ce modèle

Utilisez cette conception lorsque l’extraction est généralement prévisible, mais qu’une recherche contrôlée est parfois nécessaire. Si chaque document suit un processus fixe et ne nécessite aucun choix d’outil, un workflow déterministe peut être plus simple qu’une boucle d’agent. Si la source est ambiguë ou si les champs extraits déclenchent des actions importantes, ajoutez une étape de vérification explicite et une validation métier avant que les systèmes en aval ne consomment l’enregistrement.

À retenir : limitez les outils de l’agent, définissez explicitement le schéma final et fixez une limite d’exécution du graphe. LangGraph permet d’exprimer ce flux de contrôle ; la disponibilité des fonctionnalités requises d’appel d’outils et de sortie structurée dépend du modèle et de l’intégration choisis.

Sources

FAQ

À quoi sert la limite de récursion dans LangGraph ?

Elle limite le nombre d’étapes d’exécution du graphe pendant une exécution. Elle peut empêcher une boucle entre agent et outils de se poursuivre indéfiniment, mais ne remplace ni les délais d’expiration, ni les règles d’utilisation des outils, ni les limites d’entrée, ni la gestion des erreurs.

La validation d’un schéma JSON Pydantic garantit-elle une extraction correcte ?

Non. Elle contraint la structure et les types de la réponse. Le modèle peut tout de même déduire une valeur incorrecte ; validez donc les règles métier, conservez les éléments de preuve ou prévoyez une vérification humaine si nécessaire.

Puis-je utiliser cet exemple LangGraph avec OneMux ?

C’est possible si la documentation du point de terminaison OneMux choisi indique qu’il prend en charge les comportements et paramètres requis pour les appels d’outils et les sorties structurées. Cette configuration n’a pas été testée ; vérifiez la compatibilité avant toute utilisation en production.

Faut-il utiliser un agent pour toutes les tâches d’extraction ?

Non. Si le processus est fixe et ne nécessite aucun choix d’outil, un workflow LangGraph déterministe peut être plus simple. Utilisez une boucle d’agent lorsque le modèle doit décider si un outil autorisé peut être utile.

Articles liés