Accéder au contenu principal

Tutoriel pratique sur les agents LangGraph

Maîtrisez les principes fondamentaux de LangGraph (état, nœuds, arêtes, mémoire) et créez des agents IA évolutifs grâce aux modèles ReAct, à des outils personnalisés et à la gestion persistante des états.
Actualisé 16 juil. 2025

LangGraph est un cadre basé sur des graphes permettant de créer des agents IA capables de raisonner, de planifier et d'agir à travers des étapes interconnectées. Sa particularité réside dans le fait qu'il nous permet de créer facilement des flux de travail cycliques et ramifiés, dans lesquels chaque nœud peut exécuter un LLM, un outil ou une fonction, tout en gérant automatiquement l'état.

Cela rend LangGraph idéal pour la création de systèmes multi-agents complexes et robustes qui nécessitent de la mémoire, la gestion des erreurs et la prise de décision en temps réel.

Dans ce tutoriel, je vais vous présenter les principes fondamentaux et les fonctionnalités avancées de LangGraph, depuis la compréhension de ses composants principaux jusqu'à la création d'agents IA dotés d'un état et assistés par des outils. Si vous êtes intéressé par la créer des systèmes multi-agents avec LangGraph, veuillez consulter notre cours pratique. Vous pouvez également visionner notre tutoriel vidéo sur la création d'agents LangGraph ci-dessous.

Principes fondamentaux de LangGraph

Commençons par examiner les éléments fondamentaux de LangGraph. Ces éléments nous permettent de créer des flux de travail structurés, avec état et évolutifs pour développer des agents IA avancés.

État

L'état est un objet de mémoire partagée qui circule dans le graphe. Il stocke toutes les informations pertinentes telles que les messages, les variables, les résultats intermédiaires et l'historique des décisions. LangGraph gère automatiquement l'état, ce qui rend le développement plus efficace.

Pour compléter le système d'état, des fonctionnalités avancées sont disponibles, telles que les points de contrôle, la mémoire locale par thread et la persistance entre sessions. Diagramme de cycle illustrant la gestion des états dans LangGraphTout au long de l'exécution, l'état est exécuté en continu, comme illustré dans le diagramme ci-dessous :

Cycle de gestion d'état dans LangGraph montrant les mises à jour continues entre les nœuds

Nœud

Une unité fonctionnellede nœud est une unité fonctionnelle unique dans le flux de travail. Il peut effectuer diversesactions d', telles que :

  • Appel d'un modèle linguistique de grande taille (LLM)
  • Appel d'un outil ou d'une API
  • Exécution d'une fonction Python personnalisée
  • Logique de routage ou décisions de branchement

Chaque nœud prend en compte l'état actuel et renvoie un état mis à jour.

Arêtes et arêtes conditionnelles

Les arêtes définissent les transitions entre les nœuds. Ils déterminent le flux de contrôle du graphe et peuvent prendre en charge :

  • Connexions statiques (pour une progression linéaire)
  • Chemins cycliques (pour les comportements itératifs)
  • Branchement dynamique (basé sur des conditions d'état - créé via des arêtes conditionnelles)

Diagramme illustrant comment les arêtes relient les nœuds pour définir le flux dans LangGraph

Différents types d'arêtes définissent le flux entre les nœuds et contrôlent les informations à travers le graphe.

Les arêtes sont essentielles pour orchestrer les comportements complexes des agents.

Graphique et diagramme

Un graphique dans LangGraph définit la structure du flux de travail agentique et se compose de nœuds reliés par des arêtes.

Diagramme d'une structure LangGraph illustrant les nœuds et les arêtes formant un flux de travail

La structure graphique est une combinaison de nœuds et d'arêtes.

L' StateGraph est un graphe spécialisé qui maintient et met à jour un état partagé tout au long de l'exécution. Il permet une prise de décision contextuelle et une mémoire persistante à toutes les étapes. Nous pouvons considérer cela comme la fusion de State et Graph.

Outil et nœud d'outil

Un outil est toute fonction externe ou interne qu'un agent peut appeler, telle qu'une recherche sur le Web, une calculatrice ou un utilitaire personnalisé. Il existe deux types d'outils :

  • Outils intégrés : Outils préconfigurés et prêts à l'emploi par Langchain, accessibles dans la documentation. Documentation.
  • Outils personnalisés : Outils que nous pouvons créer nous-mêmes et utiliser dans notre application (à l'aide d'un décorateur et d'une chaîne DocString - cela sera illustré dans le code plus tard).

Un ToolNode est un type de nœud dédié à l'exécution d'outils au sein du graphe. Cela nous permet, en tant que développeurs, d'intégrer des outils sans avoir à écrire de code supplémentaire. Nous pouvons considérer cela comme la fusion de Tool et Node.

Types de messages

Les messages sont des éléments de données structurés (tels que les entrées utilisateur, les sorties système, les réponses intermédiaires, etc.) qui se déplacent dans le graphe et sont stockés dans l'état. Ils permettent la traçabilité, la mémorisation et la contextualisation des décisions des agents, ce qui contribue à la prise de décisions plus éclairées.

Il existe plusieurs types de messages dans LangGraph :

  • Message humain : Représente les données saisies par un utilisateur. Il s'agit du type de message le plus couramment utilisé pour démarrer ou poursuivre une conversation avec l'agent dans le graphique.
  • Message AIM : Représente les réponses générées par les modèles linguistiques sous-jacents. Ces informations sont stockées afin de conserver la mémoire conversationnelle et d'orienter les actions futures.
  • Message système : Fournit des instructions contextuelles ou de configuration du comportement au LLM (par exemple, « Vous êtes mon assistant personnel »). Ce message influence la manière dont le modèle réagit.
  • Message de l'outil : Encapsule la sortie d'un outil. Ces informations sont cruciales lorsque votre agent s'appuie sur des opérations externes (telles que des calculs ou des recherches) pour décider de ses prochaines étapes.
  • Supprimer le message : Utilisé pour supprimer ou annuler par programmation des messages précédemment ajoutés à l'état. Ceci est utile pour corriger des erreurs ou supprimer du contexte non pertinent.
  • Message de base : Parent principal pour tous les types de messages dans LangChain et LangGraph. Chaque type de message spécifique, tel que HumanMessage, AIMessage ou SystemMessage, hérite de BaseMessage.

Agents LangGraph

Nous allons maintenant coder ces agents dans LangGraph, en nous concentrant sur la compréhension des différentes méthodes et étapes impliquées dans le codage ainsi que dans la visualisation de ces agents. 

Flux de travail à agent unique

Commençons par créer un seul agent sans outils ni mémoire. Commençons par les importations :

from typing import TypedDict, List
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, START, END
from dotenv import load_dotenv

La première ligne indique l'TypedDict, qui est une annotation de type définie comme suit en Python :

from typing import TypedDict
class Student(TypedDict):
name: str
grade: float
s1: Student = {"name": "Sam", "grade": 92.5}

Essentiellement, un dictionnaire de type ( TypedDict ) est un dictionnaire doté de mesures robustes de sécurité des types, essentielles pour le développement d'agents IA.

HumanMessage Vous devriez maintenant être familier avec ce concept, car nous en avons déjà discuté précédemment.

ChatOpenAICependant, ce qui est nouveau, c'est que Faisons un petit détour pour expliquer cela. 

Grâce à Langchain, nous pouvons utiliser la famille d'outils d'interface utilisateur ( Chat ), qui nous permet essentiellement d'utiliser des modèles provenant de nombreux fournisseurs de LLM différents, tels que OpenAI, Anthropic, Ollama, etc., via leurs bibliothèques respectives, telles que ChatOpenAI, ChatAnthropic, ChatOllama, etc.

Fondamentalement, leurs paramètres et leur utilisation sont similaires, ce qui permet une modularité dans notre code. Vous trouverez des étapes plus détaillées dans la documentation LangChain. documentation LangChain.

Enfin, l'StateGraph, que nous avons déjà mentionné, ainsi que les sites Start et End constituent les points de départ et d'arrivée de notre graphique.

Continuons :

load_dotenv() # Obtaining over secret keys
# Creation of the state using a Typed Dictionary
class AgentState(TypedDict):
messages: List[HumanMessage] # We are going to be storing Human Messages (the user input) as a list of messages
llm = ChatOpenAI(model="gpt-4o") # Our model choice
# This is an action - the underlying function of our node
def process(state: AgentState) -> AgentState:
response = llm.invoke(state["messages"])
    print(f"\nAI: {response.content}")
    return state
graph = StateGraph(AgentState) # Initialization of a Graph
graph.add_node("process_node", process) # Adding nodes
graph.add_edge(START, "process_node") # Adding edges
graph.add_edge("process_node", END)
agent = graph.compile() # Compiling the graph

Examinons plus en détail les méthodes « .add_node() » et « .add_edge() ».

  • add.node(): Il existe deux paramètres principaux sur lesquels vous devez vous concentrer : le nom du nœud et l'action sous-jacente. Dans notre cas, l'action sous-jacente - process() - constitue la logique principale derrière le nœud, c'est-à-dire les actions qui sont effectuées lorsque nous arrivons à cette étape. Le nom du nœud peut être n'importe quoi, même le même que celui de la fonction, bien que cela puisse prêter à confusion lors du débogage.
  • add_edge.(): Il y a à nouveau deux paramètres principaux sur lesquels vous devez vous concentrer, à savoir les nœuds de début et de fin de l'arête. Veuillez noter que c'est le nom du nœud qui est saisi, et non l'action sous-jacente.

Prenons un exemple concret : 

user_input = input("Enter: ")
while user_input != "exit":
agent.invoke({"messages": [HumanMessage(content=user_input)]})
user_input = input("Enter: ")

Le code ci-dessus nous permet d'appeler l'agent plusieurs fois. Visuellement, l'agent IA que nous avons conçu se présente comme suit :

Diagramme illustrant un agent séquentiel exécutant des tâches dans un ordre fixe

Un agent séquentiel exécute des tâches étape par étape dans un ordre prédéfini, sans ramification ni raisonnement.

Pour obtenir une telle visualisation, nous pouvons utiliser le code suivant (remarque : nous utilisons le graphique compilé) :

from IPython.display import Image, display
display(Image(agent.get_graph().draw_mermaid_png()))

Agents réactifs

Les agents ReAct, agents raisonnants et agissants, sont extrêmement courants dans l'industrie, en raison de leur facilité de création et de leur robustesse. Étant donné leur grande fréquence, LangGraph dispose d'une méthode intégrée que nous pouvons exploiter pour créer de tels agents.

Heureusement, nous n'avons besoin que de deux importations supplémentaires :

from langgraph.prebuilt import create_react_agent
from langchain_google_community import GmailToolkit

La méthode create_react_agent permet de créer les agents ReAct pour nous.

tools = [GmailToolkit()] # We are using the Inbuilt Gmail tool
llm = ChatOllama(model="qwen2.5:latest") # Leveraging Ollama Models
agent = create_react_agent(
    model = llm, # Choice of the LLM
    tools = tools, # Tools we want our LLM to have
    name = "email_agent", # Name of our agent
    prompt = "You are my AI assistant that has access to certain tools. Use the tools to help me with my tasks.", # System Prompt
)

L'avantage principal de cette solution réside dans la possibilité de créer plusieurs agents et des architectures plus complexes.

Nous pouvons également créer nos propres outils personnalisés.

@tool
def send_email(email_address: str, email_content: str) -> str:
    """
Sends an email to a specified recipient with the given content.
Args:
email_address (str): The recipient's email address (e.g., 'example@example.com')
email_content (str): The body of the email message to be sent
Returns:
str: A confirmation message indicating success or failure
Example:
        >>> send_email('john.doe@example.com', 'Hello John, just checking in!')
'Email successfully sent to john.doe@example.com'
"""
    # Tool Logic goes here
    return "Done!"

Comme indiqué précédemment, deux éléments principaux sont importants lors de la création d'outils personnalisés :

  • Décorateur : Cela indique à LangGraph que cette fonction particulière est une fonction spécialisée, un outil.
  • Docstring : Ceci est nécessaire pour fournir au LLM le contexte dans lequel s'inscrit l'outil. Il est utile de fournir des exemples et des descriptions de chaque paramètre, car cela rend l'appel des outils plus fiable.

Les agents ReAct se présentent comme suit :

Diagramme illustrant le fonctionnement d'un agent ReAct combinant raisonnement et étapes d'action

Un agent ReAct alterne entre le raisonnement (pensées) et les actions pour résoudre des tâches étape par étape.

Fonctions réductrices pour la croissance de l'état

Lors de la définition de l'State e pour des systèmes agentique plus complexes et robustes, il est recommandé d'utiliser des fonctions réductrices ou simplement des « reducers ». Les « reducers » sont des annotations de données qui garantissent que chaque fois qu'un nœud renvoie un message, celui-ci est ajouté à la liste existante dans l'état, plutôt que de remplacer la valeur précédente. Cela permet à notre État de mettre en place le contexte.

# State with reducer function
class AgentState(TypedDict):
messages: Annotated[list[BaseMessage], operator.add]

Ce code intègre la fonction réductrice operator.add à l'état, garantissant ainsi que tous les messages sont conservés.

Gestion de la mémoire dans LangGraph

Dans cette section, nous nous intéresserons à un composant essentiel de tout agent : la mémoire. La mémoire est extrêmement importante pour un agent, car elle fournit le contexte nécessaire pour le rendre plus robuste et fiable. Explorons les différentes façons de gérer la mémoire dans nos agents.

Stockage externe des points de contrôle

L'état ( ) est l'élément le plus important dans LangGraph, et il existe naturellement plusieurs façons de stocker l'état en externe. Voici quelques-uns des périphériques de stockage externes les plus populaires :

  • SQLite
  • PostgreSQL
  • Amazon S3
  • Stockage Blob Azure
  • Stockage Google Cloud
  • Mem0

Toutes ces bibliothèques sont disponibles dans la documentation. documentation.

Pour l'instant, nous allons examiner SQLite :

from langgraph.checkpoint.sqlite import SqliteSaver
memory = SqliteSaver.from_conn_string(":memory:") # This is for connecting to the SQLite database
graph = graph_builder.compile(checkpointer=memory) # Compiling graph with checkpointer as SQLite backend

Utilisation de SQLite est un moyen simple d'ajouter la persistance à nos agents. La persistance est la capacité à maintenir le contexte à travers différentes interactions.

Tout cela sert à stocker et à mettre à jour l'état. Voyons maintenant comment utiliser et gérer efficacement cet état, en particulier la liste d'messages, qui devient assez longue à mesure que la conversation se poursuit.

LangGraph offre une prise en charge native de la mémoire vive ( )à court et à long terme. Explorons-les.

Mémoire à court terme

La mémoire à court terme permet à nos agents de se souvenir de l'historique des messages pendant une session, ce qui est utile pour les conversations à plusieurs tours.

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph

checkpointer = InMemorySaver()

builder = StateGraph(...)
graph = builder.compile(checkpointer=checkpointer)


# Invoking the Graph with our message
agent_graph.invoke(
    {"messages": [{"role": "user", "content": "What's the weather today?"}]},
    {"configurable": {"thread_id": "session_42"}},
)

Dans l'exemple ci-dessus, l'thread_id est utilisé pour identifier de manière unique une conversation ou une session.

Mémoire à long terme

La mémoire à long terme persiste au-delà de plusieurs sessions et est idéale pour se souvenir de choses telles que des noms, des objectifs ou des paramètres, c'est-à-dire des éléments importants qui sont nécessaires d'une session à l'autre.

from langgraph.store.memory import InMemoryStore
from langgraph.graph import StateGraph

long_term_store = InMemoryStore()
builder = StateGraph(...)
agent = builder.compile(store=long_term_store)

Cependant, comme notre conversation peut devenir longue, nous avons besoin d'un moyen de limiter l'historique de nos messages. C'est là que le rognage entre en jeu.

Élagage

Dans l'exemple ci-dessous, nous supprimons les tokens au début de l'historique des messages (en raison de la ligne : strategy="first") afin qu'après le rognage, il ne reste au maximum que 150 tokens.

from langchain_core.messages.utils import trim_messages, count_tokens_approximately

trimmed = trim_messages(
        messages=state["messages"],
        strategy="first",  # remove the messages from beginning
        token_counter=count_tokens_approximately,
        max_tokens=150
    )

Élagage basé sur la synthèse

Une autre méthode pour réduire l'historique des messages consiste à les résumer. Cela permet de conserver les informations importantes dans l'historique des messages, plutôt que de simplement supprimer des tokens d'une partie de la conversation.

from langmem.short_term import SummarizationNode
from langchain_core.messages.utils import count_tokens_approximately

summary_node = SummarizationNode(
    model=summary_llm,                       # Our summarization LLM
    max_tokens=300,                          # Total token limit
    max_tokens_before_summary=150,           # when to start summarizing
    max_summary_tokens=150,                  # summary size
    token_counter=count_tokens_approximately
)

Il est important de noter que la synthèse est effectuée par un LLM sous-jacent, dans ce cas summary_llm, qui peut être n'importe quel LLM.

Suppression sélective

La dernière opération principale requise dans la gestion de la mémoire est la suppression. Pour supprimer les messages sélectionnés, nous pouvons utiliser ce code :

from langchain_core.messages import RemoveMessage

def clean_state(state):
    # Remove all tool-related messages
    to_remove = [RemoveMessage(id=msg.id) for msg in state["messages"] if msg.role == "tool"]
    return {"messages": to_remove}

Dans le code ci-dessus, nous avons supprimé tous les messages liés aux outils, qui pouvaient être redondants (car, en réalité, le message Tool-Message est destiné au LLM à élaborer sa réponse après avoir utilisé l'outil).

Toutefois, si nous souhaitons supprimer l'historique complet des messages, nous pouvons procéder comme suit :

from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langchain_core.messages import RemoveMessage

def reset_history(state):
    # Remove entire conversation history
    return {"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]}

Conclusion

Dans l'ensemble, LangGraph est une bibliothèque puissante qui offre une approche structurée et évolutive pour la création de systèmes agentés. La modélisation de la logique sous forme de graphe de nœuds et d'arêtes, avec un état partagé et une mémoire persistante, nous permet de développer des agents robustes capables de raisonner, d'interagir et de s'adapter au fil du temps.

À mesure que les systèmes gagnent en complexité, ce cadre fournit les outils nécessaires pour gérer la mémoire, coordonner l'utilisation des outils et maintenir le contexte à long terme, tout en restant modulaire et extensible.

Les composants essentiels étant désormais en place, vous êtes prêt à concevoir et à déployer des agents IA robustes capables de gérer des flux de travail réels.

Pour continuer à vous former, nous vous invitons à consulter notre cours intitulé « Construire des systèmes multi-agents avec LangGraph. Vous pouvez également consulter notre cours « Concevoir des systèmes agentique avec LangChain »et notre tutoriel sur le RAG agentique.

FAQ sur les agents LangGraph

Qu'est-ce que LangGraph exactement ?

Un framework Python qui modélise la logique d'un agent IA sous forme de graphe de nœuds et d'arêtes, permettant le raisonnement, les appels d'outils et la mémoire.

Pourquoi devrais-je choisir LangGraph plutôt qu'une autre bibliothèque d'agents ?

LangGraph utilise une structure graphique pour définir la logique, un facteur clé qui le distingue des autres frameworks agentés populaires. LangGraph offre également une prise en charge native des boucles, des branchements, de la mémoire, de la persistance et des workflows multi-agents, ce qui le rend idéal pour les systèmes d'agents évolutifs et adaptés au monde réel.

Comment LangGraph gère-t-il et conserve-t-il la mémoire ?

Il utilise un état partagé qui peut être stocké à court terme (en mémoire) ou à long terme (SQLite, S3, etc.), ce qui permet aux agents de se souvenir des interactions passées.

Puis-je utiliser des modèles locaux à la place ?

Bien sûr ! LangGraph offre une prise en charge native des modèles Ollama, HuggingFace, LlamaCpp, etc.

Comment réduire la taille des historiques de messages longs ?

Utiliser trim_messages pour supprimer les anciens jetons ou SummarizationNode pour compresser les messages passés tout en conservant le contexte important.


Vaibhav Mehra's photo
Author
Vaibhav Mehra
LinkedIn
Sujets

Meilleurs cours DataCamp

Cours

Concevoir des systèmes agentiques avec LangChain

3 h
7K
Découvrez les composants clés des agents LangChain et créez vos propres agents de chat personnalisés.
Afficher les détailsRight Arrow
Commencer le cours
Voir plusRight Arrow