Accueil / Articles

Workflows conditionnels LangGraph : création de branches sans enchevêtrements de prompts

Encodez le routage if-else de LangGraph en arêtes conditionnelles nommées, dotées de contrats d’état clairs et de mécanismes de récupération en cas de panne, au lieu d’intégrer les branches dans les prompts.

Éditeur : REACTAPP.TOP10 min de lecture2192 mots

Sources: Conditional Workflows in LangGraph: The If-Else of Agentic AI

Ce guide permet de reconstruire un parcours fonctionnel pour : Les flux de travail conditionnels dans LangGraph : l’If-Else de l’IA agente. L’accent est mis sur les contrats, les vérifications et le code que l’on peut intégrer dans un dépôt sans devoir deviner l’intention derrière lui. Pour une vue d’ensemble, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans avoir à deviner l’état caché. Documentez conjointement le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’une amélioration ultérieure.

Qu’est-ce qu’un flux de travail conditionnel, au juste ?

Pourquoi même existerait-il un flux de travail conditionnel ? Il convient de définir les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité et non un processus embrouillé. Restreignez strictement les schémas des outils. Des arguments de texte libre trop larges facilitent les injections et rendent les audits coûteux.

Flux de travail n°1 : Résolution d’une équation quadratique

Pour le flux de travail n°1 : Résolution d’une équation quadratique, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminaisons partielles silencieuses. Restreignez strictement les schémas des outils. Des arguments de texte libre trop larges favorisent les injections et rendent les audits coûteux.

La structure du flux de travail

Pour la structure du flux de travail, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution et les coûts à côté des résultats fonctionnels. Une visibilité précoce évite des factures inattendues lorsque le flux passe d’un environnement de démonstration à un environnement partagé. Restreignez strictement les schémas des outils. Des arguments de texte libre trop larges facilitent les injections et rendent les audits coûteux. Pour la structure du flux de travail, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours idéal et le parcours de récupération. Les tentatives de répétition, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations ultérieures.

Création de l’état

Pour construire l’état, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Créez un point de contrôle après des appels coûteux au modèle afin qu’un nouvel essai ne reprenne pas le même travail.

class QuadState(TypedDict):
    a: float
    b: float
    c: float
    equation: str
    discriminant: float
    result: str

Les nœuds

Pour les nœuds, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute exécution partielle silencieuse. Créez un point de contrôle après des appels coûteux au modèle afin qu’un nouvel essai ne facture pas à nouveau le même travail.

def show_equation(state: QuadState):
    equation = f"{state['a']}x² + {state['b']}x + {state['c']}"
    return {"equation": equation}

def calculate_discriminant(state: QuadState):
    discriminant = (state['b'] ** 2) - (4 * state['a'] * state['c'])
    return {"discriminant": discriminant}

def real_roots(state: QuadState):
    r1 = (-state['b'] + state['discriminant'] ** 0.5) / (2 * state['a'])
    r2 = (-state['b'] - state['discriminant'] ** 0.5) / (2 * state['a'])
    result = f"The roots are {r1} and {r2}"
    return {"result": result}

def repeated_root(state: QuadState):
    root = -state['b'] / (2 * state['a'])
    result = f"Only repeating root is {root}"
    return {"result": result}

def no_real_roots(state: QuadState):
    return {"result": "No real roots"}

La fonction de routage — C’est la partie clé

Pour la fonction de routage — c’est l’élément essentiel : définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution et les coûts à côté des résultats fonctionnels. Une visibilité précoce évite des factures inattendues lorsque le parcours passe d’un environnement de démonstration à un environnement partagé. Instaurez un point de contrôle après des appels de modèles coûteux afin qu’un nouvel essai ne génère pas à nouveau des frais pour le même travail. Pour la fonction de routage — c’est l’élément essentiel : définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours optimal et les scénarios de récupération. Les tentatives de relance, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’améliorations ultérieures.

def check_condition(state: QuadState):
    if state['discriminant'] > 0:
        return "real_roots"
    elif state['discriminant'] == 0:
        return "repeated_root"
    else:
        return "no_real_roots"

Le mettre en œuvre

Pour le mettre en œuvre, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables à des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Séparez la planification de l’exécution par les outils. Le planificateur propose ; l’exécutant modifie ; le vérificateur contrôle les résultats par rapport à l’objectif.

graph = StateGraph(QuadState)

graph.add_node("show_equation", show_equation)
graph.add_node("calculate_discriminant", calculate_discriminant)
graph.add_node("real_roots", real_roots)
graph.add_node("repeated_root", repeated_root)
graph.add_node("no_real_roots", no_real_roots)

graph.add_edge(START, "show_equation")
graph.add_edge("show_equation", "calculate_discriminant")

# This is the magic line
graph.add_conditional_edges("calculate_discriminant", check_condition)

graph.add_edge("real_roots", END)
graph.add_edge("repeated_root", END)
graph.add_edge("no_real_roots", END)

workflow = graph.compile()

Workflow n°2 : Gestionnaire des avis clients (basé sur un LLM)

Pour le flux de travail n°2 : Gestionnaire des avis clients (basé sur un LLM), définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute exécution partielle silencieuse. Séparez la planification de l’exécution des outils. Le planificateur propose ; l’exécutant modifie ; le vérificateur compare les résultats à l’objectif.

Le scénario

Pour ce scénario, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution et les coûts à côté des résultats fonctionnels. Une visibilité précoce évite des factures inattendues lorsque le parcours passe d’un environnement de démonstration à des environnements partagés. Séparez la planification de l’exécution par les outils. Le planificateur propose ; l’exécutant modifie ; le vérificateur contrôle les résultats par rapport à l’objectif. Pour ce scénario, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours idéal et le parcours de récupération. Les tentatives de réessai, les contrôles humains et la gestion des messages non livrés font partie du produit, et non d’une mise en forme ultérieure.

Schémas de sortie structurés

Pour les schémas de sortie structurés, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Restreignez strictement les schémas des outils. Des arguments de texte libre trop larges facilitent les injections et rendent les audits coûteux.

from pydantic import BaseModel
from typing import Literal

class SentimentSchema(BaseModel):
    sentiment: Literal["positive", "negative"]

class DiagnosisSchema(BaseModel):
    issue_type: Literal["UI", "performance", "bug", "support", "other"]
    tone: Literal["frustrated", "angry", "disappointed", "neutral"]
    urgency: Literal["low", "medium", "high"]
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini")
structured_model_sentiment = model.with_structured_output(SentimentSchema)
structured_model_diagnosis = model.with_structured_output(DiagnosisSchema)

L’état

Pour l’État, il convient de définir les entrées, le responsable de l’étape et les critères de sortie avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminations partielles silencieuses. Restreignez strictement les schémas des outils. Des arguments de texte libre trop larges favorisent les injections et rendent les audits coûteux.

class ReviewState(TypedDict):
    review: str
    sentiment: Literal["positive", "negative"]
    diagnosis: dict
    response: str

Les nœuds

Pour The Nodes, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution et les coûts à côté des résultats fonctionnels. Une visibilité précoce évite des factures inattendues lorsque le parcours passe d’un environnement de démonstration à un environnement partagé. Restreignez strictement les schémas des outils. Des arguments de texte libre trop larges facilitent les injections et rendent les audits coûteux. Pour The Nodes, définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours idéal et le parcours de récupération. Les tentatives de répétition, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une amélioration ultérieure.

def find_sentiment(state: ReviewState):
    prompt = f"For the following review, find out the sentiment:\n{state['review']}"
    result = structured_model_sentiment.invoke(prompt)
    return {"sentiment": result.sentiment}
def positive_response(state: ReviewState):
    prompt = f"""Write a warm thank you message in response to this review:
    {state['review']}
    Also kindly ask the user to leave feedback on our website."""

    result = model.invoke(prompt)
    return {"response": result.content}
def run_diagnosis(state: ReviewState):
    prompt = f"""Diagnose this negative review:
    {state['review']}
    Return issue type, tone, and urgency."""

    result = structured_model_diagnosis.invoke(prompt)
    return {"diagnosis": result.model_dump()}
def negative_response(state: ReviewState):
    diagnosis = state['diagnosis']
    prompt = f"""You are a support assistant. The user had a {diagnosis['issue_type']} issue,
    sounded {diagnosis['tone']}, and marked urgency as {diagnosis['urgency']}.
    Write an empathetic, helpful resolution message."""

    result = model.invoke(prompt)
    return {"response": result.content}
def check_sentiment(state: ReviewState):
    if state['sentiment'] == "positive":
        return "positive_response"
    else:
        return "run_diagnosis"

Le graphe

Pour The Graph, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables aux scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Créez un point de contrôle après des appels coûteux au modèle afin qu’un nouvel essai ne reprenne pas le même travail.

graph = StateGraph(ReviewState)

graph.add_node("find_sentiment", find_sentiment)
graph.add_node("positive_response", positive_response)
graph.add_node("run_diagnosis", run_diagnosis)
graph.add_node("negative_response", negative_response)

graph.add_edge(START, "find_sentiment")
graph.add_conditional_edges("find_sentiment", check_sentiment)
graph.add_edge("positive_response", END)
graph.add_edge("run_diagnosis", "negative_response")
graph.add_edge("negative_response", END)

workflow = graph.compile()

Le tester

Pour le tester, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminations partielles silencieuses. Créez un point de contrôle après des appels coûteux au modèle afin qu’un nouvel essai ne facture pas à nouveau le même travail.

Le modèle mental fondamental

Pour le Modèle Mental Central, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution et les coûts à côté des résultats fonctionnels. Une visibilité précoce évite des factures inattendues lorsque le processus passe d’un environnement de démonstration à des environnements partagés. Instaurez un point de contrôle après des appels de modèle coûteux afin qu’un nouvel essai ne fasse pas payer à nouveau le même travail. Pour le Modèle Mental Central, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours idéal et le parcours de récupération. Les tentatives de relance, les contrôles humains et la gestion des messages non traités font partie intégrante du produit, et non d’une amélioration ultérieure.

Que faire ensuite

Pour ce qui vient ensuite, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier du code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Préférez des unités petites et testables à des scripts complexes. Lorsqu’une étape échoue, l’échec doit indiquer une seule responsabilité plutôt qu’un processus embrouillé. Séparez la planification de l’exécution des outils. Le planificateur propose ; l’exécutant modifie ; le vérificateur compare les résultats à l’objectif.

Apprentissage structuré au-delà des blogs

Séparez la planification de l’exécution des outils. Le planificateur propose ; l’exécutant modifie ; le vérificateur compare les résultats à l’objectif.

Cours

Séparez la planification de l’exécution des outils. Le planificateur propose ; l’exécutant modifie ; le vérificateur compare les résultats à l’objectif.

Liste de contrôle opérationnelle

Point de contrôle après les appels coûteux aux modèles afin qu’une tentative de réexécution ne facture pas à nouveau le même travail.

Gardez l’état du graphe plat et typé. Les blocs imbriqués masquent le fait que tel nœud a écrit telle champ et perturbent la reprise après interruption.

Rédigez un petit guide opérationnel : comment rotationner les clés, comment vider la file d’attente, comment annuler la dernière modification.