LangGraph, CrewAI e Agno: primeiros passos com agentes de IA em Python

🇺🇸 Read in English
Índice

Todo mundo fala de agentes de IA. Poucos explicam o que isso significa na prática — com código, sem buzzword.

A proposta aqui é simples: pegar três frameworks populares de agentes em Python — LangGraph, CrewAI e Agno — e resolver o mesmo problema com cada um. Nada de hello world. Cada exemplo usa ferramentas reais que o agente decide quando e como chamar.

💻 Código-fonte completo: todos os exemplos deste artigo estão no repositório posts.codebase — com instruções de setup para rodar localmente.

Se você já sabe chamar uma API de LLM e quer dar o próximo passo, este post é pra você.

O que é um agente de IA (versão sem hype)

Um agente de IA é um programa que usa um modelo de linguagem (LLM) dentro de um loop. Em vez de receber uma pergunta e devolver uma resposta única, ele repete um ciclo até resolver o problema. Na literatura, esse padrão se chama ReAct (Reason + Act):

Pergunta
  → [LLM pensa] → [Chama ferramenta] → [Observa resultado]
  → [LLM pensa] → [Chama ferramenta] → [Observa resultado]
  → ...
  → Resposta final

Em termos concretos:

  1. Pensa — analisa o que precisa fazer
  2. Age — chama uma ferramenta (busca, cálculo, API, banco de dados)
  3. Observa — lê o resultado da ferramenta
  4. Repete — até decidir que terminou

A diferença para uma chamada simples de API? O agente decide o que fazer. O mecanismo central que permite isso se chama tool calling: o LLM recebe a lista de ferramentas disponíveis e escolhe qual chamar, com quais argumentos. O LLM é o cérebro; as ferramentas são as mãos.

Os frameworks que vamos ver facilitam esse loop. Cada um com uma filosofia diferente.

Quando NÃO usar um agente

Nem todo problema precisa de um agente. É importante saber disso antes de sair construindo.

Se você já sabe exatamente o que precisa fazer — extrair campos de um texto, classificar um e-mail, gerar um resumo — um pipeline simples é mais barato, mais rápido e mais previsível. Uma chamada direta à API resolve.

Agentes fazem sentido quando:

  • O caminho até a resposta não é fixo — o modelo precisa decidir os próximos passos
  • Há múltiplas ferramentas possíveis — e a escolha depende do contexto
  • Você quer delegar decisões ao modelo em vez de codificar cada if/else

E os custos são reais:

  • Latência: cada iteração do loop é uma chamada ao LLM. Três ferramentas = no mínimo três round-trips
  • Tokens: o contexto cresce a cada passo. Mais passos, mais custo
  • Imprevisibilidade: o agente pode entrar em loop, chamar ferramentas erradas ou interpretar mal um resultado

Se o caminho é fixo, use um pipeline. Se o caminho é dinâmico, aí sim — agente faz sentido.

O problema que vamos resolver

Para comparar os três frameworks de forma justa, vamos resolver o mesmo problema em todos:

“Quero comprar um notebook. Quanto custa em reais com 10% de desconto?”

O agente precisa:

  1. Buscar o preço do produto (em USD)
  2. Converter de dólar para real
  3. Calcular o desconto sobre o valor em reais

São três ferramentas, três passos dependentes. O resultado de cada passo alimenta o próximo. É o tipo de problema onde um agente brilha — porque a sequência de chamadas não é óbvia sem contexto.

As três ferramentas (iguais nos três frameworks):

def buscar_preco(produto: str) -> str:
    """Busca o preço de um produto em USD. Produtos disponíveis: notebook, monitor, teclado."""
    catalogo = {"notebook": 1200.00, "monitor": 450.00, "teclado": 85.00}
    preco = catalogo.get(produto.lower())
    if preco:
        return f"{produto}: US$ {preco:.2f}"
    return f"Produto '{produto}' não encontrado."

def converter_moeda(valor: float, de: str, para: str) -> str:
    """Converte um valor entre moedas."""
    taxas = {"USD_BRL": 5.20, "BRL_USD": 0.19}
    chave = f"{de}_{para}".upper()
    taxa = taxas.get(chave)
    if taxa:
        return f"{valor:.2f} {de} = {valor * taxa:.2f} {para}"
    return f"Taxa {de}{para} não disponível."

def calcular_desconto(valor: float, percentual: float) -> str:
    """Aplica desconto percentual sobre um valor."""
    final = valor * (1 - percentual / 100)
    return f"Original: {valor:.2f} → Com {percentual}% de desconto: {final:.2f}"

Nos exemplos que seguem, a lógica das ferramentas é a mesma. O que muda é como cada framework orquestra o agente.

1) LangGraph

LangGraph é um framework de orquestração do ecossistema LangChain. A ideia central: você modela o fluxo do agente como um grafo — nós que processam, arestas que conectam, estado que persiste entre passos.

É o mais baixo nível dos três. Você monta cada peça do loop manualmente.

Instalação

pip install langgraph langchain-openai langchain

Exemplo

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, SystemMessage, ToolMessage
from langgraph.graph import StateGraph, MessagesState, START, END

@tool
def buscar_preco(produto: str) -> str:
    """Busca o preço de um produto em USD. Produtos disponíveis: notebook, monitor, teclado."""
    catalogo = {"notebook": 1200.00, "monitor": 450.00, "teclado": 85.00}
    preco = catalogo.get(produto.lower())
    if preco:
        return f"{produto}: US$ {preco:.2f}"
    return f"Produto '{produto}' não encontrado."

@tool
def converter_moeda(valor: float, de: str, para: str) -> str:
    """Converte um valor entre moedas. Taxas disponíveis: USD↔BRL."""
    taxas = {"USD_BRL": 5.20, "BRL_USD": 0.19}
    chave = f"{de}_{para}".upper()
    taxa = taxas.get(chave)
    if taxa:
        return f"{valor:.2f} {de} = {valor * taxa:.2f} {para}"
    return f"Taxa {de}{para} não disponível."

@tool
def calcular_desconto(valor: float, percentual: float) -> str:
    """Aplica desconto percentual sobre um valor."""
    final = valor * (1 - percentual / 100)
    return f"Original: {valor:.2f} → Com {percentual}% de desconto: {final:.2f}"

tools = [buscar_preco, converter_moeda, calcular_desconto]
tools_por_nome = {t.name: t for t in tools}

modelo = ChatOpenAI(model="gpt-4o-mini", temperature=0)
modelo_com_tools = modelo.bind_tools(tools)

def chamar_modelo(state: MessagesState):
    mensagens = [SystemMessage(content="Você é um assistente de compras. Sempre use as ferramentas disponíveis para buscar preços, converter moedas e calcular descontos.")] + state["messages"]
    return {"messages": [modelo_com_tools.invoke(mensagens)]}

def executar_ferramentas(state: MessagesState):
    resultados = []
    for chamada in state["messages"][-1].tool_calls:
        ferramenta = tools_por_nome[chamada["name"]]
        resultado = ferramenta.invoke(chamada["args"])
        resultados.append(ToolMessage(content=str(resultado), tool_call_id=chamada["id"]))
    return {"messages": resultados}

def decidir_proximo_passo(state: MessagesState):
    if state["messages"][-1].tool_calls:
        return "ferramentas"
    return END

grafo = StateGraph(MessagesState)
grafo.add_node("modelo", chamar_modelo)
grafo.add_node("ferramentas", executar_ferramentas)
grafo.add_edge(START, "modelo")
grafo.add_conditional_edges("modelo", decidir_proximo_passo, ["ferramentas", END])
grafo.add_edge("ferramentas", "modelo")

agente = grafo.compile()

resultado = agente.invoke({
    "messages": [HumanMessage(content="Quero comprar um notebook. Quanto custa em reais com 10% de desconto?")]
})
print(resultado["messages"][-1].content)

O que o agente faz por dentro

🤔 Pensando: preciso saber o preço do notebook
🔧 Chamando: buscar_preco("notebook")
📎 Resultado: notebook: US$ 1200.00

🤔 Pensando: agora preciso converter para reais
🔧 Chamando: converter_moeda(1200.00, "USD", "BRL")
📎 Resultado: 1200.00 USD = 6240.00 BRL

🤔 Pensando: agora aplico o desconto de 10%
🔧 Chamando: calcular_desconto(6240.00, 10)
📎 Resultado: Original: 6240.00 → Com 10% de desconto: 5616.00

✅ Resposta: O notebook custa R$ 5.616,00 com 10% de desconto.

Cada seta no grafo é uma chamada ao LLM. Três ferramentas, três iterações do loop. É isso que acontece “por baixo do capô” em qualquer framework de agentes.

Limitações reais

  • Verboso: mesmo um agente simples exige montar nós, arestas, funções de roteamento. Comparado aos outros dois, é bastante código
  • Curva de aprendizado: pensar em grafos é natural pra quem tem background em engenharia de software, mas pode ser confuso pra iniciantes
  • Dependência do ecossistema LangChain: ferramentas usam @tool do LangChain, modelos usam wrappers do LangChain. Trocar depois não é trivial

Quando brilha

Controle total. Você decide cada caminho, cada condição, cada estado. Pra workflows complexos com ramificações, human-in-the-loop e persistência de execução, não tem nada mais flexível.

2) CrewAI

CrewAI pensa em agentes como membros de uma equipe. Cada agente tem um papel, um objetivo e uma história de fundo. Você define tarefas, monta uma “crew” e manda executar. O framework cuida da coordenação.

É o mais alto nível dos três. Menos código, mais rápido pra prototipar. E o diferencial aparece de verdade quando há mais de um agente.

Instalação

pip install crewai crewai-tools

Exemplo: dois agentes colaborando

Aqui a força do CrewAI aparece: um pesquisador encontra o preço e converte a moeda, e um analista aplica o desconto e entrega o resumo.

from crewai import Agent, Task, Crew, Process
from crewai.tools import tool

@tool("BuscaPreco")
def buscar_preco(produto: str) -> str:
    """Busca o preço de um produto em USD. Produtos disponíveis: notebook, monitor, teclado."""
    catalogo = {"notebook": 1200.00, "monitor": 450.00, "teclado": 85.00}
    preco = catalogo.get(produto.lower())
    if preco:
        return f"{produto}: US$ {preco:.2f}"
    return f"Produto '{produto}' não encontrado."

@tool("ConversorMoeda")
def converter_moeda(valor: float, de: str, para: str) -> str:
    """Converte um valor entre moedas. Taxas disponíveis: USD↔BRL. Parâmetros: valor numérico, moeda de origem (ex: USD), moeda de destino (ex: BRL)."""
    taxas = {"USD_BRL": 5.20, "BRL_USD": 0.19}
    chave = f"{de}_{para}".upper()
    taxa = taxas.get(chave)
    if taxa:
        return f"{valor:.2f} {de} = {valor * taxa:.2f} {para}"
    return f"Taxa {de}{para} não disponível."

@tool("Desconto")
def calcular_desconto(valor: float, percentual: float) -> str:
    """Aplica desconto percentual. Parâmetros: valor numérico, percentual de desconto."""
    final = valor * (1 - percentual / 100)
    return f"Original: {valor:.2f} → Com {percentual}% de desconto: {final:.2f}"

# Dois agentes com papéis diferentes
pesquisador = Agent(
    role="Pesquisador de preços",
    goal="Encontrar preços e converter para a moeda solicitada",
    backstory="Especialista em pesquisa de mercado internacional.",
    tools=[buscar_preco, converter_moeda],
    verbose=True,
)

analista = Agent(
    role="Analista financeiro",
    goal="Calcular valores finais com descontos e apresentar um resumo claro",
    backstory="Analista detalhista que sempre mostra os números.",
    tools=[calcular_desconto],
    verbose=True,
)

# Tarefas encadeadas: a saída da primeira alimenta a segunda
pesquisa = Task(
    description="Encontre o preço do notebook em USD e converta para BRL.",
    expected_output="O preço do notebook em reais.",
    agent=pesquisador,
)

analise = Task(
    description="Aplique 10% de desconto no preço em BRL e apresente um resumo com preço original, desconto e valor final.",
    expected_output="Resumo com preço original em BRL, valor do desconto e preço final.",
    agent=analista,
)

crew = Crew(
    agents=[pesquisador, analista],
    tasks=[pesquisa, analise],
    process=Process.sequential,
    verbose=True,
)

resultado = crew.kickoff()
print(resultado)

O que acontece por dentro

👤 Pesquisador entra em cena
🔧 Chamando: BuscaPreco("notebook")
📎 Resultado: notebook: US$ 1200.00
🔧 Chamando: ConversorMoeda(1200.00, "USD", "BRL")
📎 Resultado: 1200.00 USD = 6240.00 BRL
📤 Entrega: "O notebook custa R$ 6.240,00"

👤 Analista recebe o contexto do pesquisador
🔧 Chamando: Desconto(6240.00, 10)
📎 Resultado: Original: 6240.00 → Com 10% de desconto: 5616.00
✅ Entrega: "Notebook: R$ 6.240,00 → com 10% de desconto: R$ 5.616,00"

O ponto-chave: o analista não recebe a pergunta original — ele recebe a saída do pesquisador como contexto. É isso que faz multi-agente funcionar: um gera, o outro consome.

Limitações reais

  • Caixa-preta: a coordenação entre agentes é abstraída. Quando algo dá errado, é difícil debugar o que cada agente decidiu e por quê
  • Menos controle: você não escolhe a ordem das chamadas de ferramentas nem o fluxo condicional — o framework decide
  • Overhead do LLM: cada agente é uma sessão separada. Dois agentes = mais tokens, mais latência, mais custo. Em problemas simples, um agente solo resolve mais rápido

Quando brilha

Equipes de agentes que colaboram. Pesquisador + escritor + revisor. Tarefas paralelas com papéis claros. Protótipos rápidos de workflows multi-agente.

3) Agno

Agno (antigo Phidata) é o mais pragmático dos três. A filosofia: um agente é um modelo + ferramentas + instruções. Sem abstrações desnecessárias. Funções Python viram ferramentas automaticamente — sem decorators especiais.

É o mais direto. Poucas linhas, agente funcional.

Instalação

pip install agno

Exemplo

from agno.agent import Agent
from agno.models.openai import OpenAIChat

def buscar_preco(produto: str) -> str:
    """Busca o preço de um produto em USD. Produtos disponíveis: notebook, monitor, teclado.

    Args:
        produto: Nome do produto para buscar.
    """
    catalogo = {"notebook": 1200.00, "monitor": 450.00, "teclado": 85.00}
    preco = catalogo.get(produto.lower())
    if preco:
        return f"{produto}: US$ {preco:.2f}"
    return f"Produto '{produto}' não encontrado."

def converter_moeda(valor: float, de: str, para: str) -> str:
    """Converte um valor entre moedas. Taxas disponíveis: USD↔BRL.

    Args:
        valor: Valor numérico a converter.
        de: Moeda de origem (ex: USD).
        para: Moeda de destino (ex: BRL).
    """
    taxas = {"USD_BRL": 5.20, "BRL_USD": 0.19}
    chave = f"{de}_{para}".upper()
    taxa = taxas.get(chave)
    if taxa:
        return f"{valor:.2f} {de} = {valor * taxa:.2f} {para}"
    return f"Taxa {de}{para} não disponível."

def calcular_desconto(valor: float, percentual: float) -> str:
    """Aplica desconto percentual sobre um valor.

    Args:
        valor: Valor numérico original.
        percentual: Percentual de desconto a aplicar.
    """
    final = valor * (1 - percentual / 100)
    return f"Original: {valor:.2f} → Com {percentual}% de desconto: {final:.2f}"

agente = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    tools=[buscar_preco, converter_moeda, calcular_desconto],
    instructions="Responda em português. Sempre use as ferramentas para buscar preços, converter moedas e calcular descontos.",
    markdown=True,
)

agente.print_response(
    "Quero comprar um notebook. Quanto custa em reais com 10% de desconto?",
    stream=True,
)

O que o agente faz por dentro

O mesmo loop ReAct dos outros dois:

🤔 Pensando: preciso buscar o preço
🔧 Chamando: buscar_preco("notebook")
📎 Resultado: notebook: US$ 1200.00

🤔 Pensando: converter para BRL
🔧 Chamando: converter_moeda(1200.00, "USD", "BRL")
📎 Resultado: 1200.00 USD = 6240.00 BRL

🤔 Pensando: aplicar desconto
🔧 Chamando: calcular_desconto(6240.00, 10)
📎 Resultado: Original: 6240.00 → Com 10% de desconto: 5616.00

✅ Resposta: O notebook custa R$ 5.616,00 com 10% de desconto.

Repare: mesmas ferramentas, mesma lógica, mesmo resultado. A diferença é que levou ~15 linhas pra definir o agente, contra ~30 do LangGraph e ~35 do CrewAI.

Limitações reais

  • Workflows complexos: pra fluxos com ramificações condicionais, loops controlados ou human-in-the-loop, o Agno não tem primitivas nativas — você precisaria implementar manualmente
  • Menos maduro: ecossistema menor, comunidade menor, menos exemplos em produção comparado ao LangGraph
  • Menos visibilidade: o que o agente faz “por dentro” é menos transparente sem configuração extra de debug

Quando brilha

Caminho mais curto do zero ao agente funcional. Qualquer função Python vira ferramenta. Excelente pra protótipos rápidos e pra usar com modelos locais (Ollama, LlamaCpp).

Comparação

LangGraphCrewAIAgno
AbstraçãoBaixa (grafo)Alta (papéis)Média (pragmático)
Curva de aprendizadoMais íngremeSuaveCurta
Multi-agenteSim (manual)Sim (nativo, com handoff)Sim (nativo)
Ferramentas@tool do LangChain@tool próprioFunções Python puras
Melhor paraWorkflows complexosEquipes de agentesProtótipos rápidos
Controle finoTotalParcialParcial
PersistênciaBuilt-inVia configVia sessions
Debug / visibilidadeBom (LangSmith)MédioBásico
Risco principalComplexidade desnecessáriaCaixa-pretaLimitação em fluxos complexos

Qual escolher?

Se você é iniciante e quer entender agentes na prática: Agno. Menos atrito, menos código, feedback imediato.

Se você quer velocidade pra prototipar com múltiplos agentes: CrewAI. Defina papéis e tarefas, o framework cuida do resto.

Se você vai pra produção séria com fluxos complexos: LangGraph. Mais trabalho inicial, mas controle total sobre cada passo.

Os três são ativamente mantidos e bem documentados. O conselho mais honesto: escolha um e construa algo. Troque depois se precisar. A melhor forma de aprender é experimentando.

E na produção?

Se os exemplos deste post são o ponto de partida, produção é outra história. Algumas coisas que importam quando o agente sai do notebook e vai pro mundo real:

  • Observabilidade: registre cada chamada de ferramenta, cada decisão do LLM, cada iteração do loop. Sem logs, debugar agentes é adivinhação
  • Retries e timeouts: ferramentas falham, APIs caem, modelos demoram. Defina limites. Um agente que entra em loop infinito queima tokens e dinheiro
  • Guardrails: restrinja quais ferramentas o agente pode chamar, valide as entradas antes de executar, limite o número máximo de iterações
  • Custo: monitore tokens por execução. Três iterações com GPT-4o são mais baratas que dez com o mesmo modelo. O design do agente afeta direto a conta

Nenhum desses frameworks resolve tudo isso automaticamente. Eles dão o esqueleto. O resto é engenharia.

Framework não resolve o problema — só organiza o caos. Um agente ruim em LangGraph continua ruim em CrewAI ou Agno. A diferença está no design, não na ferramenta.


Se quiser ir mais fundo em agentes, recomendo o post sobre o estado da arte em agentes de IA.