使用 Amazon Bedrock AgentCore 和 GitHub Actions 实现智能体自动化评估

AWS ML Blog 2026-09-10T11:50:35.202551

搭建一套持续集成与持续交付(CI/CD)的质量门禁:部署带角色权限 MCP 工具的智能体、对它进行评测,并在评测分数下降时拦截 PR。

你已经在 Amazon Bedrock AgentCore runtime 上部署了一个 AI 智能体,它通过受 OAuth 保护的 MCP 服务器调用工具。现在你希望 CI 能在代码变更导致性能变差时、在生产上线之前就发出警告。本文介绍一条 GitHub Actions 流水线,它把智能体部署到 AgentCore runtime,并借助 AgentCore Evaluate API,用评测提示词对智能体打分。如果智能体出现退化,PR 就会失败。

我们会覆盖整条技术栈:一个通过带角色权限访问控制(RBAC)连接 MCP 服务器的 Strands 智能体、一个同时服务机器对机器(M2M)和用户级授权流程的共享 Cognito 用户池、CDK 基础设施即代码,以及一套统一的评测脚本。完整的参考实现放在配套仓库里。

本文涵盖的内容

关键概念

正式开始前,先快速过一遍涉及的基础组件。如果你已经熟悉,可以直接跳过。

AgentCore runtime 是一个托管式 AI 智能体运行平台。你把智能体代码(Python,任意框架都行)部署上去,AgentCore 负责扩缩容、会话隔离和基础设施。可以把它当作「智能体版的 AWS Lambda」。

AgentCore Evaluations 是 Amazon Bedrock AgentCore 的一项能力,它用大语言模型(LLM)充当裁判,给智能体的行为打分。它读取来自 Amazon CloudWatch 的 OpenTelemetry 追踪数据,从有用性、正确性、工具选择准确度等维度给回答评分。

MCP(模型上下文协议) 是一种开放协议,智能体通过标准化接口调用外部工具。MCP 服务器对外暴露工具,智能体则去发现并调用它们。

AgentCore runtime 可以托管 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 runtime 上部署了一个智能体,它通过 MCP 服务器调用工具,其中一些是公开工具,另一些则按用户角色限制访问。每次有人修改系统提示词、更换模型或更新工具配置,你都想知道:智能体是变好了还是变差了?

手动测试无法规模化。你需要在 CI 中自动评估。这意味着:自动把智能体部署到开发环境,用有代表性的提示词调用它,给回答打分,如果质量下降就阻止合并。

麻烦在于:你的 MCP 服务器使用 OAuth,并配有基于角色的访问控制。CI 流水线没有用户上下文。面对一个受 OAuth 保护的智能体——它会把令牌转发给需要用户角色的 MCP 服务器——如何让一个无头流水线完成认证?

AgentCore Evaluations:它处在什么位置

AgentCore Evaluations 是 Amazon Bedrock AgentCore 平台中的质量测量层。它与托管智能体的 AgentCore runtime、以及负责捕获追踪数据的 AgentCore Observability 并列,共同构成「构建 → 部署 → 观测 → 评估」的完整生命周期。该服务默认使用大语言模型作为评判者(LLM-as-a-judge)来给智能体交互打分,也可以通过 AWS Lambda 选择基于代码的评估方式。

它基于 OpenTelemetry 追踪数据运行,也就是你的智能体通过 AgentCore Observability 已经发出的那些追踪数据。按需评估时,直接在 API 调用中提供 span 数据;在线评估和批量评估则从 CloudWatch 读取数据。

三种评估模式覆盖不同阶段:

评估器分为四类:

Evaluate API 接受 sessionSpans(来自 CloudWatch 的 OpenTelemetry 追踪数据),返回结构化的评分。

每次调用 evaluate() 时,传入的 span 必须来自同一个会话。混用不同会话会触发 ValidationException。这个 API 还支持通过 evaluationReferenceInputs 传入可选的基准真值(ground truth)。你可以提供 expectedResponse(供 Correctness 使用)、assertions(供 GoalSuccessRate 使用)或 expectedTrajectory(供轨迹评估器使用)。没有基准真值的 trace 会自动回退到无基准评估模式,所以只需要为你关心的那些轮次提供真值即可。

架构

这条流水线部署两个 AgentCore 运行时,共用同一个 Cognito 用户池。一个运行时跑 Strands agent,另一个跑 MCP 服务器:

架构图:Amazon Bedrock AgentCore 上运行着 Strands agent 运行时和 MCP 服务器运行时,二者位于共享的 Amazon Cognito 用户池之后,GitHub Actions 流水线负责调用 agent 并评估 trace

单个 Cognito 用户池支撑两种认证流程:

流程 授权类型 Token 内容 MCP 工具访问
M2M(CI 流水线) client_credentials 仅 scopes 所有工具(不检查角色)
用户(交互式) authorization_code Scopes + custom:roles 按角色限制的工具

GitHub Actions 流水线把 agent 栈部署到开发环境,从预置的 Cognito 实例获取 JWT token 来认证 API 调用,用评估数据集调用 agent,然后在 Amazon CloudWatch Logs 里分析生成的 trace,对照既定阈值评估性能。最后根据总分是否满足验收标准,自动批准或阻止 PR。

在 CI 中处理 OAuth 保护的 MCP 服务器

当 agent 调用受 OAuth 保护的 MCP 服务器时,CI 流水线会遇到一个难题:它没有用户上下文。MCP 服务器期望收到带角色声明的 JWT,但无头的 CI runner 无法完成交互式的 OAuth 授权同意流程。评估 agent 有三种思路,各有取舍:

方案 A:评估已存储的 trace

把评估和实时 MCP 调用彻底解耦。一条预发布流水线用有代表性的提示词运行 agent,捕获 trace,然后以 JSON fixture 的形式提交。PR 阶段,CI 直接评估这些已存储的 trace,无需实时调用。

Evaluate API 不需要运行中的智能体,它只对你提供的 OpenTelemetry 追踪数据(span)打分。这样 CI 流水线就变得确定可预期(检查已有追踪数据),也完全绕开了 OAuth 的麻烦。

代价是:你评估的是预发部署环境的行为,而不是当前 PR 里的代码。配套仓库里提供了 scripts/evaluate_stored_traces.pyfixtures/ 下的示例数据,方便你上手这种方式。

方案 B:预授权同意的服务账号

在身份提供商(IdP)中创建一个专用的测试用户。手动完成一次 OAuth 授权流程,把刷新令牌(refresh token)缓存到 AWS Secrets Manager 里。CI 就用这个令牌,以该测试用户的身份调用智能体。

代价是:刷新令牌会过期,你需要一套轮换机制,或者定期手动重新授权。

方案 C:M2M 认证(本文采用的方式)

把 MCP 服务器配置成同时支持机器对机器(M2M)授权和用户级授权。CI 使用 M2M 令牌,而交互式用户走标准的 OAuth 授权流程。

MCP 服务器的中间件会区分令牌类型:M2M 令牌里只有 scope,没有角色信息,所以角色检查会被跳过,所有工具都可访问;用户令牌则带有 custom:roles 声明(claim),因此工具级访问控制照常生效。

这种跳过是安全的,因为 M2M 令牌需要一个客户端密钥(client secret),而这个密钥从不暴露给终端用户。只有 CI 流水线和智能体运行时才能拿到这类令牌,不受信任的调用方无法获取无角色的令牌。

代价是:M2M 令牌按设计就会跳过角色检查。如果你需要让 CI 专门测试角色权限控制,那就用方案 B。

用下面的决策树判断哪种方案适合你的场景:

基于是否需要真实调用、MCP 服务器兼容性、角色测试三个维度,在方案 A、B、C 之间选择的决策树

方案 A 方案 B 方案 C
真实调用?
MCP 兼容性 所有服务器 所有服务器 需要支持双令牌认证
CI 确定性
角色测试? 否(M2M 会跳过角色检查)
最适合 快速起步 带角色控制的完整端到端测试 内部工具类智能体

小贴士:先用方案 A,快速跑起一道质量关卡。

升级到方案 C(也就是本文)可以获得完整的端到端 CI,直接测试 PR 里真实的代码改动。

前置条件

pip install boto3 requests bedrock-agentcore-starter-toolkit

注意:bedrock-agentcore-starter-toolkit 里的 Evaluation 类会自动处理 CloudWatch 的轨迹收集和打分,所以不用手动查询日志组,也不用直接调用裸的 Evaluate API。

MCP 服务器:三层鉴权

方案 C 里,MCP 服务器用三层机制来同时支持机器对机器(M2M)令牌和用户作用域令牌。这正是让 CI 评估和生产环境的角色鉴权能同时跑通的关键所在。

第一层:JWT 校验(AgentCore):请求到达你的代码之前,平台会校验签名、签发者、受众和过期时间,这部分不需要自己实现。AgentCore 通过 Custom JWT Authorizer 来完成。

第二层:请求头透传:在两个 runtime 上都设置 request_header_allowlist=["Authorization"],可以确保 JWT 能到达 agent 和 MCP 容器。AgentCore 会把调用方传来的 Authorization 头原封不动地转发给你的容器。

# infrastructure/stack.py — 在两个 CfnRuntime 构造上都要设置
request_header_configuration=CfnRuntime.RequestHeaderConfigurationProperty(

request_header_allowlist=["Authorization"]

)

第 3 层:基于角色的工具访问控制(AuthMiddleware)

这是一个 FastMCP 原生中间件,通过 fastmcp.server.dependencies.get_http_headers() 读取 JWT,用 PyJWT 解析声明(claims),再拿 custom:roles 去比对工具的 meta 信息。机器对机器(M2M)令牌只有 scope、没有角色,直接放行全部访问。用户令牌则必须带上正确的角色。这个中间件直接挂在 FastMCP 服务器实例上:

mcp.add_middleware(AuthMiddleware())

app = mcp.http_app(stateless_http=True)

基础设施:CDK 栈

CDK 栈用一条命令就能把整套环境搭起来:Cognito 用户池、两个运行时、IAM 角色,以及预先创建好的测试用户。完整实现在 infrastructure/stack.py 里。

这个栈创建的关键资源包括:

# Deploy everything

python3 -m venv .venv && source .venv/bin/activate

pip install .

npx cdk deploy --outputs-file outputs.json

GitHub Actions 工作流在开发环境中部署这个 CDK 栈,然后用创建出来的资源跑评估。

评估脚本

统一的评估脚本(scripts/agentcore_eval.py)负责整条流水线:拿令牌、等运行时就绪、调用 agent、等 trace 上报、跑评估、最后按阈值卡关。拿令牌用的是标准的 client_credentials 授权模式。

# scripts/agentcore_eval.py (key excerpt)

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

调用 Agent 走的是 HTTPS + Bearer token,而不是 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",
)

评测用的 prompt 覆盖了 Agent 会用到的全部工具,包括内置工具、公开的 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?"}
]

GitHub Actions 工作流

只要有 PR 合并到 main 分支、且改动涉及 Agent 代码、MCP server、基础设施或脚本,这个工作流就会触发。它会部署 CDK 栈、调用 Agent、运行评测、把结果以 PR 评论的形式贴出来,最后把栈拆掉。完整的实现可以看完整的 workflow 文件。关键步骤如下:

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

      # Deploy both runtimes + Cognito via CDK
      - name: CDK deploy
        run: npx cdk deploy --require-approval never --outputs-file outputs.json

id: cdk

run: |

STACK="AgentCoreCICDStack-dev"

AGENT_ARN=$(jq -r ".[\"$STACK\"].AgentRuntimeArn" outputs.json)

echo "agent_arn=$AGENT_ARN" >> "$GITHUB_OUTPUT" # ... 提取所有输出

重启运行时,加载新容器镜像并注入 M2M 密钥

run: python3 -c "..." # 带上环境变量调用 update_agent_runtime()

运行统一的评估脚本

working-directory: scripts

run: python3 agentcore_eval.py

env:

AGENT_RUNTIME_ARN: ${{ steps.cdk.outputs.agent_arn }}

EVAL_THRESHOLD: "0.8"

无论评估是否失败,都要清理资源

if: always()

run: npx cdk destroy --force

需要注意:CDK 部署命令返回后,运行时还会在 CREATING 状态停留几分钟。如果此时就调用,会因为还没进入 READY 而报 424 Failed Dependency 错误。工作流会通过 bedrock-agentcore-control 客户端轮询 get_agent_runtime,直到两个运行时都变成 READY,然后先预热 MCP 服务器,再开始评估。

CI/CD 配置

要在 CI/CD 流水线中启用自动化 agent 评估,需要先配置下面几个组件。

1. 创建 GitHub OIDC 身份提供商(只需一次)

aws iam create-open-id-connect-provider \

--url https://token.actions.githubusercontent.com \

--client-id-list sts.amazonaws.com \

--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1

2. 为 GitHub Actions 创建 IAM 角色

创建一个 IAM 角色,绑定到你仓库的信任策略,并授予 CDK、Amazon Bedrock AgentCore、Amazon Cognito、Amazon Elastic Container Registry(Amazon ECR)以及 Amazon Bedrock 的权限。完整策略见配套仓库的 README。

3. 添加 GitHub Secret

Secret Value
AWS_ROLE_ARN 上面那个 IAM 角色的 ARN

其余参数都在运行时从 CDK 输出里读取。

内置评估器参考

AgentCore 提供了多种内置评估器,按评估对象分成三类:

类别 评估器 适用场景
SESSION GoalSuccessRate 整段对话是否达成了用户的目标?
TRACE Helpfulness、Correctness、Coherence、Conciseness、Faithfulness、InstructionFollowing、ResponseRelevance、ContextRelevance、Harmfulness、Refusal、Stereotyping 单次请求的质量与安全性
TOOL_CALL ToolSelectionAccuracy、ToolParameterAccuracy、TrajectoryExactOrderMatch、TrajectoryInOrderMatch、TrajectoryAnyOrderMatch、SkillSelectionAccuracy、SkillInstructionFollowing 是否调用了正确的工具,参数是否正确?

轨迹类评估器检查工具调用顺序(需要提供 expectedTrajectory 作为基准答案)。技能类评估器检查技能选择和指令遵循情况。

本文用到四个评估器: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
──────────────────────────────────────────────────

所有评估均已通过(阈值:0.8),PR 可以合并了。

注意:用大模型当裁判打分,结果本身就有波动。同一个提示词跑两次,分数可能略有不同。所以设置阈值时,要留出一定余量,别卡得太死。

测试中的经验教训

我们完整跑了一遍这条流水线,下面这些坑提前告诉你,省得你花时间调试。

适配 Microsoft Entra ID

本文用的是 Amazon Cognito,但这套架构跟身份提供商无关。如果你的组织用的是 Microsoft Entra ID(原 Azure AD),同一条流水线只需改几个地方:

其余部分保持不变。

部署脚本里 authorizerConfiguration.customJWTAuthorizer 的结构完全一致,评估脚本不涉及认证(它通过 boto3 走 IAM),GitHub Actions 工作流的结构也没有变化。

权衡与局限

注意:尽管有这些局限,自动化评估还是明显好过完全不评估。哪怕质量门禁并不完美,也能抓到人工审查容易漏掉的明显退化。

清理资源

配套仓库会创建两个 AgentCore 运行时、一个 Cognito 用户池、若干 IAM 角色和一批预置用户。用完记得全部销毁,以免继续产生费用。一条命令就能清干净:

source .venv/bin/activate
cdk destroy --force

如果你用的是 npx 而不是全局安装的 CDK CLI,那就改成 npx aws-cdk@2 destroy --force。在 dev stack 里,cdk destroy 会一并删除两个 runtime、Cognito 用户池及其应用客户端、预创建的用户、IAM 角色,以及 AWS Secrets Manager 里的 M2M 客户端密钥。密钥的删除策略设的是 destroy,所以反复部署和拆除都不会留下垃圾。CI workflow 每次跑完也会自动拆掉同一个 stack,因为它的 CDK destroy 步骤带了 if: always()。只有你自己手动部署 stack 时,才需要自己敲上面这条命令。

核心要点

MCP 认证的三层结构(平台层 JWT 校验 → 中间件提取 claim → 工具级角色检查)把职责分得很清楚,不用改代码就能同时支持 M2M 和用户级流程。

CDK 搞定一切。 一条 cdk deploy 就能创建 Cognito 用户池、两个 runtime、IAM 角色和预创建用户;一条 cdk destroy 全部拆除。

bedrock-agentcore-starter-toolkit 简化了评估流程。 Evaluation 类自动从 CloudWatch 收集 trace 并打分,不需要手动查日志组,也不用直接调 Evaluate API 传 sessionSpans

Token 转发打通了 CI 和生产环境。 Agent 会检查传来的 JWT,判断是用户 token(转发给 MCP 做角色检查)还是 M2M token(用共享客户端,跳过角色检查)。同一套代码同时服务两种调用方。

Evaluate API 和 agent runtime 是解耦的。 评估 trace 时不需要 agent 正在运行——这是让 Approach A(使用已存储 trace)可行的关键,也是通往 CI 质量门禁的直接路径。

从四个评估器起步,再逐步扩展。 GoalSuccessRateCorrectnessToolSelectionAccuracyToolParameterAccuracy 覆盖了基本场景。面向客户的 agent 可以再加安全评估器。Ground truth 和基于代码的评估器可以进一步扩展工具箱。Trajectory 评估器是编程式的,不额外收费,特别适合 CI。基于代码的评估器能在同一次评估调用里,把确定性的 Lambda 检查和 LLM-as-judge 打分结合起来跑。

自己动手试试

配套仓库包含完整实现:用于 Cognito 和两个运行时的 CDK 基础设施、带 MCP 客户端和令牌转发的 agent、带基于角色访问控制的 MCP 服务器、统一的评估脚本、一个 GitHub Actions 工作流,以及两个演示脚本。

部署和基于角色的访问测试,用 scripts/deploy_and_test_rbac.py;评估流水线用 scripts/evaluation_pipeline.py

想扩展这个项目,可以先从方案 A 入手,直接对打包好的测试数据运行 python3 scripts/evaluate_stored_traces.py,不需要任何部署。之后再试着给 MCP 服务器加一个受角色控制的新工具(见 mcp-server/README.md),或者用你自己的 LLM 作为评判(LLM-as-judge)提示词写一个自定义评估器。也可以按环境调整 EVAL_THRESHOLD,比如开发环境用 0.7,预发环境用 0.8,生产环境用 0.9。你还可以配置在线评估,对生产环境做持续监控,或者针对自己的场景对比按需评估和在线评估。

参考资料

关于作者

Mahsa Paknezhad

Mahsa 是 AWS 生成式 AI 创新中心的机器学习工程师,博士。她专注于 MLOps 和生成式 AI,帮助各类组织设计并落地生产级 AI 系统,创造有实际价值的业务成果。她在矿业和医疗行业的项目交付上有可靠的成绩。

Shoaib Javed

Shoaib 是 AWS AgentCore 评估与优化团队的软件开发经理。他热衷解决的问题是「如何让我信任生产环境中的 AI agent」。在 Amazon,他曾带领多个团队规模扩张,构建了世界上一些最复杂的分布式系统。

Ishan Singh

Ishan 是高级……

Amazon Web Services 应用科学家,帮助客户打造创新且负责任的生成式 AI 方案与产品。Ishan 有扎实的 AI/ML 背景,专攻能带来业务价值的生成式 AI 方案。工作之外,他喜欢打排球、探索当地的骑行路线,也喜欢陪妻子和爱犬。

查看原文