Alternar tema

Gerenciamento de estado no LangGraph na prática: checkpoint, thread state e recuperação de falhas

Easton editorial illustration: one central state ledger with three controlled graph branches

Atualização de 08/06/2026: revisei os fatos sujeitos a mudanças — o Pydantic v3 foi lançado no fim de 2025 e se tornou a versão estável atual (com validação e serialização várias vezes mais rápidas que no v2); o plano gratuito do LangSmith oferece 5.000 traces por mês, retidos por 14 dias, e o Plus custa US$ 39 por usuário ao mês e inclui 10 mil traces; também corrigi a forma de interromper e retomar processos human-in-the-loop de acordo com a API atual do LangGraph. O foco continua sendo permitir que cada execução do agente seja recuperada, rastreada e reproduzida.

O repositório do LangGraph no GitHub já ultrapassou 30 mil stars, tornando-se um dos frameworks de agentes mais ativos de 2026. Mesmo assim, muita gente ainda o utiliza com a mentalidade de que basta fazê-lo funcionar. Conflitos de estado, falhas de persistência e dificuldades de implantação em produção aparecem pouco nos tutoriais, mas se repetem em projetos reais.

O relatório State of Agent Engineering, publicado pela LangChain em 2026, aponta que mais de 60% dos incidentes com agentes em produção estão relacionados ao gerenciamento de estado. Este artigo se concentra justamente no que os tutoriais raramente contam: padrões de projeto para o State Schema, uso prático de funções reducer, escolha da persistência, comparação entre frameworks e integração de observabilidade. Ao final, você terá modelos de código reutilizáveis e critérios para escolher a arquitetura mais adequada.

Fundamentos do gerenciamento de estado no LangGraph: do StateGraph ao reducer

Se você já usou Chain no LangChain, talvez o StateGraph pareça estranho à primeira vista. Uma Chain é linear: uma etapa após a outra, como em uma linha de produção. A lógica de um agente real, porém, raramente é tão comportada. Em determinado nó, talvez seja preciso decidir se a intenção do usuário é conversar ou fazer uma consulta e, então, seguir por ramificações diferentes. Também pode ser necessário executar vários nós em paralelo e consolidar os resultados no fim. É para isso que existe o StateGraph.

1.1 Padrão de construção do StateGraph

A principal diferença entre StateGraph e um Graph comum está no estado. Em um Graph comum, os nós trocam entradas e saídas fixas. No StateGraph, todos os nós compartilham o mesmo objeto de estado. Cada nó pode ler e alterar esse estado, e a versão atualizada é encaminhada automaticamente para o próximo nó.

from langgraph.graph import StateGraph, MessagesState
from langchain_openai import ChatOpenAI

# Define a estrutura do estado (herda de MessagesState e já inclui o campo messages)
class AgentState(MessagesState):
    next_action: str  # Próxima ação
    retry_count: int = 0  # Número de tentativas

# Inicializa o grafo
graph = StateGraph(AgentState)

# Adiciona os nós
graph.add_node("classify", classify_intent)
graph.add_node("respond", generate_response)
graph.add_node("fallback", handle_fallback)

# Define as arestas (ramificações condicionais)
graph.add_conditional_edges(
    "classify",
    lambda state: state["next_action"],
    {
        "respond": "respond",
        "fallback": "fallback"
    }
)

# Compila — esta etapa é obrigatória; sem ela o grafo não pode ser executado
app = graph.compile()

Muita gente esquece o método .compile(). Eu mesmo caí nessa armadilha quando comecei a usar o LangGraph: passei um bom tempo escrevendo nós e arestas para, na execução, receber diretamente o erro Graph not compiled. A compilação verifica tipos e conectividade das arestas, além de injetar o checkpointer de acordo com a configuração.

Um detalhe importante é que o estado do StateGraph é atualizado de forma incremental, e não substituído por completo. Se você alterar retry_count no nó A, por exemplo, o nó B precisa apenas ler esse campo, sem se preocupar com o restante do estado. Esse projeto viabiliza a execução paralela: vários nós podem rodar ao mesmo tempo, cada um alterando campos diferentes, e os resultados são mesclados no final.

1.2 Evolução do projeto do schema de estado

Há três maneiras de definir a estrutura do estado, cada uma com vantagens e desvantagens.

TypedDict é a alternativa mais básica. Oferece segurança de tipos, mas não aceita valores padrão:

from typing import TypedDict, Annotated

class SimpleState(TypedDict):
    messages: list
    context: str
    # Não aceita valores padrão; todos os campos precisam ter seu tipo declarado

dataclass aceita valores padrão nativos do Python e oferece boas sugestões na IDE:

from dataclasses import dataclass

@dataclass
class DataclassState:
    messages: list
    context: str = ""
    retry_count: int = 0  # Pode ter um valor padrão

Pydantic BaseModel é a opção recomendada em 2026. Ele oferece validação recursiva e conversão de tipos, além de se integrar perfeitamente às ferramentas do LangChain:

from pydantic import BaseModel, Field

class OptimizedState(BaseModel):
    messages: list = Field(default_factory=list)
    context: str = ""
    retry_count: int = Field(default=0, ge=0)  # Validação: precisa ser >= 0

    class Config:
        # Configuração do Pydantic v2
        extra = "forbid"  # Impede campos adicionais e evita a contaminação do estado

Para ser sincero, eu usava TypedDict o tempo todo e achava que era suficiente. Até que, em uma execução, um campo inválido entrou no estado do agente. Era um campo temporário de depuração que eu havia esquecido de remover. Os nós seguintes começaram a receber dados estranhos, e levei um bom tempo para encontrar a causa. Desde então, uso a configuração extra="forbid" do Pydantic para bloquear campos inválidos já na entrada.

1.3 Como funcionam as funções reducer

Este é o aspecto mais importante — e também um dos mais mal compreendidos — do gerenciamento de estado no LangGraph.

Quando vários nós são executados em paralelo, eles podem alterar o mesmo campo de estado ao mesmo tempo. Por padrão, o LangGraph faz com que a execução posterior sobrescreva a anterior, mas muitas vezes não é isso que você quer. A função reducer define como essas alterações paralelas serão mescladas.

O LangGraph inclui um reducer muito usado, chamado add_messages. Ele mescla listas de mensagens, remove duplicatas automaticamente e mantém a versão mais recente:

from langgraph.graph import add_messages

class ChatState(TypedDict):
    messages: Annotated[list, add_messages]

Quando dois nós paralelos adicionam mensagens a messages, add_messages faz uma mesclagem inteligente em vez de simplesmente sobrescrever o valor.

Um reducer personalizado nada mais é que uma função que recebe dois parâmetros: o valor atual e o novo valor. Ela deve retornar o resultado da mesclagem.

def merge_contexts(existing: str, new: str) -> str:
    """Mescla strings de contexto e preserva a versão mais longa"""
    if not existing:
        return new
    if not new:
        return existing
    return existing if len(existing) >= len(new) else new

class CustomState(TypedDict):
    context: Annotated[str, merge_contexts]

Em um projeto, usei um reducer personalizado para tratar um cenário de recuperação por várias fontes. Três nós de busca consultavam em paralelo um banco de dados vetorial, um índice de palavras-chave e um grafo de conhecimento, cada um retornando sua própria lista de candidatos. No fim, o reducer reunia os resultados, eliminava duplicatas e os ordenava por relevância. Esse método foi quase três vezes mais rápido que a chamada sequencial.

Persistência e checkpoints: a base de um agente pronto para produção

O incidente de madrugada citado na introdução teve uma causa simples: eu não havia configurado corretamente a persistência. O MemorySaver mantém o estado apenas na memória; quando o processo reinicia, tudo desaparece. O agente parou no meio de uma execução e todo o diálogo do usuário foi perdido. Esse tipo de incidente é inaceitável em produção.

2.1 Tipos de checkpointer e como escolher

O LangGraph oferece três checkpointers, indicados para cenários bem diferentes.

CheckpointerCenário indicadoVantagensDesvantagens
MemorySaverDesenvolvimento local e testes rápidosSem configuração e muito rápidoPerde os dados quando o processo reinicia
SqliteSaverImplantação em uma única máquina e validação de protótiposLeve e sem dependências externasEscrita limitada, inadequada para alta concorrência
PostgresSaverAmbiente de produçãoConfiável e compatível com alta concorrênciaExige a manutenção do PostgreSQL

Minha recomendação é direta: use MemorySaver durante o desenvolvimento e PostgresSaver em produção. Evite o SqliteSaver — o gargalo de escrita sob alta concorrência pode se tornar um problema sério.

# Exemplo de configuração para produção
from langgraph.checkpoint.postgres import PostgresSaver
import psycopg

# Versão síncrona
conn = psycopg.connect("postgres://user:pass@host:5432/db")
checkpointer = PostgresSaver(conn)

# Versão assíncrona (recomendada para alta concorrência)
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
import psycopg_pool

pool = psycopg_pool.AsyncConnectionPool(
    "postgres://user:pass@host:5432/db",
    min_size=5,
    max_size=20
)
async_checkpointer = AsyncPostgresSaver(pool)

# Injeta durante a compilação
app = graph.compile(checkpointer=async_checkpointer)

2.2 Como funciona o Thread ID

O Thread ID é o mecanismo central do LangGraph para isolar vários usuários e várias sessões. Cada thread_id corresponde a um histórico de estado independente e não interfere nos demais.

# Primeira conversa
config = {"configurable": {"thread_id": "user_123_session_1"}}
result = app.invoke(
    {"messages": [{"role": "user", "content": "Meu nome é João"}]},
    config
)

# Segunda conversa (com o mesmo thread_id)
# O agente se lembrará de que o usuário disse "Meu nome é João"
result2 = app.invoke(
    {"messages": [{"role": "user", "content": "Qual é o meu nome?"}]},
    config  # O mesmo thread_id
)

# Outro thread_id = uma conversa nova e totalmente independente
config_new = {"configurable": {"thread_id": "user_456_session_1"}}
result3 = app.invoke(
    {"messages": [{"role": "user", "content": "Qual é o meu nome?"}]},
    config_new  # O agente não sabe que o nome é "João"
)

O mecanismo é engenhoso, mas fácil de usar de forma incorreta. Certa vez, defini thread_id com um valor fixo. O resultado foi que todos os usuários passaram a compartilhar o mesmo histórico de conversa: o usuário B conseguia ver a resposta dada à pergunta do usuário A. A abordagem correta é usar uma combinação de ID do usuário + ID da sessão como thread_id.

Salvar e carregar automaticamente é outra característica implícita do checkpointer. Você não precisa chamar save() nem load() manualmente: toda chamada a invoke() ou stream() aciona essas operações. Isso é conveniente, mas também significa que o banco de dados precisa suportar escritas frequentes.

2.3 Serialização e tipos compatíveis

Por padrão, o LangGraph usa JsonPlusSerializer para serializar o estado. Ele é compatível com:

  • Tipos nativos do Python (list, dict, str, int, float, bool)
  • Objetos datetime
  • Tipos de mensagem do LangChain (HumanMessage, AIMessage etc.)
  • Valores de enum
from datetime import datetime
from langchain_core.messages import HumanMessage

class RichState(TypedDict):
    messages: list
    created_at: datetime  # Aceita datetime
    status: str

# É possível armazenar datetime diretamente, sem convertê-lo em string
state = {
    "messages": [HumanMessage(content="Hello")],
    "created_at": datetime.now(),
    "status": "active"
}

Alguns tipos, porém, não são aceitos, como set no Python. Se houver um set no estado, converta-o em list antes de salvar e faça a conversão inversa na leitura. Em um projeto, usei um set para armazenar os IDs dos nós já visitados. A serialização falhou, e demorei algum tempo para identificar o motivo.

2.4 Armadilhas da implantação em produção

Armadilha 1: desempenho de escrita do SqliteSaver

O bloqueio de escrita do SQLite vale para o banco inteiro, portanto apenas uma operação de escrita pode ocorrer por vez. Se o agente precisa processar mais de 100 conversas simultâneas, o SqliteSaver se torna um gargalo. Os sintomas são requisições mais lentas, aumento da taxa de erros e logs cheios de database is locked.

A solução é migrar diretamente para PostgreSQL e usar a versão assíncrona AsyncPostgresSaver.

Armadilha 2: escolha da API assíncrona

As APIs síncronas e assíncronas do LangGraph são separadas. Se a sua aplicação usa um framework assíncrono, como FastAPI ou aiohttp, escolha obrigatoriamente a versão assíncrona:

# API síncrona (bloqueante)
result = app.invoke(state, config)

# API assíncrona (não bloqueante)
result = await app.ainvoke(state, config)

# A saída em streaming também exige o método assíncrono correspondente
async for chunk in app.astream(state, config):
    yield chunk

Misturar chamadas síncronas e assíncronas causa problemas. Certa vez, chamei invoke() de forma síncrona em uma rota do FastAPI e bloqueei todo o loop de eventos. Todas as outras requisições ficaram travadas.

Armadilha 3: ausência de um mecanismo de recuperação de erros

O checkpointer salva o estado, mas não detecta falhas automaticamente. Se o agente falhar no nó C, o estado ficará parado no ponto anterior ao nó C. Você ainda precisa implementar a lógica para retomar a partir desse ponto:

# Retoma a partir do último ponto interrompido
state = app.get_state(config)
if state.values.get("current_node") == "C":
    # Executa novamente o nó C
    result = app.invoke(state.values, config)

O LangGraph oferece as APIs app.get_state() e app.update_state(), que permitem ler e alterar manualmente o estado. Isso é muito útil na depuração: você pode voltar a um checkpoint anterior e executar o processo novamente.

Comparação de frameworks: LangGraph vs. CrewAI vs. AutoGen

Escolher um framework é como escolher uma linguagem de programação: não existe o melhor em termos absolutos, mas o mais adequado a cada situação. Já usei os três em projetos, e cada um tem suas peculiaridades.

3.1 Filosofia de projeto dos três frameworks

LangGraph: estrutura em grafo + orientação por estado

O conceito central do LangGraph é a estrutura explícita em grafo. Você define nós, arestas e estado, e o framework cuida da execução. A vantagem é o alto grau de controle: fica claro como os dados circulam e quais decisões são tomadas em cada nó. A desvantagem é a curva de aprendizado acentuada e a quantidade relativamente maior de código.

# Estilo LangGraph: define explicitamente cada nó e aresta
graph = StateGraph(AgentState)
graph.add_node("research", research_node)
graph.add_node("write", write_node)
graph.add_node("review", review_node)
graph.add_edge("research", "write")
graph.add_conditional_edges("write", should_review, {"review": "review", "end": END})

CrewAI: orientação por papéis + alto nível de abstração

A proposta do CrewAI é definir papéis e deixá-los colaborar. Você cria Agent (papel), Task (tarefa) e Crew (equipe), e o framework faz a orquestração automaticamente. É fácil começar e poucas linhas de código bastam para executar um fluxo. O controle, porém, é menor: a lógica de orquestração subjacente fica encapsulada, o que dificulta a depuração quando algo dá errado.

# Estilo CrewAI: define papéis e tarefas
researcher = Agent(role="Researcher", goal="Find information", ...)
writer = Agent(role="Writer", goal="Write articles", ...)

task1 = Task(description="Research topic X", agent=researcher)
task2 = Task(description="Write article based on research", agent=writer)

crew = Crew(agents=[researcher, writer], tasks=[task1, task2])
crew.kickoff()  # Inicia com uma única linha

AutoGen: orientação por conversas + colaboração

O AutoGen vem da Microsoft Research e se baseia em conversas entre agentes. Você define vários agentes, que colaboram por meio de diálogos para concluir a tarefa. Ele funciona bem em situações que exigem comunicação e negociação frequentes, como revisão de código e discussão de soluções. O consumo de tokens, porém, é elevado, pois as conversas entre agentes ocupam grande parte do contexto.

# Estilo AutoGen: os agentes colaboram por meio de conversas
assistant = AssistantAgent("assistant", llm_config=...)
user_proxy = UserProxyAgent("user_proxy", ...)

# Conversa automática entre os agentes
user_proxy.initiate_chat(
    assistant,
    message="Ajude-me a escrever um algoritmo de ordenação"
)
# assistant e user_proxy conversarão em várias rodadas até concluir a tarefa

3.2 Tabela comparativa por dimensão técnica

Com base na minha experiência prática, comparei os frameworks em várias dimensões:

DimensãoLangGraphCrewAIAutoGen
Curva de aprendizadoAcentuadaSuaveIntermediária
ControleMuito altoMédioMédio
Maturidade para produçãoA mais altaEstávelEm evolução
Gerenciamento de estadoNativoEncapsuladoEncapsulado
Capacidade de depuraçãoAlta (trace visual)MédiaMédia
Eficiência no uso de tokensAltaMédiaBaixa (alto custo de conversação)
Execução paralelaNativaCompatívelCompatível
PersistênciaVários backendsLimitadaLimitada
Qualidade da documentaçãoDetalhadaRazoávelRazoável

Curva de aprendizado: o CrewAI é o mais acessível; basta definir os papéis. O LangGraph exige compreender conceitos como StateGraph, reducer e checkpointer, o que prolonga o aprendizado inicial.

Controle: o LangGraph vence. Você controla com precisão as entradas e saídas de cada nó, as ramificações condicionais e a execução paralela. No CrewAI e no AutoGen, a lógica de orquestração é encapsulada, dificultando a identificação de problemas.

Eficiência no uso de tokens: o mecanismo de conversa do AutoGen aumenta o consumo. Cada mensagem trocada entre agentes ocupa parte da janela de contexto. O modelo orientado por estado do LangGraph é mais eficiente: o estado armazena apenas as informações necessárias e não cresce sem limite.

3.3 Estrutura para a decisão

Se você está em dúvida sobre qual escolher, use os critérios a seguir.

Escolha CrewAI se:

  • Você precisa criar rapidamente um protótipo ou uma demonstração
  • A equipe tem pouca experiência no desenvolvimento de agentes
  • O fluxo de tarefas é relativamente fixo e não exige ramificações condicionais complexas
  • O projeto é curto e prioriza a entrega

Escolha LangGraph se:

  • Você está construindo um sistema para produção
  • Precisa controlar precisamente o fluxo e o estado
  • Há ramificações condicionais complexas ou necessidade de execução paralela
  • O sistema terá manutenção e evolução de longo prazo

Escolha AutoGen se:

  • A tarefa exige negociação e discussão entre vários agentes
  • Há cota de LLM disponível e o consumo de tokens não é um problema
  • O projeto é de pesquisa e explora formas de colaboração entre agentes

Minha sugestão: se ainda estiver em dúvida, comece pelo LangGraph. Seus conceitos são mais fundamentais; depois de dominá-los, fica mais fácil entender CrewAI e AutoGen. Além disso, a documentação e o suporte da comunidade do LangGraph são atualmente os melhores entre os três.

Observabilidade e implantação em produção na prática

Quando um agente entra em produção, surge outro problema: sua execução se torna uma caixa-preta. Você não sabe em qual nó ele travou, por que gerou uma resposta estranha ou se o consumo de tokens está dentro do esperado. As ferramentas de observabilidade existem para resolver esse problema.

4.1 Integração com LangSmith

LangSmith é a plataforma oficial de observabilidade do LangChain. Ela rastreia todas as chamadas, visualiza o caminho de execução do agente e avalia a qualidade das respostas.

import os

# Configura as variáveis de ambiente (basta fazer isso uma vez na inicialização)
os.environ["LANGSMITH_API_KEY"] = "your-api-key"
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_PROJECT"] = "my-agent-project"

# Todas as chamadas seguintes a invoke serão reportadas automaticamente
result = app.invoke({"messages": [...]})

# No console do LangSmith, você verá:
# - Cadeia completa de chamadas
# - Entradas e saídas de cada nó
# - Detalhamento do consumo de tokens
# - Distribuição do tempo de execução

O recurso de trace do LangSmith é o que mais uso ao depurar agentes. Certa vez, um usuário relatou que o agente ocasionalmente gerava conteúdo irrelevante. Ao examinar os traces no LangSmith, descobri que um nó de busca havia retornado um resultado incorreto. Levei menos de dez minutos para localizar a causa, e a correção também foi rápida: bastou adicionar uma condição de filtragem.

Quanto ao custo, o LangSmith tem uma cota gratuita de 5.000 traces por mês, suficiente para projetos pequenos. O plano para equipes começa em US$ 39 por mês e é voltado à colaboração entre várias pessoas.

4.2 Langfuse como alternativa de código aberto

Se o projeto lida com dados sensíveis ou você prefere controlar os próprios dados de observabilidade, o Langfuse é uma alternativa de código aberto.

# Instalação
# pip install langfuse

from langfuse.langchain import CallbackHandler

# Inicializa o handler
langfuse_handler = CallbackHandler(
    public_key="pk-xxx",
    secret_key="sk-xxx",
    host="https://cloud.langfuse.com"  # Ou o endereço da instância auto-hospedada
)

# Injeta na chamada a invoke
result = app.invoke(
    {"messages": [...]},
    config={"callbacks": [langfuse_handler]}
)

# O Langfuse registra:
# - prompt e completion
# - Parâmetros do modelo
# - Uso de tokens
# - Tempo de execução

O Langfuse aceita auto-hospedagem e pode ser implantado com Docker em um único comando. Ele tem menos recursos que o LangSmith, mas oferece os componentes essenciais, como traces, avaliações e gerenciamento de conjuntos de dados. Em um dos meus projetos, os requisitos de conformidade impediam o envio de dados a terceiros. Por isso, usamos uma instância auto-hospedada do Langfuse em um cluster privado de Kubernetes.

Comparação de recursos:

RecursoLangSmithLangfuse
Rastreamento de tracesCompatívelCompatível
VisualizaçãoAvançadaIntermediária
Auto-hospedagemNão compatívelCompatível
PreçoUS$ 0 a US$ 39+/mêsGratuito e de código aberto
Gerenciamento de conjuntos de dadosCompatívelCompatível
Sistema de avaliaçãoCompatívelCompatível

4.3 Métricas personalizadas

Além de usar uma plataforma pronta de observabilidade, você pode instrumentar o sistema e coletar suas próprias métricas.

Rastreamento das transições de estado: registre os horários de entrada e saída de cada nó para calcular a distribuição do tempo de execução.

import time
from datetime import datetime

# Wrapper personalizado para os nós
def timed_node(node_func):
    def wrapper(state):
        start = time.time()
        print(f"[{datetime.now()}] Entering {node_func.__name__}")
        result = node_func(state)
        elapsed = time.time() - start
        print(f"[{datetime.now()}] Exiting {node_func.__name__}, took {elapsed:.2f}s")
        return result
    return wrapper

# Uso
@timed_node
def my_research_node(state):
    # Lógica do nó
    return state

Visualização do caminho de decisão: registre a sequência de nós percorrida pelo agente para analisar os caminhos mais comuns.

# Adiciona ao estado um campo para o caminho
class TrackedState(MessagesState):
    visited_nodes: list = []

# Adiciona um registro após a execução de cada nó
def track_visit(state, node_name):
    state["visited_nodes"].append({
        "node": node_name,
        "timestamp": datetime.now().isoformat()
    })
    return state

Essas métricas personalizadas podem ser enviadas ao seu próprio sistema de monitoramento, como Prometheus e Grafana, e analisadas junto às métricas de negócio. Certa vez, percebi que um agente ficava mais lento nos horários de pico. Com métricas personalizadas, identifiquei timeouts em chamadas a uma API externa. Depois de adicionar novas tentativas e um circuit breaker, a latência p99 caiu de 15 para 3 segundos.

Tendências da engenharia de agentes em 2026 e a evolução do LangGraph

A tecnologia muda rapidamente, mas algumas tendências merecem atenção desde já.

5.1 Principais conclusões do relatório State of Agent Engineering da LangChain

No início de 2026, a LangChain publicou o relatório State of Agent Engineering, baseado na análise de centenas de sistemas de agentes em produção. Três conclusões me chamaram a atenção.

Conclusão 1: arquiteturas em grafo se tornam predominantes

Mais de 70% dos agentes em produção adotaram algum tipo de estrutura em grafo — DAG ou máquina de estados — em vez de uma Chain linear simples. A razão é prática: fluxos de negócio reais raramente seguem uma única linha do início ao fim. O usuário pode interromper, pedir esclarecimentos ou mudar de assunto a qualquer momento, e uma estrutura em grafo lida melhor com essas situações complexas.

Conclusão 2: padronização do human-in-the-loop

Sessenta por cento dos sistemas de agentes incorporaram pontos de intervenção humana. Em vez de deixar o agente executar tudo automaticamente, o processo é pausado em decisões críticas e só continua após a confirmação de uma pessoa. A API interrupt do LangGraph foi criada para esse padrão:

from langgraph.types import interrupt, Command

# Chama interrupt() dentro do nó para pausar e enviar o contexto à revisão humana
def human_review(state):
    decision = interrupt({"need": "approval", "draft": state.get("draft")})
    return {"approved": decision["approved"]}

graph.add_node("human_review", human_review)

# Após a revisão, retoma do ponto de interrupção com Command(resume=...)
result = app.invoke(Command(resume={"approved": True}), config)

Esse padrão é especialmente importante em áreas de alto risco, como finanças e saúde. Não se deve permitir que um agente faça transferências financeiras ou prescreva medicamentos automaticamente; uma pessoa precisa aprovar essas ações.

Conclusão 3: amadurecimento das ferramentas de observabilidade

O relatório apresenta um dado importante: o tempo médio para investigar falhas em agentes com ferramentas de observabilidade é 60% menor do que nos sistemas sem essas ferramentas. Isso corresponde à minha experiência: sem traces, depurar um agente é como tatear no escuro.

5.2 Novos recursos do LangGraph em 2026

O LangGraph recebeu atualizações importantes em 2026.

Definição de estado com Pydantic v3 se torna padrão

O desempenho do Pydantic v3 é de 5 a 10 vezes superior ao do v2, com validações mais rápidas. O LangGraph recomenda oficialmente o uso de Pydantic BaseModel para definir o estado em novos projetos.

Modularização com subgraphs

Você pode dividir um agente complexo em vários subgraphs. Cada subgraph é uma máquina de estados independente, que pode ser testada e reutilizada separadamente.

# Subgrafo: agente de pesquisa independente
research_subgraph = StateGraph(ResearchState)
research_subgraph.add_node("search", search_node)
research_subgraph.add_node("summarize", summarize_node)
research_subgraph.compile()

# Grafo principal: chama o subgrafo
main_graph = StateGraph(MainState)
main_graph.add_node("research", research_subgraph)
main_graph.add_node("write", write_node)

Esse recurso é valioso em projetos grandes: equipes diferentes podem desenvolver seus próprios subgraphs e integrá-los depois.

Deep Agents: planejamento + subagentes + sistema de arquivos

O LangGraph introduziu o conceito de Deep Agents. Um agente principal fica responsável pelo planejamento, chama vários subagentes para executar tarefas específicas e também pode operar no sistema de arquivos. Assim, o agente consegue lidar com fluxos mais complexos, como analisar um PDF, gerar um relatório e salvá-lo em um diretório específico.

5.3 Perspectivas para o futuro

Evolução da governança de agentes

Quando um agente entra em produção, a governança é um dos primeiros desafios: quem pode aprovar ações de alto risco, como atribuir responsabilidade por decisões incorretas e se os logs de auditoria atendem às exigências de conformidade. A proposta de AgentOps promovida pela LangChain é incorporar esses aspectos a uma gestão completa do ciclo de vida, semelhante ao DevOps.

Compatibilidade com agentes multimodais

Hoje, os agentes trabalham principalmente com texto. No futuro, eles devem combinar cada vez mais imagens, áudio e vídeo. O LangGraph já oferece suporte a tipos de mensagem multimodais, embora fluxos completos entre diferentes modalidades ainda estejam em fase de exploração.

Nem todas essas previsões necessariamente se confirmarão. A engenharia de agentes ainda é uma área jovem, e APIs e boas práticas podem mudar a cada seis meses. É justamente por isso que volto periodicamente a este artigo para revisar versões e preços.

Conclusão

Este artigo abordou as principais dimensões do gerenciamento de estado no LangGraph:

  • Construção com StateGraph: estrutura em grafo e orientação por estado são o paradigma básico do desenvolvimento de agentes
  • Padrão reducer: o mecanismo essencial para mesclar estados durante a execução paralela
  • Escolha da persistência: MemorySaver no desenvolvimento e PostgresSaver em produção
  • Comparação de frameworks: LangGraph oferece o maior controle, CrewAI é o mais fácil para começar e AutoGen funciona bem em cenários de colaboração
  • Observabilidade: escolha LangSmith ou Langfuse, mas não deixe de usar um deles

Algumas recomendações práticas:

  1. Revise seus projetos de agentes atuais. Se ainda estiver usando MemorySaver, planeje imediatamente a migração para PostgresSaver.
  2. Leia o relatório State of Agent Engineering da LangChain para conhecer as tendências do setor.
  3. Adicione observabilidade ao agente. Pode ser LangSmith ou uma instância auto-hospedada do Langfuse; o importante é começar.
  4. Se você está começando a desenvolver agentes, consulte os artigos desta série sobre sistemas de memória para agentes e projeto de arquitetura de agentes para montar uma stack completa.

A engenharia de agentes continua evoluindo rapidamente, e as práticas recomendadas de hoje podem ficar ultrapassadas no ano que vem. Dominar os princípios básicos — gerenciamento de estado, persistência e observabilidade — ajudará você a compreender e adotar novas ferramentas.

Tabela de escolha da solução de gerenciamento de estado

NecessidadeSolução recomendadaNão recomendadoMotivo
Experimentos locaisMemorySaverComeçar diretamente com um banco de dados complexoPermite validar o schema de estado e o reducer com baixo custo
Conversas e tarefas longas em produçãoPostgres checkpointer + thread_idSalvar apenas o resultado finalOferece retomada após interrupções, reprodução do histórico e intervenção humana
Orquestração com vários agentesEstado explícito do LangGraph + checkpointDepender apenas da memória no promptPermite localizar o nó que contaminou o estado após uma falha
Fluxos colaborativos de pesquisaAutoGen/CrewAI + registro de estado externoDiscussões sem estadoFluxos colaborativos também precisam de estado da tarefa e monitoramento de timeouts

Leitura complementar: do gerenciamento de estado ao ecossistema de agentes

FAQ

Que problema o checkpoint do LangGraph resolve?
O checkpoint salva um snapshot do estado de uma thread, permitindo que tarefas longas sejam retomadas após interrupções, timeouts, aprovações humanas ou reinicializações do serviço. Não é um simples log, mas um ponto de recuperação para agentes em produção.
Qual é a função do thread_id no gerenciamento de estado do LangGraph?
O thread_id diferencia sessões ou instâncias de tarefa. Um mesmo grafo pode atender vários usuários, mas o estado, o histórico e os checkpoints de cada thread precisam permanecer isolados.
Qual é a diferença entre o gerenciamento de estado do LangGraph e o do AutoGen?
O LangGraph trata o estado como parte central da execução do grafo, sendo indicado para processos de produção recuperáveis e monitoráveis. O AutoGen prioriza discussões entre vários agentes e exige um projeto adicional para o estado da tarefa e o registro de timeouts.
Como implementar a recuperação de falhas em produção?
No mínimo, salve checkpoints, entradas e saídas dos nós, causa do erro, retry_count e estado da intervenção humana. Na recuperação, continue a partir do checkpoint confiável mais recente em vez de executar todo o fluxo novamente.

22 min de leitura · Publicado em: 24 abr 2026 · Atualizado em: 4 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog