⚡ Construindo agentes linguísticos como gráficos ⚡
Observação
Procurando a versão JS? Clique aqui (documentos JS).
LangGraph é uma biblioteca para construir aplicativos multiatores com estado com LLMs, usados para criar fluxos de trabalho de agentes e multiagentes. Em comparação com outras estruturas LLM, ela oferece estes benefícios principais: ciclos, controlabilidade e persistência. O LangGraph permite definir fluxos que envolvem ciclos, essenciais para a maioria das arquiteturas agênticas, diferenciando-o das soluções baseadas em DAG. Como uma estrutura de nível muito baixo, ela fornece controle refinado sobre o fluxo e o estado do seu aplicativo, crucial para a criação de agentes confiáveis. Além disso, o LangGraph inclui persistência integrada, permitindo recursos avançados de interação humana e memória.
LangGraph é inspirado em Pregel e Apache Beam. A interface pública é inspirada no NetworkX. LangGraph foi desenvolvido pela LangChain Inc, os criadores do LangChain, mas pode ser usado sem o LangChain.
A plataforma LangGraph é uma infraestrutura para implantação de agentes LangGraph. É uma solução comercial para implantação de aplicativos de agente em produção, construída na estrutura LangGraph de código aberto. A plataforma LangGraph consiste em vários componentes que trabalham juntos para apoiar o desenvolvimento, implantação, depuração e monitoramento de aplicativos LangGraph: LangGraph Server (APIs), LangGraph SDKs (clientes para as APIs), LangGraph CLI (ferramenta de linha de comando para construir o servidor ), LangGraph Studio (UI/depurador),
Para saber mais sobre LangGraph, confira nosso primeiro curso da LangChain Academy, Introdução ao LangGraph , disponível gratuitamente aqui.
A plataforma LangGraph é uma solução comercial para implantação de aplicativos de agente em produção, construída na estrutura LangGraph de código aberto. Aqui estão alguns problemas comuns que surgem em implantações complexas, que a plataforma LangGraph aborda:
pip install -U langgraph
Um dos conceitos centrais do LangGraph é estado. Cada execução do gráfico cria um estado que é passado entre os nós do gráfico conforme eles são executados, e cada nó atualiza esse estado interno com seu valor de retorno após a execução. A maneira como o gráfico atualiza seu estado interno é definida pelo tipo de gráfico escolhido ou por uma função personalizada.
Vejamos um exemplo simples de agente que pode usar uma ferramenta de pesquisa.
pip install langchain-anthropic
export ANTHROPIC_API_KEY=sk-...
Opcionalmente, podemos configurar o LangSmith para a melhor observabilidade da categoria.
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?"
Agora, quando passamos o mesmo "thread_id"
, o contexto da conversa é retido através do estado salvo (ou seja, lista armazenada de mensagens)
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
como nosso LLM. NOTA: precisamos ter certeza de que o modelo sabe que possui essas ferramentas disponíveis para chamada. Podemos fazer isso convertendo as ferramentas LangChain no formato para chamada de ferramenta OpenAI usando o método .bind_tools()
.StateGraph
) passando o esquema de estado (no nosso caso MessagesState
)MessagesState
é um esquema de estado pré-construído que possui um atributo - uma lista de objetos LangChain Message
, bem como lógica para mesclar as atualizações de cada nó no estadoExistem dois nós principais que precisamos:
agent
: responsável por decidir quais ações (se houver) tomar.tools
que invoca ferramentas: se o agente decidir realizar uma ação, este nó executará essa ação. Primeiro, precisamos definir o ponto de entrada para execução do gráfico - nó agent
.
Então definimos uma aresta normal e uma condicional. Borda condicional significa que o destino depende do conteúdo do estado do gráfico ( MessageState
). No nosso caso, o destino não é conhecido até que o agente (LLM) decida.
.invoke()
, .stream()
e .batch()
com suas entradasMemorySaver
- um simples checkpoint na memória LangGraph adiciona a mensagem de entrada ao estado interno e, em seguida, passa o estado para o nó do ponto de entrada, "agent"
.
O nó "agent"
é executado, invocando o modelo de chat.
O modelo de chat retorna um AIMessage
. LangGraph adiciona isso ao estado.
O gráfico percorre as etapas a seguir até que não haja mais tool_calls
em AIMessage
:
AIMessage
tiver tool_calls
, o nó "tools"
será executado"agent"
é executado novamente e retorna AIMessage
A execução progride para o valor END
especial e gera o estado final. E como resultado, obtemos uma lista de todas as nossas mensagens de chat como saída.
Para mais informações sobre como contribuir, veja aqui.