⚡ Construire des agents linguistiques sous forme de graphiques ⚡
Note
Vous recherchez la version JS ? Cliquez ici (documents JS).
LangGraph est une bibliothèque permettant de créer des applications multi-acteurs avec état avec des LLM, utilisées pour créer des flux de travail d'agent et multi-agents. Par rapport à d'autres frameworks LLM, il offre les avantages fondamentaux suivants : cycles, contrôlabilité et persistance. LangGraph vous permet de définir des flux impliquant des cycles, essentiels pour la plupart des architectures agentiques, ce qui le différencie des solutions basées sur DAG. En tant que framework de très bas niveau, il offre un contrôle précis sur le flux et l'état de votre application, crucial pour créer des agents fiables. De plus, LangGraph inclut une persistance intégrée, permettant des fonctionnalités avancées d'intervention humaine et de mémoire.
LangGraph s'inspire de Pregel et Apache Beam. L'interface publique s'inspire de NetworkX. LangGraph est construit par LangChain Inc, les créateurs de LangChain, mais peut être utilisé sans LangChain.
LangGraph Platform est une infrastructure pour le déploiement d'agents LangGraph. Il s'agit d'une solution commerciale permettant de déployer des applications agentiques en production, construite sur le framework open source LangGraph. La plateforme LangGraph se compose de plusieurs composants qui fonctionnent ensemble pour prendre en charge le développement, le déploiement, le débogage et la surveillance des applications LangGraph : LangGraph Server (API), LangGraph SDK (clients pour les API), LangGraph CLI (outil de ligne de commande pour créer le serveur ), LangGraph Studio (UI/débogueur),
Pour en savoir plus sur LangGraph, consultez notre premier cours LangChain Academy, Introduction à LangGraph , disponible gratuitement ici.
LangGraph Platform est une solution commerciale permettant de déployer des applications agentiques en production, construite sur le framework open source LangGraph. Voici quelques problèmes courants qui surviennent dans les déploiements complexes, et que LangGraph Platform résout :
pip install -U langgraph
L'un des concepts centraux de LangGraph est l'état. Chaque exécution de graphique crée un état qui est transmis entre les nœuds du graphique au fur et à mesure de leur exécution, et chaque nœud met à jour cet état interne avec sa valeur de retour après son exécution. La manière dont le graphique met à jour son état interne est définie soit par le type de graphique choisi, soit par une fonction personnalisée.
Jetons un coup d'œil à un exemple simple d'agent pouvant utiliser un outil de recherche.
pip install langchain-anthropic
export ANTHROPIC_API_KEY=sk-...
En option, nous pouvons configurer LangSmith pour une observabilité de premier ordre.
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=lsv2_sk_...
from typing import Annotated , Literal , TypedDict
from langchain_core . messages import HumanMessage
from langchain_anthropic import ChatAnthropic
from langchain_core . tools import tool
from langgraph . checkpoint . memory import MemorySaver
from langgraph . graph import END , START , StateGraph , MessagesState
from langgraph . prebuilt import ToolNode
# Define the tools for the agent to use
@ tool
def search ( query : str ):
"""Call to surf the web."""
# This is a placeholder, but don't tell the LLM that...
if "sf" in query . lower () or "san francisco" in query . lower ():
return "It's 60 degrees and foggy."
return "It's 90 degrees and sunny."
tools = [ search ]
tool_node = ToolNode ( tools )
model = ChatAnthropic ( model = "claude-3-5-sonnet-20240620" , temperature = 0 ). bind_tools ( tools )
# Define the function that determines whether to continue or not
def should_continue ( state : MessagesState ) -> Literal [ "tools" , END ]:
messages = state [ 'messages' ]
last_message = messages [ - 1 ]
# If the LLM makes a tool call, then we route to the "tools" node
if last_message . tool_calls :
return "tools"
# Otherwise, we stop (reply to the user)
return END
# Define the function that calls the model
def call_model ( state : MessagesState ):
messages = state [ 'messages' ]
response = model . invoke ( messages )
# We return a list, because this will get added to the existing list
return { "messages" : [ response ]}
# Define a new graph
workflow = StateGraph ( MessagesState )
# Define the two nodes we will cycle between
workflow . add_node ( "agent" , call_model )
workflow . add_node ( "tools" , tool_node )
# Set the entrypoint as `agent`
# This means that this node is the first one called
workflow . add_edge ( START , "agent" )
# We now add a conditional edge
workflow . add_conditional_edges (
# First, we define the start node. We use `agent`.
# This means these are the edges taken after the `agent` node is called.
"agent" ,
# Next, we pass in the function that will determine which node is called next.
should_continue ,
)
# We now add a normal edge from `tools` to `agent`.
# This means that after `tools` is called, `agent` node is called next.
workflow . add_edge ( "tools" , 'agent' )
# Initialize memory to persist state between graph runs
checkpointer = MemorySaver ()
# Finally, we compile it!
# This compiles it into a LangChain Runnable,
# meaning you can use it as you would any other runnable.
# Note that we're (optionally) passing the memory when compiling the graph
app = workflow . compile ( checkpointer = checkpointer )
# Use the Runnable
final_state = app . invoke (
{ "messages" : [ HumanMessage ( content = "what is the weather in sf" )]},
config = { "configurable" : { "thread_id" : 42 }}
)
final_state [ "messages" ][ - 1 ]. content
"Based on the search results, I can tell you that the current weather in San Francisco is:nnTemperature: 60 degrees FahrenheitnConditions: FoggynnSan Francisco is known for its microclimates and frequent fog, especially during the summer months. The temperature of 60°F (about 15.5°C) is quite typical for the city, which tends to have mild temperatures year-round. The fog, often referred to as "Karl the Fog" by locals, is a characteristic feature of San Francisco's weather, particularly in the mornings and evenings.nnIs there anything else you'd like to know about the weather in San Francisco or any other location?"
Désormais, lorsque nous transmettons le même "thread_id"
, le contexte de conversation est conservé via l'état enregistré (c'est-à-dire la liste de messages stockée)
final_state = app . invoke (
{ "messages" : [ HumanMessage ( content = "what about ny" )]},
config = { "configurable" : { "thread_id" : 42 }}
)
final_state [ "messages" ][ - 1 ]. content
"Based on the search results, I can tell you that the current weather in New York City is:nnTemperature: 90 degrees Fahrenheit (approximately 32.2 degrees Celsius)nConditions: SunnynnThis weather is quite different from what we just saw in San Francisco. New York is experiencing much warmer temperatures right now. Here are a few points to note:nn1. The temperature of 90°F is quite hot, typical of summer weather in New York City.n2. The sunny conditions suggest clear skies, which is great for outdoor activities but also means it might feel even hotter due to direct sunlight.n3. This kind of weather in New York often comes with high humidity, which can make it feel even warmer than the actual temperature suggests.nnIt's interesting to see the stark contrast between San Francisco's mild, foggy weather and New York's hot, sunny conditions. This difference illustrates how varied weather can be across different parts of the United States, even on the same day.nnIs there anything else you'd like to know about the weather in New York or any other location?"
ChatAnthropic
comme notre LLM. REMARQUE : nous devons nous assurer que le modèle sait qu'il dispose de ces outils pour appeler. Nous pouvons le faire en convertissant les outils LangChain au format d'appel d'outils OpenAI à l'aide de la méthode .bind_tools()
.StateGraph
) en passant le schéma d'état (dans notre cas MessagesState
)MessagesState
est un schéma d'état prédéfini qui possède un attribut : une liste d'objets Message
LangChain, ainsi qu'une logique pour fusionner les mises à jour de chaque nœud dans l'état.Nous avons besoin de deux nœuds principaux :
agent
: responsable de décider des actions (le cas échéant) à entreprendre.tools
qui invoque les outils : si l'agent décide d'effectuer une action, ce nœud exécutera alors cette action. Tout d’abord, nous devons définir le point d’entrée pour l’exécution du graphique – le nœud agent
.
Ensuite, nous définissons une arête normale et une arête conditionnelle. Le bord conditionnel signifie que la destination dépend du contenu de l'état du graphique ( MessageState
). Dans notre cas, la destination n’est connue que lorsque l’agent (LLM) le décide.
.invoke()
, .stream()
et .batch()
avec vos entrées.MemorySaver
- un simple point de contrôle en mémoire LangGraph ajoute le message d'entrée à l'état interne, puis transmet l'état au nœud de point d'entrée, "agent"
.
Le nœud "agent"
s'exécute, en invoquant le modèle de discussion.
Le modèle de chat renvoie un AIMessage
. LangGraph ajoute ceci à l'état.
Graph effectue les étapes suivantes jusqu'à ce qu'il n'y ait plus tool_calls
sur AIMessage
:
AIMessage
a tool_calls
, le nœud "tools"
s'exécute"agent"
s'exécute à nouveau et renvoie AIMessage
L'exécution progresse jusqu'à la valeur spéciale END
et génère l'état final. Et par conséquent, nous obtenons une liste de tous nos messages de discussion en sortie.
Pour plus d’informations sur la façon de contribuer, voir ici.