控制请求数和支出上限

CloudflareBeginner
立即练习

简介

AI 应用需要两种不同的流量保护机制。速率限制会统计时间窗口内的请求数,在突发流量到达模型之前将其拦截。支出限制会在更长的时间窗口内跟踪模型的预计成本,从而保护预算。前者控制调用方可以多频繁地发送任务,后者控制这些任务最多可以产生多少成本

你将创建一个临时的、需要身份验证的 AI Gateway。它只允许短时间滑动窗口内的两个请求,因此三个很小的请求就可以演示 429 Too Many Requests 响应,而不会产生浪费性的模型流量。窗口清空后,你将验证普通推理已经恢复。你还将添加一条每日 5 美元的支出规则,并将其限定到 Workers AI 和所选模型。你会直接读取已保存的规则,而不是实际花费资金将预算耗尽。

如果你是直接进入本课程的,请先完成将 LabEx 连接到你的 Cloudflare 账户。该实验会介绍 LabEx 终端、Wrangler 设备授权和账户 ID。还要先完成通过网关路由推理,因为本实验会复用其中独立的网关和上游授权边界。

本实验使用 Cloudflare 托管的 @cf/meta/llama-3.3-70b-instruct-fp8-fast 模型,并采用标准的 Workers AI 计费方式。不需要 Workers Paid、Unified Billing 或外部提供商凭据。只有三个很小的请求应该到达模型。如果共享的每日 Workers AI 配额不可用,请停止操作,不要反复重试。

初始化过程会在 /home/labex/project/ai-gateway-limits 中安装 Node.js 22.22.0 和项目本地的 Wrangler 4.132.0,并准备独立的只读检查。但它不会授权 Wrangler、创建网关、创建令牌或发送模型流量。实验结束后,LabEx 会销毁虚拟机;不过你仍然需要删除云端网关和令牌,因为销毁虚拟机无法移除远程资源。

授权虚拟机并命名实验资源

在本步骤中,你将把全新的虚拟机连接到你的学习账户,并记录你所拥有资源的唯一名称。

每个 LabEx 实验都会从一台全新的虚拟机开始。授权这台虚拟机后,Wrangler 才能在你的学习账户中调用 Workers AI;但此操作还不会创建网关。

进入已准备好的项目目录,确认固定版本的 CLI,并开始设备授权:

cd /home/labex/project/ai-gateway-limits
npx wrangler --version
npx wrangler login --device --browser=false --scopes account:read user:read ai:write

打开命令显示的链接,输入代码,然后授权目标学习账户。接着检查结构化的身份信息:

npx wrangler whoami --json

预期会看到 Wrangler 4.132.0 和 loggedIn: true。将 YOUR_ACCOUNT_ID 替换为目标账户显示的实际 32 位 ID:

GATEWAY_ID="labex-c09-g04-$(openssl rand -hex 6)"
TOKEN_NAME="$GATEWAY_ID-token"
cat > .labex/state.json <<JSON
{
  "accountId": "YOUR_ACCOUNT_ID",
  "gatewayId": "$GATEWAY_ID",
  "tokenName": "$TOKEN_NAME"
}
JSON
cat .labex/state.json

这些标识符不是秘密信息。保存它们后,后续的读取和清理操作就只会针对本实验创建的临时资源。

创建具有短请求限制的网关

在本步骤中,你将配置一个作用于整个网关的请求计数器,以安全地演示突发流量保护。

请求速率限制会统计时间窗口内的请求数。本实验使用滑动窗口:在任意时刻,AI Gateway 都会回看前 20 秒内的请求。在该时间段内已有两个请求后,下一个请求会在到达 Workers AI 之前被 HTTP 429 拒绝。

打开 Cloudflare Dashboard,选择 AI → AI Gateway → Create a custom gateway。使用已保存的 gatewayId。保持 Collect LogsAuthenticated Gateway 启用。打开 Rate Limit Requests,选择 Change,并设置:

  • 限制:2 个请求;
  • 间隔:20 秒;
  • 技术:sliding

关闭缓存和重试。将 Workers AI 计费保持为 Standard,然后创建网关。先创建请求策略,可以在添加独立的费用策略前获得一个稳定的资源。

添加限定范围的支出限制并读取配置

在本步骤中,你将为同一个网关添加费用预算,并精确限定哪些请求属于该预算。

支出限制是预算,而不是请求计数器。AI Gateway 会根据模型定价和用量估算每个已完成请求的成本,然后将成本计入匹配的规则。该估算最终会保持一致,因此并发流量可能会暂时超过预算。即使存在支出规则,速率限制仍然有用。

打开新网关的 Settings 标签页。启用 Spend Limits,选择 Add rule,并配置一条规则:

  • 成本限制:$5
  • 窗口:1 day
  • 技术:Sliding
  • 提供商筛选:workers-ai
  • 模型筛选:meta/llama-3.3-70b-instruct-fp8-fast

保存规则,然后检查这两项控制。模型字段使用 author/model 格式,因为提供商已经单独选定;后续的推理 URL 仍然使用以 @cf/ 开头的完整 Workers AI 名称。

网关设置显示两请求滑动限制和一条已启用的支出限制规则

提供商和模型筛选条件将这条规则限定为狭窄范围,而不是为网关中不相关的流量共享一个预算。对于本次小实验来说,5 美元是刻意设置的较高额度:你只需验证策略,不要尝试将预算耗尽。

打开 My Profile → API Tokens,选择 Create Token → Create Custom Token,并使用已保存的 tokenName。添加两个账户权限:AI Gateway — EditAI Gateway — Run,然后只包含目标学习账户。Edit 允许实验读取并随后删除指定的网关;Run 用于验证推理流量。上游 Workers AI 凭据由 Wrangler 单独提供。

检查摘要后,创建令牌。Cloudflare 会在验证命令中只显示一次该令牌。只复制 Bearer 后面的令牌值,不要复制外层的 curl 命令,然后通过隐藏输入将其保存:

bash -c '
while :; do
  read -ersp "Paste the AI Gateway token: " GATEWAY_TOKEN
  printf "\n"
  [ -n "$GATEWAY_TOKEN" ] && break
  printf "Token cannot be empty; paste it again.\n" >&2
done
umask 077
printf "%s" "$GATEWAY_TOKEN" > .labex/gateway-token
unset GATEWAY_TOKEN
chmod 600 .labex/gateway-token
'

通过管理 API 读取重要的非机密字段:

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  > .labex/gateway.json
unset GATEWAY_TOKEN
node - <<'NODE'
const b=require('./.labex/gateway.json'), g=b.result||{}, spend=g.spend_limits||{};
console.log(JSON.stringify({
  success:b.success,
  id:g.id,
  rate:{limit:g.rate_limiting_limit,interval:g.rate_limiting_interval,technique:g.rate_limiting_technique},
  spend_limits:{enabled:spend.enabled,rules:spend.rules}
},null,2));
NODE

预期会看到两请求、20 秒、滑动窗口的速率规则,以及一条已启用的每日 5 美元费用规则,其中包含提供商和模型筛选条件。该回读结果证明配置已经保存,但不表示预算已经被消耗。

通过三个请求观察请求被拒绝

在本步骤中,你将发送三个很小的请求,在不产生大量突发流量的情况下观察请求计数策略。

现在依次发送三个很小的请求。前两个应该被允许,第三个应该收到 429,并且不会到达模型。与生成大量突发流量相比,这种方式更安全、成本也更低。

先私密保存这台虚拟机上短期有效的 Wrangler 令牌,用于上游 Workers AI 授权:

umask 077
npx wrangler auth token --json \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>process.stdout.write(JSON.parse(s).token))' \
  > .labex/upstream-token
chmod 600 .labex/upstream-token

发送三个请求。每个请求都包含合成元数据,因此可以在日志中轻松识别;支出规则本身则通过 Workers AI 提供商和模型筛选条件匹配这些请求:

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(cat .labex/upstream-token)
for NUMBER in 1 2 3; do
  METADATA=$(printf '{"lab":"g04-limits","request":"burst-%s","synthetic":true}' "$NUMBER")
  STATUS=$(curl --http1.1 -sS \
    -o ".labex/burst-$NUMBER-response.json" -w '%{http_code}' \
    -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
    -H "Authorization: Bearer $UPSTREAM_TOKEN" \
    -H "cf-aig-metadata: $METADATA" \
    -H 'Content-Type: application/json' \
    --data "{\"prompt\":\"Reply with the number $NUMBER.\",\"max_tokens\":4}" \
    "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
  printf '%s\n' "$STATUS" | tee ".labex/burst-$NUMBER-status.txt"
done
unset GATEWAY_TOKEN UPSTREAM_TOKEN METADATA

预期输出:

200
200
429

429 表示保护策略正常生效。它说明请求在网关处被拦截,因此没有额外消耗模型推理次数,也没有增加支出计数器。

等待滑动窗口恢复

在本步骤中,你将等待短时间窗口清空,并验证网关再次允许正常推理。

速率限制应该保护突发流量,而不是永久禁用应用。等待时间略长于 20 秒的窗口,然后再发送一个很小的请求:

sleep 22
ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
MODEL='@cf/meta/llama-3.3-70b-instruct-fp8-fast'
GATEWAY_TOKEN=$(cat .labex/gateway-token)
UPSTREAM_TOKEN=$(cat .labex/upstream-token)
STATUS=$(curl --http1.1 -sS \
  -o .labex/recovery-response.json -w '%{http_code}' \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'cf-aig-metadata: {"lab":"g04-limits","request":"recovery","synthetic":true}' \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"Reply only with recovered.","max_tokens":4}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset GATEWAY_TOKEN UPSTREAM_TOKEN
printf '%s\n' "$STATUS" | tee .labex/recovery-status.txt
node -e 'const b=require("./.labex/recovery-response.json"); console.log(b.result?.response ?? b.result)'

预期会收到 HTTP 200 和一段简短的生成结果。恢复过程证明之前的 429 来自配置的时间窗口,而不是凭据错误或模型故障。

将策略与 Dashboard 证据对应起来

在本步骤中,你将把 API 和 HTTP 结果与 Dashboard 中显示的控制项和日志对应起来。

返回 AI → AI Gateway,选择已保存的网关,然后打开 Settings。确认速率限制仍显示为两个请求、20 秒和滑动方式。在 Spend Limits 中检查唯一的规则,确认其费用为 5 美元、窗口为一天且采用滑动方式,并设置了提供商和模型筛选条件。

选中的网关显示已保存的速率限制和限定范围的支出控制

然后打开 Logs。最初的两个成功请求和恢复后的请求应该会在日志正常传播后出现。第三个被拒绝的请求可能以不同方式显示,因为它在提供商推理之前就被拦截;已保存的 HTTP 状态是速率限制的权威证据。

网关日志显示速率限制测试期间仅有少量获准的 Workers AI 请求

注意以下操作不需要进行:不需要花费 5 美元,不需要将规则降低到危险的小值,也不需要循环重试直到出现费用拒绝。管理 API 的回读结果证明了支出策略的适用范围,而三个请求的实验则单独证明了请求计数限制确实生效。

删除临时网关

在本步骤中,你将只删除实验资源清单中指定名称的网关,并在授权仍然可用时验证它已经不存在。

趁管理令牌仍然可以验证资源状态时删除网关:

ACCOUNT_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).accountId')
GATEWAY_ID=$(node -p 'JSON.parse(require("fs").readFileSync(".labex/state.json")).gatewayId')
GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS -X DELETE \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways/$GATEWAY_ID" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s);if(!b.success)process.exit(1);console.log("gateway deletion accepted")})'
unset GATEWAY_TOKEN

GATEWAY_TOKEN=$(cat .labex/gateway-token)
curl --http1.1 -fsS \
  -H "Authorization: Bearer $GATEWAY_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai-gateway/gateways" \
  > .labex/gateways-after-delete.json
unset GATEWAY_TOKEN
node -e 'const b=require("./.labex/gateways-after-delete.json"),id=process.argv[1],found=(b.result||[]).some(g=>g.id===id);console.log("gateway absent:",!found);if(found)process.exit(1)' "$GATEWAY_ID"

预期输出 gateway absent: true。通过已授权的资源清单检查,可以区分真正的删除、网络故障以及无权访问页面等情况。

撤销令牌并退出登录

在本步骤中,你将撤销剩余的 Dashboard 令牌,删除虚拟机中的两份令牌副本,并断开 Wrangler。

在 Cloudflare Dashboard 中打开 My Profile → API Tokens。找到准确的 tokenName,打开 Actions,选择 Delete,检查确认信息,然后只删除该令牌。现在可以安全地撤销令牌,因为网关删除操作已经完成验证。

删除两份临时令牌副本,并让 Wrangler 退出登录:

shred -u .labex/gateway-token .labex/upstream-token
npx wrangler logout
npx wrangler whoami --json || true
test ! -e .labex/gateway-token -a ! -e .labex/upstream-token \
  && echo "local token files removed"

预期会看到 loggedIn: falselocal token files removed。Dashboard 会话是独立的,仍会保持登录状态。实验结束时,LabEx 会销毁这台临时虚拟机,而不会保留它。

总结

你应用了两种互补的 AI Gateway 控制机制。一个两请求的滑动窗口将第三个低流量请求拒绝为 HTTP 429,窗口清空后又自动允许流量通过。另一个独立的每日 5 美元支出规则被限定到 Workers AI 和一个模型,并且在不浪费模型用量的情况下验证了其已保存的配置。

下一个实验将使用另一种网关可靠性控制:有界回退。你会将一次受控的主模型故障路由到兼容的第二个模型,同时确保正常的主模型请求仍然在第一次尝试时完成。