AWS 介绍如何在 Amazon Bedrock AgentCore 网关中按用户和目标实施请求数、Token 数及连接数限制。限流范围可依据 JWT 声明或 IAM 身份划分,用于保护下游模型、工具和 Agent。
Amazon Bedrock AgentCore gateway 是一种完全托管的无服务器 AI 网关,为 AI 流量提供统一且安全的入口。AgentCore gateway 可将流量路由到托管式 Web 搜索、托管式知识库、MCP 服务器、推理模型(LLM)、智能体(A2A、作为工具的智能体等)或 HTTP 端点。今天,我们宣布 AgentCore gateway 开始支持速率限制,让你能够精细控制各个用户可通过网关使用的流量。
AgentCore gateway 中的速率限制让你能够按用户控制工具、推理模型和智能体的使用情况。你可以基于 OAuth 或 IAM,为每分钟请求数、并发连接数和令牌吞吐量定义规则,从而确保下游服务在流量激增时仍然可用。
AgentCore gateway 提供三种目标类型:MCP 目标、推理目标和 HTTP 直通目标。这些目标支持以下速率限制指标。
请求速率限制以每秒请求数(RPS)和每分钟请求数(RPM)衡量,适用于所有目标类型。每项限制都定义了指定时间窗口内允许的最大请求数,网关会依据该限制衡量每个传入请求。无论请求需要多长时间才能完成,每个请求都只计为一个单位;一个在 50 毫秒内完成的请求和一个持续流式传输 90 秒的请求,在每秒或每分钟限制中都恰好消耗一个单位。
令牌速率限制以每分钟令牌数(TPM)衡量,仅适用于推理目标。令牌速率限制同时计算输入令牌和输出令牌。请求完整往返过程中的令牌开销都会计入限制。AgentCore gateway 使用通用分词器估算请求的传入令牌数,并在网关发出推理调用之前,预先从速率限制桶中扣除相应额度。推理调用返回响应后,响应中会包含模型提供商报告的实际输入和输出令牌用量,网关将根据真实的令牌消耗量对限制额度进行校准。
连接速率限制以每秒连接数(CPS)衡量,适用于所有目标类型。与请求速率限制不同,连接速率限制会跟踪每个请求保持连接打开的时长。例如,如果一次流式推理调用需要 100 秒才能完成,该请求将在整个持续期间占用一个连接槽位。当你需要限制目标能够维持的同时连接数,而不是限制每个时间窗口内到达的请求数时,CPS 提供了一种额外的目标保护机制,尤其适合防范长期存续的并发会话。
对于此用例,假设存在三个用户组:Basic、Advanced 和 Beta。AgentCore Identity 使用 JSON Web Token(JWT)处理入站身份验证,以 Microsoft Entra ID 作为身份提供商,同时还充当出站目标的令牌分发服务。Amazon Bedrock AgentCore 中的 Policy 会实施基于角色的访问控制(RBAC),将每个用户组的访问范围限定到特定目标和模型。下图展示了这一配置。
图 1:包含用户组、身份验证和策略执行的 AgentCore gateway 速率限制架构
Basic 用户受到的速率限制比 Advanced 用户更严格,而 Beta 用户对受限模型拥有更高的限制额度,使组织能够在将这些模型推广到更广泛的组织范围之前,对其性能和适用性进行基准测试。在为各个用户组设置速率限制之前,请先了解速率限制的结构。
速率限制配置由两部分组成:维度键和条目。维度键定义网关如何将传入流量划分到不同的速率桶中。条目定义每个桶允许的吞吐量。
在本文中,我们使用 AWS Command Line Interface(AWS CLI)创建速率限制配置。以下示例展示了维度键与条目之间的关系。此速率限制使用 targetName 作为维度键,并定义两个条目:一个是针对高流量目标 Booking(MCP 服务器)的特定条目,限制为每秒 100 个请求;另一个是通配符条目,分别对其余每个目标应用每秒 10 个请求的限制,这意味着其他每个目标都会获得各自独立的 10 RPS 速率桶。
图 2:包含维度键和条目的速率限制结构
维度键定义网关如何将流量划分到速率桶中。当请求到达时,网关会从请求上下文中解析每个维度键对应的值,并使用生成的值组合将请求分配到正确的速率桶。AgentCore gateway 支持以下维度键:targetName、toolName、qualifiedModelId、$.context.jwt.<claim>、$.context.iam.principal 和 $.context.iam.sourceIdentity。在后续章节中,我们将通过示例逐一介绍这些维度键。
条目是速率限制中的规则。每个条目指定一组需要匹配的维度键,以及该匹配项允许的吞吐量。条目支持特殊的全匹配默认值 *,它会按配置的速率为每个不同的值提供各自独立的速率桶。当网关评估请求时,会先检查是否存在按名称匹配的条目,然后再回退到通配符。具名条目具有更高优先级,因为它显式引用了对应的值,而不是依赖全匹配规则。
仍以前面的速率限制为例,当针对 Booking 目标(MCP 服务器)的请求到达时,网关会匹配第一个条目,并允许最高 100 RPS。由于最具体的值匹配优先于默认值 *,且该条目通过名称明确引用了 Booking 目标,因此它具有更高优先级。对于其他任何目标,因为不存在具名条目,所以网关会回退到通配符条目,并允许每秒最多 10 个请求。每个与通配符匹配的目标(Docs、BedrockMantle、CustomPlatform 和 awsdocsagent)都会获得各自独立的速率桶。
你可以组合多个维度键,以实现更细粒度的控制。例如,dimensionKeys: [“targetName”, “$.context.jwt.role”] 会同时按目标和调用方身份的角色声明对流量进行分组,使每个用户组(即前述示例中的 Basic、Advanced 或 Beta)在每个目标上都拥有各自独立的速率桶。
AgentCore gateway 实施两层速率限制:客户定义的速率限制和 Service Quotas。系统会先评估客户定义的速率限制。如果请求通过,再评估服务配额。以下各节将说明服务配额以及不同类型的客户定义速率限制。
这些是服务按 AWS 账户对 AgentCore gateway 实施的限制。服务托管配额定义了客户所定义的速率限制不能超过的上限。请求的实际生效速率取客户定义限制与服务托管限制中的较小值。你可以使用 Service Quotas 控制台申请提高部分配额。
用户级限制使用 $.context.jwt.<claim>、$.context.iam.principal 和 $.context.iam.sourceIdentity 作为维度键,控制单个用户或整个用户组可以使用多少流量。这些限制能够确保所有调用方得到公平使用,并防止任何单一调用方独占网关容量。以下示例为不同用户组分配了不同的请求速率。JWT role 声明是一个数组,因此每种唯一组合都需要对应的条目。
aws bedrock-agentcore-control create-gateway-rate-limit \
--gateway-identifier my-gateway-abc1234567 \
--dimension-keys '["$.context.jwt.role"]' \
--description "Per-role request and connection limit" \
--entries '[
{
"dimensions": {"$.context.jwt.role": "[\"Basic\"]"},
"requests": [{"rate": 100, "period": "minute"}],
"connections": [{"rate": 50, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\"]"},
"requests": [{"rate": 300, "period": "minute"}],
"connections": [{"rate": 150, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\", \"Beta\"]"},
"requests": [{"rate": 300, "period": "minute"}],
"connections": [{"rate": 200, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "*"},
"requests": [{"rate": 80, "period": "minute"}],
"connections": [{"rate": 10, "period": "second"}]
}
]'
在此配置中,Basic 用户获得两个桶:100 RPM 和 50 CPS。这意味着,任何 Basic 用户的每个请求都会计入同一个 100 RPM 总限额,每个连接都会计入同一个 50 CPS 总限额。如果一名 Basic 用户在一分钟内发送了 80 个请求,那么在该时间窗口内,留给其他所有 Basic 用户的请求额度就只剩 20 个。Advanced 用户拥有自己的两个桶,限额分别为 300 RPM 和 150 CPS,并遵循相同的共享机制。同时属于 [“Advanced”, “Beta”] 组的用户拥有两个桶,限额分别为 300 RPM 和 200 CPS。更高的连接限额可以满足他们以流式传输为主的基准测试工作负载。
然而,在同一个组内,单个用户仍然可能耗尽整个组的速率桶,从而导致该组中的其他所有用户都受到限流。例如,一名 Basic 用户在一分钟内发送 100 个请求,就会使其他所有 Basic 用户的可用容量降为零。为避免这种情况,我们还创建以下速率限制配置。
aws bedrock-agentcore-control create-gateway-rate-limit \
--gateway-identifier my-gateway-abc1234567 \
--dimension-keys '["$.context.jwt.role", "$.context.jwt.sub"]' \
--description "Per-user request and connection limit within each role" \
--entries '[
{
"dimensions": {"$.context.jwt.role": "[\"Basic\"]", "$.context.jwt.sub": "*"},
"requests": [{"rate": 20, "period": "minute"}],
"connections": [{"rate": 10, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\"]", "$.context.jwt.sub": "*"},
"requests": [{"rate": 60, "period": "minute"}],
"connections": [{"rate": 30, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\", \"Beta\"]", "$.context.jwt.sub": "*"},
"requests": [{"rate": 60, "period": "minute"}],
"connections": [{"rate": 50, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "*", "$.context.jwt.sub": "*"},
"requests": [{"rate": 20, "period": "minute"}],
"connections": [{"rate": 20, "period": "second"}]
}
]'
通过此配置,无论一个组中有多少用户,每位用户都会受到各自独立速率的限制。JWT 中的 $.context.jwt.sub 声明可以唯一标识每位用户,使网关能够在单个用户层面跟踪并实施限制。即使组级限制允许 Basic 用户合计使用 100 RPM,任何单个用户从该共享池中消耗的额度也不能超过 20 RPM 和 10 CPS。同样的逻辑也适用于 Advanced 和 Beta 用户,并按照各自的个人上限执行。组级限制和用户级限制共同构成了双层执行模型:组级上限有助于防止一个组挤占其他组的容量,用户级上限则有助于防止某个用户挤占同组其他用户的容量。
两个速率限制使用 AND 语义独立求值。请求必须同时通过组级限制和用户级限制才能继续处理。如果任一检查拒绝请求,网关就会返回限流响应。例如,如果 Arnav(Basic)个人已经用完 20 RPM,那么即使 Basic 组仍有 80 RPM 的剩余容量,他的下一个请求也会被用户级限制拒绝。相反,如果 Basic 组整体已经用完 100 RPM,那么无论每位 Basic 用户各自使用了多少额度,所有 Basic 用户都会受到限流。
客户定义的目标级限制。
目标级限制使用 targetName、qualifiedModelId 或 toolName 作为维度键,以控制发往特定下游目标、模型或工具的吞吐量。这些限制可以保护后端容量,并在各目标资源之间分配负载。以下示例按目标限制流量。
aws bedrock-agentcore-control create-gateway-rate-limit \
--gateway-identifier my-gateway-abc1234567 \
--dimension-keys '["targetName"]' \
--description "Per-target rate limit" \
--entries '[
{
"dimensions": {"targetName": "Booking"},
"requests": [{"rate": 20, "period": "second"}]
},
{
"dimensions": {"targetName": "Docs"},
"requests": [{"rate": 15, "period": "second"}]
},
{
"dimensions": {"targetName": "awsdocsagent"},
"requests": [{"rate": 10, "period": "second"}],
"connections": [{"rate": 60, "period": "second"}]
},
{
"dimensions": {"targetName": "BedrockMantle"},
"tokens": [{"rate": 100000, "period": "minute"}],
"connections": [{"rate": 250, "period": "second"}]
},
{
"dimensions": {"targetName": "CustomPlatform"},
"tokens": [{"rate": 50000, "period": "minute"}],
"connections": [{"rate": 100, "period": "second"}]
},
{
"dimensions": {"targetName": "*"},
"tokens": [{"rate": 10000, "period": "minute"}],
"requests": [{"rate": 10, "period": "second"}],
"connections": [{"rate": 50, "period": "second"}]
}
]'
你还可以使用 qualifiedModelId 为每个模型设置连接速率限制(CPS),或者使用 toolName 为每个工具设置请求速率限制(RPS),例如 Booking___bookTool 或 Docs___searchDocsTool。
注意:我们的用例配置中不包含客户定义的目标级速率限制。Beta 用户会针对受限模型运行高负载的基准测试工作负载,从而消耗共享目标级限额中远高于其他用户的份额。由于此限制仅以 targetName 作为维度,因此所有用户共享同一个上限,这意味着来自某个组或个人的大量流量可能会挤占该目标上其他所有用户的容量。如果预计一部分用户会在特定目标上占用大部分 token 或连接资源,请改为按身份划定限制范围,例如 [“targetName”, “$.context.jwt.role”]。请参阅以下示例。
客户定义的目标—用户级限制。
混合限制将目标维度和用户维度组合在同一份速率限制配置中,为你提供最精细的控制能力。通过使用多维度键,你可以将速率限制限定到特定目标、模型或工具上的某个特定用户或用户组。
以下示例在模型级别实施 token 限制,并将其限定到各个组中的每位用户。qualifiedModelId 维度是推理目标的完全限定模型标识符,用于唯一标识正在调用的模型(请参阅文档)。
aws bedrock-agentcore-control create-gateway-rate-limit \
--gateway-identifier my-gateway-abc1234567 \
--dimension-keys '["$.context.jwt.role", "qualifiedModelId", "$.context.jwt.sub"]' \
--description "Per-user per-role per-model TPM and access limit" \
--entries '[
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\", \"Beta\"]", "qualifiedModelId": "anthropic.claude-fable-5", "$.context.jwt.sub": "*"},
"tokens": [{"rate": 80000, "period": "minute"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Basic\"]", "qualifiedModelId": "anthropic.claude-fable-5", "$.context.jwt.sub": "*"},
"requests": [{"rate": 0, "period": "second"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\"]", "qualifiedModelId": "anthropic.claude-fable-5", "$.context.jwt.sub": "*"},
"requests": [{"rate": 0, "period": "second"}]
},
... (repeat for openai.gpt-5.6-luna and openai.gpt-5.6-terra)
{
"dimensions": {"$.context.jwt.role": "[\"Advanced\"]", "qualifiedModelId": "*", "$.context.jwt.sub": "*"},
"tokens": [{"rate": 40000, "period": "minute"}]
},
{
"dimensions": {"$.context.jwt.role": "[\"Basic\"]", "qualifiedModelId": "*", "$.context.jwt.sub": "*"},
"tokens": [{"rate": 20000, "period": "minute"}]
}
]'
在此配置中,anthropic.claude-fable-5 是一个受限模型。只有拥有 [“Advanced”, “Beta”] 角色的用户才能调用该模型,并且每位用户可获得 80,000 TPM,用于基准测试和评估工作负载。[“Basic”] 和 [“Advanced”] 用户调用此模型时都会被零速率限制阻止*。相同的模式也适用于其他受限模型(openai.gpt-5.6-luna 和 openai.gpt-5.6-terra),请务必为每个模型添加遵循相同结构的条目。对于普遍可用的模型,通过通配符条目,Basic 用户每人可获得 20,000 TPM,Advanced 用户每人可获得 40,000 TPM。
具体条目遵循“最具体匹配优先”规则,优先级高于通配符。当 María(sub:“María”,role:[“Advanced”, “Beta”])调用 anthropic.claude-fable-5 时,网关会匹配显式条目,并对 María 个人应用 80,000 TPM 的限制。如果 María 耗尽了 80,000 TPM 限额,其他 Beta 用户不会受到影响,因为 $.context.jwt.sub 上的 * 会为每位用户提供各自隔离的桶。当 John(sub:“John”,role:[“Advanced”])尝试调用 anthropic.claude-fable-5 时,网关会匹配该模型的显式 [“Advanced”] 条目,该条目将请求数设置为零,从而阻止此次调用。当 John 调用 anthropic.claude-sonnet-5 之类的正式可用模型时,由于不存在针对该模型与角色组合的显式条目,网关会继续匹配 [“Advanced”] 的通配符条目,并应用 40,000 TPM。当 Arnav(sub:“Arnav”,role:[“Basic”])调用同一个正式可用模型时,他会通过 Basic 通配符条目获得 40,000 TPM。
你还可以组合不同维度,例如使用 [“$.context.jwt.role”, “targetName”] 设置按角色、按目标划分的请求限制,使用 [“$.context.jwt.sub”, “targetName”] 设置按用户、按目标划分的请求和令牌组合限制,或者使用 [“$.context.jwt.role”, “toolName”] 设置按角色、按工具划分的请求限制。有关更多速率限制配置,请参阅速率限制 API 示例。
请考虑以下 AgentCore 网关配置,其中用户调用 AWS Documentation Agent。该智能体通过网关使用两个下游资源:用于文档搜索和检索的 Docs MCP 目标,以及通过 anthropic.claude-sonnet-5 模型进行推理的 BedrockMantle 推理目标。以下架构展示了这一过程:
图 3:具有下游资源消耗的 AI 智能体工作负载速率限制
对于 AI 智能体工作负载,需要考虑两类速率限制:
第一类用于限制用户或其他服务调用智能体的频率。这些是作用域限定到智能体目标本身的请求(RPM)和连接(CPS)限制。最简单的方式是仅使用 targetName 作为维度,例如 {“targetName”: “awsdocsagent”},这样所有用户将共享同一个调用上限。若要进行更精细的控制,可以将 targetName 与用户维度配对,例如 [“targetName”, “$.context.jwt.role”] 或 [“targetName”, “$.context.jwt.role”, “$.context.jwt.sub”],以限制每个用户组或每位用户调用智能体的频率。
第二类用于保护智能体每次调用时所消耗的下游资源。AWS Documentation Agent 会触发多个下游请求。该智能体会调用 Docs MCP 目标检索文档,并调用 BedrockMantle 目标进行推理。如何对这些下游调用实施速率限制,取决于智能体在调用这些资源时如何向网关进行身份验证。
如果智能体基于用户传入的 JWT 令牌执行代表用户(OBO)令牌交换,则下游请求会携带原始用户的身份。所有现有的基于用户的速率限制都会生效。你之前配置的按角色和按用户限制,将应用于智能体的下游调用,就像这些调用由用户直接发起一样。
但是,如果智能体通过机器到机器授权获取新令牌(例如客户端凭证流程),下游请求携带的将是智能体自身的身份,而不是调用者的身份。在这种情况下,基于用户的速率限制将无法匹配用户的声明。你应该根据身份提供商添加能够识别智能体本身的速率限制,使用可以唯一标识智能体的声明(例如 $.context.jwt.azp,即授权方),并据此实施限制,防止单个智能体耗尽共享资源。
使用 AgentCore 网关创建速率限制时,请遵循以下最佳实践:
如果你正在使用 AgentCore 中的 Policy 强制实施 RBAC 授权,理解求值顺序非常重要。系统会先应用速率限制,之后才对 AgentCore Policy 求值。这意味着,即使某个用户或角色最终被 AgentCore Policy 拒绝访问,其请求仍会在被拒绝之前消耗速率限制桶中的配额。为避免这种消耗,请创建一个速率限制条目,明确将 AgentCore Policy 会阻止的用户或组的速率设为零。这样可以确保请求在速率限制层被拒绝,而不会消耗授权调用者可用的预算。
网关会优先对包含更多维度键的速率限制进行求值(更具体的限制具有更高优先级)。当维度数量相同时,网关会优先对速率更严格(更低)的限制进行求值。一旦首次拒绝请求,求值便会短路,这意味着请求被拒绝后,网关不会再对剩余的速率限制进行求值。设计速率限制配置时,应将最严格的限制放在维度数量最多的层级上(例如三键限制 [“$.context.jwt.role”,“qualifiedModelId”,“$.context.jwt.sub”])。
不能创建维度键相同但顺序不同的两个速率限制。例如,不能在同一个网关上分别使用 [“$.context.jwt.role”, “qualifiedModelId”, “$.context.jwt.sub”] 和 [“qualifiedModelId”, “$.context.jwt.role”, “$.context.jwt.sub”] 作为维度键创建速率限制。不过,维度键的顺序确实很重要。当一个速率限制包含多个维度键时,其声明顺序决定了通配符的使用方式。用于匹配所有值的默认通配符 * 只能出现在末尾位置。如果在位置 N 使用 *,其后的所有位置也必须是 *。这种仅允许尾随通配符的约束有助于实现可预测的匹配行为。要了解这种行为,请参阅示例。
避免使用高基数或无边界的 JWT 声明作为维度键(例如 $.context.jwt.jti、$.context.jwt.nonce 或请求 ID)。这会创建数量无界的速率桶,并可能降低速率限制的有效性。应改用稳定且有界的标识符,例如 sub、role、team 或 tier。
网关在速率限制求值中采用故障开放语义。由于存在故障开放行为,不要仅依赖速率限制作为安全边界。应使用速率限制进行流量管理和服务质量控制,并使用身份验证、授权以及 AWS WAF 规则实施安全管控。
请在 AgentCore 网关上启用应用程序日志。这样便可以访问速率限制日志。对于每个执行了客户速率限制求值的请求,网关都会在服务器跨度上发出 OpenTelemetry(OTEL)跨度属性。可使用这些属性进行调试和监控。
请确保包含一个匹配所有值的条目。为简单起见,请考虑一个仅包含单项速率限制的网关:
aws bedrock-agentcore-control create-gateway-rate-limit \
--gateway-identifier my-gateway-abc1234567 \
--dimension-keys '["$.context.jwt.sub"]' \
--description "Per-sub request limit" \
--entries '[
{
"dimensions": {"$.context.jwt.sub": "Arnav"},
"requests": [{"rate