Inteligência artificial, sem ruído.
Agentes de IA11 min

Tutorial: Construa agentes de IA com LangGraph em Python — do zero à memória persistente

Tutorial completo: construa um agente de IA com ferramentas, memória persistente e rastreabilidade usando LangGraph em Python. Do zero à produção em 7 passos.

Tutorial: Construa agentes de IA com LangGraph em Python — do zero à memória persistente

Por que os agentes de IA mudaram em 2026

Até recentemente, construir um agente de IA que chamasse APIs, lembrasse de conversas anteriores e tomasse decisões em cadeia exigia semanas de desenvolvimento e centenas de linhas de código customizado. Hoje, com frameworks maduros como o LangGraph, você constrói o mesmo fluxo em uma tarde — e com visibilidade total sobre cada decisão que o modelo toma.

O que mudou? Em 2024, a maioria dos agentes era single-turn: recebe uma pergunta, chama o modelo, devolve a resposta. Os problemas reais — consultar bancos de dados, manter contexto entre conversas, auditar decisões — exigiam infraestrutura customizada que quebrava a cada novo caso de uso. O LangGraph resolve isso representando o agente como um grafo direcionado, onde cada nó é uma unidade de trabalho e as arestas definem o fluxo de execução.

Neste tutorial, você vai construir um agente completo do zero: de uma única chamada de modelo até um sistema com ferramentas, memória persistente e visibilidade total da cadeia de raciocínio.

O que você ganha (e o que não ganha)

✅ Vantagens

  • Estado compartilhado explícito: cada nó lê e escreve no mesmo estado. Nada passa entre nós de outra forma. Isso torna o fluxo previsível e fácil de debugar.
  • Memória de conversa automática: o MessagesState acumula o histórico completo de mensagens com um reducer dedicado. Sem stitching manual.
  • Troca de modelos sem reescrever o grafo: trocar OpenAI por Anthropic ou um modelo local via Ollama é mudar uma linha de import.
  • Ferramentas com two-way routing: o modelo decide quando usar uma ferramenta; o grafo executa e devolve o resultado automaticamente para o modelo interpretar.
  • Persistência plug-and-play: um checkpointer transforma um agente stateless em stateful com duas linhas de código.
  • Rastreabilidade completa: cada passo de raciocínio, chamada de ferramenta e resposta fica registrado no estado do grafo.

⚠️ Limitações

  • Cada uso de ferramenta custa duas chamadas de modelo: uma para decidir o que consultar, outra para interpretar o resultado. Isso impacta latência e custo conforme você adiciona ferramentas.
  • Curva de aprendizado dos primitivos: State, Node, Edge e reducers formam uma abstração poderosa, mas exigem compreensão sólida antes de escalar.
  • InMemorySstore não é para produção: o checkpointer em memória some quando o processo reinicia. Produção exige PostgreSQL, Redis ou outro backend durável.

Pré-requisitos

ComponenteMínimoRecomendadoIdeal
Python3.103.113.12
RAM4 GB8 GB16 GB
Chave de APIOpenAIOpenAI + AnthropicMulti-provedor
Conhecimento prévioPython básicoConceitos de LLMExperiência com LangChain
Tempo estimado45 min30 min20 min
Sistema operacionalQualquer com PythonmacOS / LinuxLinux (Docker)
Requisitos para acompanhar o tutorial

Passo 1: Instalação e configuração do ambiente

Comece criando um ambiente virtual e instalando as dependências:

# Criar e ativar ambiente virtual (Linux/macOS)
python3 -m venv .venv
source .venv/bin/activate

# Windows
# python -m venv .venv
# .venv\Scripts\activate

# Instalar pacotes necessários
pip install langgraph langchain-openai python-dotenv

Crie um arquivo .env na raiz do projeto com sua chave da OpenAI:

OPENAI_API_KEY=sk-seu-token-aqui

Carregue as variáveis de ambiente no início do seu script Python, antes de qualquer import do LangChain ou LangGraph:

from dotenv import load_dotenv
load_dotenv()  # Lê o .env e define as variáveis de ambiente

Passo 2: Entendendo os três primitivos fundamentais

Todo grafo no LangGraph é construído com apenas três conceitos. Dominá-los evita confusão quando o grafo ficar mais complexo.

State (Estado)

Um TypedDict que funciona como memória compartilhada do grafo inteiro. Cada nó lê dele e devolve um dicionário parcial com os campos que quer modificar. Campos não mencionados permanecem inalterados.

Nodes (Nós)

Funções Python puras. Recebem o estado atual como argumento e retornam um dicionário com as atualizações. Registrar uma função com add_node é o que a torna parte do grafo — sem decorators especiais ou classes base.

Edges (Arestas)

Definem a ordem de execução. add_edge(A, B) significa: depois do nó A, execute o nó B. add_conditional_edges significa: depois do nó A, chame uma função de roteamento e vá para onde ela apontar.

Para campos que devem acumular em vez de substituir (como histórico de mensagens), use um reducer. O operator.add em uma lista faz append em vez de replace:

from typing import TypedDict
import operator

class State(TypedDict):
    messages: list  # Reducer padrão: replace
    log: list       # Vai acumular com operator.add

Passo 3: Gerenciando histórico de conversa com MessagesState

Para um agente conversacional, o estado precisa carregar o histórico completo — entradas do usuário, respostas do modelo, resultados de ferramentas. O LangGraph fornece MessagesState pronto para isso:

from langgraph.graph import MessagesState

# MessagesState é um TypedDict com um único campo 'messages'
# que usa o reducer add_messages (append automático)

O reducer add_messages é mais inteligente que um simples append: ele lida com deduplicação e ordenação de objetos de mensagem. Você pode estender o MessagesState com campos adicionais como customer_id ou priority, mas messages já vem pronto para acumular.

Passo 4: Chamando o modelo dentro de um nó

Com o estado definido, o nó central de qualquer agente LangGraph é uma função que passa a lista de mensagens atual para o modelo e anexa a resposta:

from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage

model = ChatOpenAI(model="gpt-4o")

def call_model(state: MessagesState):
    # SystemMessage define o papel do modelo sem poluir o estado
    system_msg = SystemMessage(content="Você é um assistente útil.")
    response = model.invoke([system_msg] + state["messages"])
    # Retornar a resposta como AIMessage a adiciona ao estado
    return {"messages": [response]}

Por que funciona: o modelo recebe todo o histórico (state["messages"]), gera uma resposta (AIMessage), e o reducer add_messages a anexa automaticamente. Trocar de provedor significa mudar o import e a string do modelo; o resto do nó permanece idêntico.

Passo 5: Registrando ferramentas e roteando chamadas

Até aqui o modelo responde com conhecimento de treinamento. Para acessar dados específicos — contas, assinaturas, histórico de tickets — você precisa de ferramentas:

from langchain_core.tools import tool

@tool
def get_customer_tier(customer_id: str) -> str:
    """Retorna o tier de assinatura (free, pro, enterprise)
    para um determinado customer_id."""
    # Simula consulta a banco de dados
    tiers = {"cust_1001": "pro", "cust_1002": "enterprise"}
    return tiers.get(customer_id, "free")

A docstring da função é o que o modelo lê para decidir se deve usar a ferramenta. Seja preciso: docstrings vagas levam a chamadas perdidas ou argumentos malformados.

Agora vincule a ferramenta ao modelo e configure o nó de execução:

from langgraph.prebuilt import ToolNode, tools_condition

model_with_tools = model.bind_tools([get_customer_tier])

def call_model(state: MessagesState):
    response = model_with_tools.invoke(state["messages"])
    return {"messages": [response]}

# Construir o grafo
from langgraph.graph import StateGraph, START

builder = StateGraph(MessagesState)
builder.add_node("agent", call_model)
builder.add_node("tools", ToolNode([get_customer_tier]))

builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", tools_condition)
builder.add_edge("tools", "agent")

graph = builder.compile()

O que acontece no loop: O modelo recebe a mensagem do usuário. Se decidir usar uma ferramenta, retorna AIMessage com tool_calls preenchido em vez de content. O tools_condition detecta isso e roteia para ToolNode, que executa a função com os argumentos que o modelo especificou. A aresta de "tools" de volta para "agent" fecha o loop: o resultado da ferramenta volta ao modelo para ele produzir a resposta final.

Para confirmar que funcionou: execute graph.invoke({"messages": [{"role": "user", "content": "Qual é o tier do cliente cust_1001?"}]}) e verifique que o último AIMessage contém a resposta em content.

Passo 6: Rastreando a cadeia de raciocínio

Entender o que acontece dentro do grafo é essencial para debugging. No loop ReAct (Reasoning + Acting), cada uso de ferramenta produz 4 mensagens no estado:

  1. HumanMessage: a pergunta original do usuário
  2. AIMessage com tool_calls: o modelo sinalizando “quero consultar X” (content vazio)
  3. ToolMessage: o resultado da execução da ferramenta
  4. AIMessage final: o modelo interpretando o resultado e respondendo (content preenchido)

Custo implícito: cada uso de ferramenta consome duas chamadas de modelo — uma para decidir o que consultar, outra para interpretar o resultado. Isso é relevante ao planejar latência e custo conforme você adiciona mais ferramentas ao agente.

Passo 7: Persistindo conversas entre chamadas com Checkpointer

Sem persistência, cada graph.invoke() começa com estado zerado. Para manter contexto entre mensagens:

from langgraph.checkpoint.memory import InMemorySaver

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

# Mesmo thread_id = mesma conversa
config = {"configurable": {"thread_id": "conversa-1"}}
result1 = graph.invoke({"messages": [{"role": "user", "content": "Meu nome é João"}]}, config)
result2 = graph.invoke({"messages": [{"role": "user", "content": "Qual é o meu nome?"}]}, config)
# O modelo lembra: "Seu nome é João"

O checkpointer restaura o estado do thread_id antes da execução e salva o estado atualizado depois. Threads diferentes têm estados independentes. Para produção, substitua InMemorySaver por um backend persistente como PostgreSQL ou Redis — o resto do código permanece idêntico.

Comparação: LangGraph vs alternativas

FrameworkModelo mentalMelhor paraCurva de aprendizado
LangGraphGrafo direcionado com estadoAgentes complexos, multi-step, auditáveisMédia
CrewAIAgentes com papéis e tarefasPrototipagem rápida multi-agenteBaixa
AutoGenConversa entre agentesSistemas multi-agente conversacionaisMédia
OpenAI SwarmHandoff entre agentesRoteamento simples de agentesBaixa
Raw API callsRequisições HTTP com loop manualMáximo controle, mínima dependênciaAlta
Comparação de frameworks para construção de agentes de IA (julho/2026)

Casos de uso reais

  1. Suporte ao cliente com acesso a banco de dados: agente que consulta tier de assinatura, histórico de pedidos e status de ticket antes de responder, com auditoria completa de cada decisão.
  2. Assistente de pesquisa jurídica: busca em múltiplas bases de jurisprudência, cruza resultados e gera parecer com citações rastreáveis.
  3. Pipeline de dados com aprovação humana: agente que processa dados, identifica anomalias e pausa para revisão humana antes de publicar relatórios.
  4. Onboarding de desenvolvedores: agente que acessa a documentação interna, configura repositórios e gera boilerplate personalizado para novos membros do time.
  5. Monitoramento de infraestrutura: agente que consulta métricas de cloud, detecta anomalias, escala recursos automaticamente e notifica o time com diagnóstico.

Troubleshooting: 5 erros comuns (e como resolver)

TypeError: messages field expects a list
Causa: o nó retornou um dicionário com "messages" como string ou objeto único, não como lista.
Solução: sempre retorne {"messages": [response]} com a resposta dentro de uma lista.
O modelo nunca chama a ferramenta
Causa: docstring vaga ou ausente na função @tool. O modelo não entende quando ou por que usá-la.
Solução: escreva uma docstring precisa explicando o que a ferramenta faz e quais argumentos espera.
ImportError: cannot import name ‘MessagesState’
Causa: versão antiga do LangGraph (anterior à 0.2.0).
Solução: atualize com pip install --upgrade langgraph.
Graph recusion limit reached
Causa: loop infinito no grafo — as arestas condicionais nunca levam a END.
Solução: verifique que tools_condition roteia para "__end__" quando não há tool calls. Adicione builder.add_edge("agent", END) como fallback.
Memória some entre execuções
Causa: usando InMemorySaver em produção ou esquecendo de passar o mesmo thread_id no config.
Solução: em desenvolvimento, confirme que o thread_id é consistente entre chamadas. Em produção, migre para SqliteSaver ou PostgresSaver.

FAQ: Perguntas que você faria depois de implementar

Posso usar modelos locais como Llama ou Mistral?
Sim. Substitua ChatOpenAI por ChatOllama ou ChatHuggingFace. O grafo permanece idêntico — apenas o nó do modelo muda.
Quantas ferramentas um agente pode ter?
Não há limite técnico, mas cada ferramenta adicional ocupa espaço no context window do modelo. Acima de 10-15 ferramentas, considere agrupar por domínio ou usar um roteador.
Qual a diferença entre Checkpointer e Store?
Checkpointer persiste o estado do grafo por thread (conversa). Store persiste dados de aplicação compartilhados entre threads, como perfis de usuário ou preferências globais.
Funciona com streaming de tokens?
Sim. Use graph.stream() em vez de graph.invoke() para receber atualizações parciais conforme o modelo gera tokens.
Como implementar human-in-the-loop?
Adicione um interrupt_before ou interrupt_after ao compilar o grafo. A execução pausa no nó especificado e só continua após aprovação via graph.update_state().

O futuro dos agentes: para onde estamos indo

O LangGraph estabeleceu um padrão que está sendo adotado por toda a indústria: agentes como grafos auditáveis, com estado explícito e ferramentas plugáveis. Em 2027, a tendência é que esse modelo se torne o padrão para qualquer sistema de IA que precise tomar decisões em cadeia — de chatbots de suporte a pipelines autônomos de descoberta de medicamentos como o que a Bristol Myers Squibb está construindo com a NVIDIA.

O próximo salto será a integração nativa entre agentes e bancos de dados vetoriais, permitindo que o estado do grafo inclua não apenas mensagens, mas embeddings, documentos e conhecimento institucional recuperado em tempo real. Se você domina os primitivos que construímos hoje — state, nodes, edges, tools, checkpointers — está pronto para o que vier.


Descubra mais sobre noticiAI

Assine para receber nossas notícias mais recentes por e-mail.

R
Sobre o autorRedação Noticiai

Equipe editorial dedicada a explicar inteligência artificial com clareza, independência e contexto.