O problema: guardrails de modelo não cobrem tudo
Quem já colocou agentes de IA em produção sabe que o Amazon Bedrock Guardrails protege o que acontece na fronteira do modelo — valida o prompt antes da inferência e a resposta depois. Mas agentes fazem muito mais do que chamar modelos. Eles invocam ferramentas, buscam dados em fontes externas, se comunicam com servidores via Protocolo de Contexto de Modelo (MCP) e retornam resultados para usuários ou sistemas downstream.
Todo esse fluxo acontece fora da fronteira do modelo, onde os guardrails de nível de modelo simplesmente não chegam. A AWS identificou quatro exposições concretas que surgem dessa lacuna:
- Parâmetros de ferramentas passam sem verificação. O modelo decide qual ferramenta usar e quais parâmetros enviar. Se esses parâmetros contiverem Informações de Identificação Pessoal (PII) ou conteúdo que viola políticas, a ferramenta executa com esse conteúdo sem nenhuma barreira.
- Dados externos entram sem validação. Respostas de ferramentas, saídas de servidores MCP e retornos de APIs chegam ao agente sem passar por nenhum guardrail, podendo influenciar o comportamento do modelo antes de qualquer avaliação.
- Conteúdo enganoso afeta o raciocínio. Um agente que consome dados imprecisos de uma fonte externa pode tratá-los como autoritativos, gerando recomendações distorcidas em áreas críticas como crédito, saúde ou assessoria jurídica.
- Sistemas multi-agente propagam dados problemáticos. Em arquiteturas com múltiplos agentes, um componente mal configurado pode passar conteúdo que viola políticas para agentes downstream — e os guardrails de cada agente individualmente não inspecionam o que trafega entre eles na camada de ferramentas.
A solução: três pontos de validação com lifecycle hooks
Para fechar essas lacunas, a abordagem proposta pela AWS adiciona três pontos de validação em cada fronteira de confiança onde dados entram ou saem do agente. Esses pontos são implementados com os lifecycle hooks do Strands Agents SDK, sem exigir nenhuma alteração nas ferramentas existentes ou na lógica do agente.

Ponto 1 — Validação de dados de entrada (BeforeInvocationEvent)
O primeiro ponto verifica os dados antes de chegarem ao modelo: entrada do usuário, dados vindos de outros agentes, servidores MCP e pipelines de Geração Aumentada por Recuperação (RAG). O hook BeforeInvocationEvent dispara antes da inferência ou da execução de qualquer ferramenta. Se o conteúdo violar políticas, a requisição é bloqueada e o modelo nunca vê esse conteúdo.
Ponto 2 — Supervisão de interação com ferramentas (BeforeToolCallEvent)
O segundo ponto age antes de o agente chamar uma ferramenta, verificando os parâmetros que seriam enviados. É exatamente a lacuna que os guardrails de nível de modelo não cobrem: o modelo já decidiu o que enviar, mas nada verificou se esse conteúdo é seguro para ser executado. O hook BeforeToolCallEvent cancela a chamada se os parâmetros forem problemáticos, antes que qualquer ação real aconteça.
Ponto 3 — Validação de dados de saída (AfterToolCallEvent)
O terceiro ponto valida os resultados antes de retorná-los ao usuário ou repassá-los a sistemas downstream. É especialmente importante para ferramentas que consomem conteúdo externo, como uma ferramenta de busca na web que traz páginas de sites fora do seu controle. O hook AfterToolCallEvent valida o retorno da ferramenta e o substitui por uma mensagem de bloqueio se o conteúdo violar políticas.
A intensidade de validação de cada ponto pode ser ajustada de forma independente. No Ponto 1, faz sentido usar um guardrail completo com detecção de PII, filtragem de conteúdo e aplicação de tópicos. O Ponto 2 pode ser mais leve — um guardrail separado com regras específicas para a ferramenta em questão, ou verificações locais como validação de expressão regular ou de schema. O Ponto 3 deve focar na detecção de conteúdo indesejado nas saídas que trazem dados externos. Combinar verificações determinísticas rápidas (regex, validação de schema, listas de permissão) com avaliações baseadas em IA mantém a latência baixa.
Implementação passo a passo
A implementação usa o boto3, o SDK da AWS para Python, para chamar a API ApplyGuardrail. O Strands Agents SDK expõe um evento de lifecycle por ponto de validação.
Pré-requisitos
Antes de implementar a abordagem com múltiplos pontos de validação, você precisará de:
- Uma conta AWS com acesso ao Amazon Bedrock
- Amazon Bedrock Guardrails configurado
- Python 3.11 ou superior instalado
- Strands Agents SDK instalado:
pip install strands-agents - Credenciais AWS configuradas com permissões para
bedrock:ApplyGuardrailebedrock:InvokeModel - O ID e a versão do seu guardrail, obtidos no console do Amazon Bedrock (navegue até Guardrails, selecione seu guardrail e copie o ID)
Este guia pressupõe que você já tem um agente Strands funcionando com acesso mínimo privilegiado às ferramentas, prompts de sistema com escopo definido e lógica de negócios validada. Se estiver começando do zero, a AWS recomenda consultar o artigo Strands Agents SDK: A technical deep dive into agent architectures and observability para um passo a passo completo de construção e implantação com o Amazon Bedrock Agent Core.
Criando o hook de validação de guardrail
A classe GuardrailHook é um HookProvider do Strands. Ela registra três callbacks, um para cada evento de lifecycle. Quando o Strands dispara um evento, o callback correspondente executa: validate_inbound verifica mensagens do usuário, validate_input verifica parâmetros de ferramentas antes da execução e validate_output verifica os resultados das ferramentas. Os três usam o método compartilhado _check, que chama a API ApplyGuardrail do Amazon Bedrock.
Crie um arquivo guardrail_hook.py e adicione a implementação abaixo. Use o parâmetro opcional tool_names para restringir o hook a ferramentas específicas, ou passe None para aplicar em todas:
import boto3
from strands.hooks import HookProvider, HookRegistry
from strands.hooks.events import (
BeforeInvocationEvent,
BeforeToolCallEvent,
AfterToolCallEvent,
)
class GuardrailHook(HookProvider):
def __init__(self, guardrail_id, guardrail_version, region_name, tool_names=None):
self.client = boto3.client("bedrock-runtime", region_name=region_name)
self.guardrail_id = guardrail_id
self.guardrail_version = guardrail_version
self.tool_names = tool_names # None = apply to all tools
def register_hooks(self, registry: HookRegistry, **kwargs):
registry.add_callback(BeforeInvocationEvent, self.validate_inbound)
registry.add_callback(BeforeToolCallEvent, self.validate_input)
registry.add_callback(AfterToolCallEvent, self.validate_output)
def _check(self, content, source="INPUT"):
"""Call Bedrock ApplyGuardrail. Returns True if content is safe."""
response = self.client.apply_guardrail(
guardrailIdentifier=self.guardrail_id,
guardrailVersion=self.guardrail_version,
source=source, # "INPUT" applies input policies; "OUTPUT" applies output policies
content=[{"text": {"text": content}}],
)
return response["action"] != "GUARDRAIL_INTERVENED"
# Checkpoint 1 — BeforeInvocationEvent
# Validates user input before model inference or tool execution occurs.
# The model does not see blocked content.
async def validate_inbound(self, event: BeforeInvocationEvent):
for msg in reversed(event.messages):
if msg.get("role") == "user":
for block in msg.get("content", []):
text = block.get("text", "")
if text and not self._check(text):
event.messages.clear()
event.messages.append({
"role": "user",
"content": [{"text": "Request blocked by safety guardrail."}],
})
return
break
# Checkpoint 2 — BeforeToolCallEvent
# Validates tool input parameters before the tool executes.
# Skips tools not in tool_names (if a filter is set).
async def validate_input(self, event: BeforeToolCallEvent):
if self.tool_names and event.tool_use.get("name") not in self.tool_names:
return
tool_input = event.tool_use.get("input", {})
for param_value in tool_input.values():
if isinstance(param_value, str) and not self._check(param_value):
event.cancel_tool = "This request was blocked by a safety guardrail."
return
# Checkpoint 3 — AfterToolCallEvent
# Validates tool output before it reaches the agent.
# Skips tools not in tool_names (if a filter is set).
async def validate_output(self, event: AfterToolCallEvent):
if self.tool_names and event.tool_use.get("name") not in self.tool_names:
return
content_parts = [
block["text"]
for block in event.result.get("content", [])
if "text" in block
]
content = "\n".join(content_parts)
if content and not self._check(content, source="OUTPUT"):
event.result = {
"toolUseId": event.result["toolUseId"],
"status": "error",
"content": [{"text": "Content blocked by safety guardrail."}],
}
Definindo ferramentas
O Strands descobre ferramentas pelo decorator @tool, que transforma uma função Python comum em uma ferramenta que o modelo pode chamar, usando a docstring e as type hints como contrato da ferramenta. Abaixo estão dois exemplos simples usados nas seções de registro:
from strands import tool
@tool
def web_search(query: str) -> str:
"""Search the web and return a result snippet."""
# Replace with your actual search implementation
return f"Search results for: {query}"
@tool
def get_customer_data(customer_id: str) -> str:
"""Retrieve customer record by ID."""
# Replace with your actual data lookup implementation
return f"Customer record for: {customer_id}"
Registrando o hook
O Strands ativa hooks pelo parâmetro hooks no construtor do Agent. Após o registro, os callbacks do hook executam automaticamente em cada evento de lifecycle correspondente, sem nenhuma alteração nas ferramentas ou na lógica do agente.
Para um único guardrail aplicado a todas as ferramentas, crie uma instância do hook e passe-a ao agente:
from strands import Agent
from strands.models import BedrockModel
from guardrail_hook import GuardrailHook
from tools import web_search, get_customer_data # Example tools - replace with your tools
# Example model and region selection
model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-5",
region_name="us-east-1",
)
guardrail_hook = GuardrailHook(
guardrail_id="your-guardrail-id", # Copy it from the Amazon Bedrock console > Guardrails
guardrail_version="1", # Use "DRAFT" for testing
region_name="us-east-1", # Region where the guardrails are defined
)
agent = Agent(
model=model,
tools=[web_search, get_customer_data], # Example tools
system_prompt="You are a helpful assistant.", # Example system prompt
hooks=[guardrail_hook], # Applied to all tool calls
)
Usando guardrails diferentes por ferramenta
Ferramentas diferentes carregam riscos diferentes. Uma ferramenta de busca na web traz conteúdo externo de sites não confiáveis e precisa de filtragem de saída rigorosa. Uma ferramenta de dados de clientes retorna registros internos e pode precisar de detecção de PII configurada de forma diferente.
O parâmetro tool_names restringe um hook a ferramentas específicas. O Strands ainda executa todos os hooks registrados em cada evento, mas os hooks ignoram a chamada quando o nome da ferramenta não corresponde. Registre um hook por guardrail:
from strands import Agent
from strands.models import BedrockModel
from guardrail_hook import GuardrailHook
from tools import web_search, get_customer_data # Example tools - replace with your tools
# Example model and region selection
model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-5",
region_name="us-east-1",
)
# Strict content filtering and PII detection for web search results
web_search_hook = GuardrailHook(
guardrail_id="gr-websearch-id", # Guardrail ID with content filtering + PII detection
guardrail_version="1", # Or set to DRAFT
region_name="us-east-1", # Change to your region
tool_names={"web_search"}, # Only applies to the web_search tool
)
# PII detection for customer data — prevents sensitive records from leaking into tool parameters
customer_data_hook = GuardrailHook(
guardrail_id="gr-customerdata-id", # Guardrail ID with PII detection
guardrail_version="1", # Or set to DRAFT
region_name="us-east-1", # Change to your region
tool_names={"get_customer_data"}, # Only applies to the get_customer_data tool
)
agent = Agent(
model=model,
tools=[web_search, get_customer_data], # Example tools
system_prompt="You are a helpful assistant.", # Example system prompt
hooks=[web_search_hook, customer_data_hook], # Each hook runs only for its assigned tools
)
Cada guardrail é configurado de forma independente no console do Amazon Bedrock, permitindo ajustar a rigidez da validação ao nível de risco de cada ferramenta, em vez de aplicar uma política única para todo o agente.
Testando a implementação
Para validar o funcionamento, crie uma pasta de projeto com os seguintes arquivos:
guardrail_hook.py— a classeGuardrailHooktools.py— as definições das ferramentasweb_searcheget_customer_dataagent.py— a configuração do agente da seção de registro do hook
Em agent.py, adicione um prompt de teste ao final:
# Send a test prompt
response = agent("Search the web for the latest news on AI security.")
print(response)
Atualize os IDs de guardrail, a região AWS e o ID do modelo em agent.py para corresponder à sua configuração. Execute o agente a partir da pasta do projeto:
python agent.py
O hook de guardrail executa em cada ponto de validação. Se o prompt ou qualquer saída de ferramenta for sinalizado, você verá a mensagem de bloqueio na resposta em vez do resultado da ferramenta.
Reutilizando o hook em toda a organização
A classe GuardrailHook é um HookProvider independente. Construída uma vez, ela pode ser anexada a agentes Strands passando-a no parâmetro hooks. O mesmo pacote de hook pode ser publicado como uma biblioteca interna e consumido por:
- Múltiplos agentes dentro de uma única aplicação
- Agentes implantados em diferentes runtimes (AWS Lambda, Amazon Elastic Container Service (Amazon ECS), Amazon Bedrock Agent Core Runtime)
- Times em toda a organização, com IDs de guardrail específicos por ambiente injetados via configuração (por exemplo, dev, staging, prod)
É possível trocar configurações de guardrail ou adicionar verificações como regex ou validação de schema sem tocar no código do agente ou das ferramentas.
Conclusão
O Amazon Bedrock Guardrails protege a fronteira do modelo, mas agentes também chamam ferramentas, consomem dados externos e retornam resultados que nunca passam pelas verificações de nível de modelo. Os três pontos de validação apresentados neste guia fecham essa lacuna usando os lifecycle hooks do Strands Agents SDK: BeforeInvocationEvent valida a entrada do usuário, BeforeToolCallEvent valida os parâmetros das ferramentas e AfterToolCallEvent valida a saída das ferramentas.
A mesma classe GuardrailHook suporta tanto um guardrail compartilhado quanto guardrails diferentes com escopo por ferramenta, e pode ser implantada sem alterações desde o teste local até o Amazon Bedrock Agent Core Runtime.
Para se aprofundar no tema, a AWS recomenda consultar também o OWASP Top 10 para Aplicações Agênticas, que traz as principais vulnerabilidades a considerar nesse tipo de arquitetura.
Fonte
Extend Amazon Bedrock Guardrails to Tool Interactions Using the Strands Agents SDK (https://aws.amazon.com/blogs/security/extend-amazon-bedrock-guardrails-to-tool-interactions-using-the-strands-agents-sdk/)
Leave a Reply