bedrock-agent-starter
Starter de agente no Bedrock com tools, memória, Terraform e evals já ligados
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
O bedrock-agent-starter é um template em Python para colocar um agente de IA no Amazon Bedrock com o que um agente de verdade precisa: loop de tool-use sobre a Converse API, memória plugável, logs estruturados, métricas EMF, Terraform e um harness de evals.
Por que este repositório existe
Chamar um modelo no Bedrock é uma linha de SDK. Entregar um agente é outra coisa. Entre o converse() e um endpoint que alguém opera em produção existe uma lista de peças que todo time acaba montando do zero: registro de tools, memória entre turnos, log com session_id, métrica de tokens por turno, tratamento de erro de tool, IaC e alguma forma de saber se a mudança de prompt de ontem quebrou o comportamento de hoje.
O problema não é o esforço de escrever cada peça uma vez, é manter as peças coerentes entre si quando o modelo muda, quando entra uma tool nova ou quando alguém troca o backend de memória. Montei este starter para que essas decisões estejam tomadas e visíveis no código, num formato que dá para ler numa tarde.
A proposta é ser opinativo onde a opinião economiza tempo (Converse API, Pydantic para schema de tool, JSON estruturado no log) e substituível onde o contexto de cada empresa manda (backend de estado do Terraform, tags, naming, limites de IAM). Faça fork, configure AWS_REGION e o modelo, e você tem um agente respondendo no terminal antes de pensar em infraestrutura.
O que vem no template
calculator, get_time e um stub de web_search) e um decorator @tool para adicionar as suas.session_id, turn, model_id e métricas EMF no namespace BedrockAgent.Como uma pergunta percorre o agente
O mesmo núcleo em src/agent/ atende o CLI local e o handler Lambda. Só a borda e o backend de memória mudam.
- agent chat · CLI
- Memória · in-memory
- API Gateway · HTTP API
- Lambda · Python 3.12
- Agent loop · Converse API
- Tool registry · @tool
- Amazon Bedrock · BEDROCK_MODEL_ID
- DynamoDB · sessions
- CloudWatch · logs + EMF
Instalar e usar
- 1
Clone e crie o ambiente
Requer Python 3.11 ou superior. Crie um virtualenv e instale com
pip install -e ".[dev]", que traz ruff, mypy e pytest junto. - 2
Configure credenciais e modelo
Exporte
AWS_REGION(ouAWS_PROFILE) eBEDROCK_MODEL_ID. O padrão do README é um Claude Sonnet; o modelo precisa estar habilitado na sua conta e região, senão a primeira chamada voltaAccessDeniedException. - 3
Converse no terminal
Rode
agent chat. Cada chamada de tool aparece como linha[tool]antes da resposta, o que torna visível quando o modelo escolheu a tool errada. - 4
Rode as evals antes de mudar prompt ou modelo
pytest tests/evals/reexecutagolden.jsonle falha se a substring ou a chamada de tool esperada sumir. - 5
Faça o deploy com Terraform
Em
terraform/, rodeterraform initeterraform apply -var="project=my-agent". Defina antes o backend de estado: o template não traz um.
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]"
export AWS_REGION=us-east-1
export BEDROCK_MODEL_ID=anthropic.claude-3-5-sonnet-20241022-v2:0
agent chat
# > what time is it in Tokyo, and what is (123 * 456) - 789?
# [tool] get_time(tz="Asia/Tokyo")
# [tool] calculator(expression="(123 * 456) - 789") -> 55299Como o loop funciona
A escolha central foi a Converse API em vez de InvokeModel. Com InvokeModel, cada família de modelo tem seu próprio formato de payload, e trocar Claude por Nova vira refatoração. A Converse normaliza mensagens, toolConfig e blocos toolUse/toolResult, então BEDROCK_MODEL_ID passa a ser configuração, não código.
O turno segue o ciclo clássico: o agente envia o histórico e a lista de tools, o modelo responde com texto ou com um ou mais toolUse, o registro executa a função Python correspondente, o resultado volta como toolResult e o ciclo repete até o modelo devolver texto final. Na pergunta do exemplo, get_time e calculator entram no mesmo turno.
O histórico mora atrás de uma interface de memória. Local, fica num dicionário e some quando o processo termina. Na Lambda, vai para a tabela DynamoDB de sessões, chaveada por session_id, que é o que permite conversa de vários turnos sobre uma função sem estado.
O CLI e o handler Lambda chamam o mesmo núcleo em src/agent/. Isso importa mais do que parece: o comportamento que você valida no terminal é o que vai para produção, e as evals exercitam o mesmo código.
# 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 translatedObservabilidade e evals: o que separa demo de serviço
Cada turno emite uma linha JSON com session_id, turn, model_id, input_tokens, output_tokens, tool_calls e duration_ms. Com isso, uma busca no CloudWatch Logs Insights por session_id reconstrói a conversa inteira de um usuário que reclamou, sem guardar prompt em texto livre em outro lugar.
As métricas vão em formato EMF para o namespace BedrockAgent: Turns, InputTokens, OutputTokens, Duration e ToolErrors. EMF evita chamar PutMetricData no caminho da requisição; a métrica sai do próprio log. InputTokens é a que vira alarme de custo, porque histórico longo cresce o input a cada turno sem ninguém perceber. ToolErrors é a que avisa de falha silenciosa: o modelo costuma contornar uma tool quebrada e responder algo plausível, e sem essa métrica o erro só aparece na reclamação.
O harness de evals é deliberadamente simples: um golden.jsonl com prompt, substring esperada e tool esperada, executado pelo pytest. Não mede qualidade semântica. Mede regressão, que é o defeito mais comum quando alguém troca o modelo ou reescreve o system prompt numa sexta-feira.
O que o Terraform deixa para você, de propósito
O módulo provisiona Lambda, API Gateway HTTP API, tabela DynamoDB, roles IAM e log group. Backend de estado, tags, naming e permission boundaries ficam de fora porque cada organização já tem os seus. Rodar terraform apply sem backend remoto grava o estado local na sua máquina: o próximo colega que aplicar vai tentar recriar tudo. Configure o backend e revise a policy da role da Lambda (escopo de bedrock:InvokeModel por ARN de modelo) antes do primeiro deploy.
Perguntas frequentes
Preciso usar Claude?
Não. Como o loop usa a Converse API, basta trocar BEDROCK_MODEL_ID por um modelo Nova, Llama ou Mistral habilitado na sua conta. Confira se o modelo escolhido suporta tool-use na Converse; nem todos suportam.
A tool `web_search` funciona?
Não, é um stub. Ela existe para mostrar o formato de uma tool que chama serviço externo. Ligar a um provedor real é trabalho seu, inclusive timeout e tratamento de erro.
Por que não Bedrock Agents gerenciado?
Use o serviço gerenciado quando quiser que a AWS opere o loop e aceitar a configuração dele. Este starter serve quando você quer o loop em código Python, testável com pytest e com log e métrica sob seu controle.
Para quem é
Use quando você precisa de um agente com poucas tools, conversa de vários turnos e um endpoint HTTP, e quer começar com observabilidade e evals já no lugar em vez de adicioná-las depois do primeiro incidente. Não use como está se o seu caso exige orquestração de vários agentes, RAG com base vetorial ou guardrails de conteúdo: nada disso vem no template, e o esforço de adaptação passa a ser maior que o de partir de outra base. Trate-o como esqueleto a ser lido e cortado, não como framework a ser seguido.
Deep dives de arquitetura, AWS, IA e mercado: direto no seu email. Grátis.
Sem spam · cancele quando quiser