Python & AI Tutorials Logo
LangChain & LangGraph

5. Prévia de Agente — O Momento "Aha!"

Até este ponto, você construiu sistemas onde você controla o fluxo. Você escreve o prompt, chama o LLM e processa a resposta. O LLM é poderoso, mas ainda está apenas seguindo suas instruções.

Este capítulo introduz uma mudança fundamental: e se o LLM decidisse o que acontece a seguir?

Por Que Este Capítulo Existe

O Problema: Se você continuar construindo chatbots até o Capítulo 11 sem esta prévia, provavelmente pensará "agentes são apenas chatbots melhores."

A Verdade: Agentes são fundamentalmente diferentes. Eles tomam decisões que controlam seu programa, não apenas geram texto.

A Solução: Este capítulo mostra para onde estamos indo, então quando você construir pipelines e gerenciamento de estado nos próximos capítulos, entenderá por que cada peça importa.

O Que Você Aprenderá (E O Que Não Aprenderá)

Este capítulo (Capítulo 5):

  • Uma prévia mínima de 15 minutos do pensamento agêntico
  • Como a saída do LLM pode acionar diferentes caminhos de código
  • A diferença conceitual entre roteamento e loops de agente

Capítulos posteriores (A partir do Capítulo 12):

  • Sistemas de agentes reais com ferramentas, loops e autocorreção
  • Implementações prontas para produção
  • Padrões avançados como coordenação multi-agente

Por que a lacuna? Antes de construir agentes, você precisa de fundamentos: engenharia de prompt (Cap 4), pipelines de execução (Cap 6), saída estruturada (Cap 7), gerenciamento de estado (Cap 8) e integração de conhecimento (Cap 9-11).

Uma nota sobre a abordagem de aprendizado: Este capítulo foca em conceitos, não em detalhes de implementação. As técnicas reais de design e desenvolvimento vêm no Capítulo 12 e além. Não se preocupe se você não souber como implementar tudo o que vê aqui—isso é intencional. Entender o que é um agente conceitualmente é suficiente por enquanto.

Vamos começar.

5.1) De Chatbot a Tomador de Decisões

O Conceito: Em vez de responder a pergunta, o LLM decide qual ferramenta usar

Nos Capítulos 3 e 4, você construiu sistemas de chat onde o LLM gera respostas de texto. O fluxo era direto:

  1. Usuário faz uma pergunta
  2. LLM gera uma resposta
  3. Você exibe a resposta

Esta é uma cadeia estática: o fluxo é predeterminado. O único trabalho do LLM é produzir texto.

Agora vamos mudar o tipo de solicitação. Um usuário pergunta: "Quanto é 847 × 923?"

Seu chatbot do Capítulo 3 tentaria responder isso, mas LLMs não calculam de fato—eles preveem tokens com aparência plausível. Para "2 + 2", a resposta "4" aparece com tanta frequência nos dados de treinamento que o LLM acerta. Mas para "847 × 923"—um cálculo que o LLM nunca viu—ele gerará algo que parece um número, mas provavelmente está errado.

O que você realmente quer:

  1. LLM reconhece: "Isso é um problema matemático"
  2. LLM decide: "Use a ferramenta calculadora, não minha previsão de tokens"
  3. Python executa: 847 × 923 = 781.781
  4. Sistema retorna: A resposta correta

O trabalho do LLM não é calcular—é rotear para a ferramenta que pode.

Aqui está o insight chave: o LLM não precisa resolver a matemática—ele precisa decidir usar uma calculadora.

Esta é a mudança de chatbot para tomador de decisões. O LLM examina a solicitação e a roteia para a ferramenta apropriada. Está tomando uma decisão sobre o fluxo do programa, não apenas gerando texto.

Vamos visualizar esta diferença:

Cadeia Estática (Chatbot)

Usuário: Quanto é 847 × 923?

LLM gera texto

Exibe: 'Aproximadamente 780.000...'

Roteamento Dinâmico (Tomador de decisões)

Usuário: Quanto é 847 × 923?

LLM decide: CALC necessário

Executa: Calculadora Python

Exibe: 781.781

Na cadeia estática, o LLM tenta responder tudo diretamente. No sistema de roteamento dinâmico, o LLM roteia a solicitação para a ferramenta certa.

O Visual: Compare uma "Cadeia Linear" (Estática) vs. um "Roteador" (Dinâmico)

Aqui está como uma cadeia estática lida com qualquer solicitação do usuário:

Entrada do Usuário

LLM

Resposta de Texto

Exibe ao Usuário

O LLM tenta responder tudo diretamente. Seja você perguntando "Qual é a capital da França?" ou "Quanto é 15% de 240?", o LLM gera uma resposta de texto. Ele pode acertar a capital (viu "Paris" muitas vezes nos dados de treinamento), mas provavelmente calculará errado a porcentagem.

O problema: O LLM usa a mesma abordagem para todas as perguntas—previsão de tokens—mesmo quando existem ferramentas melhores.


Agora vamos introduzir um sistema que pode lidar com diferentes tipos de solicitações de forma diferente:

  1. Perguntas factuais: "Qual é a capital da França?" → Use uma ferramenta de busca
  2. Problemas matemáticos: "Quanto é 15% de 240?" → Use uma calculadora
  3. Conversacional: "Como você está?" → LLM responde diretamente

Aqui está um roteador dinâmico que torna isso possível:

Factual

Matemática

Conversacional

Entrada do Usuário

Camada de Decisão LLM

Ferramenta de Busca

Ferramenta Calculadora

Resposta Direta

Formata Resultado

Exibe ao Usuário

O LLM examina a entrada e escolhe um caminho baseado no tipo de solicitação. Esta é a lógica de roteamento, e o LLM age como o roteador.

A diferença chave: Em vez de sempre gerar texto, o LLM agora decide como lidar com cada solicitação—roteando-a para a ferramenta apropriada.

Conclusão Chave: De Gerar Respostas a Escolher Ações

Esta é a mudança fundamental em sistemas agênticos:

Uso tradicional de LLM: Você faz uma pergunta, o LLM escreve uma resposta.

Uso agêntico de LLM: Você faz uma pergunta, o LLM decide o que fazer, e seu código executa essa decisão.

A saída do LLM não é mais apenas texto para o usuário—são instruções para seu programa.

Pense assim: em um chatbot tradicional, o LLM é um funcionário que responde perguntas de clientes. Em um sistema agêntico, o LLM é um gerente que decide qual departamento deve lidar com cada solicitação.

Esta capacidade de tomada de decisão é a essência dos sistemas agênticos. O LLM não apenas responde—ele controla o que seu programa faz a seguir. Baseado na entrada, ele pode acionar uma calculadora, chamar uma API de busca ou responder diretamente. O comportamento do programa muda baseado na decisão do LLM.

Mas como realmente implementamos isso? Vamos ver o código mínimo que faz isso funcionar.

5.2) A Execução Mínima

O Gatilho: Um prompt de sistema que força saída estruturada

Para fazer o LLM agir como um roteador, precisamos restringir sua saída. Em vez de gerar uma resposta completa, queremos que ele produza uma decisão estruturada—um objeto JSON que diz ao nosso código tanto o que fazer quanto quais dados usar.

Aqui está um prompt de sistema que faz isso:

python
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
import json
 
llm = ChatOpenAI(model="gpt-4o-mini")
 
system_prompt = """Você é um assistente de roteamento. Analise a solicitação do usuário e responda com JSON.
 
Formato de saída:
{
  "action": "CALC" | "SEARCH" | "CHAT",
  "input": "entrada limpa para a ferramenta"
}
 
Exemplos:
Usuário: "Calcule 15 vezes 7"
Saída: {"action": "CALC", "input": "15 * 7"}
 
Usuário: "Qual é a capital do Japão?"
Saída: {"action": "SEARCH", "input": "capital do Japão"}
 
Usuário: "Olá!"
Saída: {"action": "CHAT", "input": "Olá!"}
 
Extraia a informação essencial e formate-a para a ferramenta apropriada.
Produza apenas JSON válido, nada mais."""
 
def get_routing_decision(user_input: str) -> dict:
    messages = [
        SystemMessage(content=system_prompt),
        HumanMessage(content=user_input)
    ]
    response = llm.invoke(messages)
    
    # Analisa resposta JSON
    try:
        decision = json.loads(response.content.strip())
        return decision
    except json.JSONDecodeError:
        # Fallback se o LLM não produzir JSON válido
        return {"action": "CHAT", "input": user_input}
 
# Teste com entradas DIFERENTES dos exemplos
print(get_routing_decision("Quanto é 25 * 48?"))  
# Saída: {'action': 'CALC', 'input': '25 * 48'}
 
print(get_routing_decision("Quem escreveu Hamlet?"))  
# Saída: {'action': 'SEARCH', 'input': 'autor de Hamlet'}
 
print(get_routing_decision("Como você está hoje?"))  
# Saída: {'action': 'CHAT', 'input': 'Como você está hoje?'}

Este prompt é deliberadamente restritivo. Não estamos pedindo ao LLM para ser criativo—estamos pedindo para classificar a entrada e extrair a informação relevante em um formato estruturado.

Observe o que está acontecendo aqui:

  1. O LLM lê a pergunta do usuário
  2. Ele determina a intenção (cálculo, busca factual, conversa)
  3. Ele extrai e limpa a informação essencial
  4. Ele produz um objeto JSON com tanto a ação quanto a entrada limpa
  5. Nosso código recebe esses dados estruturados e roteia adequadamente

O LLM não está respondendo a pergunta—está decidindo o que deve responder a pergunta.

A Ponte: Conectando Decisões do LLM à Execução de Ferramentas

Agora precisamos conectar a decisão do LLM à execução real da ferramenta. Aqui está a ponte mínima:

python
def safe_calculator(expression: str) -> float:
    try:
        # Use eval com namespace restrito para segurança
        # Nota: eval() tem riscos de segurança.
        # Em produção, use uma biblioteca de análise matemática como sympy ou avaliação baseada em ast.
        result = eval(expression, {"__builtins__": {}}, {})
        return float(result)
    except:
        raise ValueError(f"Não foi possível calcular: {expression}")
 
def search(query: str) -> str:
    """Função de busca placeholder"""
    # Na realidade, isso chamaria uma API de busca
    # Agora recebe consulta limpa como "autor de Hamlet"
    return f"Resultados de busca para: {query}"
 
def route_and_execute(user_input: str) -> str:
    """Obtém decisão do LLM e executa a ferramenta apropriada"""
    decision = get_routing_decision(user_input)
    
    action = decision["action"]
    tool_input = decision["input"]  # Entrada limpa pelo LLM
    
    if action == "CALC":
        try:
            result = safe_calculator(tool_input)
            return f"Resultado do cálculo: {result}"
        except ValueError as e:
            return f"Não foi possível realizar o cálculo: {e}"
    
    elif action == "SEARCH":
        result = search(tool_input)
        return result
    
    else:  # CHAT
        # Para consultas conversacionais, deixe o LLM responder diretamente
        response = llm.invoke([HumanMessage(content=tool_input)])
        return response.content
 
# Teste o fluxo completo
print(route_and_execute("Quanto é 25 * 48?"))
# LLM extrai "25 * 48" → calculadora recebe entrada limpa
# Saída: Resultado do cálculo: 1200.0
 
print(route_and_execute("Quem escreveu Hamlet?"))
# LLM reformata para "autor de Hamlet" → melhor consulta de busca
# Saída: Resultados de busca para: autor de Hamlet
 
print(route_and_execute("Como você está hoje?"))
# Saída: Estou bem, obrigado por perguntar!

Este é o padrão de roteamento mínimo em sua forma mais simples:

  1. Decisão do LLM: Obtém decisão de roteamento do LLM
  2. Execução de Código: Código Python verifica a decisão
  3. Invocação de Ferramenta: Função apropriada é chamada
  4. Retorno de Resultado: Saída é formatada e retornada

O insight crítico: A saída do LLM não é mais texto para o usuário—são dados estruturados que controlam o comportamento do seu programa. O campo action diz ao seu código qual caminho seguir, e o campo input fornece os dados limpos para aquela ferramenta. Esta resposta JSON se torna lógica executável.

Isso é fundamentalmente diferente de um chatbot. Em um chatbot, a saída do LLM vai diretamente para o usuário. Aqui, a saída do LLM vai para seu código, que então decide o que executar.

O que construímos nesta seção é um roteador—um precursor de agentes completos. Ele demonstra o princípio fundamental (LLM controla o fluxo), mas carece da iteração e autocorreção que definem loops de agentes verdadeiros.

Este sistema de roteamento simples tem uma limitação importante: ele não pode corrigir seus próprios erros. Vamos explorar por que isso importa e o que vem a seguir.

5.3) Entendendo a Terminologia: Roteador vs Agente

O que acabamos de construir é um roteador. Mas como ele se compara a agentes completos? Vamos estabelecer definições claras:

Roteador (o que acabamos de construir)

  • Faz uma decisão de classificação por solicitação
  • Escolhe qual ferramenta/caminho executar
  • Executa uma vez e retorna
  • Sem iteração, sem estado, sem autocorreção
  • Exemplo: Classificador de email, detector de intenção, seletor de ferramenta

Assistente com chamada de ferramentas (Capítulo 13)

  • LLM pode invocar ferramentas diretamente via API de chamada de função
  • Ainda tipicamente de turno único (uma solicitação → uma resposta)
  • Mais sofisticado que roteamento, mas não necessariamente iterativo
  • Exemplo: "Busque o clima e resuma" em uma chamada

Agente (loop completo) (Capítulos 14-17)

  • Itera através de ciclos pensar → agir → observar
  • Carrega estado entre iterações
  • Pode revisar decisões baseado em resultados
  • Implementa autocorreção
  • Exemplo: Assistente de depuração que tenta correções até o código funcionar

Sistema agêntico (termo guarda-chuva)

  • Qualquer sistema onde a saída do LLM influencia o fluxo de controle
  • Inclui roteadores, assistentes com chamada de ferramentas e agentes completos
  • "Agêntico" descreve a propriedade; "agente" descreve uma arquitetura específica
  • Exemplo: Todos os acima exibem comportamento agêntico

O que construímos em 5.2 é um roteador—ele faz uma decisão e a executa. Isso funciona bem para tarefas de classificação diretas, mas não pode lidar com situações que requerem múltiplas etapas, verificação ou correção de curso. Se a decisão inicial é subótima ou se a tarefa se revela mais complexa do que o esperado, o roteador não tem mecanismo para se adaptar.

Agentes resolvem esta limitação introduzindo iteração. Eles podem observar o resultado de uma ação, reconsiderar sua abordagem e tentar novamente. Isso os torna adequados para tarefas complexas de múltiplas etapas onde o caminho para a solução não está claro desde o início.

Nos Capítulos 14-17, você aprenderá como construir esses loops de agentes iterativos.

Nota: Recentemente, modelos de raciocínio como o1 e o3 podem lidar com algumas tarefas de múltiplas etapas internamente, reduzindo a necessidade de loops explícitos em certos cenários. Exploraremos quando usar loops vs. modelos de raciocínio conforme você constrói agentes reais na Parte IV.


O que você deve entender agora:

  1. Sistemas agênticos começam com fluxo de controle: A saída do LLM determina o que seu código faz a seguir
  2. Roteamento é a forma mais simples: Uma decisão, uma ferramenta, um resultado—o que construímos em 5.2
  3. Agentes reais precisam de loops: Para lidar com tarefas de múltiplas etapas, verificação e recuperação de erros (Capítulos 14-17)
  4. Autocorreção é a diferença chave: Agentes podem observar resultados e ajustar sua abordagem

O que não cobrimos (e não cobriremos até capítulos posteriores):

  • Como compor pipelines de execução (Capítulo 6)
  • Como lidar com saída estruturada (Capítulo 7)
  • Como gerenciar memória de conversa (Capítulo 8)
  • Como definir ferramentas adequadamente (Capítulo 12)
  • Como implementar loops de agentes com autocorreção (Capítulos 14-17)
  • Como tornar agentes prontos para produção (Capítulos 18-26)

Este capítulo foi sobre a mudança conceitual—entender o que faz um sistema exibir comportamento agêntico. Os detalhes de implementação vêm depois.

No próximo capítulo, continuaremos construindo fundamentos práticos: compondo pipelines de execução com LangChain Expression Language (LCEL). Estes são os blocos de construção que você usará quando implementarmos agentes reais na Parte IV.

O momento "aha!" está completo. Você agora entende que sistemas agênticos são aqueles onde o LLM decide, e seu código executa. Todo o resto—ferramentas, loops, gerenciamento de estado—é sobre tornar esse ciclo de decisão-execução mais robusto e capaz.

Vamos continuar construindo a fundação.