

# 使用配置包运行 A/B 测试
<a name="ab-testing-config-bundle"></a>

如果您正在测试的更改纯粹是配置（不同的系统提示、不同的型号 ID 或不同的工具描述），请使用配置包模式。这两个变体在同一个 AgentCore 运行时上运行，配置包版本不同。 AgentCore Gateway 通过 W3C 行李标头将正确的捆绑包引用注入到每个请求中，您的代理会在运行时读取它。这意味着您需要部署一个 AgentCore 运行时配置和一个在线评估配置。

配置包 A/B 测试的关键配置：
+ 变体配置：`variantConfiguration.configurationBundle`包含捆绑包 ARN 和版本
+ 评估配置：单一共享 `onlineEvaluationConfigArn` 

如果您正在测试的更改涉及代码更改、框架升级或完全不同的代理实现，请改用基于目标的路由。请参见使用[基于目标的路由进行 A/B 测试](ab-testing-target-based.md)。

本演练以客户支持代理为例。代理负责处理订单查询、退货和折扣请求。您将部署代理，创建两个具有不同系统提示（控制和处理）的配置包，创建 A/B 测试，发送流量，查看结果，然后部署获胜者。

## 步骤 1：创建项目
<a name="config-bundle-create-project"></a>

使用 AgentCore CLI 创建项目：

```
agentcore create --name ABTestConfigBased --no-agent
cd ABTestConfigBased
```

## 第 2 步：添加运行时
<a name="config-bundle-add-runtime"></a>

添加代理运行时：

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

项目结构：

```
ABTestConfigBased/
├── agentcore/
│   ├── agentcore.json      # Project and resource configuration
│   ├── aws-targets.json    # Deployment target (account and region)
│   └── cdk/                # CDK infrastructure (auto-managed)
└── app/
    └── csAgent/
        ├── main.py         # Agent entrypoint
        └── pyproject.toml  # Python dependencies
```

## 步骤 3：更新代理代码并部署
<a name="config-bundle-agent-code"></a>

`app/csAgent/main.py`替换为以下内容。关键的补充是在运行时读取活动配置包的`BeforeModelCallEvent`挂钩：

```
"""Customer support agent with configuration bundle integration."""
from strands import Agent, tool
from strands.models.bedrock import BedrockModel
from strands.hooks.events import BeforeModelCallEvent
from bedrock_agentcore.runtime import BedrockAgentCoreApp, BedrockAgentCoreContext

app = BedrockAgentCoreApp()
DEFAULT_MODEL_ID = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
DEFAULT_SYSTEM_PROMPT = "You are a helpful customer support assistant."


@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}."


def dynamic_config_hook(event: BeforeModelCallEvent):
    """Read config bundle and apply system prompt before every model call."""
    config = BedrockAgentCoreContext.get_config_bundle()
    event.agent.system_prompt = config.get("system_prompt", DEFAULT_SYSTEM_PROMPT)


agent = Agent(
    model=BedrockModel(model_id=DEFAULT_MODEL_ID),
    tools=[lookup_order, initiate_return, apply_discount],
    system_prompt=DEFAULT_SYSTEM_PROMPT,
)
agent.hooks.add_callback(BeforeModelCallEvent, dynamic_config_hook)


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

将客户支持代理部署到 AgentCore Runtime：

```
agentcore deploy
```

部署后，记下输出中的运行时 ARN（例如）。`arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/csAgent-abc123`您将需要它来创建配置包。

验证代理是否正在运行：

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

`BeforeModelCallEvent`挂钩在每次 LLM 调用之前触发，从请求上下文中读取活动配置包。在 A/B 测试期间， AgentCore Gateway 会将每个会话分配给一个变体，并通过 W3C 行李标头传播相应的捆绑包引用。运行时通过使其可用`BedrockAgentCoreContext`，因此控制会话接收捆绑包 v1，治疗会话接收捆绑包 v2 — 代理会应用它收到的捆绑包中的任何系统提示。

有关更多详细信息，请参阅[在运行时使用配置包](configuration-bundles-runtime.md)。

## 步骤 4：创建配置包
<a name="config-bundle-create-bundles"></a>

创建两个配置包 — 一个用于控制（当前提示），另一个用于治疗（优化提示）。 A/B 测试将在这些提示之间分配流量，以衡量哪个提示会产生更好的评估者分数。

控制包 — 当前系统提示符：

```
agentcore add config-bundle \
  --name customerSupportControl \
  --components '{
    "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/csAgent-abc123": {
      "configuration": {
        "system_prompt": "You are a helpful customer support assistant for Acme Store."
      }
    }
  }'

agentcore deploy
```

治疗包 — 一种经过优化的系统提示，可指示代理更加积极主动：

```
agentcore add config-bundle \
  --name customerSupportTreatment \
  --components '{
    "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/csAgent-abc123": {
      "configuration": {
        "system_prompt": "You are a customer support assistant for Acme Store. Be proactive: check order status before the customer asks, offer discounts for delayed orders, and summarize actions taken at the end of each response."
      }
    }
  }'

agentcore deploy
```

每次部署后，请记下输出中的捆绑包 ARN 和版本 ID，创建测试时将需要这些。 A/B 

## 步骤 5：创建在线评估配置
<a name="config-bundle-online-eval"></a>

 A/B 测试需要在线评估配置才能对两种变体的会话进行评分。在线评估让评估人员根据实时流量进行评估，并将分数提供给 A/B 测试的统计引擎。

对于配置包变体，请创建一个用于监控共享 AgentCore 运行时的在线评估配置：

```
agentcore add online-eval \
  --name customerSupportEval \
  --runtime csAgent \
  --evaluator "Builtin.Helpfulness" \
  --sampling-rate 100.0 \
  --enable-on-create

agentcore deploy
```

部署后，请记下输出中的在线评估配置 ARN，创建测试时将需要它。 A/B 

**提示**  
`--sampling-rate 100.0`在 A/B 测试期间进行设置，以便对每个会话进行评估，结果更快地达到统计学意义。您可以在测试结束后降低费率。

有关评估器选项和配置的更多详细信息，请参阅[创建在线评估](create-online-evaluations.md)。

## 步骤 6：创建网关和目标
<a name="config-bundle-create-gateway"></a>

config-bundle A/B 测试通过 AgentCore 网关路由流量，因此在开始测试之前，必须已经部署了网关及其目标。添加以运行时为`http-runtime`目标的网关，然后部署：

```
agentcore add gateway --name csGateway

agentcore add gateway-target \
  --name customer-support \
  --gateway csGateway \
  --type http-runtime \
  --runtime csAgent

agentcore deploy
```

## 步骤 7：创建 A/B 测试
<a name="config-bundle-create-test"></a>

创建在控制提示和治疗提示 80/20 之间分配流量的 A/B 测试。这两个变体都引用同一 AgentCore Runtime 上的配置包，并共享一个用于评分的在线评估配置。

**Example**  

```
agentcore run ab-test \
  --mode config-bundle \
  --name customerSupportPromptTest \
  --gateway csGateway \
  --runtime csAgent \
  --control-bundle customerSupportControl \
  --control-version <control-bundle-version-id> \
  --treatment-bundle customerSupportTreatment \
  --treatment-version <treatment-bundle-version-id> \
  --online-eval customerSupportEval \
  --control-weight 80 \
  --treatment-weight 20
```
 `agentcore run ab-test`在服务上启动 A/B 测试作业。命令返回后，测试即在运行。传球`--disable-on-create`来创建它已停止。要查看作业`agentcore view ab-test <id>`，请运行或查看 JSON 下的作业`.cli/jobs/ab-tests/`。该`--gateway`标志为必填项，并且必须引用您在步骤 6 中部署的网关。每个网关一次只能运行一个测试。该命令会打印测试的作业 ID，也可以从`id`字段中`--json`获得。以下生命周期命令需要此 ID。  
`--control-version`和`--treatment-version`值是在步骤 3 中部署配置包时返回的版本 ID。

```
import boto3
import uuid

client = boto3.client("bedrock-agentcore", region_name="us-west-2")

response = client.create_ab_test(
    name="customerSupportPromptTest",
    gatewayArn="arn:aws:bedrock-agentcore:us-west-2:123456789012:gateway/gw-abc123",
    roleArn="arn:aws:iam::123456789012:role/ABTestRole",
    evaluationConfig={
        "onlineEvaluationConfigArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:online-evaluation-config/eval-abc123"
    },
    variants=[
        {
            "name": "C",
            "weight": 80,
            "variantConfiguration": {
                "configurationBundle": {
                    "bundleArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:configuration-bundle/customerSupportControl-Ab1Cd2Ef3G",
                    "bundleVersion": "12345678-1234-1234-1234-123456789012"
                }
            }
        },
        {
            "name": "T1",
            "weight": 20,
            "variantConfiguration": {
                "configurationBundle": {
                    "bundleArn": "arn:aws:bedrock-agentcore:us-west-2:123456789012:configuration-bundle/customerSupportTreatment-Ab1Cd2Ef3G",
                    "bundleVersion": "12345678-1234-5678-9abc-123456789012"
                }
            }
        }
    ],
    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']}")
```

## 步骤 8：通过 AgentCore 网关发送流量
<a name="config-bundle-send-traffic"></a>

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

### 变体赋值的工作原理
<a name="_how_variant_assignment_works"></a>

 AgentCore Gateway 使用`X-Amzn-Bedrock-AgentCore-Runtime-Session-Id`标头来确定要提供哪种配置包变体。此标头是**可选**的，如果您不提供该标头，则运行时会自动生成会话 ID。然后， AgentCore 网关使用会话 ID（无论是您提供的，还是运行时生成的），根据您配置的流量权重将请求分配给变体。

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

### 生成用于测试的流量
<a name="_generate_traffic_for_testing"></a>

将以下脚本另存为 `loadgen.sh``<gateway-id>`，`<target-name>`用部署输出中的值替换和：

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

## 第 9 步：获取结果
<a name="config-bundle-get-results"></a>

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

**Example**  
获取当前结果（`<ab-test-id>`替换为步骤 6 中的任务 ID）：  

```
agentcore view ab-test <ab-test-id>
```
以 JSON 格式获取结果：  

```
agentcore view ab-test <ab-test-id> --json
```
在结果达到统计意义之前进行民意调查：  

```
import boto3
import time

client = boto3.client("bedrock-agentcore", region_name="us-west-2")

ab_test_id = "customerSupportPromptTest-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：**没有足够的证据来得出差异结论。继续收集样本或增加前往治疗的流量。
+  **检查所有评估者：**一种治疗可以改善一个指标，而另一个指标却倒退。在做出决定之前，请查看所有评估者的结果。

有关结果结构和字段定义的详细说明，请参阅基于目标的路由指南中的[了解结果](ab-testing-target-based.md#target-based-results-shape)。

## 第 10 步：确认结果并停止 A/B 测试
<a name="config-bundle-confirm-stop"></a>

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

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

1.  **停止 A/B 测试。**运行 `agentcore stop ab-test -i <ab-test-id>`。流量路由立即结束，所有请求都恢复为默认配置。请参阅[查看、暂停、恢复和停止](ab-testing-manage.md#manage-ab-test-start-stop)。

## 第 11 步：部署获胜者
<a name="config-bundle-deploy-winner"></a>

停止 A/B 测试后，将所有流量路由到获胜的配置包版本。

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

 `promote`停止 A/B 测试（如果仍在运行）并更新控制配置包以使用治疗版本。运行`agentcore deploy`以应用更改。

或者，您可以通过执行以下任一操作来手动部署获胜者：
+  **选项 A：**使用[AgentCore 网关路由规则路由](gateway-rules.md)获胜配置包版本的所有流量。
+  **选项 B：**更新控制配置包以使用获胜的系统提示符并重新部署。
+  **选项 C：**在代理代码中将获胜的捆绑包版本设置为默认版本，然后删除 A/B 测试配置。

部署获胜者后：
+  **删除 A/B 测试以**清理资源。请参阅[删除 A/B 测试](ab-testing-manage.md#manage-ab-test-remove)。
+  **监控新基线。**在线评估继续对获胜配置进行评分。注意回归。
+  **开始下一次迭代。**获胜配置的新痕迹为下一个推荐周期奠定了基础。查看[其工作原理](optimization-how-it-works.md)。

## 示例： A/B 测试工具描述
<a name="config-bundle-tool-description-example"></a>

您可以使用相同的配置包模式来测试优化的工具描述。与代理直接读取捆绑包的系统提示 A/B 测试不同，工具描述覆盖由 AgentCore 网关应用。当代理`tools/list`通过网关调用时，网关会读取配置包并返回应用替代项的工具描述。无需更改代理代码。

有关网关如何应用工具描述覆盖的详细信息，请参阅 [MCP 目标上的行为](gateway-rules-propagation.md#gateway-rules-propagation-mcp)。

### 配置捆绑包
<a name="_configuration_bundles"></a>

控制包-当前工具描述：

```
agentcore add config-bundle \
  --name toolDescControl \
  --components '{
    "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/csAgent-abc123": {
      "configuration": {
        "tools": {
          "lookup_order": {
            "description": "Look up an order by ID."
          },
          "initiate_return": {
            "description": "Initiate a return for an order."
          },
          "apply_discount": {
            "description": "Apply a discount to an order."
          }
        }
      }
    }
  }'

agentcore deploy
```

治疗套装 — 根据建议对工具描述进行了优化：

```
agentcore add config-bundle \
  --name toolDescTreatment \
  --components '{
    "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/csAgent-abc123": {
      "configuration": {
        "tools": {
          "lookup_order": {
            "description": "Look up order details including status, item, and total by order ID. Use when the customer asks about an order or references an order number."
          },
          "initiate_return": {
            "description": "Start a return process for an order. Use only when the customer explicitly requests a return or exchange, not for order status inquiries."
          },
          "apply_discount": {
            "description": "Apply a percentage discount to an order. Use when compensating for service issues such as delivery delays. Requires a reason."
          }
        }
      }
    }
  }'

agentcore deploy
```

### 工作原理
<a name="_how_it_works"></a>

1. 当代理`tools/list`通过网关（MCP 目标）呼叫时， A/B 测试会将每个会话分配给网关上的变体（控制或处理），并解析相应的配置包。

1. Gateway 读取配置包并返回应用替代项的工具描述。

1. 代理使用返回的描述进行工具选择，无需更改代理代码。

### 创建 A/B 测试
<a name="_create_the_ab_test"></a>

```
agentcore run ab-test \
  --mode config-bundle \
  --name toolDescTest \
  --gateway csGateway \
  --runtime csAgent \
  --control-bundle toolDescControl \
  --control-version <control-bundle-version-id> \
  --treatment-bundle toolDescTreatment \
  --treatment-version <treatment-bundle-version-id> \
  --online-eval customerSupportEval \
  --control-weight 80 \
  --treatment-weight 20
```

其余步骤（发送流量、获取结果、部署获胜者）与前面的系统提示示例相同。

## 问题排查
<a name="config-bundle-troubleshooting"></a>

要对 A/B 测试问题（例如发送流量后缺少结果）进行故障排除，请参阅基于目标的路由指南中的[故障排除](ab-testing-target-based.md#target-based-troubleshooting)。