O LangGraph é um framework para criar aplicativos LLM stateful, o que o torna uma boa escolha para a construção de agentes ReAct (Reasoning and Acting).
Os agentes ReAct combinam o raciocínio do LLM com a execução de ações. Eles pensam de forma iterativa, usam ferramentas e agem com base em observações para alcançar as metas do usuário, adaptando dinamicamente a abordagem. Apresentado em "ReAct: Synergizing Reasoning and Acting in Language Models" (2023), esse padrão tenta imitar a solução de problemas flexível e humana em fluxos de trabalho rígidos.
Embora o LangGraph ofereça um agente ReAct pré-criado (create_react_agent
), ele se destaca quando você precisa de mais controle e personalização para suas implementações do ReAct.
O LangGraph modela agentes como gráficos usando três componentes principais:
State
: estrutura de dados compartilhada (normalmenteTypedDict
ouPydantic BaseModel
) que representa o snapshot atual do aplicativo.Nodes
: codifica a lógica dos seus agentes. Elas recebem o estado atual como entrada, executam alguma computação ou efeito colateral e retornam um estado atualizado, como chamadas de LLM ou de ferramentas.Edges
: define a próximaNode
a ser executada com base naState
atual, permitindo lógica condicional e transições fixas.
Se você ainda não tem uma chave de API, é possível receber uma sem custo financeiro no Google AI Studio.
pip install langgraph langchain-google-genai geopy requests
Defina a chave de API na variável de ambiente GEMINI_API_KEY
.
import os
# Read your API key from the environment variable or set it manually
api_key = os.getenv("GEMINI_API_KEY")
Para entender melhor como implementar um agente ReAct usando o LangGraph, vamos analisar um exemplo prático. Você vai criar um agente simples com o objetivo de usar uma ferramenta para encontrar a previsão do tempo atual em um local especificado.
Para esse agente de previsão do tempo, o State
precisa manter o histórico de conversas em andamento (como uma lista de mensagens) e um contador para o número de etapas realizadas para ilustrar melhor o gerenciamento de estado.
O LangGraph fornece um auxiliar conveniente, add_messages
, para atualizar listas de mensagens no estado. Ele funciona como um redutor, ou seja, ele pega a lista atual e as novas mensagens e retorna uma lista combinada. Ele processa de forma inteligente as atualizações por ID de mensagem e usa por padrão um comportamento "somente de adição" para mensagens novas e exclusivas.
from typing import Annotated,Sequence, TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages # helper function to add messages to the state
class AgentState(TypedDict):
"""The state of the agent."""
messages: Annotated[Sequence[BaseMessage], add_messages]
number_of_steps: int
Em seguida, você define sua ferramenta de clima.
from langchain_core.tools import tool
from geopy.geocoders import Nominatim
from pydantic import BaseModel, Field
import requests
geolocator = Nominatim(user_agent="weather-app")
class SearchInput(BaseModel):
location:str = Field(description="The city and state, e.g., San Francisco")
date:str = Field(description="the forecasting date for when to get the weather format (yyyy-mm-dd)")
@tool("get_weather_forecast", args_schema=SearchInput, return_direct=True)
def get_weather_forecast(location: str, date: str):
"""Retrieves the weather using Open-Meteo API for a given location (city) and a date (yyyy-mm-dd). Returns a list dictionary with the time and temperature for each hour."""
location = geolocator.geocode(location)
if location:
try:
response = requests.get(f"https://api.open-meteo.com/v1/forecast?latitude={location.latitude}&longitude={location.longitude}&hourly=temperature_2m&start_date={date}&end_date={date}")
data = response.json()
return {time: temp for time, temp in zip(data["hourly"]["time"], data["hourly"]["temperature_2m"])}
except Exception as e:
return {"error": str(e)}
else:
return {"error": "Location not found"}
tools = [get_weather_forecast]
Em seguida, você inicializa o modelo e vincula as ferramentas a ele.
from datetime import datetime
from langchain_google_genai import ChatGoogleGenerativeAI
# Create LLM class
llm = ChatGoogleGenerativeAI(
model= "gemini-2.5-pro",
temperature=1.0,
max_retries=2,
google_api_key=api_key,
)
# Bind tools to the model
model = llm.bind_tools([get_weather_forecast])
# Test the model with tools
res=model.invoke(f"What is the weather in Berlin on {datetime.today()}?")
print(res)
A última etapa antes de executar o agente é definir os nós e as arestas. Neste exemplo, há dois nós e uma aresta.
- Nodo call_tool
que executa o método da ferramenta. O LangGraph tem um nó pré-criado para isso chamado ToolNode.
- Nó call_model
que usa o model_with_tools
para chamar o modelo.
- Borda should_continue
que decide se vai chamar a ferramenta ou o modelo.
O número de nós e arestas não é fixo. Você pode adicionar quantos nós e arestas quiser ao seu gráfico. Por exemplo, você pode adicionar um nó para adicionar saída estruturada ou um nó de autoverificação/reflexão para verificar a saída do modelo antes de chamar a ferramenta ou o modelo.
from langchain_core.messages import ToolMessage
from langchain_core.runnables import RunnableConfig
tools_by_name = {tool.name: tool for tool in tools}
# Define our tool node
def call_tool(state: AgentState):
outputs = []
# Iterate over the tool calls in the last message
for tool_call in state["messages"][-1].tool_calls:
# Get the tool by name
tool_result = tools_by_name[tool_call["name"]].invoke(tool_call["args"])
outputs.append(
ToolMessage(
content=tool_result,
name=tool_call["name"],
tool_call_id=tool_call["id"],
)
)
return {"messages": outputs}
def call_model(
state: AgentState,
config: RunnableConfig,
):
# Invoke the model with the system prompt and the messages
response = model.invoke(state["messages"], config)
# We return a list, because this will get added to the existing messages state using the add_messages reducer
return {"messages": [response]}
# Define the conditional edge that determines whether to continue or not
def should_continue(state: AgentState):
messages = state["messages"]
# If the last message is not a tool call, then we finish
if not messages[-1].tool_calls:
return "end"
# default to continue
return "continue"
Agora você tem todos os componentes para criar seu agente. Vamos juntar tudo.
from langgraph.graph import StateGraph, END
# Define a new graph with our state
workflow = StateGraph(AgentState)
# 1. Add our nodes
workflow.add_node("llm", call_model)
workflow.add_node("tools", call_tool)
# 2. Set the entrypoint as `agent`, this is the first node called
workflow.set_entry_point("llm")
# 3. Add a conditional edge after the `llm` node is called.
workflow.add_conditional_edges(
# Edge is used after the `llm` node is called.
"llm",
# The function that will determine which node is called next.
should_continue,
# Mapping for where to go next, keys are strings from the function return, and the values are other nodes.
# END is a special node marking that the graph is finish.
{
# If `tools`, then we call the tool node.
"continue": "tools",
# Otherwise we finish.
"end": END,
},
)
# 4. Add a normal edge after `tools` is called, `llm` node is called next.
workflow.add_edge("tools", "llm")
# Now we can compile and visualize our graph
graph = workflow.compile()
Você pode visualizar seu gráfico usando o método draw_mermaid_png
.
from IPython.display import Image, display
display(Image(graph.get_graph().draw_mermaid_png()))
Agora vamos executar o agente.
from datetime import datetime
# Create our initial message dictionary
inputs = {"messages": [("user", f"What is the weather in Berlin on {datetime.today()}?")]}
# call our graph with streaming to see the steps
for state in graph.stream(inputs, stream_mode="values"):
last_message = state["messages"][-1]
last_message.pretty_print()
Agora você pode continuar a conversa e, por exemplo, perguntar sobre o clima em outra cidade ou comparar as informações.
state["messages"].append(("user", "Would it be in Munich warmer?"))
for state in graph.stream(state, stream_mode="values"):
last_message = state["messages"][-1]
last_message.pretty_print()