1
resposta

[Dúvida] Criação de Agentes com LangChain e LangGraph Combinado

Olá,

Após a última aula que o professor explica a criação de agentes padrão com o LangChain (from langchain.agents import create_agent) e a atividade comparando a necessidade de usos entre LangChain (uso mais simples) e LangGraph (problema mais complexo), acredito que poderia se utilizar uma solução híbrida, contstituída por um grafo com LangGraph e um dos nós ser representado pelo agente do LangChain com LLM, memória e ferramentas acopladas. Desta forma, poderíamos utilizar um sistema completo com multiagentes, executando uma triagem anteriormente com um roteador de tarefas no grafo onde seria levado posteriormente para cada agente especializado, de acordo com uma tarefa específica, com suas próprias ferramentas, representando um nó distinto do grafo. Isto seria uma boa prática na criação de agentes?

Outra dúvida é como ficaria o código para garantir o gerencimento de estado (AgentState) e memórias (MemorySaver) dos nós no grafo com cada agente desempenhando sua função de acordo com a chamada do roteamento do grafo?

Grato desde já!

1 resposta

Ola, nelson!

Sim, essa abordagem híbrida que você descreveu não só faz sentido como é, na prática, uma arquitetura bastante utilizada em cenários mais avançados.

Usar o LangGraph como orquestrador e, dentro dele, ter nós que encapsulam agentes criados com create_agent do LangChain é uma forma bem equilibrada de unir simplicidade com controle. O LangGraph cuida do fluxo (roteamento, estados, decisões), enquanto cada agente fica responsável por resolver um tipo específico de tarefa com suas próprias ferramentas e contexto.

Isso é especialmente útil quando você tem:

  • múltiplos domínios (ex: financeiro, suporte, CRM),
  • ferramentas diferentes por contexto,
  • necessidade de roteamento inteligente antes da execução.

Nesse cenário, o seu “roteador” no grafo decide qual agente chamar, e cada agente atua como um nó especializado. Ou seja: você não está “misturando errado”, está compondo responsabilidades — o que é uma boa prática.

Sobre a segunda parte (estado e memória), aqui está o ponto mais importante: no LangGraph, o estado pertence ao grafo, não ao agente isolado. Então você precisa pensar em dois níveis de memória:

  1. Estado global do grafo (AgentState)
    Esse estado é compartilhado entre os nós e geralmente contém coisas como:
  • histórico de mensagens
  • intenção identificada
  • dados intermediários

Exemplo conceitual:

from typing import TypedDict, List
from langchain.schema import BaseMessage

class AgentState(TypedDict):
    messages: List[BaseMessage]
    user_name: str
    intent: str
  1. Memória por agente (opcional)
    Se você usar create_agent com MemorySaver, cada agente pode manter sua própria memória, mas aí entra uma decisão de arquitetura:
  • Se você quer memória centralizada → use só o estado do grafo
  • Se você quer memória especializada por agente → cada nó pode ter seu próprio checkpointer

Exemplo simplificado de arquitetura híbrida

from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import MemorySaver
from langchain.agents import create_agent

memory = MemorySaver()

# agentes especializados
agent_financeiro = create_agent(model=llm, tools=tools_fin, checkpointer=memory)
agent_suporte = create_agent(model=llm, tools=tools_sup, checkpointer=memory)

def roteador(state: AgentState):
    ultima_msg = state["messages"][-1].content
    
    if "pagamento" in ultima_msg:
        return "financeiro"
    return "suporte"

def no_financeiro(state: AgentState):
    resposta = agent_financeiro.invoke(
        {"messages": state["messages"]},
        config={"configurable": {"thread_id": "user1"}}
    )
    return {"messages": resposta["messages"]}

def no_suporte(state: AgentState):
    resposta = agent_suporte.invoke(
        {"messages": state["messages"]},
        config={"configurable": {"thread_id": "user1"}}
    )
    return {"messages": resposta["messages"]}

graph = StateGraph(AgentState)

graph.add_node("roteador", roteador)
graph.add_node("financeiro", no_financeiro)
graph.add_node("suporte", no_suporte)

graph.set_entry_point("roteador")

graph.add_conditional_edges(
    "roteador",
    lambda state: roteador(state),
    {
        "financeiro": "financeiro",
        "suporte": "suporte"
    }
)

Ponto de atenção importante

Se você usar o mesmo thread_id para todos os agentes, a memória pode “vazar” entre contextos. Algumas estratégias:

  • usar thread_id por usuário (ex: "user_123")
  • ou por agente + usuário ("user_123_financeiro")

Abçs.