Construa um agente de IA funcional do zero, sem frameworks externos, usando apenas a Anthropic API. Você entenderá o loop agentic completo — Pensar, Agir, Observar — implementando manualmente o ciclo de function calling.
Todos os arquivos prontos — extraia e comece em minutos
Instale as dependências
pip install -r requirements.txt
Configure sua chave Anthropic
cp .env.example .env # abra o .env e coloque sua ANTHROPIC_API_KEY
Execute o agente
python agent.py
Sem Python? Baixe em python.org. Sem chave Anthropic? Crie em console.anthropic.com.
agent.py
Principal
Loop agentic + ferramentas + dispatcher
requirements.txt
Dependências
anthropic, python-dotenv
.env.example
Configuração
Template de variáveis de ambiente
index.html
Este guia
Documentação interativa do projeto
Clique em cada tópico para expandir o conteúdo.
A etapa de instalação configura o ambiente Python isolado com as dependências corretas e a chave de API da Anthropic. Um ambiente limpo garante que seu agente rode de forma reproduzível em qualquer máquina — do seu laptop até servidores de produção.
Gerenciar dependências e segredos de forma correta é a base de qualquer projeto de IA em produção. Variáveis de ambiente evitam que chaves de API sejam expostas em commits do Git — um erro que pode custar caro se sua chave for comprometida.
Ambiente Virtual (venv)
Isola as dependências do projeto das bibliotecas globais do sistema.
python-dotenv
Carrega variáveis do arquivo .env para os.environ automaticamente.
ANTHROPIC_API_KEY
Chave de autenticação obtida em console.anthropic.com. Nunca commite no Git.
Ferramentas (tools) são capacidades externas que o modelo de linguagem pode invocar. Cada ferramenta é descrita por um schema JSON que especifica nome, descrição e parâmetros. O Claude decide quando e como chamar cada ferramenta com base no contexto da conversa.
Ferramentas transformam um LLM passivo em um agente ativo. Sem elas, o modelo só pode gerar texto. Com ferramentas, ele pode buscar dados em tempo real, executar código, chamar APIs externas e persistir informações — tornando-o genuinamente útil.
input_schema
JSON Schema que define os parâmetros aceitos pela ferramenta. O Claude gera inputs válidos automaticamente.
description
Texto em linguagem natural que explica ao modelo quando usar a ferramenta. Quanto mais clara, melhor a decisão.
tool_use block
Quando o Claude decide usar uma ferramenta, ele retorna um bloco tool_use com id, nome e inputs.
O dispatcher é a função responsável por receber o nome da ferramenta solicitada pelo modelo e rotear a execução para a função Python correta. Ele age como um intermediário entre as decisões do Claude e as implementações reais das ferramentas.
Sem um dispatcher, o loop agentic seria caótico. Centralizar a lógica de roteamento facilita adicionar novas ferramentas, tratar erros de forma uniforme e registrar (logar) todas as chamadas para debugging e auditoria.
Roteamento por nome
O dispatcher usa if/elif ou um dicionário de funções para mapear nomes de ferramentas para implementações.
Tratamento de erros
Sempre retorne uma string descritiva de erro — o modelo usará essa informação para corrigir a chamada na próxima iteração.
eval() seguro
Use eval(expr, {"__builtins__": {}}) para bloquear funções perigosas em avaliação de expressões matemáticas.
O loop agentic é o coração do agente. Ele repete o ciclo
Pensar → Agir → Observar até que o modelo
decida que tem informação suficiente para responder ao usuário sem chamar mais ferramentas.
O sinal de término é o campo stop_reason == "end_turn".
Entender o loop manual revela o que frameworks como LangChain e LlamaIndex fazem nos bastidores. Com esse conhecimento, você pode depurar comportamentos inesperados, otimizar o número de chamadas à API e implementar lógicas customizadas que frameworks genéricos não suportam.
stop_reason
"end_turn" = resposta final. "tool_use" = o modelo quer executar ferramentas.
Histórico de mensagens
Cada iteração adiciona a resposta do assistente e os resultados das ferramentas ao array mensagens.
max_iteracoes
Limite de segurança para evitar loops infinitos e custos inesperados com a API.
Memória é a capacidade do agente de reter e acessar informações entre chamadas de ferramentas.
No projeto, usamos um dicionário Python simples (notas = {})
como memória de trabalho. Em produção, isso pode ser um banco de dados vetorial para RAG.
Um agente sem memória recomeça do zero a cada sessão. Com memória, ele pode aprender preferências do usuário, acumular resultados de pesquisa e executar tarefas complexas de múltiplos passos que ultrapassam a janela de contexto de uma única conversa.
Memória de curto prazo
O array mensagens da sessão atual — tudo que o modelo já viu nesta conversa.
Memória de longo prazo
O dicionário notas persiste entre chamadas dentro da mesma execução do processo.
RAG (Retrieval Augmented Generation)
Técnica de buscar documentos relevantes em uma base de conhecimento e injetar no contexto antes de chamar o modelo.
A fase de execução e teste valida se o agente se comporta como esperado em diferentes cenários. Inclui testar chamadas únicas de ferramentas, encadeamento de múltiplas ferramentas e situações de erro onde o modelo precisa se recuperar.
Agentes têm comportamento não-determinístico. Testar com casos variados revela quando o modelo escolhe ferramentas erradas, entra em loops ou falha silenciosamente. Bons testes identificam esses problemas antes da produção.
Teste de ferramenta única
Peça algo simples como "Quanto é 125 * 8?" para verificar se a ferramenta calcular é acionada.
Encadeamento
Peça "Pesquise sobre Python e salve um resumo" — o agente deve usar buscar_na_web e depois salvar_nota.
Observar logs
Os prints do loop mostram cada iteração, ferramenta chamada e resultado — use para depurar comportamentos inesperados.
""" Agente do Zero — Agentic Engineering Masterclass INEMA.CLUB — Projeto 1: Agente sem framework Demonstra o loop agentic manual com Anthropic API: - Tools (function calling) - Loop Pensar → Agir → Observar - Sem frameworks externos """ import os import json import anthropic from dotenv import load_dotenv load_dotenv() client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY")) # ─── FERRAMENTAS ────────────────────────────────────────────────────────────── tools = [ { "name": "buscar_na_web", "description": "Busca informações na web sobre qualquer tema", "input_schema": { "type": "object", "properties": { "query": { "type": "string", "description": "O que buscar. Seja específico." } }, "required": ["query"] } }, { "name": "calcular", "description": "Executa cálculos matemáticos. Recebe expressão Python válida.", "input_schema": { "type": "object", "properties": { "expressao": { "type": "string", "description": "Expressão matemática. Ex: '2 + 2' ou '100 * 0.15'" } }, "required": ["expressao"] } }, { "name": "salvar_nota", "description": "Salva uma nota ou resultado importante em memória", "input_schema": { "type": "object", "properties": { "titulo": {"type": "string"}, "conteudo": {"type": "string"} }, "required": ["titulo", "conteudo"] } } ] # ─── DISPATCHER ─────────────────────────────────────────────────────────────── notas = {} # Memória simples em dicionário def executar_ferramenta(nome: str, inputs: dict) -> str: """Despacha a ferramenta correta e retorna o resultado.""" if nome == "buscar_na_web": query = inputs["query"] return f"[Resultado de busca para '{query}']: Encontrado 3 resultados relevantes." elif nome == "calcular": try: resultado = eval(inputs["expressao"], {"__builtins__": {}}) return f"Resultado: {resultado}" except Exception as e: return f"Erro no cálculo: {str(e)}" elif nome == "salvar_nota": notas[inputs["titulo"]] = inputs["conteudo"] return f"Nota '{inputs['titulo']}' salva com sucesso." return f"Ferramenta '{nome}' não encontrada." # ─── LOOP AGENTIC ───────────────────────────────────────────────────────────── def executar_agente(mensagem_usuario: str, max_iteracoes: int = 10) -> str: """ Loop agentic principal: 1. Envia mensagem ao LLM 2. Se o LLM chamar ferramentas → executa e retorna resultados 3. Repete até stop_reason == end_turn """ mensagens = [{"role": "user", "content": mensagem_usuario}] iteracao = 0 print(f"\n{'='*60}") print(f"AGENTE INICIADO") print(f"{'='*60}") while iteracao < max_iteracoes: iteracao += 1 print(f"\n[Iteração {iteracao}] Pensando...") resposta = client.messages.create( model="claude-opus-4-6", max_tokens=4096, system="Você é um assistente inteligente com acesso a ferramentas.", tools=tools, messages=mensagens ) if resposta.stop_reason == "end_turn": resposta_final = next( (b.text for b in resposta.content if hasattr(b, "text")), "Sem resposta." ) print(f"\n{'='*60}") print(f"RESPOSTA FINAL:") print(f"{'='*60}") print(resposta_final) return resposta_final resultados_ferramentas = [] for bloco in resposta.content: if bloco.type == "tool_use": print(f" → Usando: {bloco.name}({json.dumps(bloco.input)})") resultado = executar_ferramenta(bloco.name, bloco.input) print(f" ← Resultado: {resultado[:100]}...") resultados_ferramentas.append({ "type": "tool_result", "tool_use_id": bloco.id, "content": resultado }) mensagens.append({"role": "assistant", "content": resposta.content}) mensagens.append({"role": "user", "content": resultados_ferramentas}) return "Máximo de iterações atingido." # ─── MAIN ───────────────────────────────────────────────────────────────────── if __name__ == "__main__": print("Agente do Zero — INEMA.CLUB") print("Pressione Ctrl+C para sair\n") while True: try: mensagem = input("Você: ").strip() if not mensagem: continue if mensagem.lower() in ["sair", "exit", "quit"]: break executar_agente(mensagem) except KeyboardInterrupt: print("\nAté logo!") break except Exception as e: print(f"Erro: {e}")
Continue sua jornada na Agentic Engineering Masterclass com os próximos projetos.
Agente com Claude Code
Use Claude Code como agente de engenharia autônomo no seu terminal.
Agente Multi-Step
Planejamento e execução de tarefas complexas com múltiplos sub-agentes.
Agente de Código
Gere, revise e refatore código automaticamente com agentes especializados.