bedrock-agent-starter
Agente Bedrock com tools, memória, evals e Terraform — do clone ao chat em 30 minutos.
git clone https://github.com/fernando-moretes/app-bedrock-agent-starter.gitOuvir guia
gerado ao ouvirGerado apenas no primeiro play
Com tecnologia Amazon Polly + OmniVoice
Um template Python para agentes na Amazon Bedrock que já vem com o que o console não entrega: registro de tools, memória multi-turno, logs estruturados, harness de evals e Terraform para Lambda + API Gateway — para você forkar, apontar o AWS_PROFILE e ter um agente respondendo no terminal antes de decidir qualquer coisa de arquitetura.
Por que este repositório existe
A Bedrock resolve bem um problema: chamar um modelo. O que ela não resolve é o resto — e o resto é o que consome semanas quando você tenta colocar um agente em produção. Quem já tentou sabe a lista: registro de tools com schema JSON, memória entre turnos, log que dá para consultar no CloudWatch às 2h da manhã, um conjunto de casos para provar que a mudança no prompt não regrediu nada, IaC, tratamento de erro, fallback de modelo.
Eu escrevi este starter depois de montar essa mesma base mais de uma vez em projetos diferentes. Cada vez a estrutura era 80% igual e os 20% restantes eram a decisão de negócio de verdade. O template cristaliza os 80%.
A pergunta que ele responde não é "como chamo o Claude pela Bedrock?" — é "o que preciso ter em volta da chamada para confiar nela em produção?". Por isso o loop do agente usa a Converse API, que é estável entre Claude, Nova, Llama e Mistral e trata tool-use como cidadão de primeira classe. Trocar de modelo é mudar BEDROCK_MODEL_ID, não reescrever o parser de resposta.
Opinativo onde deve, substituível onde não deve: o registro de tools, a observabilidade e o harness de evals são opiniões fortes. A memória (in-memory local, DynamoDB em produção) e o backend do Terraform são pontos de troca deliberados.
O que vem na caixa
calculator, get_time e um stub de web_search; adicionar a sua é um decorator e uma função.session_id, turn, model_id, tokens e duration_ms; métricas EMF no namespace BedrockAgent.tests/evals/golden.jsonl verificando substrings e tool-calls esperados — falha em regressão.Instalar e conversar com o agente
- 1
Clone e crie o ambiente
git clone https://github.com/fernando-moretes/app-bedrock-agent-starter.git && cd app-bedrock-agent-starter && python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]". Python 3.11+ é obrigatório; o extradevtraz ruff, mypy e pytest. - 2
Aponte para a conta e o modelo
export AWS_REGION=us-east-1eexport BEDROCK_MODEL_ID=anthropic.claude-3-5-sonnet-20241022-v2:0(ou o modelo que você tem habilitado). UseAWS_PROFILEem vez de chave estática — confira comaws sts get-caller-identityque é a conta certa antes do primeiro turno. - 3
Converse no terminal
agent chat. Pergunte "what time is it in Tokyo, and what is (123 * 456) - 789?" e veja as duas tools serem chamadas na sequência, com o resultado de cada uma impresso antes da resposta final. - 4
Rode os evals antes de mudar qualquer prompt
pytest tests/evals/. O runner replayagolden.jsonle compara substring e tool-call esperados com a saída real. Faça isso passar uma vez limpo para ter linha de base — sem linha de base, regressão de prompt é invisível. - 5
Suba para a AWS quando estiver pronto
cd terraform && terraform init && terraform apply -var="project=my-agent". Provisiona Lambda, API Gateway HTTP API, tabela DynamoDB de sessões, roles IAM e log group. Backend de state, tags, naming e permission boundaries ficam por sua conta — de propósito.
# src/agent/tools.py
from agent.tools import tool
@tool(description="Translate text between languages using a deterministic table.")
def translate(text: str, source_lang: str, target_lang: str) -> str:
...
return translatedComo um turno atravessa o sistema
O mesmo núcleo (src/agent/) serve o CLI local e o handler Lambda; só a memória e a entrada mudam.
- CLI `agent chat` · src/agent
- Memória in-memory · sessão por processo
- pytest tests/evals · golden.jsonl
- API Gateway · HTTP API
- Lambda Python 3.12 · handler + agent loop
- DynamoDB · tabela de sessões
- Bedrock Converse API · Claude / Nova / Llama
- CloudWatch · JSON logs + EMF `BedrockAgent`
- Tool registry · @tool + Pydantic schema
- calculator · get_time · web_search (stub)
Como funciona por dentro
O loop: cada turno monta a lista de mensagens a partir da memória, anexa os specs das tools registradas e chama Converse. Se a resposta contém um bloco toolUse, o registro despacha a função Python correspondente, devolve um toolResult e chama o modelo de novo — até vir uma resposta final sem tool-use. É o mesmo ciclo que você faria à mão, só que com um teto de iterações e tratamento de erro no lugar certo.
As tools: o decorator @tool lê as anotações de tipo da função e pede ao Pydantic o schema JSON que a Converse API espera. Isso elimina a classe de bug mais comum em agentes caseiros — schema declarado à mão que diverge da assinatura real. As três tools que vêm no repo existem para provar o caminho, não para serem usadas como estão: web_search é um stub e você troca por Tavily, Brave ou o AgentCore Gateway conforme o caso.
A memória: a interface é uma só; a implementação in-memory serve para o CLI e a DynamoDB serve para o Lambda, onde cada invocação é sem estado e o histórico precisa viver fora do processo, chaveado por session_id.
A observabilidade: cada turno vira uma linha JSON com session_id, turn, model_id, input_tokens, output_tokens, tool_calls e duration_ms. Em paralelo, métricas EMF (Turns, InputTokens, OutputTokens, Duration, ToolErrors) vão para o namespace BedrockAgent no CloudWatch sem chamada extra de API — o formato embutido faz o CloudWatch extrair a métrica do próprio log. É o que permite um alarme em ToolErrors > 0 no primeiro dia, e um gráfico de custo por sessão no segundo.
O que o Terraform deixa de fora — de propósito
O terraform apply funciona com state local e sem tags, o que é ótimo para experimentar e péssimo para produção. Antes de subir em conta compartilhada: configure um backend remoto (S3 + lock), defina a convenção de nomes, aplique tags de custo e coloque um permission boundary na role do Lambda. Também confira o BEDROCK_MODEL_ID — o default do README é um id de Sonnet 3.5 de 2024; use o id que está habilitado na sua região e revise o custo por token antes de abrir o endpoint para tráfego real.
Evals e CI: o que separa um demo de um agente
O custo de um agente não está na primeira versão que funciona — está em cada mudança de prompt, de modelo ou de tool feita depois, sem saber o que quebrou. Por isso o harness de evals é parte do template e não um apêndice.
tests/evals/golden.jsonl guarda prompts com a saída esperada: substrings que devem aparecer na resposta e tools que devem ter sido chamadas. pytest tests/evals/ replaya cada linha contra o agente real e falha se algum caso regrediu. Não é benchmark de qualidade absoluta; é detector de regressão, e detector de regressão é o que você precisa para trocar claude-3-5-sonnet por Nova com alguma confiança.
O CI roda ruff, mypy e pytest a cada push. O workflow de docs publica o MkDocs Material no GitHub Pages. A landing em frontend/ é HTML estático sem dependência — sobe na Vercel sem build.
O repositório também carrega automação de higiene DevSecOps (checks de dependência, Conventional Commits) que vem do meu portfólio como um todo; ela é útil, mas não é o que faz o agente funcionar — pode remover sem perder nada do núcleo.
Perguntas frequentes
Preciso usar Claude?
Não. O loop usa a Converse API, então qualquer modelo da Bedrock com suporte a tool-use funciona — Claude, Nova, Llama, Mistral. Mude BEDROCK_MODEL_ID e rode os evals para ver o que mudou.
Por que não Bedrock Agents (o serviço gerenciado) ou AgentCore?
Porque aqui o objetivo é você ser dono do loop. Bedrock Agents e AgentCore são boas escolhas quando o runtime gerenciado, memória e guardrails num único plano de controle valem mais que o controle fino — este starter é para quando você quer ver e testar cada iteração, e migrar depois com o registro de tools já pronto.
Quanto custa rodar?
Localmente, só tokens da Bedrock. Na AWS, Lambda e API Gateway HTTP API e DynamoDB on-demand ficam próximos de zero em baixo volume; o custo dominante é sempre token de modelo. As métricas InputTokens/OutputTokens existem justamente para você medir antes de escalar.
A tool `web_search` funciona?
É um stub. Está lá para mostrar como uma tool com efeito externo se encaixa no registro. Troque a implementação pela API de busca que você já paga.
Referências
Quando usar
Use este starter quando: você quer ser dono do loop do agente e testar cada mudança com evals, precisa de um agente com tools próprias em Lambda sem depender de runtime gerenciado, e o time já opera Terraform e CloudWatch. Não use quando: a equipe prefere não manter código de orquestração — Bedrock Agents ou AgentCore Runtime vão custar menos em manutenção ao longo de anos — ou quando o caso é uma chamada única sem tool-use, onde um converse() direto basta. Em qualquer dos casos, o registro de tools com schema inferido e o golden set de evals são as duas peças que vale levar junto.
Deep dives de arquitetura, AWS, IA e mercado — direto no seu email. Grátis.
Sem spam · cancele quando quiser