2. Fundamentos para Construção de Agentes
No Capítulo 1, você fez sua primeira chamada a um LLM e viu o fluxo básico de requisição-resposta. Agora precisamos entender o que estamos, de fato, construindo: sistemas de IA agêntica (agentic AI). Este capítulo estabelece os conceitos fundamentais que você usará ao longo do livro.
Ao final deste capítulo, você entenderá:
- O que torna um sistema de IA “agêntico” (e por que isso importa)
- Por que frameworks como LangChain e LangGraph existem
- Como os LLMs realmente funcionam por baixo dos panos (e por que isso afeta o design de agentes)
- A economia do uso de LLM (tokens, custos e seleção de modelos)
- Como escrever prompts eficazes para sistemas de agentes
Este é um capítulo conceitual — voltaremos ao código prático no Capítulo 3. Mas esses conceitos são críticos para entender as decisões de design que você vai tomar ao construir agentes.
2.1) O que é IA Agêntica? (Chatbot vs Agente)
Quando a maioria das pessoas pensa em “aplicações de IA”, imagina chatbots: você faz uma pergunta, a IA responde, a conversa termina. Mas a IA agêntica é fundamentalmente diferente. Um agente não apenas responde — ele age de forma autônoma para alcançar objetivos.
A Distinção Central
Vamos começar com uma definição clara:
Chatbot: Um sistema que responde à entrada do usuário com texto gerado. A interação é puramente conversacional. O chatbot não tem capacidade de realizar ações no mundo além de gerar sua próxima mensagem.
Agente: Um sistema que pode:
- Perceber seu ambiente (por exemplo, ler o status de um pedido, verificar estoque)
- Decidir quais ações executar (por exemplo, escolher entre: criar ticket, enviar e-mail ou escalar)
- Agir com base nessas decisões (por exemplo, chamar API, atualizar banco de dados)
- Iterar até atingir um objetivo (por exemplo, verificar pedido → criar ticket → confirmar → concluído)
A diferença principal é autonomia e ação. Um chatbot é reativo; um agente é proativo.
Exemplo Concreto: Suporte ao Cliente
Vamos ver essa distinção na prática.
Abordagem de Chatbot:
Usuário: "Quero um reembolso para o pedido #12345"
Chatbot: "Entendo que você gostaria de um reembolso. Para processar isso, por favor:
1. Visite nosso portal de reembolsos em example.com/refunds
2. Insira o número do seu pedido
3. Selecione um motivo
4. Envie o formulário
5. Aguarde 24-48 horas para revisão manual
Há mais alguma coisa com que eu possa ajudar?"O chatbot fornece informação mas não executa nenhuma ação. O usuário precisa fazer todo o trabalho.
Abordagem de Agente:
Usuário: "Quero um reembolso para o pedido #12345"
Agente (raciocínio interno):
1. Usuário quer reembolso do pedido #12345
2. Preciso verificar se esse pedido existe
3. [Chama get_order_details(order_id="12345")]
4. Pedido encontrado, elegível para reembolso
5. [Chama create_refund_ticket(order_id="12345", reason="customer_request")]
6. Ticket criado: TICKET-789
Agente: "Criei o ticket de reembolso TICKET-789 para o pedido #12345.
Nossa equipe de reembolsos vai processar isso em 3-5 dias úteis.
Você receberá um e-mail de confirmação em breve."O agente executou uma ação: verificou o pedido, criou um ticket e confirmou o resultado. O problema do usuário é resolvido sem etapas manuais.
Por Que Isso Importa para o Desenvolvimento
Entender essa distinção molda como você projeta seu sistema:
Desenvolvimento de Chatbot:
- Foco na qualidade das respostas e no fluxo de conversa
- Principal preocupação: gerar texto útil e preciso
- Arquitetura simples: prompt → LLM → resposta
- Sem necessidade de integrações externas
Desenvolvimento de Agente:
- Foco em tomada de decisão e execução de ações
- Principais preocupações: escolher ações corretas, lidar com erros, manter estado
- Arquitetura complexa: percepção → raciocínio → seleção de ação → execução → verificação
- Requer integrações com ferramentas, tratamento de erros, gerenciamento de estado
O Espectro de Autonomia
Nem todos os agentes são igualmente autônomos. Existe um espectro:
Nível 1: Ações Assistidas
- O agente sugere ações, e o usuário aprova cada uma
- Exemplo: “Posso criar um ticket de reembolso. Devo prosseguir?”
- Abordagem mais segura para operações de alto risco
Nível 2: Autonomia Delimitada
- O agente age dentro de restrições predefinidas
- Exemplo: pode criar tickets e enviar e-mails, mas não pode processar reembolsos acima de US$ 500 nem acessar sistemas de pagamento diretamente
- Mais comum em sistemas em produção (equilíbrio entre eficiência e segurança)
Nível 3: Autonomia Total
- O agente age de forma independente para alcançar objetivos
- Exemplo: executa todo o fluxo de reembolso sem intervenção humana
- Requer guardrails e monitoramento robustos
Características-Chave de Agentes
Para resumir, um sistema de IA agêntica tem estas propriedades centrais:
- Uso de Ferramentas: Pode chamar funções, APIs e serviços externos (sem isso, é apenas um chatbot)
- Orientado a Objetivos: Trabalha em direção a resultados específicos, não apenas responde
- Multietapas: Divide tarefas complexas em sequências de ações
- Adaptativo: Ajusta o comportamento com base em resultados intermediários
- Com Estado: Mantém contexto ao longo de múltiplas interações
As duas primeiras são essenciais — sem ferramentas e objetivos, você não tem um agente. O restante são fatores de qualidade que separam bons agentes de agentes excelentes.
Agora você entende o que são agentes e por que eles são poderosos.
2.2) Por Que LangChain e LangGraph?
Talvez você esteja se perguntando: “Por que eu preciso de frameworks? Não posso simplesmente chamar a API da OpenAI diretamente?” Vamos explorar por que frameworks existem e quais problemas eles resolvem.
A Complexidade do Desenvolvimento de Agentes
Construir um chatbot simples com chamadas diretas de API é simples:
import openai
response = openai.chat.completions.create(
model="gpt-5-mini",
messages=[{"role": "user", "content": "Olá!"}]
)
print(response.choices[0].message.content)Isso funciona bem para casos de uso básicos. Mas assim que você quer construir um agente, a complexidade explode:
Desafio 1: Fluxos Multietapas Seu agente precisa:
- Recuperar documentos relevantes de uma base de conhecimento
- Decidir qual ferramenta chamar com base na intenção do usuário
- Executar a ferramenta e lidar com erros
- Formatar resultados e responder ao usuário
Cada etapa exige orquestração cuidadosa, tratamento de erros e gerenciamento de estado.
Desafio 2: Abstração de Provedor E se você quiser:
- Trocar de OpenAI para Anthropic ou Google?
- Usar modelos diferentes para tarefas diferentes?
- Fazer fallback para um modelo mais barato se o principal falhar?
Com chamadas diretas de API, você teria que reescrever uma parte significativa do código para cada provedor.
Desafio 3: Memória de Conversa Agentes precisam lembrar de contexto:
- Mensagens anteriores na conversa
- Documentos recuperados de consultas anteriores
- Resultados intermediários de chamadas de ferramentas
Gerenciar esse estado manualmente é sujeito a erros e cansativo.
Desafio 4: Integração de Ferramentas Seu agente precisa:
- Definir ferramentas disponíveis com schemas
- Permitir que o LLM escolha qual ferramenta chamar
- Interpretar argumentos de ferramenta a partir da saída do LLM
- Executar ferramentas com segurança e validação
- Lidar com erros de ferramentas e lógica de retry
Isso exige muito boilerplate e considerações de segurança em cada etapa.
Desafio 5: Roteamento Complexo Agentes reais precisam de lógica condicional:
- “Se o usuário perguntar sobre reembolsos, recuperar documentos de política”
- “Se o usuário quiser um reembolso, criar um ticket”
- “Se a pergunta for fora do tema, recusar educadamente”
Implementar isso com if-else vira algo difícil de manter rapidamente.
O Que o LangChain Fornece
LangChain é um framework para construir aplicações com LLM. Ele fornece:
1. Abstração de Modelos
Interface unificada para diferentes provedores de LLM (OpenAI, Anthropic, Google, etc.).
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
# Mesma interface, provedores diferentes
openai_llm = ChatOpenAI(model="gpt-5-mini")
anthropic_llm = ChatAnthropic(model="claude-4-5-sonnet")
# Ambos usam .invoke() com o mesmo formato de mensagem
response = openai_llm.invoke([{"role": "user", "content": "Olá"}])Troque provedores sem reescrever a lógica da aplicação.
2. Cadeias Componíveis (LCEL)
LangChain Expression Language — uma sintaxe para conectar componentes em pipelines.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Componha um pipeline com o operador | (como pipes do Unix)
chain = prompt | llm | output_parser
# Execute o pipeline inteiro com uma chamada
result = chain.invoke({"input": "pergunta do usuário"})Construa fluxos complexos sem passar dados manualmente entre etapas. Vamos aprender LCEL no Capítulo 6.
3. Memória de Conversa
Gerenciamento de histórico de mensagens para conversas com estado.
from langchain_core.chat_history import InMemoryChatMessageHistory
# Helper de histórico de mensagens
history = InMemoryChatMessageHistory()
history.add_user_message("Oi")
history.add_ai_message("Olá!")
# Recupere mensagens quando necessário
messages = history.messages
response = llm.invoke(messages)Abstraia o armazenamento de mensagens com classes auxiliares em vez de gerenciar listas manualmente. Neste estágio, o histórico ainda é passado explicitamente para o modelo. Vamos integrar isso em cadeias no Capítulo 8. O LangGraph (Capítulos 15+) torna isso ainda mais simples com gerenciamento de estado embutido.
4. Integração de Ferramentas
Sistema baseado em decoradores para expor funções Python a LLMs.
from langchain_core.tools import tool
@tool
def create_ticket(order_id: str, reason: str) -> str:
"""Cria um ticket de suporte para um pedido."""
# Implementação aqui
return f"Ticket criado para {order_id}"
# O LangChain lida com geração de schema e integração com o LLMTransforme qualquer função Python em uma ferramenta que pode ser descoberta e chamada por LLMs com suporte a ferramentas ou agentes — sem escrever schemas JSON manualmente.
5. Carregadores de Documentos e Vector Stores
Componentes prontos para carregar documentos de várias fontes e armazená-los como embeddings pesquisáveis.
from langchain_community.document_loaders import TextLoader
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
# Carrega documentos
docs = TextLoader("support_docs.txt").load()
# Cria índice pesquisável
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(docs, embeddings)
# Recupera documentos relevantes
results = vectorstore.similarity_search("política de reembolso")Construa sistemas RAG usando carregadores e vector stores prontos em vez de implementar parsing, embedding e recuperação do zero.
O Que o LangGraph Fornece
LangGraph estende o LangChain para fluxos complexos de agentes. Ele fornece:
1. Gerenciamento Explícito de Estado
Defina todos os dados do agente em um único schema tipado em vez de espalhá-los por variáveis.
from typing import TypedDict, Optional
from langchain_core.messages import BaseMessage
from langchain_core.documents import Document
class AgentState(TypedDict):
messages: list[BaseMessage]
retrieved_docs: list[Document]
current_step: Optional[str]
# Todos os dados do agente vivem aqui — um lugar para inspecionar ao depurarChega de procurar onde os dados vivem ou como fluem entre etapas. Mudanças de estado são explícitas: nós leem de state e retornam atualizações. Sua IDE completa nomes de campos, e verificadores de tipo detectam erros antes do runtime.
2. Workflows Baseados em Grafo
Construa workflows declarando etapas (nós) e suas conexões (arestas), não escrevendo código de orquestração.
graph = StateGraph(AgentState)
# Define nós (etapas no seu workflow)
graph.add_node("retrieve", retrieve_docs)
graph.add_node("answer", generate_answer)
# Define arestas (transições entre etapas)
graph.add_edge("retrieve", "answer")Você define a estrutura — “retrieve roda, depois answer roda” — e o LangGraph lida com a execução. Não há necessidade de escrever código de orquestração para passar estado entre etapas. O fluxo de controle, como sequenciamento ou ramificação, é declarado na própria estrutura do grafo.
3. Roteamento Condicional
Tomada de decisão em runtime sobre qual caminho seguir no workflow.
from langchain_core.messages import BaseMessage
def route_request(state):
last_message = state["messages"][-1].content
if "refund" in last_message:
return "create_ticket"
else:
return "answer_question"
graph.add_conditional_edges(
"classify",
route_request,
{
"create_ticket": "create_ticket",
"answer_question": "answer_question",
}
)O insight principal: A função de roteamento retorna o nome do próximo nó (“create_ticket” ou “answer_question”).
Por que isso importa: Sua lógica de decisão fica separada da execução. Quer mudar as regras de roteamento? Edite uma função. Quer ver todos os caminhos possíveis? Olhe a definição do grafo. Quer depurar qual caminho foi tomado? Inspecione o execution trace — sem ter que cavar por chamadas aninhadas de funções.
4. Checkpointing e Persistência
O estado é automaticamente checkpointado após cada etapa, permitindo recuperação de falhas e workflows de pausar-retomar.
from langgraph.checkpoint.sqlite import SqliteSaver
checkpointer = SqliteSaver("agent_state.db")
graph = graph.compile(checkpointer=checkpointer)
# O estado é automaticamente salvo a cada etapa
result = graph.invoke(
input_state,
config={"configurable": {"thread_id": "user-123"}}
)Após cada etapa, o LangGraph faz checkpoint do estado atual em armazenamento persistente. Se o processo cair, a execução pode retomar a partir do checkpoint mais recente associado ao mesmo thread ID.
Checkpointing viabiliza workflows de pausar e retomar, como esperar aprovação humana, quando combinado com roteamento condicional ou interrupções.
Quando Usar Cada Framework
Use LangChain quando:
- Construir cadeias simples (prompt → LLM → parser)
- Implementar sistemas RAG
- Lidar com contexto baseado em mensagens (passando histórico de chat explicitamente)
- Abstrair entre provedores de LLM
Use LangGraph quando:
- Construir workflows de agentes multietapas
- Implementar lógica de roteamento condicional
- Gerenciar estado complexo entre etapas
- Precisar de checkpointing e recuperação de falhas
2.3) Como os LLMs Funcionam (para Quem Constrói Agentes)
Para construir agentes eficazes, você precisa entender como os LLMs realmente funcionam. Isso não é sobre a matemática dos transformers — é sobre o modelo mental que molda como você projeta sistemas de agentes.
O Mecanismo Central: Predição de Tokens
Aqui está o insight fundamental: LLMs não “sabem” fatos da forma como bancos de dados sabem. Eles predizem o próximo token.
Vamos detalhar isso com um exemplo concreto.
Entrada: “A capital da França é”
O que você pode achar que acontece:
- O LLM “consulta” a capital da França em sua base de conhecimento
- O LLM “recupera” a resposta: Paris
- O LLM retorna “Paris”
O que realmente acontece:
- O LLM converte a entrada em tokens:
["The", "capital", "of", "France", "is"] - O LLM calcula uma distribuição de probabilidade sobre TODOS os possíveis próximos tokens
- Token seguinte mais provável:
"Paris"(maior probabilidade) - O LLM amostra da distribuição (normalmente escolhendo a maior probabilidade)
- O LLM retorna “Paris”
O LLM não “sabe” que Paris é a capital. Ele prediz que “Paris” é o próximo token mais provável dado o padrão de entrada.
(Observação: tokenização e probabilidades são conceituais e variam por modelo e tokenizer.)
Por Que Isso Importa para Agentes
Esse modelo de predição de tokens tem implicações profundas para o design de agentes:
Implicação 1: LLMs Podem Alucinar
Como LLMs predizem tokens (não recuperam fatos), eles podem gerar informação plausível, porém incorreta.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke("Qual é a capital de Atlântida?")
print(response.content)
# Nota: A saída real pode variar.
# Modelos modernos podem reconhecer Atlântida como fictícia e recusar responder.
# O ponto principal:
# sem checagem explícita de fatos, LLMs podem gerar informação incorreta com aparência plausível.Possível saída (histórica ou sem restrições):
A capital de Atlântida é Etheria. De acordo com os registros de Platão, Etheria era uma cidade portuária localizada na ponta mais oriental da ilha, e seu nome derivava da crença de que ela alcançava os céus.O LLM gera uma resposta com aparência razoável, mesmo que Atlântida seja fictícia. Para agentes, isso significa:
- Nunca confie cegamente na saída do LLM
- Valide fatos contra fontes autorizadas
- Implemente guardrails
Implicação 2: Contexto é Tudo
LLMs só veem os tokens que você fornece. Eles não têm memória de conversas anteriores a menos que você inclua explicitamente esse contexto.
# Primeira chamada
response1 = llm.invoke("Meu nome é Alice")
print(response1.content) # "Prazer em conhecer você, Alice!"
# Segunda chamada (invocação separada)
response2 = llm.invoke("Qual é o meu nome?")
print(response2.content) # "Eu não tenho acesso ao seu nome..."A segunda chamada não tem contexto da primeira. Para agentes, isso significa:
- Você precisa gerenciar o histórico da conversa
- Os limites da janela de contexto importam
- Gerenciamento de estado é crítico
Implicação 3: Prompts são Instruções, Não Consultas
Como LLMs predizem tokens, a forma como você redige seu prompt afeta drasticamente a qualidade da saída.
# Prompt fraco (estilo consulta)
response = llm.invoke("política de reembolso")
# Saída: "O que você gostaria de saber sobre a política de reembolso?"
# Prompt forte (estilo instrução)
response = llm.invoke(
"Você é um atendente de suporte ao cliente. Explique nossa política de reembolso de forma clara e concisa."
)
# Saída: "Nossa política de reembolso permite devoluções em até 30 dias..."Para agentes, isso significa:
- Prompts são seu principal mecanismo de controle
- Engenharia de prompt é uma habilidade central
- Mensagens de sistema definem o comportamento do agente
Implicação 4: Saída Estruturada Exige Orientação
LLMs naturalmente geram texto livre. Obter saída estruturada (JSON, formatos específicos) requer instrução explícita.
# Sem orientação de estrutura
response = llm.invoke("Extraia o ID do pedido de: 'Quero um reembolso para o pedido #12345'")
print(response.content)
# Saída: "O ID do pedido é 12345" (texto simples, formato inconsistente)
# Com orientação de estrutura
response = llm.invoke(
'Extraia o ID do pedido e retorne APENAS um objeto JSON no formato: {"order_id": "..."}\n\n'
"Texto: 'Quero um reembolso para o pedido #12345'"
)
print(response.content)
# Saída: {"order_id": "12345"} (estruturado, parseável)Para agentes, isso significa:
- Use schemas para restringir o formato de saída
- Especifique formatos de saída explicitamente
- Valide e faça parse das respostas do LLM
Texto livre é otimizado para humanos. Agentes exigem formatação explícita para garantir legibilidade por máquina.
Determinismo, Estocasticidade e LLMs Modernos
LLMs são, fundamentalmente, sistemas probabilísticos. Eles geram texto ao predizer os tokens seguintes mais prováveis, não ao executar regras determinísticas. Como resultado, a mesma entrada nem sempre garante a mesma saída.
Em modelos mais antigos, desenvolvedores controlavam explicitamente essa aleatoriedade usando parâmetros como temperature. Valores menores produziam saídas mais previsíveis, enquanto valores maiores incentivavam variação e criatividade.
Muitos modelos modernos orientados a raciocínio não expõem mais parâmetros como temperature ou top_p. Em vez disso, eles gerenciam estratégias de decodificação e amostragem internamente para priorizar raciocínio estável e estruturado. No entanto, isso não significa que esses modelos sejam totalmente determinísticos.
Mesmo esses modelos não garantem saídas idênticas. As saídas podem variar devido a:
- Amostragem interna: o modelo pode seguir diferentes caminhos de raciocínio, produzindo saídas que variam em estrutura, detalhe ou formulação.
- Atualizações do modelo: provedores atualizam modelos continuamente sem aviso, então o mesmo prompt pode gerar respostas diferentes ao longo do tempo.
- Filtros de segurança: moderação de conteúdo pode fazer o modelo responder diretamente em um caso, mas fazer ressalvas, recusar ou reformular em outro.
- Políticas de ferramentas: em sistemas de agentes, o modelo pode invocar ferramentas diferentes — ou nenhuma ferramenta — para a mesma entrada, mudando caminhos de execução.
O que isso significa para quem constrói agentes:
A preocupação principal não é ajuste de parâmetros — é previsibilidade. Sistemas de agentes devem ser projetados assumindo que saídas de LLM podem variar em palavras, estrutura ou até conclusões, a menos que sejam explicitamente restringidas.
Isso leva a vários princípios de design concretos para sistemas de agentes:
- Nunca dependa de redação exata para decisões de lógica — o fluxo de controle deve depender de sinais estruturados (schemas, enums, flags), não de correspondência de frases específicas na saída do modelo.
- Force estrutura nas fronteiras — sempre que a saída de um LLM for consumida por código, restrinja-a usando schemas, validadores ou formatos estritos para que o programa nunca precise “interpretar” texto livre.
- Verifique qualquer coisa que importe — fatos que afetam dinheiro, permissões ou ações irreversíveis devem ser checados com ferramentas ou sistemas externos, não confiados apenas ao modelo.
- Trate saídas de LLM como propostas, não decisões — o modelo sugere o que fazer, mas o sistema decide se, quando e como agir.
Em sistemas modernos de agentes, a confiabilidade vem do design do sistema, não do ajuste de parâmetros. Quanto mais crítica a tarefa, menos liberdade o modelo deve ter — e mais estrutura seu agente deve impor.
Principal Conclusão: Construa agentes confiáveis com schemas, validação e integração de ferramentas — não esperando saídas consistentes do LLM.
Na próxima seção, exploraremos as implicações econômicas do processamento baseado em tokens.
2.4) Tokens: O Recurso Fundamental
Tokens são a unidade básica que LLMs processam. Entender tokens é essencial porque eles definem tanto o que é possível (restrições) quanto o que é caro (custos) em sistemas de agentes.
O que é um Token?
Um token é a menor unidade de texto sobre a qual um LLM raciocina e gera.
Dependendo do idioma e do contexto, um token pode representar:
- Uma palavra (
agent) - Parte de uma palavra (
calculat,ion) - Um número ou símbolo (
#,123) - Pontuação ou espaços em branco
Tokens não são caracteres e não são palavras — eles são unidades específicas do modelo criadas pelo tokenizer.
Toda informação enviada ao modelo ou gerada por ele é medida em tokens:
- Instruções do sistema
- Mensagens do usuário
- Documentos recuperados
- Descrições de ferramentas
- Saídas do modelo
Tokens são a moeda fundamental da interação com LLM.
Tokens como Restrição do Sistema
Tokens não são apenas um custo — eles são um limite rígido do que seu agente pode fazer em uma única requisição.
Todo LLM tem uma janela de contexto: um número máximo fixo de tokens que ele consegue processar de uma vez.
Cenário de exemplo: Seu agente de suporte ao cliente precisa de:
- Instruções do sistema: 200 tokens
- Últimas 10 mensagens: ~2.000 tokens
- 3 artigos de ajuda recuperados: ~1.500 tokens
- Resposta gerada: ~200 tokens
- Total: 3.900 tokens
Se a janela de contexto do seu modelo é de 4.000 tokens, você está em 97,5% da capacidade. Mais uma mensagem longa e o sistema para de funcionar.
(Modelos modernos normalmente têm janelas de contexto de 128K+ tokens, mas o princípio permanece: contexto é finito, e você precisa projetar levando esse limite em conta.)
O que acontece quando você excede o limite:
- Mensagens antigas são descartadas → O agente esquece contexto anterior, quebrando a continuidade da conversa
- Documentos recuperados são truncados → Informação crítica se perde, levando a respostas incorretas
- A requisição falha totalmente → O sistema não consegue responder
Você não pode pagar por mais espaço. A janela de contexto é um limite rígido — como tentar colocar 2 litros em uma garrafa de 1 litro.
Por isso, agentes de longa execução precisam gerenciar ativamente o que permanece no contexto e o que não permanece. Gestão de tokens é uma preocupação arquitetural central, não um detalhe de otimização.
O que os Tokens Afetam Diretamente
Além do limite imediato da janela de contexto, tokens moldam duas decisões de design críticas:
1. Estratégia de Memória: Histórico Completo vs Sumarização
Manter o histórico completo da conversa preserva detalhes, mas faz o uso de tokens crescer continuamente.
Uma alternativa comum é sumarização de memória:
- Substituir mensagens antigas por um resumo compacto
- Preservar a intenção enquanto reduz custo de tokens
Esse trade-off afeta:
- Custo
- Precisão
- Consistência do agente a longo prazo
Portanto, design de memória é um problema de gestão de tokens.
2. Tamanho de Chunk e Estratégia de Recuperação em RAG
Em Retrieval-Augmented Generation (RAG), documentos são divididos em chunks antes da recuperação.
-
Chunks grandes
- Menos chamadas de recuperação
- Maior custo de tokens por requisição
- Mais contexto irrelevante
-
Chunks pequenos
- Menor custo de tokens
- Maior precisão
- Risco de perder informação-chave
Tamanho de chunk é uma decisão crítica de design — impacta diretamente custo e qualidade da resposta.
Economia de Tokens
Entender custos de tokens ajuda você a construir sistemas custo-efetivos.
Preços Típicos (2026):
| Modelo | Entrada (por 1M tokens) | Saída (por 1M tokens) |
|---|---|---|
| GPT-5 | $1.25 | $10.00 |
| GPT-5-mini | $0.25 | $2.00 |
| Claude 4.5 Sonnet | $3.00 | $15.00 |
| Gemini 3 Pro | $2.00 | $12.00 |
| Gemini 3 Flash | $0.50 | $3.00 |
Insight principal: Tokens de saída custam 4–8x mais do que tokens de entrada, o que significa que geração sem controle muitas vezes é o maior fator de custo em sistemas em produção.
Estimativa Rápida de Custo:
Para uma requisição típica com 500 tokens de entrada e 50 tokens de saída usando GPT-5-mini:
- Entrada: (500 / 1.000.000) × $0.25 = $0.000125
- Saída: (50 / 1.000.000) × $2.00 = $0.0001
- Total: ~$0.000225 por requisição
Em 10.000 requisições/dia: ~$67.5/mês
Otimização de Custo na Prática
Estratégia 1: Combine o Modelo com a Complexidade da Tarefa
Use modelos menores e mais baratos para tarefas simples:
from langchain_openai import ChatOpenAI
# Modelo caro para raciocínio complexo
complex_llm = ChatOpenAI(model="gpt-5")
# Modelo barato para tarefas simples
simple_llm = ChatOpenAI(model="gpt-5-nano")
def get_llm_for_task(task_type):
if task_type == "complex_reasoning":
return complex_llm
else:
return simple_llmEstratégia 2: Equilibre Tamanho de Contexto com Qualidade
Inclua apenas o contexto necessário:
# Eficiente: Inclui apenas chunks relevantes
relevant_chunks = retrieve_top_k(user_question, k=3) # ~500 tokens
prompt = f"Contexto: {relevant_chunks}\n\nPergunta: {user_question}"Importante: Redução agressiva demais de contexto pode prejudicar a precisão da resposta. Equilibre economia de custo com qualidade.
Estratégia 3: Controle o Comprimento da Saída
Limite quanto o modelo gera:
# Custo controlado
llm = ChatOpenAI(model="gpt-5-mini", max_tokens=100)
response = llm.invoke(messages)
# Máximo de 100 tokens de saídaPrincipal Conclusão: Gestão de tokens não é apenas sobre reduzir custos — é sobre projetar sistemas de agentes confiáveis e escaláveis dentro de restrições rígidas de recursos.
Na próxima seção, vamos explorar o panorama de modelos e aprender como escolher o modelo certo para cada tarefa.
2.5) Entendendo o Panorama de Modelos
Escolher o LLM certo para o seu agente exige equilibrar:
- Janela de contexto: quanto texto o modelo consegue processar?
- Custo: quanto custa cada requisição?
- Latência: quão rápido o modelo responde?
- Capacidade: quão bem o modelo raciocina?
Vamos analisar o panorama de modelos em 2026.
Principais Famílias de Modelos
Modelos OpenAI GPT
| Modelo | Janela de Contexto | Custo de Entrada | Custo de Saída | Latência | Melhor Para |
|---|---|---|---|---|---|
| GPT-5 | 400K tokens | $1.25 / 1M | $10.00 / 1M | ~2–4s | Raciocínio complexo, código avançado |
| GPT-5-mini | 400K tokens | $0.25 / 1M | $2.00 / 1M | ~1.5–3s | Tarefas gerais, chat, sumarização |
| GPT-5-nano | 400K tokens | $0.05 / 1M | $0.40 / 1M | ~1–2s | Classificação, extração |
Modelos Anthropic Claude
| Modelo | Janela de Contexto | Custo de Entrada | Custo de Saída | Latência | Melhor Para |
|---|---|---|---|---|---|
| Claude Opus 4.5 | 200K tokens | $5.00 / 1M | $25.00 / 1M | ~2–4s | Raciocínio profundo, análise |
| Claude Sonnet 4.5 | 200K tokens | $3.00 / 1M | $15.00 / 1M | ~1.5–3s | Performance equilibrada, programação |
Modelos Google Gemini
| Modelo | Janela de Contexto | Custo de Entrada | Custo de Saída | Latência | Melhor Para |
|---|---|---|---|---|---|
| Gemini 3.0 Pro | 1M tokens | $2.00 / 1M | $12.00 / 1M | ~3–5s | Contexto massivo, pesquisa |
| Gemini 3.0 Flash | 1M tokens | $0.50 / 1M | $3.00 / 1M | ~1–2s | Aplicações de alto throughput |
Funcionalidades Específicas por Provedor
OpenAI:
- Melhor para: agentes de propósito geral, workflows amplos multi-domínio, function calling
- Forte em: raciocínio versátil, ferramentas e ecossistema fortes para desenvolvedores, atualizações frequentes de modelos
Anthropic:
- Melhor para: workflows sensíveis a segurança, raciocínio estruturado e estendido
- Forte em: análise profunda, saídas metódicas, pensamento estendido com alinhamento forte
Google:
- Melhor para: ingestão de contexto massivo e tarefas multimodais
- Forte em: análise de documentos em larga escala, compreensão multimodal, processamento de alto throughput
Combinando Modelos com Tarefas
Escolha com base na complexidade da tarefa, tamanho de contexto e necessidades de latência:
Por Complexidade da Tarefa
Tarefas Simples → Modelos otimizados para custo (GPT-5-nano, GPT-5-mini):
- Classificação de intenção, análise de sentimento, extração de palavras-chave, formatação simples
- Escolha quando: custo é a preocupação principal
Tarefas Moderadas → Modelo equilibrado (GPT-5-mini):
- Perguntas e respostas, sumarização, seleção de ferramentas
- Escolha quando: precisa equilibrar custo e qualidade
Tarefas Complexas → Modelos focados em performance (GPT-5, Claude Sonnet, Gemini Pro):
- Raciocínio multietapas, geração de código, análise detalhada
- Escolha quando: capacidade de raciocínio importa, custo é aceitável
Complexidade Máxima → Modelos premium (Claude Opus):
- Raciocínio profundamente complexo, decisões mission-critical
- Escolha quando: precisão é primordial, custo é secundário
Por Necessidades de Latência
Tempo Real (~1s ou menos de latência percebida) → Modelos rápidos (GPT-5-nano, Gemini Flash):
- Chat voltado ao usuário
- Aplicações interativas
Quase em Tempo Real (1–3s) → A maioria dos modelos:
- Tarefas padrão de agentes
Em Lote (>3s) → Modelos capazes:
- Análise em background
Considerações de Janela de Contexto
Tarefas padrão: Todos os principais modelos suportam 200K+ tokens, suficiente para a maioria dos workflows de agentes.
Casos especiais:
- Precisa de 400K tokens: família GPT-5 (análise de documentos completos, grandes codebases)
- Precisa de 1M tokens: modelos Gemini (livros inteiros, conjuntos massivos de documentos)
Conselho prático: Mesmo com janelas de contexto grandes, recuperação seletiva (RAG) normalmente produz melhores resultados.
Principais Conclusões
- Não existe um único modelo “melhor” → modelos diferentes se destacam em tarefas diferentes
- Combine o modelo com a complexidade da tarefa → não pague a mais por tarefas simples
- Janela de contexto ≠ melhor → use recuperação seletiva
- Latência afeta a experiência do usuário → considere tempo de resposta para tarefas interativas
Na prática: A maioria dos agentes usa múltiplos modelos — modelos baratos para tarefas simples, modelos capazes para raciocínio complexo. Vamos implementar isso em capítulos posteriores.
Na próxima seção, aprenderemos como controlar o comportamento do modelo com prompting eficaz.
2.6) Fundamentos de Prompting para Sistemas de Agentes
Prompts são sua interface principal para controlar o comportamento do LLM. Para agentes, prompting eficaz é crítico — ele determina se seu agente toma decisões corretas, chama as ferramentas certas e produz saídas confiáveis.
A Anatomia de um Prompt
Um prompt completo tem três componentes:
1. Mensagem de Sistema (Papel e Restrições) Define a persona, capacidades e limites do agente.
2. Contexto (Informações Relevantes) Fornece as informações necessárias para concluir a tarefa.
3. Instrução (Tarefa Específica) Diz ao agente exatamente o que fazer.
Vamos ver isso na prática:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-5-mini")
response = llm.invoke([
# Mensagem de sistema: Define papel e restrições
{
"role": "system",
"content": """Você é um atendente de suporte ao cliente da TechCorp.
Suas capacidades:
- Responder perguntas sobre políticas de reembolso
- Criar tickets de suporte
- Fornecer orientação de troubleshooting
Suas restrições:
- Responda apenas perguntas sobre produtos TechCorp
- Nunca faça promessas sobre prazos de reembolso
- Seja sempre educado e profissional"""
},
# Mensagem do usuário: Contexto + Instrução
{
"role": "user",
"content": """Contexto: Cliente comprou o laptop modelo X500 em 2026-01-15.
Hoje é 2026-02-20. Nossa política de reembolso permite devoluções em até 30 dias.
Instrução: O cliente quer um reembolso. O que devo dizer a ele?"""
}
])
print(response.content)Saída:
Entendo que você gostaria de um reembolso para seu laptop modelo X500. Infelizmente,
como sua compra foi em 15 de janeiro e hoje é 20 de fevereiro, estamos
além da nossa janela de devolução de 30 dias. No entanto, terei prazer em criar um ticket de suporte
para explorar outras opções, como serviço de garantia ou troca.
Você gostaria que eu prosseguisse com isso?Mensagens de Sistema: Definindo o Comportamento do Agente
A mensagem de sistema é onde você define a personalidade e as capacidades do seu agente. Esta é a parte mais importante do prompting para agentes.
Mensagem de Sistema Fraca:
system_message = "Você é um assistente prestativo."Mensagem de Sistema Forte:
system_message = """Você é um atendente de suporte ao cliente da TechCorp.
PAPEL:
Você ajuda clientes com solicitações de reembolso, dúvidas sobre produtos e problemas técnicos.
CAPACIDADES:
- Responder perguntas usando a documentação fornecida
- Criar tickets de suporte quando necessário
- Fornecer troubleshooting passo a passo
RESTRIÇÕES:
- Responda apenas perguntas sobre produtos TechCorp
- Se você não souber algo, diga — nunca chute
- Sempre cite fontes ao usar documentação
- Nunca prometa prazos ou resultados específicos
TOM:
Profissional, empático e focado em soluções.
"""Por que a versão forte funciona melhor:
- Capacidades explícitas → O agente sabe o que pode fazer
- Restrições claras → O agente sabe o que evitar
- Tom definido → Personalidade consistente
- Instruções específicas → Reduz ambiguidade
Clareza de Instrução: Seja Específico
LLMs seguem instruções literalmente. Instruções vagas produzem resultados não confiáveis.
Instrução Vaga:
instruction = "Ajude o cliente com o reembolso."Instrução Específica:
instruction = """Analise a solicitação do cliente e determine:
1. O pedido é elegível para reembolso? (Verifique data da compra vs política de reembolso)
2. Se elegível: Explique o processo de reembolso
3. Se não elegível: Explique o motivo e ofereça alternativas
Formate sua resposta como:
- Elegibilidade: [SIM/NÃO]
- Motivo: [Explicação breve]
- Próximos Passos: [O que o cliente deve fazer]
"""Gerenciamento de Contexto: Forneça o Que É Necessário
Agentes precisam de contexto para tomar decisões, mas contexto demais desperdiça tokens e confunde o modelo.
Contexto em Excesso (Desperdício):
context = f"""
Histórico da Empresa: A TechCorp foi fundada em 1995...
Catálogo de Produtos: Vendemos mais de 500 produtos incluindo...
Política de Reembolso: {refund_policy_text}
Política de Envio: {shipping_policy_text}
Política de Garantia: {warranty_policy_text}
Histórico do Cliente: {full_customer_history}
"""
# 5000+ tokens, a maioria irrelevanteContexto Seletivo (Eficiente):
context = f"""
Política Relevante: {refund_policy_text}
Detalhes do Pedido: {order_details}
"""
# 200 tokens, tudo relevanteFormatação de Saída: Estruture Suas Respostas
Para agentes, muitas vezes você precisa de saída estruturada (JSON, formatos específicos) em vez de texto livre.
Saída Não Estruturada (Difícil de Parsear):
response = llm.invoke([
{"role": "system", "content": "Você é um atendente de suporte."},
{"role": "user", "content": "Devemos criar um ticket para esta solicitação de reembolso?"}
])
print(response.content)
# Saída: "Sim, eu acho que devemos criar um ticket porque..."
# Problema: Difícil de parsear, formato inconsistenteSaída Estruturada (Fácil de Parsear):
response = llm.invoke([
{"role": "system", "content": """Você é um atendente de suporte.
Sempre responda neste formato JSON:
{
"action": "CREATE_TICKET" ou "ANSWER_QUESTION" ou "ESCALATE",
"reason": "Explicação breve",
"response_text": "O que dizer ao cliente"
}"""},
{"role": "user", "content": "Cliente quer reembolso do pedido #12345, comprado há 40 dias"}
])
print(response.content)Saída:
{
"action": "CREATE_TICKET",
"reason": "Pedido está fora da janela de reembolso de 30 dias, precisa de revisão manual",
"response_text": "Criei um ticket de suporte para revisar sua solicitação de reembolso. Nossa equipe entrará em contato com você em até 24 horas."
}Usaremos schemas Pydantic para saída estruturada robusta no Capítulo 7.
Exemplos Few-Shot: Mostre, Não Apenas Diga
Para tarefas complexas, fornecer exemplos é mais efetivo do que instruções longas.
Zero-Shot (Somente Instruções):
prompt = """Extraia o ID do pedido, o nome do produto e o problema a partir de mensagens de clientes.
Mensagem do cliente: "Meu laptop X500 pedido #12345 não liga"
"""
# O modelo pode ter dificuldade com o formatoFew-Shot (Com Exemplos):
prompt = """Extraia o ID do pedido, o nome do produto e o problema a partir de mensagens de clientes.
Exemplo 1:
Input: "Meu laptop X500 do pedido #12345 não liga"
Output: {"order_id": "12345", "product": "laptop X500", "issue": "não liga"}
Exemplo 2:
Input: "Pedido 67890 - telefone não carrega"
Output: {"order_id": "67890", "product": "telefone", "issue": "não carrega"}
Agora extraia desta mensagem:
Input: "Meu tablet do pedido #11111 está com a tela rachada"
Output:
"""O modelo aprende o padrão pelos exemplos e o aplica de forma consistente.
Padrões de Engenharia de Prompt para Agentes
Padrão 1: Chain of Thought (Raciocínio)
Para decisões complexas, peça ao modelo para “pensar passo a passo”:
prompt = """Você precisa decidir se deve criar um ticket de suporte.
Pense nisso passo a passo:
1. O que o cliente está pedindo?
2. Isso pode ser respondido com a documentação existente?
3. Isso exige intervenção manual?
4. Que ação devemos tomar?
Mensagem do cliente: "Quero um reembolso para o pedido #12345 mas perdi o recibo"
Raciocínio:
"""O modelo mostrará explicitamente seu raciocínio, tornando as decisões mais transparentes e confiáveis.
Padrão 2: Geração Restrita (Segurança)
Limite as saídas possíveis do modelo:
prompt = """Classifique a intenção do cliente. Responda com EXATAMENTE UMA destas opções:
- REFUND_REQUEST
- PRODUCT_QUESTION
- TECHNICAL_ISSUE
- OFF_TOPIC
Mensagem do cliente: "Como eu redefino minha senha?"
Classificação:
"""Isso evita que o modelo gere saídas inesperadas. Ao restringir explicitamente opções de saída:
- Evita erros de parsing (sempre uma de quatro opções definidas)
- Bloqueia ações não intencionais (evita execução de ações não definidas)
- Simplifica o debug (espaço de saída limitado torna problemas mais fáceis de rastrear)
Padrão 3: Auto-Crítica (Qualidade)
Peça ao modelo para verificar e melhorar a própria saída:
prompt = """Gere uma resposta para o cliente e depois critique-a.
Mensagem do cliente: "Quero um reembolso"
Etapa 1 - Gerar resposta:
[Sua resposta aqui]
Etapa 2 - Crítica:
- Esta resposta está correta?
- É útil?
- Segue a política da empresa?
- O que pode ser melhorado?
Etapa 3 - Resposta final (incorporando a crítica):
[Resposta melhorada aqui]
"""Essa abordagem multietapas frequentemente produz saídas de maior qualidade porque:
- Captura erros cedo: o modelo revisa o próprio raciocínio antes de finalizar
- Melhora tom e clareza: a auto-reflexão ajuda a identificar linguagem confusa ou inadequada
- Garante conformidade com política: a etapa de crítica verifica aderência às diretrizes
Erros Comuns de Prompting
Erro 1: Assumir que o Modelo “Sabe” Coisas
LLMs não têm acesso a informações em tempo real nem a contexto implícito. Sempre forneça explicitamente todos os dados necessários.
# Ruim: Assume que o modelo sabe a data atual
prompt = "Este pedido é elegível para reembolso? Pedido #12345"
# Bom: Fornece todas as informações necessárias
prompt = f"""Este pedido é elegível para reembolso?
Pedido #12345
comprado em {purchase_date}
Hoje: {current_date}
Política: devoluções em até 30 dias
"""Erro 2: Instruções Ambíguas
Verbos vagos como “lidar”, “processar” ou “resolver” deixam espaço demais para interpretação. Seja explícito sobre a ação exata necessária.
# Ruim: O que significa "lidar"?
prompt = "Lide com esta solicitação de reembolso"
# Bom: Ação explícita
prompt = "Determine se esta solicitação de reembolso é elegível. Se sim, crie um ticket. Se não, explique o motivo."Erro 3: Sobrecarregar com Contexto
Incluir informação irrelevante desperdiça tokens, aumenta latência e pode confundir o modelo. Recupere apenas o que é necessário para a tarefa específica.
# Ruim: 10.000 tokens de contexto, a maioria irrelevante
prompt = f"""
{entire_knowledge_base}
Pergunta: Qual é a política de reembolso?
"""
# Bom: Recupera apenas a seção relevante
prompt = f"""
{refund_policy_section}
Pergunta: Qual é a política de reembolso?
"""Erro 4: Formatação Inconsistente
Quando o formato de saída varia, o código a jusante quebra. Sempre especifique o formato exato esperado, especialmente para dados estruturados.
# Ruim: Às vezes JSON, às vezes texto simples
prompt = "Responda com sua decisão"
# Bom: Sempre especifica formato
prompt = 'Responda em formato JSON: {"decision": "...", "reason": "..."}'Principais Conclusões
Prompts eficazes para agentes exigem:
- Mensagens de sistema claras → Definem papel, capacidades e restrições
- Instruções específicas → Dizem ao modelo exatamente o que fazer
- Contexto seletivo → Fornece apenas informação relevante
- Saída estruturada → Especifica o formato explicitamente
- Exemplos few-shot → Mostram o padrão desejado
- Prompts de raciocínio → Pedem pensamento passo a passo
Prompting é uma habilidade que melhora com a prática. Ao longo deste livro, você verá esses padrões aplicados em sistemas reais de agentes.
Resumo do Capítulo
Agora você entende os conceitos fundamentais para construir sistemas de IA agêntica:
IA Agêntica vs Chatbots:
- Agentes agem de forma autônoma para alcançar objetivos
- Agentes usam ferramentas e tomam decisões multietapas
- Agentes mantêm estado e se adaptam com base nos resultados
Por que Frameworks Importam:
- LangChain fornece abstração de modelos, cadeias, memória, ferramentas e RAG
- LangGraph adiciona gerenciamento de estado, roteamento e checkpointing
- Frameworks reduzem boilerplate e possibilitam workflows complexos
Mecânica de LLM:
- LLMs predizem tokens; eles não recuperam fatos
- Contexto é explícito, não implícito
- Prompts são instruções, não consultas
- Saída estruturada exige orientação
- Janelas de contexto são finitas
Economia de Tokens:
- Tokens de saída custam 4–8x mais do que tokens de entrada
- Escolha de modelo tem impacto de custo de 10–100x
- Contexto seletivo reduz custos drasticamente
- Monitoramento e orçamentos evitam gastos fora de controle
Seleção de Modelos:
- Combine modelo com a complexidade da tarefa
- Considere requisitos de contexto e restrições de latência
- Use arquiteturas multi-modelo para otimização de custos
- Comece barato; faça upgrade apenas se necessário
Fundamentos de Prompting:
- Mensagens de sistema definem o comportamento do agente
- Instruções específicas produzem resultados confiáveis
- Contexto seletivo melhora qualidade e reduz custo
- Saída estruturada permite parsing e validação
- Exemplos few-shot ensinam padrões de forma eficaz