Workflows agênticos com SageMaker AI e Bedrock AgentCore: guia completo com observabilidade

O problema real de misturar modelos gerenciados e próprios

Quem já tentou montar um workflow agêntico em produção sabe que um dos maiores desafios é combinar Modelos Fundamentais (FM) gerenciados com modelos próprios — seja por custo, domínio específico ou requisitos de residência de dados — sem ter que reescrever toda a lógica do agente cada vez que algo muda.

A AWS publicou um guia técnico abordando exatamente esse problema. A solução combina endpoints com suporte à API compatível com OpenAI no Amazon SageMaker AI com o runtime do Amazon Bedrock AgentCore, entregando uma arquitetura pronta para produção que cobre otimização de custos, controle de residência de dados e flexibilidade de modelos em um único stack.

O exemplo prático usa o modelo Qwen 3.5 9B implantado no SageMaker AI, integrado a um sistema multi-agente com o Strands Agents, rodando ao lado de modelos do Amazon Bedrock. O workflow completo é então publicado no Amazon Bedrock AgentCore runtime.

Como a arquitetura está organizada

A solução conecta três caminhos distintos de hospedagem de modelos dentro de um único contêiner do Amazon Bedrock AgentCore:

  • Agente orquestrador (Claude Haiku 4.5 no Bedrock) — classifica a intenção do usuário e roteia as tarefas usando inferência cross-region global.
  • Agente de orçamento (Claude Sonnet 4.6 no Bedrock) — executa análises de orçamento com divisão 50/30/20 e saída estruturada via Pydantic.
  • Agente de análise financeira (Qwen 3.5 9B no SageMaker AI) — realiza análise de ações e construção de portfólios usando chamadas de ferramentas (tool-calling).

O fluxo de execução é o seguinte: a requisição do usuário chega ao agente orquestrador, que opera dentro do Amazon Bedrock AgentCore runtime. Usando o padrão agents as tools do Strands Agents, o orquestrador decide se encaminha a tarefa para o agente de orçamento ou para o agente de análise financeira. Cada agente especializado invoca seu modelo correspondente — o de orçamento chama o Claude Sonnet 4.6 via Bedrock, e o de análise financeira chama o Qwen 3.5 9B via endpoint real-time do SageMaker usando a API compatível com OpenAI. Os resultados retornam pelo orquestrador até o usuário.

Vale lembrar que a disponibilidade dos modelos do Bedrock varia por Região AWS. Consulte os modelos suportados por Região no Amazon Bedrock antes de começar. O código-fonte completo está disponível no repositório GitHub de acompanhamento.

Pré-requisitos

  • Conta AWS com permissões para Amazon SageMaker AI, Amazon Bedrock e AgentCore.
  • Instalação dos pacotes: pip install sagemaker-core openai httpx strands-agents[otel] yfinance pydantic bedrock-agentcore
  • Papel IAM com sagemaker:InvokeEndpoint e sagemaker:CallWithBearerToken.
  • Acesso aos modelos Claude Haiku 4.5 e Claude Sonnet 4.6 no Bedrock.
  • Python 3.12 ou superior.

Passo 1: Implantar o Qwen 3.5 9B no SageMaker AI

O primeiro passo é implantar o Qwen 3.5 9B usando o contêiner de aprendizado profundo (DLC) vLLM, na imagem vllm:0.22.1-gpu-py312-cu130, em uma instância ml.g6e.2xlarge:

region = "us-west-2"
model_id = "Qwen/Qwen3.5-9B"
instance_type = "ml.g6e.2xlarge" # 1x L40S (48GB VRAM)
num_gpu = 1

# vLLM 0.22.1, Python 3.12, CUDA 13.0, Ubuntu 22.04
inference_image = f"763104351884.dkr.ecr.{region}.amazonaws.com/vllm:0.22.1-gpu-py312-cu130-ubuntu22.04-sagemaker"

env = {
    "SM_VLLM_MODEL": model_id,
    "SM_VLLM_TENSOR_PARALLEL_SIZE": "1",
    "SM_VLLM_MAX_MODEL_LEN": "32768",
}

# Create Model
sm.create_model(
    ModelName=model_name,
    ExecutionRoleArn=role,
    PrimaryContainer={"Image": inference_image, "Environment": env},
)

# Create Endpoint Config + Endpoint
sm.create_endpoint_config(
    EndpointConfigName=endpoint_config_name,
    ProductionVariants=[{
        "VariantName": "v1",
        "ModelName": model_name,
        "InstanceType": instance_type,
        "InitialInstanceCount": 1,
        "ContainerStartupHealthCheckTimeoutInSeconds": 1200,
        "InferenceAmiVersion": inference_ami_version,
    }],
)

sm.create_endpoint(EndpointName=endpoint_name, EndpointConfigName=endpoint_config_name)

Passo 2: Construir o sistema multi-agente

A API compatível com OpenAI do SageMaker AI exige um token bearer para autenticação. Como esses tokens expiram, é necessário renová-los automaticamente a cada requisição em sessões longas. A solução usa uma subclasse de httpx.Auth para fazer essa renovação automática:

import httpx
from openai import AsyncOpenAI
from sagemaker.core.token_generator import generate_token

class SageMakerAuth(httpx.Auth):
    def __init__(self, region):
        self.region = region

    def auth_flow(self, request):
        request.headers["Authorization"] = f"Bearer {generate_token(region=self.region)}"
        yield request

strands_client = AsyncOpenAI(
    base_url=f"https://runtime.sagemaker.{REGION}.amazonaws.com/endpoints/{ENDPOINT_NAME}/openai/v1",
    api_key="sagemaker",
    http_client=httpx.AsyncClient(auth=SageMakerAuth(region=REGION)),
)

Em seguida, o sistema multi-agente é montado usando o padrão agents as tools do Strands Agents, com instâncias frescas de agente por invocação:

from strands import Agent, tool
from strands.models.openai import OpenAIModel

qwen_model = OpenAIModel(
    client=strands_client,
    model_id="",
    params={"temperature": 0.7, "max_tokens": 4096, "stream_options": {"include_usage": True}},
)

@tool
def financial_analysis_agent_tool(query: str) -> str:
    fresh = Agent(model=qwen_model, tools=[...], callback_handler=None)
    return str(fresh(query))

orchestrator = Agent(
    model=BedrockModel(model_id="global.anthropic.claude-haiku-4-5-20251001-v1:0"),
    tools=[budget_agent_tool, financial_analysis_agent_tool],
)

Passo 3: Publicar no Amazon Bedrock AgentCore runtime

A publicação usa o bedrock-agentcore-starter-toolkit. O notebook completo de implantação está disponível em deploy_agentcore.ipynb:

from bedrock_agentcore_starter_toolkit import Runtime

agentcore_runtime = Runtime()
agentcore_runtime.configure(
    entrypoint="main.py",
    auto_create_execution_role=True,
    auto_create_ecr=True,
    requirements_file="requirements.txt",
    region="ap-south-1",
    agent_name="personal_finance_agent",
)

launch_result = agentcore_runtime.launch(
    env_vars={
        "SAGEMAKER_ENDPOINT_NAME": "qwen35-9b-260612-082732",
        "SAGEMAKER_REGION": "ap-south-1",
        "AGENT_OBSERVABILITY_ENABLED": "true",
    }
)

O ponto crítico: observabilidade nos endpoints do SageMaker

Este é o aspecto mais importante de todo o guia. O Amazon Bedrock AgentCore runtime instrumenta os agentes automaticamente com OpenTelemetry (OTel), mas essa instrumentação não se aplica igualmente a todos os provedores de modelos.

O problema: tokens invisíveis

Chamadas a modelos do Bedrock recebem spans completos de IA generativa com contagem de tokens automaticamente — sem nenhum trabalho extra. Já os endpoints compatíveis com OpenAI do SageMaker (via OpenAIModel do Strands) não recebem telemetria automática de tokens. A instrumentação simplesmente não os reconhece como chamadas de IA generativa.

Na prática, todos os tokens consumidos pelo agente de análise financeira ao chamar o Qwen 3.5 9B no SageMaker ficam completamente invisíveis nos traces. Sem essa visibilidade, monitorar custos, detectar regressões ou depurar latência se torna impossível.

A causa raiz está no fato de que a integração OpenTelemetry do Strands emite spans para chamadas de ferramentas e eventos do ciclo de vida do agente, mas não emite spans gen_ai.chat com atributos de token para o provedor OpenAIModel. A auto-instrumentação do AgentCore só reconhece chamadas de inferência do Bedrock (feitas via boto3) como operações de IA generativa.

A solução: spans OpenTelemetry customizados

A saída é emitir manualmente um span gen_ai.chat que envolva a invocação do agente no SageMaker e extraia o uso de tokens a partir do AgentResult.metrics.accumulated_usage do Strands:

from opentelemetry import trace

tracer = trace.get_tracer("financial_analysis_agent")

@tool
def financial_analysis_agent_tool(query: str) -> str:
    """Route investment queries to Qwen on SageMaker with observability."""
    with tracer.start_as_current_span("gen_ai.chat", attributes={
        "gen_ai.system": "openai",
        "gen_ai.request.model": f"qwen3.5-9b ({SAGEMAKER_ENDPOINT_NAME})",
        "gen_ai.operation.name": "chat",
    }) as span:
        fa_agent = Agent(
            model=OpenAIModel(
                client=strands_client,
                model_id="",
                params={"temperature": 0.7, "max_tokens": 4096, "stream_options": {"include_usage": True}},
            ),
            system_prompt=FINANCIAL_ANALYSIS_PROMPT,
            tools=[get_stock_analysis, create_diversified_portfolio, compare_stock_performance],
            callback_handler=None,
        )
        result = fa_agent(query)

        # Extract token usage from Strands agent metrics
        usage = result.metrics.accumulated_usage
        span.set_attribute("gen_ai.usage.input_tokens", usage.get("inputTokens", 0))
        span.set_attribute("gen_ai.usage.output_tokens", usage.get("outputTokens", 0))
        span.set_attribute("gen_ai.usage.total_tokens", usage.get("totalTokens", 0))

        return str(result)

Um detalhe importante: o Strands rastreia o uso de tokens internamente com as chaves inputTokens, outputTokens e totalTokens. Esse dicionário só é populado se o provedor do modelo retornar dados de uso.

Por que o stream_options é obrigatório no vLLM

Por padrão, o vLLM não inclui um chunk de uso nas respostas em streaming. O Strands recebe os chunks de texto, mas nunca recebe o objeto de uso final — o que faz o accumulated_usage ficar zerado. Adicionar stream_options: {"include_usage": True} instrui o vLLM a enviar um chunk final extra com a contagem de tokens. Sem esse parâmetro, os spans gen_ai.chat reportarão 0 tokens, tornando toda a instrumentação inútil.

Configuração passo a passo da observabilidade

Para ativar a observabilidade completa, é necessário:

  • Ativar o Amazon CloudWatch Transaction Search (uma vez por conta ou Região): aws xray update-trace-segment-destination --region ap-south-1 --destination CloudWatchLogs e aws xray update-indexing-rule --region ap-south-1 --name "Default" --rule '{"Probabilistic": {"DesiredSamplingPercentage": 100}}'
  • Instalar o Strands com extras OTel: strands-agents[otel]>=1.0.0
  • Definir AGENT_OBSERVABILITY_ENABLED=true nas variáveis de ambiente
  • Usar opentelemetry-instrument como CMD do contêiner
  • Adicionar stream_options: {"include_usage": True} nos parâmetros do OpenAIModel
  • Criar o span gen_ai.chat customizado envolvendo a chamada do agente SageMaker

Com essa configuração, o trace de saída fica assim:

{
  "name": "gen_ai.chat",
  "attributes": {
    "gen_ai.system": "openai",
    "gen_ai.request.model": "qwen3.5-9b (qwen35-9b-260612-082732)",
    "gen_ai.operation.name": "chat",
    "gen_ai.usage.input_tokens": 1391,
    "gen_ai.usage.output_tokens": 1432,
    "gen_ai.usage.total_tokens": 2823
  },
  "durationNano": 37237386894
}

Esse trace exibe o span gen_ai.chat do modelo Qwen hospedado no SageMaker AI ao lado dos spans automaticamente instrumentados do Bedrock AgentCore, com contagem de tokens visível para ambos. A referência completa de convenções semânticas está nas convenções semânticas de IA generativa do OpenTelemetry.

Principais aprendizados

  • Bedrock AgentCore auto-instrumenta chamadas Bedrock — nenhum trabalho extra é necessário para Claude ou Amazon Nova.
  • Endpoints OpenAI do SageMaker precisam de spans manuais — o Strands não emite spans gen_ai.chat para o OpenAIModel.
  • Uso de tokens exige stream_options — o vLLM não envia uso em streaming por padrão.
  • Use result.metrics.accumulated_usage — chaves: inputTokens, outputTokens, totalTokens.
  • Taxa de amostragem do AWS X-Ray importa — o padrão de 1% descarta a maioria dos traces. Use 100% durante o desenvolvimento.
  • Instâncias frescas de agente por requisição — singletons causam erros em invocações concorrentes.

Como expandir essa arquitetura

Essa arquitetura é composável e pode ser estendida em várias direções:

  • Trocar por modelos fine-tuned: basta apontar SM_VLLM_MODEL para o checkpoint fine-tuned no Amazon S3. A camada de autenticação, os spans OTel e a implantação no AgentCore permanecem inalterados.
  • Testes A/B com componentes de inferência: implante variantes base e fine-tuned no mesmo endpoint do SageMaker e adicione um atributo de variante ao span OTel para comparar qualidade nos traces.
  • Roteamento por custo: verifique a complexidade da consulta antes do despacho. Roteie consultas simples para o Haiku no Bedrock e reserve o endpoint de GPU do SageMaker para tarefas de raciocínio em múltiplos passos.

Limpeza dos recursos

Para evitar cobranças futuras, os recursos devem ser removidos:

agentcore_control = boto3.client("bedrock-agentcore-control", region_name=region)
agentcore_control.delete_agent_runtime(agentRuntimeId=launch_result.agent_id)

sagemaker_client.delete_endpoint(EndpointName=ENDPOINT_NAME)
sagemaker_client.delete_endpoint_config(EndpointConfigName=f"qwen35-9b-epc-{TIMESTAMP}")
sagemaker_client.delete_model(ModelName=f"qwen35-9b-{TIMESTAMP}")

Conclusão

O guia publicado pela AWS demonstra como conectar um modelo auto-hospedado no Amazon SageMaker AI ao Amazon Bedrock AgentCore runtime e, principalmente, como obter observabilidade completa em nível de tokens para endpoints do SageMaker que o Strands Agents não instrumenta por padrão. Os três pilares centrais da solução são:

  • httpx.Auth + generate_token() + AsyncOpenAI — autenticação SageMaker pronta para produção dentro do AgentCore.
  • Span OTel gen_ai.chat customizado + stream_options: {"include_usage": True} — visibilidade total de tokens para endpoints SageMaker.
  • result.metrics.accumulated_usage — a API do Strands para extrair contagens de tokens.

Para começar, clone o repositório de acompanhamento e consulte o OBSERVABILITY.md para a referência completa. Recursos adicionais: documentação de observabilidade do Amazon Bedrock AgentCore.

Fonte

Building agentic workflows with SageMaker AI and Bedrock AgentCore (https://aws.amazon.com/blogs/machine-learning/building-agentic-workflows-with-sagemaker-ai-and-bedrock-agentcore/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *