View a markdown version of this page

使用基于目标的路由进行 A/B 测试 - Amazon Bedrock AgentCore

使用基于目标的路由进行 A/B 测试

当您正在测试的更改涉及代码更改、框架升级或完全不同的代理实现时,请使用基于目标的路由模式。 Target-based 路由在同一 AgentCore 运行时的多个版本(命名端点)之间或完全不同的 AgentCore 运行时之间路由流量。 AgentCore 网关将每个端点注册为单独的目标,并根据 A/B 测试的流量权重将每个会话路由到一个或另一个端点。

基于目标的 A/B 测试的关键配置:

  • 变体配置:variantConfiguration.target使用 AgentCore 网关目标名称

  • 评估配置:perVariantOnlineEvaluationConfig(每个变体都有一个在线评估配置,因为每个端点都有自己的日志组)

  • 网关过滤器: A/B 测试截获的 AgentCore 网关路径的gatewayFilter.targetPaths作用域

本演练部署了两个版本的客户支持代理——一个使用 Claude Sonnet(控制),另一个使用 Claude Opus(治疗)——为每个版本创建命名端点、创建 A/B 测试、发送流量、查看结果并部署获胜者。

注意

本演练适用于 AgentCore 运行时上托管的代理。如果您的代理在 AgentCore 运行时外部运行(第三方代理或自托管代理,例如在 Lamb AWS da 上),请参阅改为运行 A/B 时外部 AgentCore托管的代理运行测试

有关 A/B 测试模式的详细比较,请参阅选择模式

步骤 1:创建项目

使用 AgentCore CLI 创建项目:

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

第 2 步:添加运行时

添加代理运行时。您将部署此运行时的两个版本(一个用于控制,一个用于治疗),然后创建命名的端点来为每个版本设置别名。

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

项目结构:

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

步骤 3:部署控制和治疗版本

app/csAgent/main.py替换为控制版本(使用 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()

更新app/csAgent/pyproject.toml依赖关系:

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", ]

部署控件版本(这将创建版本 1):

agentcore deploy

现在更新main.py为对治疗变体使用不同的模型并进行部署(这将创建版本 2):

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

为每个版本创建命名端点并部署:

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

你现在有:

  • 运行时端点 control — 与 Claude Sonnet 一起提供版本 1。

  • 运行时端点 treatment — 使用 Claude Opus 提供版本 2。

验证运行时是否正常运行:

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

你现在有:

  • 运行时端点 control — 与 Claude Sonnet 一起提供版本 1。

  • 运行时端点 treatment — 使用 Claude Opus 提供版本 2。

步骤 4:创建在线评估配置

每个端点都有自己的日志组(日志组名称以端点名称结尾),因此每个变体都需要一个在线评估配置:

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

每次部署后,请记下在线评估配置 ARN,创建测试时需要两者。 A/B

有关评估器选项和配置的更多详细信息,请参阅创建在线评估

步骤 5:创建网关和目标

基于目标的 A/B 测试通过 AgentCore 网关路由流量,因此在开始测试之前,必须已经部署了网关及其两个目标。添加网关并将每个运行时端点注册为http-runtime目标,然后部署:

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

步骤 6:创建 A/B 测试

使用开始 A/B 测试agentcore run ab-test。每个变体都引用您创建的网关目标之一,并且有自己的在线评估配置。该命令直接在服务上针对已部署的网关启动测试。

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

命令返回后,测试即在运行。传球--disable-on-create来创建它已停止。该--gateway标志为必填项,并且必须引用您在步骤 5 中部署的网关。每个网关一次只能运行一个测试。该命令会打印测试的作业 ID,也可以从id字段中--json获得。以下生命周期命令需要此 ID。

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']}")

步骤 7:通过 AgentCore 网关发送流量

A/B 测试运行后,通过 AgentCore 网关 HTTP 端点发送流量。 AgentCore Gateway 根据运行时会话 ID 将每个请求分配给变体(对照或治疗)。

变体赋值的工作原理

AgentCore 网关使用标X-Amzn-Bedrock-AgentCore-Runtime-Session-Id头来确定要将流量路由到哪个目标。此标头是可选的,如果您不提供该标头,则运行时会自动生成会话 ID。然后, AgentCore 网关使用会话 ID(无论是您提供的,还是运行时生成的),根据您配置的流量权重将请求分配给变体。

会话分配是粘性的:将会话 ID 分配给变体后,所有具有相同会话 ID 的后续请求都会路由到同一个目标。这样可以确保在会话中获得一致的体验,同时仍能根据您的流量分配跨变体分配新会话。

生成用于测试的流量

将以下脚本另存为 loadgen.sh<gateway-id><target-name>用部署输出中的值替换和。您也可以从agentcore view ab-test <ab-test-id>以下地址复制完整的调用 URL:

#!/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

运行脚本:

bash loadgen.sh

第 8 步:获取结果

随着样本量的增长,对 A/B 测试进行轮询以监控结果。轮询不影响统计的有效性。

AgentCore CLI

获取当前结果(<ab-test-id>替换为步骤 6 中的任务 ID):

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

以 JSON 格式获取结果:

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

在结果达到统计意义之前进行民意调查:

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
注意

显示结果所需的时间主要取决于在线评估配置中配置的会话超时。如果在超时窗口内没有新的请求到达,则认为会话已完成。会话结束后,结果通常会在 15 分钟内出现。结果会随着更多会话的完成而累积——统计显著性随着样本量的增加而提高。

解析结果
  • p 值 < 0.05 且呈阳性percentChange治疗明显优于对照组。考虑部署治疗方案。

  • p 值 < 0.05 且为阴性percentChange治疗明显恶化。保持控制权。

  • p 值 >= 0.05:没有足够的证据来得出差异结论。继续收集样本或增加前往治疗的流量。

  • 检查所有评估者:一种治疗可以改善一个指标,而另一个指标却倒退。在做出决定之前,请先查看所有评估者的结果。

第 9 步:确认结果并停止 A/B 测试

一旦 A/B 检验达到统计显著性,请查看结果并停止实验。

  1. 确认重要性。验证目标评估者对isSignificant: true治疗变异的检测结果是否为阳性percentChange(或者如果治疗恶化,则确认对照组是赢家)。

  2. 停止 A/B 测试。运行 agentcore stop ab-test -i <ab-test-id>。流量路由立即结束,所有请求都恢复到默认目标。请参阅查看、暂停、恢复和停止

第 10 步:部署获胜者

停止 A/B 测试后,将所有流量路由到获胜的变体。

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

promote停止 A/B 测试(如果仍在运行),更新控制端点以指向治疗版本(例如,control从版本 1 更新到版本 2),并移除治疗端点。运行agentcore deploy以应用更改。

或者,您可以通过执行以下任一操作来手动部署获胜者:

  • 选项 A:使用AgentCore 网关路由规则将流量从两个目标引导到获胜目标。

  • 选项 B:从 AgentCore 网关中移除失败的目标,并将所有流量路由到获胜者。

  • 选项 C:更新失败的目标以指向获胜端点。

后续步骤

部署获胜者后:

  • 删除 A/B 测试以清理资源。请参见删除 A/B 测试

  • 监控新基线。在线评估继续对获胜配置进行评分。注意回归。

  • 开始下一次迭代。获胜配置的新痕迹为下一个推荐周期奠定了基础。查看其工作原理

了解结果

当您调用时GetABTest,一旦聚合管道处理了足够的会话,响应就会包含一个results对象。结果包含按变体细分的每个评估者的指标。

结果结构

{ "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 } ] } ] } }

字段引用

字段 说明

analysisTimestamp

服务上次计算统计数据的时间。

evaluatorMetrics

在线评估配置中每位评估者只能输入一个条目。

controlStats.mean

所有对照会话中评估者的平均分数。

controlStats.sampleSize

对照变体的得分会话数。

variantResults[].mean

所有治疗疗程中评估者的平均分数。

variantResults[].sampleSize

该治疗变体的评分疗程数。

variantResults[].absoluteChange

治疗均值和对照均值之间的差异。

variantResults[].percentChange

相对于对照组的改善百分比(正)或回归(负)。

variantResults[].pValue

概率观测到的差异是偶然造成的。低于 0.05 表示统计学显著性。

variantResults[].confidenceInterval

绝对变化(lowerupper界限)的 95% 置信区间。

variantResults[].isSignificant

true当 p 值 < 0.05 且样本数量足够时。

问题排查

A/B 发送流量后测试未显示任何结果

结果不会立即出现。所需时间取决于在线评估配置中配置的会话超时——只有在超时窗口内没有新的请求到达后,才会认为会话已完成。会话结束后,预计将在大约 15 分钟内获得结果。

如果在此窗口之后仍未显示结果:

  • 验证在线评估日志组。在线评估配置必须指向运行时代理的输出日志组。如果在线评估配置引用了不同的日志组(或未从运行时接收跨度的日志组),则不会对会话进行评分, A/B 测试也永远不会产生结果。

  • 检查日志组名称。对于基于目标的路由,每个端点都有自己的日志组(日志组名称以终端节点名称结尾)。确保每个在线评估配置都引用了正确的端点日志组。

  • 确认运行时正在发出跨度。检查 CloudWatch 日志以了解预期的日志组。你要在每个跨度上寻找的关键属性:

    • aws.agentcore.gateway.routing_experiment_arn

    • aws.agentcore.gateway.routing_experiment_variant_name(值:CT1

    • session.id

  • 验证配置 CLI-created 与手动配置。如果您使用了agentcore add online-eval --runtime <name>,CLI 会自动配置正确的日志组。如果您通过 API 手动创建了在线评估配置,请确保 Onl AgentCore ine Eval Config dataSourceConfig.cloudWatchLogs.logGroupNames 与运行时的跨度日志组相匹配。