Adotei o LangGraph esperando que "o gerenciamento de estado e o controle de fluxo ficassem mais limpos", mas o código acabou ficando mais complexo.
Este é um registro e compartilhamento de uma experiência em que vi na prática que a estrutura pode piorar mesmo após a adoção de um framework.
Ao diagnosticar, a situação era a seguinte:
- Havia apenas um nó no grafo. Como a estrutura era current_step → END, não havia arestas condicionais nem ramificações, e
graph.invoke()era igual a chamar a função diretamente. A transição de etapas era decidida pelo código de serviço fora do grafo. - O mesmo estado era armazenado em dois lugares. O LangGraph MemorySaver (em memória) e um Checkpointer próprio em PostgreSQL salvavam e restauravam a mesma sessão em duplicidade, causando inconsistências.
- Havia duplicação em três códigos de execução do LangGraph (Executor), com cerca de 8.700 linhas. A lógica central de fato era basicamente "chamada ao LLM + montagem do prompt", e a maior parte do restante era gerenciamento de estado, ramificações condicionais e patches para casos extremos.
Superficialmente, o problema era ter adotado o framework apenas como uma casca, sem usar seus recursos reais (arestas condicionais, checkpointer integrado, Human-in-the-Loop), mas, ao investigar mais a fundo, a causa era outra.
- A maior parte foi criada por vibe coding, mas durante o processo de criação seguimos implementando a partir de requisitos e intenções a cada vez, sem examinar profundamente o código interno nem os princípios de design.
- O problema não era o vibe coding em si, mas avançar sem validação. Ele apenas otimiza a funcionalidade imediata, não preserva os limites de responsabilidade da estrutura como um todo. O checkpointing duplicado, o estado espalhado e a lógica repetida eram todos acúmulos de otimizações parciais.
- Não é que não houvesse um projetista; a causa real foi dar instruções em cima do framework sem entender suficientemente quais responsabilidades ele foi projetado para assumir.
Então refleti e reverti da seguinte forma.
- Separação de sessões com topologia independente + isolamento por thread_id
- Manter apenas metadados no State e mover o corpo para o Store
- Usar
tool_usenativo em vez de parsing por regex - Separar nós para permitir testes
- Eu mesmo precisava de uma compreensão correta do framework e de uma estrutura para aproveitá-lo
Este é um registro/compartilhamento não sobre "como usar", mas sobre "como usei errado".
2 comentários
Parece que todos os casos de uso de langchain e langgraph podem ser substituídos pelo AI SDK
Pois é. Concordo. Embora isso acabe criando uma dependência do SDK, a curva de aprendizado é alta, então talvez seja até melhor.