将 AI Agent 评估接入 CI 流水线,AgentCore 运行时部署 MCP 服务器后自动评分,Agent 行为退化时自动 block PR。
构建一个持续集成和持续交付(CI/CD)质量门禁,部署具备基于角色 MCP 工具的 AI 智能体,在评估分数下降时阻止 Pull Request。
你在 Amazon Bedrock AgentCore 运行时上部署了一个 AI 智能体,它通过受 OAuth 保护的 MCP 服务器调用工具。现在你希望在代码变更导致性能下降时,在进入生产环境之前就能得到 CI 的反馈。
本文详细介绍一个 GitHub Actions 流水线,它将 AI 智能体部署到 AgentCore 运行时,并使用 AgentCore Evaluate API 通过评估提示词对智能体进行评估。如果智能体出现退化,PR 将失败。
我们将覆盖全栈技术:一个 Strands 智能体连接到具备基于角色访问控制的 MCP 服务器、一个同时服务于机器对机器(M2M)和用户作用域认证流程的共享 Cognito 池、CDK 基础设施即代码,以及一个统一的评估脚本。完整的参考实现可在附随的代码仓库中获取。
在深入之前,这里有一个关于构建块的快速入门。如果你已经熟悉,可以跳过。
AgentCore 运行时是一个用于托管 AI 智能体的托管平台。你部署自己的智能体代码(Python,任意框架),AgentCore 负责处理扩展、会话隔离和基础设施。可以把它想象成面向智能体的 AWS Lambda。
AgentCore Evaluations 是 Amazon Bedrock AgentCore 的一项功能,使用大型语言模型(LLM)作为评判者来对 AI 智能体行为进行评分。它读取 Amazon CloudWatch 中的 OpenTelemetry 追踪数据,并根据有用性、正确性和工具选择准确性等维度对响应进行评分。
MCP(Model Context Protocol)是一个开放协议,智能体通过标准化接口调用外部工具。MCP 服务器暴露工具,智能体发现并调用它们。AgentCore 运行时可以托管 MCP 服务器并将智能体连接到这些服务器。
OpenID Connect(OIDC)联合是 GitHub Actions 在不存储长期凭证的情况下承担 AWS Identity and Access Management(AWS IAM)角色的方式。GitHub 发布一个短期令牌,AWS 验证它,工作流获得临时凭证。
质量门禁(Quality Gate)是一种 CI/CD 模式,在构建可以继续之前,流水线步骤必须通过阈值。在我们的例子中,智能体的评估分数必须达到最低标准(例如,满分 1.0 中达到 0.8),否则 PR 保持阻止状态。
为什么这很重要:没有自动化评估,智能体质量就是主观的。开发者修改了系统提示词,智能体开始给出更差的答案,但没有人注意到,直到用户投诉。质量门禁在 PR 阶段就能捕获这个问题,防止它进入生产环境。
场景是这样的。你有一个部署在 AgentCore 运行时上的智能体。它通过 MCP 服务器调用工具,其中一些工具是公开的,另一些则按用户角色受限。每次有人修改系统提示词、切换模型或更新工具配置时,你都想知道:智能体变好了还是变差了?
手动测试无法扩展。你需要在 CI 中进行自动化评估。这意味着在开发环境中自动部署智能体、用代表性提示词调用它、对响应进行评分,如果质量下降就阻止合并。
复杂之处在于:你的 MCP 服务器使用带基于角色访问控制的 OAuth。CI 流水线没有用户上下文。如何对无头流水线进行 OAuth 保护的智能体身份验证,而该智能体会将令牌转发到期望用户角色的 MCP 服务器?
AgentCore Evaluations:它在哪里发挥作用
AgentCore Evaluations 是 Amazon Bedrock AgentCore 平台中的质量测量层。它与托管智能体的 AgentCore 运行时以及 Amazon Bedrock AgentCore 的一项功能——AgentCore Observability(捕获追踪数据)并驾齐驱,完成了构建 → 部署 → 观察 → 评估的完整生命周期。
该服务使用 LLM 作为评判者对智能体交互进行评分,默认情况下启用,也可选择通过 AWS Lambda 进行基于代码的评估。它操作 OpenTelemetry 追踪数据,即你的智能体已经通过 AgentCore Observability 发送的相同追踪数据。对于按需评估,你在 API 调用中直接提供跨度数据;在线评估和批量评估从 CloudWatch 读取。
三种评估模式覆盖不同阶段:
按需评估在任何时候评估特定的会话。你提供跨度数据、选择评估器,然后获得评分。这是为 CI/CD 质量门禁提供支持的模式,也是本文的重点。
在线评估持续监控生产流量,采样率可配置。结果流入 CloudWatch 仪表板用于趋势监控。
批量评估在单个异步作业中评分多个会话。你指向 CloudWatch Logs、选择评估器,获得汇总结果和每个会话的结果。这是为基准测量和预/后回归测试提供支持的模式。
评估器分为四类:
内置评估器涵盖常见的质量维度:Helpfulness、Correctness、GoalSuccessRate、ToolSelectionAccuracy、ToolParameterAccuracy 等。它们在会话、追踪和工具调用级别操作。三个轨迹评估器(TrajectoryExactOrderMatch、TrajectoryInOrderMatch、TrajectoryAnyOrderMatch)将实际工具调用序列与预期轨迹进行比较。
自定义评估器使用你自己的 LLM 作为评判者的提示词进行领域特定评分。真实字段(expectedResponse、assertions、expectedTrajectory)也可以作为占位符用于自定义评估器提示词。
基于代码的评估器对每个追踪或会话运行 Lambda 函数,返回由你的自定义实现计算的分数、标签和解释。用于确定性检查,如正则匹配、模式验证或关键词存在性检查,无需 LLM 成本。
第三方评估器来自 DeepEval 和 AutoEval 开源库,由服务像内置评估器一样管理。按 ID 选择,无需模型或配置。你也可以从内置或第三方评估器派生自定义评估器,在你自己的模型上运行其逻辑。
Evaluate API 接受 sessionSpans(来自 CloudWatch 的 OpenTelemetry 追踪数据)并返回结构化分数。每次 evaluate() 调用必须仅包含来自单个会话的跨度。混合会话会导致 ValidationException。
API 还通过 evaluationReferenceInputs 接受可选的真实数据。你可以提供 expectedResponse(由 Correctness 使用)、assertions(由 GoalSuccessRate 使用)或 expectedTrajectory(由轨迹评估器使用)。没有真实数据的追踪会回退到无真实数据评估,所以你只需要为你关心的轮次提供它。
该流水线在共享的 Cognito 用户池后面部署两个 AgentCore 运行时。一个用于 Strands 智能体,一个用于 MCP 服务器:
架构图显示了一个 Strands 智能体运行时和一个 MCP 服务器运行时在 Amazon Bedrock AgentCore 上,位于共享的 Amazon Cognito 用户池后面,GitHub Actions 流水线调用智能体并评估追踪数据

单个 Cognito 用户池服务于两种认证流程:
GitHub Actions 流水线将智能体栈部署到开发环境,从配置好的 Cognito 实例检索 JWT 令牌以认证 API 调用,用评估数据集调用智能体,并分析 Amazon CloudWatch Logs 中生成的追踪数据,根据定义的阈值评估性能。它根据总体分数是否达到接受标准自动批准或阻止 PR。
在 CI 中处理受 OAuth 保护的 MCP 服务器
当你的智能体调用受 OAuth 保护的 MCP 服务器时,CI 流水线面临一个挑战:它们没有用户上下文。MCP 服务器期望带有角色声明的 JWT,但无头 CI 运行器无法完成交互式 OAuth 同意流程。
评估智能体有三种方法,各有权衡:
方法 A:评估存储的追踪
完全将评估与实时 MCP 调用解耦。暂存流水线使用代表性提示词运行智能体、捕获追踪并将它们作为 JSON 固定数据提交。PR 阶段,CI 评估这些存储的追踪。不需要实时调用。
Evaluate API 不需要实时智能体。它对你提供的 OpenTelemetry 跨度进行评分。你的 CI 流水线变得确定性(检查现有追踪),你完全绕过了 OAuth 问题。
方案 A 的权衡:评估的是 staging 部署的行为,而非当前 PR 中的代码。配套仓库中包含 scripts/evaluate_stored_traces.py 和 fixtures/ 下的样本 fixture,可帮助你快速上手这种方案。
方案 B:服务账号与预授权同意
在身份提供商中创建一个专用的测试用户。完成一次 OAuth 同意流程(交互式),并将刷新令牌缓存到 AWS Secrets Manager。CI 使用该令牌以该测试用户身份调用智能体。
方案 B 的权衡:刷新令牌会过期,需要建立轮换机制或定期手动重新授权。
方案 C:M2M 认证(本文采用)
配置 MCP 服务器同时支持 M2M 和用户作用域授权类型。CI 使用 M2M 令牌,而交互用户走标准 OAuth 同意流程。
MCP 服务器中间件区分令牌类型:M2M 令牌包含 scope 但不包含角色,因此跳过角色检查,所有工具均可访问。用户令牌携带自定义 roles 声明,因此强制执行工具级访问控制。这种绕过是安全的,因为 M2M 令牌需要客户端密钥,该密钥不会暴露给最终用户。只有 CI 流水线和工作流运行时可以获取这些令牌,从而防止不可信调用者获取无角色令牌。
方案 C 的权衡:M2M 令牌按设计绕过角色检查。如果你需要 CI 具体测试角色强制执行,请使用方案 B。
使用下面的决策树找出哪种方案适合你的用例:

提示:从方案 A 开始可以快速建立质量门。升级到方案 C(本文)可获得完整端到端 CI,真正测试当前 PR 的代码变更。
pip install boto3 requests bedrock-agentcore-starter-toolkit注意:bedrock-agentcore-starter-toolkit 中的 Evaluation 类负责自动从 CloudWatch 收集 trace 并进行评分,因此你不需要手动查询日志组或调用原始 Evaluate API。
对于方案 C,MCP 服务器使用三层来同时支持 M2M 和用户作用域令牌。这是使 CI 评估与生产角色强制执行并存工作的关键模式。
第一层:JWT 验证(AgentCore):平台在请求到达你的代码之前验证签名、签发者、受众和过期时间。无需实现。AgentCore 通过自定义 JWT Authorizer 处理此过程。
第二层:请求头透传:两个运行时上的 request_header_allowlist=["Authorization"] 确保 JWT 到达智能体和 MCP 容器。AgentCore 将调用者的 Authorization 请求头原封不动地转发到你的容器。
# infrastructure/stack.py — on both CfnRuntime constructs
request_header_configuration=CfnRuntime.RequestHeaderConfigurationProperty(
request_header_allowlist=["Authorization"]
)
第三层:基于角色的工具访问(AuthMiddleware):一个 FastMCP 原生中间件,通过 fastmcp.server.dependencies.get_http_headers() 读取 JWT,使用 PyJWT 解码声明,并根据工具元数据强制执行 custom:roles。M2M 令牌(有 scope 但无 roles)获得完全访问权限。用户令牌需要具有正确的角色。
中间件直接添加到 FastMCP 服务器实例:
mcp.add_middleware(AuthMiddleware())
app = mcp.http_app(stateless_http=True)
CDK 堆栈一键部署所有资源:Cognito 用户池、两个运行时、IAM 角色和预创建的测试用户。完整实现见 infrastructure/stack.py。
堆栈创建的关键资源包括:
client_credentials 流程),供 CI 使用。authorization_code 流程),供交互使用。user-a(FinanceUser)和 user-b(HRUser)。MCP),带 JWT 授权器。HTTP),带 JWT 授权器。# 部署所有资源
python3 -m venv .venv && source .venv/bin/activate
pip install .
npx cdk deploy --outputs-file outputs.json
GitHub Actions 工作流将 CDK 堆栈部署到开发环境,并使用创建的资源运行评估。
统一的评估脚本(scripts/agentcore_eval.py)处理完整流水线:获取令牌、等待运行时、调用智能体、等待 trace、运行评估、根据阈值决定是否放行。
令牌获取使用标准的 client_credentials 授权:
# scripts/agentcore_eval.py(关键摘录)
def get_token() -> str:
"""Client-credentials grant"""
resp = http_requests.post(
os.environ["TOKEN_ENDPOINT"],
data={
"grant_type": "client_credentials",
"client_id": os.environ["OAUTH_CLIENT_ID"],
"client_secret": os.environ["OAUTH_CLIENT_SECRET"],
"scope": os.environ.get("OAUTH_SCOPE", ""),
},
)
resp.raise_for_status()
return resp.json()["access_token"]
智能体调用使用 HTTPS + Bearer 令牌(非 boto3):
def invoke_agent(agent_arn, session_id, prompt, region, token):
"""Invoke via HTTPS with Bearer token"""
escaped_arn = urllib.parse.quote(agent_arn, safe="")
url = f"https://bedrock-agentcore.{region}.amazonaws.com" \
f"/runtimes/{escaped_arn}/invocations?qualifier=DEFAULT"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": session_id,
}
resp = http_requests.post(url, headers=headers,
data=json.dumps({"prompt": prompt}))
resp.raise_for_status()
return resp.json()
脚本使用 bedrock-agentcore-starter-toolkit 的 Evaluation 类运行评估,该类自动处理从 CloudWatch 收集 trace:
from bedrock_agentcore_starter_toolkit import Evaluation
results = Evaluation(region=region).run(
agent_id=agent_id,
session_id=session_id,
evaluators=[
"Builtin.GoalSuccessRate",
"Builtin.Correctness",
"Builtin.ToolSelectionAccuracy",
"Builtin.ToolParameterAccuracy",
],
output="evals_results/ci_output.json",
)
评估提示覆盖智能体的完整工具表面,包括内置工具、公共 MCP 工具和角色限制的 MCP 工具:
[
{"prompt": "How much is 2+2?"},
{"prompt": "What is the current time in UTC?"},
{"prompt": "What is the stock price of AAPL?"},
{"prompt": "How many employees are in the engineering department?"}
]
该工作流在每次有智能体代码、MCP 服务器、基础设施或脚本变动的 PR 合并到 main 时触发。它部署 CDK 堆栈、调用智能体、运行评估、将结果作为 PR 评论发布,然后拆除堆栈。完整实现见工作流文件。
关键步骤如下:
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-southeast-2
# 通过 CDK 部署两个运行时 + Cognito
- name: CDK deploy
run: npx cdk deploy --require-approval never --outputs-file outputs.json
# 提取 CDK 输出(智能体 ARN、运行时 ID、Cognito 端点)
- name: Extract CDK outputs
id: cdk
run: |
STACK="AgentCoreCICDStack-dev"
AGENT_ARN=$(jq -r ".[\"$STACK\"].AgentRuntimeArn" outputs.json)
echo "agent_arn=$AGENT_ARN" >> "$GITHUB_OUTPUT" # ... extract all outputs
# 重启运行时以加载新容器镜像 + 注入 M2M 密钥
- name: Restart runtimes
run: python3 -c "..." # update_agent_runtime() with env vars
# 运行统一评估脚本
- name: Run evaluation
working-directory: scripts
run: python3 agentcore_eval.py
env:
AGENT_RUNTIME_ARN: ${{ steps.cdk.outputs.agent_arn }}
EVAL_THRESHOLD: "0.8"
# 始终拆除 — 即使评估失败
- name: CDK destroy
if: always()
run: npx cdk destroy --force
警告:CDK 部署返回后,运行时会在几分钟内保持 CREATING 状态,在运行时 READY 之前调用会导致 424 Failed Dependency 错误。工作流通过 bedrock-agentcore-control 客户端轮询 get_agent_runtime,直到两个运行时都为 READY 状态,然后在对评估之前先预热 MCP 服务器。
配置以下组件以在 CI/CD 流水线中激活自动化智能体评估。
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com \
--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
创建一个角色,包含针对你仓库的信任策略以及 CDK、Amazon Bedrock AgentCore、Amazon Cognito、Amazon Elastic Container Registry (Amazon ECR) 和 Amazon Bedrock 的权限。完整策略参见配套仓库的 README。
其他所有内容在运行时从 CDK 输出中读取。
内置评估器参考
AgentCore 提供多种内置评估器,按其评估维度组织:
本文使用了四个评估器:GoalSuccessRate、Correctness、ToolSelectionAccuracy 和 ToolParameterAccuracy。对于带有 MCP 工具的智能体,工具调用评估器尤其相关。它们验证智能体是否选择了正确的工具并传递了正确的参数。
提示:在 CI 中从四到五个评估器开始。为工具调用型智能体添加轨迹评估器,为面向客户的智能体添加安全评估器(Harmfulness、Stereotyping、Refusal)。使用代码型评估器进行确定性检查。在周期性深度评估中使用完整的评估器集。
测试流水线:失败、修复、通过
建立质量门信心的一种可靠方法是观察它捕获真实的回归。
故意失败:将智能体的系统提示词改为无用的内容:
# agent/src/assistant_agent.py — 故意设置的无用提示词
system_prompt="Respond to every question with exactly: 'I cannot help you.'"
推送到功能分支并打开 PR。流水线运行后你会看到:
──────────────────────────────────────────────────
Evaluator Score Result
──────────────────────────────────────────────────
Builtin.GoalSuccessRate 0.0 Failed
Builtin.Correctness 0.0 Failed
Builtin.ToolSelectionAccuracy 1.0 Passed
Builtin.ToolParameterAccuracy 0.0 Failed
──────────────────────────────────────────────────
FAILED: metrics below 0.8
注意:ToolSelectionAccuracy 可能仍然通过,因为即使系统提示词很差,智能体可能仍然选择了正确的工具。评估器独立测量不同的维度。
修复并通过:恢复正常的系统提示词,再次推送。流水线重新运行:
──────────────────────────────────────────────────
Evaluator Score Result
──────────────────────────────────────────────────
Builtin.GoalSuccessRate 1.0 Passed
Builtin.Correctness 0.9 Passed
Builtin.ToolSelectionAccuracy 1.0 Passed
Builtin.ToolParameterAccuracy 1.0 Passed
──────────────────────────────────────────────────
All evaluations PASSED (threshold: 0.8)
警告:LLM 即评判者的分数存在固有方差。因此,同一提示词评估两次可能产生略有不同的分数。在设置阈值时,要在你的目标可靠性下方留出一定余量,以应对这种方差。
我们端到端运行了这条流水线。以下是踩过的坑。把调试时间留给自己。
要调用 OAuth 保护的 AgentCore 运行时,直接使用 Bearer token POST 到 HTTPS 端点,而不是使用 boto3 中的 invoke_agent_runtime() 方法。
追踪传播需要 30-90 秒。评估脚本每 30 秒重试一次,最多等待 10 分钟。调用后不要立即查询 CloudWatch。
需要 ARM64 镜像。AgentCore 运行时需要 ARM64 容器。GitHub runner 是 x86_64。因此,使用 QEMU + Docker Buildx 进行跨平台编译。
CDK 部署后运行时需要重启。在运行时就绪之前调用会导致 424 Failed Dependency 错误,所以工作流会轮询 get_agent_runtime 直到两个运行时都就绪(并预热 MCP 服务器),然后才进行调用。
sessionSpans 是 API 参数名。Evaluate API 接受 evaluationInput: {"sessionSpans": [...]}。每次调用必须只包含来自同一会话的跨度。混合会话会导致 ValidationException。
时间戳必须是整数。OpenTelemetry 纳秒时间戳(如 startTimeUnixNano)必须是 JSON 整数,而不是带引号的字符串。字符串时间戳会导致 ValidationException。
适配 Microsoft Entra ID
本文使用 Amazon Cognito,但架构与身份提供商无关。如果你的组织使用 Microsoft Entra ID(前身是 Azure AD),同一套流水线经过针对性修改后同样适用:
Token 端点:将 Amazon Cognito 的区域端点改为 https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token。
发现 URL:改为 https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration。
客户端凭证:用 Entra ID 应用程序 ID 和作用域 URI 替换 Cognito 客户端 ID 和受众。
其他一切保持不变。部署脚本的 authorizerConfiguration.customJWTAuthorizer 结构相同,评估脚本不涉及身份验证(它通过 boto3 使用 IAM),GitHub Actions 工作流结构也未改变。
权衡与局限
流水线耗时约 10 分钟。包括 CDK 部署 + 运行时启动 + 追踪传播 + 评估。适合 PR 门控,但对 pre-commit 来说太慢。
LLM 即评判者存在固有方差。同一追踪评估两次可能产生略有不同的分数。设置阈值时要留出余量。
每次运行的成本。每个评估器调用都会调用评判模型。4 个评估器 × 5 个提示词 = 每次 PR 20 次评判调用。规模化后监控 Bedrock 成本。
M2M token 绕过角色检查。按设计,CI 需要访问所有工具。如果你需要 CI 测试角色强制执行,使用方案 B(服务账户)。
注意:尽管存在这些限制,自动化评估严格优于无评估。即使不完美的质量门也能捕获人工审查遗漏的明显回归。
配套仓库配置了两个 AgentCore 运行时、一个 C