View a markdown version of this page

Execute um A/B teste com roteamento baseado em metas - Amazon Bedrock AgentCore

Execute um A/B teste com roteamento baseado em metas

Use o padrão de roteamento baseado em destino quando a alteração que você está testando envolver alterações de código, uma atualização da estrutura ou uma implementação de agente totalmente diferente. Target-based o roteamento roteia o tráfego entre várias versões do mesmo AgentCore Runtime (endpoints nomeados) ou entre Runtimes totalmente diferentes AgentCore . O AgentCore Gateway registra cada endpoint como um destino separado e encaminha cada sessão para um endpoint ou outro com base nos pesos de tráfego do A/B teste.

Configuração principal para A/B testes baseados em metas:

  • Configuração da variante: variantConfiguration.target com o nome de destino do AgentCore Gateway

  • Configuração de avaliação: perVariantOnlineEvaluationConfig (uma configuração de avaliação on-line por variante, já que cada endpoint tem seu próprio grupo de registros)

  • Filtro de gateway: gatewayFilter.targetPaths define quais caminhos de AgentCore gateway o A/B teste intercepta

Este passo a passo implanta duas versões do agente de suporte ao cliente — uma usando Claude Sonnet (controle) e outra usando Claude Opus (tratamento) — cria endpoints nomeados para cada versão, cria um A/B teste, envia tráfego, analisa os resultados e implanta o vencedor.

nota

Este passo a passo é para agentes hospedados em um AgentCore Runtime. Se seu agente é executado fora de um AgentCore Runtime (um agente terceirizado ou auto-hospedado, por exemplo, no AWS Lambda), consulte Executar A/B um teste para agentes hospedados fora do AgentCore.

Para uma comparação detalhada dos padrões de A/B teste, consulte Escolha de um padrão.

Etapa 1: criar o projeto

Crie o projeto com a AgentCore CLI:

agentcore create --name ABTestTargetBased --no-agent cd ABTestTargetBased

Etapa 2: adicionar o tempo de execução

Adicione o tempo de execução do agente. Você implantará duas versões desse tempo de execução — uma para controle e outra para tratamento — e criará endpoints nomeados para criar um alias para cada versão.

agentcore add agent \ --name csAgent \ --language Python \ --framework Strands \ --model-provider Bedrock \ --memory none \ --build CodeZip

Estrutura do projeto:

ABTestTargetBased/
├── agentcore/
│   ├── agentcore.json
│   ├── aws-targets.json
│   └── cdk/
└── app/
    └── csAgent/
        ├── main.py
        └── pyproject.toml

Etapa 3: implantar versões de controle e tratamento

app/csAgent/main.pySubstitua pela versão de controle (usando Claude Sonnet):

"""Customer support agent — control variant.""" from strands import Agent, tool from strands.models.bedrock import BedrockModel from bedrock_agentcore.runtime import BedrockAgentCoreApp app = BedrockAgentCoreApp() MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" SYSTEM_PROMPT = "You are a helpful customer support assistant for Acme Store." @tool def lookup_order(order_id: str) -> str: """Look up an order by ID.""" orders = { "ORD-1001": {"status": "delivered", "item": "Blue T-Shirt", "total": "$29.99"}, "ORD-1002": {"status": "in_transit", "item": "Running Shoes", "est_delivery": "2026-04-05"}, "ORD-1003": {"status": "delayed", "item": "Wireless Headphones", "days_late": 5}, } return str(orders.get(order_id, {"error": f"Order {order_id} not found"})) @tool def initiate_return(order_id: str, reason: str) -> str: """Initiate a return for an order.""" return f"Return initiated for {order_id}. Reason: {reason}. Return label sent to customer email." @tool def apply_discount(order_id: str, discount_percent: int, reason: str) -> str: """Apply a discount to an order.""" return f"Applied {discount_percent}% discount to {order_id}. Reason: {reason}." agent = Agent( model=BedrockModel(model_id=MODEL_ID), tools=[lookup_order, initiate_return, apply_discount], system_prompt=SYSTEM_PROMPT, ) @app.entrypoint def invoke(payload, context): result = agent(payload.get("prompt", "Hello")) return {"response": result.message["content"][0]["text"]} if __name__ == "__main__": app.run()

Atualizar app/csAgent/pyproject.toml dependências:

dependencies = [ "aws-opentelemetry-distro", "bedrock-agentcore >= 1.8.0", "boto3", "botocore[crt] >= 1.35.0", "strands-agents[otel] >= 1.13.0", "opentelemetry-distro", "opentelemetry-instrumentation", ]

Implante a versão de controle (isso cria a versão 1):

agentcore deploy

Agora, atualize main.py para usar um modelo diferente para a variante de tratamento e implante (isso cria a versão 2):

MODEL_ID = "global.anthropic.claude-opus-4-6-v1"
agentcore deploy

Crie endpoints nomeados para cada versão e implante:

agentcore add runtime-endpoint \ --runtime csAgent \ --endpoint control \ --version 1 \ --description "Control variant — Claude Sonnet" agentcore add runtime-endpoint \ --runtime csAgent \ --endpoint treatment \ --version 2 \ --description "Treatment variant — Claude Opus" agentcore deploy

Agora você tem:

  • Endpoint de tempo de execução control — servindo a versão 1 com Claude Sonnet.

  • Endpoint de tempo de execução treatment — servindo a versão 2 com Claude Opus.

Verifique se o tempo de execução está funcionando:

agentcore invoke --runtime csAgent --prompt "What is the status of order ORD-1003?"

Agora você tem:

  • Endpoint de tempo de execução control — servindo a versão 1 com Claude Sonnet.

  • Endpoint de tempo de execução treatment — servindo a versão 2 com Claude Opus.

Etapa 4: criar configurações de avaliação on-line

Cada endpoint tem seu próprio grupo de log (o nome do grupo de log termina com o nome do endpoint), então você precisa de uma configuração de avaliação on-line por variante:

agentcore add online-eval \ --name controlEvalTb \ --runtime csAgent \ --endpoint control \ --evaluator "Builtin.Helpfulness" \ --sampling-rate 100.0 \ --enable-on-create agentcore add online-eval \ --name treatmentEvalTb \ --runtime csAgent \ --endpoint treatment \ --evaluator "Builtin.Helpfulness" \ --sampling-rate 100.0 \ --enable-on-create agentcore deploy

Depois de cada implantação, anote o ARN da configuração de avaliação on-line — você precisará de ambos ao criar A/B o teste.

Para obter mais detalhes sobre as opções e a configuração do avaliador, consulte Criar avaliação on-line.

Etapa 5: criar o gateway e os destinos

Um A/B teste baseado em destinos roteia o tráfego por meio de um AgentCore Gateway, portanto, o gateway e seus dois alvos já devem estar implantados antes de você iniciar o teste. Adicione um gateway e registre cada endpoint de tempo de execução como um http-runtime destino e, em seguida, implante:

agentcore add gateway --name csGateway agentcore add gateway-target \ --name customer-support-control \ --gateway csGateway \ --type http-runtime \ --runtime csAgent \ --runtime-endpoint control agentcore add gateway-target \ --name customer-support-treatment \ --gateway csGateway \ --type http-runtime \ --runtime csAgent \ --runtime-endpoint treatment agentcore deploy

Etapa 6: criar o A/B teste

Comece o A/B teste comagentcore run ab-test. Cada variante faz referência a um dos destinos de gateway que você criou e tem sua própria configuração de avaliação on-line. O comando inicia o teste diretamente no serviço em relação ao gateway já implantado.

exemplo
AgentCore CLI
agentcore run ab-test \ --mode target-based \ --name customerSupportTargetTest \ --gateway csGateway \ --runtime csAgent \ --control-target customer-support-control \ --treatment-target customer-support-treatment \ --control-online-eval controlEvalTb \ --treatment-online-eval treatmentEvalTb \ --control-weight 80 \ --treatment-weight 20

O teste é EXECUTADO assim que o comando retorna. Passe --disable-on-create para criá-lo parado. O --gateway sinalizador é obrigatório e deve fazer referência ao gateway que você implantou na Etapa 5. Somente um teste pode ser executado por gateway por vez. O comando imprime o ID do trabalho do teste, que também está disponível no id campo. --json Você precisa desse ID para os comandos de ciclo de vida abaixo.

AWS SDK (boto3)
import boto3 import uuid REGION = "us-west-2" ACCOUNT_ID = "123456789012" # Runtime ARNs from Step 2 deployment output CONTROL_RUNTIME_ARN = f"arn:aws:bedrock-agentcore:{REGION}:{ACCOUNT_ID}:runtime/ABTestTargetBased_CustomerSupportControl-abc123" TREATMENT_RUNTIME_ARN = f"arn:aws:bedrock-agentcore:{REGION}:{ACCOUNT_ID}:runtime/ABTestTargetBased_CustomerSupportTreatment-def456" # Online evaluation config ARNs from Step 3 CONTROL_EVAL_ARN = f"arn:aws:bedrock-agentcore:{REGION}:{ACCOUNT_ID}:online-evaluation-config/controlEvalTb-abc123" TREATMENT_EVAL_ARN = f"arn:aws:bedrock-agentcore:{REGION}:{ACCOUNT_ID}:online-evaluation-config/treatmentEvalTb-def456" # IAM roles GATEWAY_ROLE_ARN = f"arn:aws:iam::{ACCOUNT_ID}:role/AgentCoreGatewayRole" AB_TEST_ROLE_ARN = f"arn:aws:iam::{ACCOUNT_ID}:role/ABTestRole" cp_client = boto3.client("bedrock-agentcore-control", region_name=REGION) dp_client = boto3.client("bedrock-agentcore", region_name=REGION) # 1. Create an AgentCore Gateway gateway_response = cp_client.create_gateway( name="customerSupportTargetTest-gw", roleArn=GATEWAY_ROLE_ARN, authorizerType="AWS_IAM", clientToken=str(uuid.uuid4()), ) gateway_id = gateway_response["gatewayId"] gateway_arn = gateway_response["gatewayArn"] print(f"Created AgentCore Gateway: {gateway_id}") # 2. Add control runtime as an AgentCore Gateway target cp_client.create_gateway_target( gatewayIdentifier=gateway_id, name="customer-support-control", targetConfiguration={ "http": { "agentcoreRuntime": { "arn": CONTROL_RUNTIME_ARN, "qualifier": "DEFAULT" } } }, clientToken=str(uuid.uuid4()), ) print("Added target: customer-support-control") # 3. Add treatment runtime as an AgentCore Gateway target cp_client.create_gateway_target( gatewayIdentifier=gateway_id, name="customer-support-treatment", targetConfiguration={ "http": { "agentcoreRuntime": { "arn": TREATMENT_RUNTIME_ARN, "qualifier": "DEFAULT" } } }, clientToken=str(uuid.uuid4()), ) print("Added target: customer-support-treatment") # 4. Create the A/B test response = dp_client.create_ab_test( name="customerSupportTargetTest", gatewayArn=gateway_arn, roleArn=AB_TEST_ROLE_ARN, evaluationConfig={ "perVariantOnlineEvaluationConfig": [ {"name": "C", "onlineEvaluationConfigArn": CONTROL_EVAL_ARN}, {"name": "T1", "onlineEvaluationConfigArn": TREATMENT_EVAL_ARN} ] }, gatewayFilter={ "targetPaths": ["/customer-support-control/*"] }, variants=[ { "name": "C", "weight": 80, "variantConfiguration": { "target": {"name": "customer-support-control"} } }, { "name": "T1", "weight": 20, "variantConfiguration": { "target": {"name": "customer-support-treatment"} } } ], enableOnCreate=True, clientToken=str(uuid.uuid4()), ) ab_test_id = response["abTestId"] print(f"Created A/B test: {ab_test_id}") print(f"Status: {response['status']}") print(f"Execution status: {response['executionStatus']}")

Etapa 7: Enviar tráfego pelo AgentCore Gateway

Depois que o A/B teste estiver em execução, envie tráfego pelo endpoint HTTP do AgentCore Gateway. O AgentCore Gateway atribui cada solicitação a uma variante (controle ou tratamento) com base no ID da sessão de tempo de execução.

Como funciona a atribuição de variantes

O AgentCore Gateway usa o X-Amzn-Bedrock-AgentCore-Runtime-Session-Id cabeçalho para determinar para qual destino rotear o tráfego. Esse cabeçalho é opcional — se você não o fornecer, o tempo de execução gerará uma ID de sessão automaticamente. Em seguida, o AgentCore Gateway usa a ID da sessão (seja ela fornecida por você ou gerada pelo tempo de execução) para atribuir a solicitação a uma variante com base nos pesos de tráfego configurados.

A atribuição da sessão é fixa: quando uma ID de sessão é atribuída a uma variante, todas as solicitações subsequentes com a mesma ID de sessão são encaminhadas para o mesmo destino. Isso garante uma experiência consistente em uma sessão e, ao mesmo tempo, distribui novas sessões entre variantes de acordo com sua divisão de tráfego.

Gere tráfego para testes

Salve o script a seguir comoloadgen.sh, substituindo <gateway-id> e <target-name> com os valores de sua saída de implantação. Você também pode copiar o URL de invocação completo de: agentcore view ab-test <ab-test-id>

#!/bin/bash export AWS_ACCESS_KEY_ID=$(aws configure get aws_access_key_id) export AWS_SECRET_ACCESS_KEY=$(aws configure get aws_secret_access_key) export AWS_SESSION_TOKEN=$(aws configure get aws_session_token) GATEWAY_URL="https://<gateway-id>.gateway.bedrock-agentcore.us-west-2.amazonaws.com/<target-name>/invocations" PROMPTS=( "What is the status of order ORD-1003?" "I want to return order ORD-1001, it doesn't fit." "My order ORD-1003 is late. Can I get a discount?" "Where is my order ORD-1002?" "I need help with a return for order ORD-1001. The color is wrong." "Can you check on order ORD-1003? I've been waiting forever." "I'd like to cancel order ORD-1002 if it hasn't shipped yet." "Order ORD-1003 is delayed again. This is unacceptable." "What's your return policy for order ORD-1001?" "My headphones order ORD-1003 still hasn't arrived. What can you do?" ) for i in $(seq 1 30); do PROMPT="${PROMPTS[$(( (i - 1) % ${#PROMPTS[@]} ))]}" echo "=== Request $i: $PROMPT ===" curl -s --aws-sigv4 "aws:amz:us-west-2:bedrock-agentcore" \ --user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \ -H "x-amz-security-token: $AWS_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -H "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id: $(uuidgen)" \ -d "{\"prompt\": \"$PROMPT\"}" \ -X POST \ "$GATEWAY_URL" echo "" sleep 2 done

Execute o script :

bash loadgen.sh

Etapa 8: obter resultados

Faça uma pesquisa com o A/B teste para monitorar os resultados à medida que o tamanho das amostras aumenta. A pesquisa não afeta a validade estatística.

exemplo
AgentCore CLI

Obtenha os resultados atuais (<ab-test-id>substitua pelo ID do trabalho da Etapa 6):

agentcore view ab-test <ab-test-id>

Obtenha resultados como JSON:

agentcore view ab-test <ab-test-id> --json
AWS SDK (boto3)

Faça uma pesquisa até que os resultados atinjam significância estatística:

import boto3 import time client = boto3.client("bedrock-agentcore", region_name="us-west-2") ab_test_id = "customerSupportTargetTest-Ab1Cd2Ef3G" while True: response = client.get_ab_test(abTestId=ab_test_id) status = response["status"] exec_status = response["executionStatus"] print(f"Status: {status}, Execution: {exec_status}") results = response.get("results") if results: print(f"Analysis timestamp: {results.get('analysisTimestamp')}") for metric in results["evaluatorMetrics"]: evaluator = metric["evaluatorArn"] control = metric["controlStats"] print(f"\nEvaluator: {evaluator}") print(f" Control: mean={control['mean']:.3f}, n={control['sampleSize']}") for variant in metric["variantResults"]: print(f" {variant['variantName']}: mean={variant['mean']:.3f}, " f"n={variant['sampleSize']}, " f"pValue={variant.get('pValue', 'N/A')}, " f"significant={variant['isSignificant']}") if variant["isSignificant"]: print(f" >>> Statistically significant! " f"Change: {variant.get('percentChange', 0):.1f}%") # Check if any evaluator has reached significance all_significant = all( variant["isSignificant"] for metric in results["evaluatorMetrics"] for variant in metric["variantResults"] ) if all_significant: print("\nAll evaluators have reached statistical significance.") break time.sleep(300) # Poll every 5 minutes
nota

O tempo necessário para que os resultados apareçam depende principalmente do tempo limite da sessão configurado nas configurações de avaliação on-line. Uma sessão é considerada concluída quando nenhuma nova solicitação chega dentro da janela de tempo limite. Após o término de uma sessão, os resultados geralmente aparecem em 15 minutos. Os resultados se acumulam à medida que mais sessões são concluídas — a significância estatística melhora com o tamanho da amostra.

Como interpretar os resultados do
  • valor de p < 0,05 e positivopercentChange: O tratamento é significativamente melhor do que o controle. Considere implantar o tratamento.

  • valor de p < 0,05 e negativopercentChange: O tratamento é significativamente pior. Mantenha o controle.

  • valor de p >= 0,05: Não há evidências suficientes para concluir uma diferença. Continue coletando amostras ou aumente o tráfego para o tratamento.

  • Verifique todos os avaliadores: um tratamento pode melhorar uma métrica enquanto regride outra. Analise todos os resultados do avaliador antes de decidir.

Etapa 9: Confirme os resultados e interrompa o A/B teste

Quando o A/B teste atingir significância estatística, revise os resultados e interrompa o experimento.

  1. Confirme a importância. Verifique se o avaliador-alvo tem isSignificant: true um resultado positivo percentChange na variante do tratamento (ou confirme se o controle é o vencedor se o tratamento regrediu).

  2. Pare o A/B teste. Executar agentcore stop ab-test -i <ab-test-id>. O roteamento de tráfego termina imediatamente e todas as solicitações são revertidas para a meta padrão. Consulte Exibir, pausar, retomar e parar.

Etapa 10: implantar o vencedor

Depois de interromper o A/B teste, direcione todo o tráfego para a variante vencedora.

agentcore promote ab-test -i <ab-test-id> agentcore deploy

promoteinterrompe o A/B teste (se ainda estiver em execução), atualiza o endpoint de controle para apontar para a versão do tratamento (por exemplo, atualizando control da versão 1 para a versão 2) e remove o endpoint do tratamento. Execute agentcore deploy para aplicar as alterações.

Como alternativa, você pode implantar manualmente o vencedor fazendo o seguinte:

  • Opção A: Use as regras de roteamento do AgentCore Gateway para direcionar o tráfego de ambos os alvos para o alvo vencedor.

  • Opção B: Remova o alvo perdedor do AgentCore Gateway e direcione todo o tráfego para o vencedor.

  • Opção C: Atualize o alvo perdedor para apontar para o endpoint vencedor.

Próximas etapas

Depois de posicionar o vencedor:

  • Exclua o A/B teste para limpar os recursos. Consulte Excluir um A/B teste.

  • Monitore a nova linha de base. A avaliação on-line continua pontuando as sessões na configuração vencedora. Fique atento às regressões.

  • Comece a próxima iteração. Novos traços da configuração vencedora fornecem a base para o próximo ciclo de recomendação. Veja como funciona.

Entendendo os resultados

Quando você ligaGetABTest, a resposta inclui um results objeto quando o pipeline de agregação processa sessões suficientes. Os resultados contêm métricas por avaliador, divididas por variante.

Estrutura de resultados

{ "results": { "analysisTimestamp": "2026-04-30T18:45:00Z", "evaluatorMetrics": [ { "evaluatorArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:evaluator/Builtin.Helpfulness", "controlStats": { "variantName": "C", "sampleSize": 24, "mean": 0.72 }, "variantResults": [ { "variantName": "T1", "sampleSize": 6, "mean": 0.85, "absoluteChange": 0.13, "percentChange": 18.1, "pValue": 0.032, "confidenceInterval": { "lower": 0.02, "upper": 0.24 }, "isSignificant": true } ] } ] } }

Referência dos campos

Campo Description

analysisTimestamp

Quando o serviço calculou as estatísticas pela última vez.

evaluatorMetrics

Uma entrada por avaliador na configuração de avaliação on-line.

controlStats.mean

Pontuação média do avaliador em todas as sessões de controle.

controlStats.sampleSize

Número de sessões pontuadas para a variante de controle.

variantResults[].mean

Pontuação média do avaliador em todas as sessões de tratamento.

variantResults[].sampleSize

Número de sessões pontuadas para a variante de tratamento.

variantResults[].absoluteChange

Diferença entre média de tratamento e média de controle.

variantResults[].percentChange

Melhoria percentual (positiva) ou regressão (negativa) em relação ao controle.

variantResults[].pValue

Probabilidade: a diferença observada é devida ao acaso. Abaixo de 0,05 indica significância estatística.

variantResults[].confidenceInterval

Intervalo de confiança de 95% para a mudança absoluta (lowere upper limites).

variantResults[].isSignificant

truequando o valor de p < 0,05 e os tamanhos das amostras são suficientes.

Solução de problemas

A/B o teste não mostra resultados após o envio do tráfego

Os resultados não aparecem imediatamente. O tempo necessário depende do tempo limite da sessão configurado em sua configuração de avaliação on-line — uma sessão é considerada concluída somente depois que nenhuma nova solicitação chega dentro da janela de tempo limite. Após o término da sessão, espere resultados em aproximadamente 15 minutos.

Se os resultados ainda não aparecerem após essa janela:

  • Verifique o grupo de registros de avaliação on-line. A configuração de avaliação on-line deve apontar para o grupo de registros de saída do agente de tempo de execução. Se a configuração de avaliação on-line fizer referência a um grupo de registros diferente (ou a um que não receba intervalos do seu tempo de execução), as sessões não serão pontuadas e o A/B teste nunca produzirá resultados.

  • Verifique o nome do grupo de registros. Para roteamento baseado em destino, cada endpoint tem seu próprio grupo de log (o nome do grupo de log termina com o nome do endpoint). Certifique-se de que cada configuração de avaliação on-line faça referência ao grupo correto de registros do endpoint.

  • Confirme se o tempo de execução está emitindo intervalos. Verifique CloudWatch os registros para ver o grupo de registros esperado. Os principais atributos que você está procurando em cada período:

    • aws.agentcore.gateway.routing_experiment_arn

    • aws.agentcore.gateway.routing_experiment_variant_name(valores: C ouT1)

    • session.id

  • Verifique CLI-created versus configurações manuais. Se você usouagentcore add online-eval --runtime <name>, a CLI configura automaticamente o grupo de registros correto. Se você criou a configuração de avaliação on-line manualmente por meio da API, certifique-se de que a dataSourceConfig.cloudWatchLogs.logGroupNames Configuração de avaliação AgentCore on-line corresponda ao grupo de registros de extensão do seu tempo de execução.