はじめに
AI アプリケーションには、2 種類のトラフィック保護が必要です。レート制限は、一定の時間枠内のリクエスト数を数え、急激なバーストがモデルに到達する前に停止します。支出制限は、より長い時間枠で推定モデルコストを追跡し、予算を保護します。一方は呼び出し元が処理を送信できる「頻度」を制御し、もう一方はその処理にかけられる「費用」を制御します。
この実験では、使い捨ての認証済み AI Gateway を 1 つ作成します。短いスライディングウィンドウ内で許可するリクエストを 2 件だけに設定し、3 件の小さなリクエストを送信して、無駄なモデル通信を発生させずに 429 Too Many Requests レスポンスを確認します。ウィンドウが終了した後は、通常の推論が復旧することを確認します。また、Workers AI と選択したモデルだけを対象にした、1 日 5 ドルの支出ルールも追加します。予算を使い切るのではなく、保存されたルールを読み取って確認します。
このコースを直接開いた場合は、まず LabEx を Cloudflare アカウントに接続する を完了してください。LabEx ターミナル、Wrangler のデバイス認証、アカウント ID について学べます。さらに、先に ゲートウェイ経由で推論をルーティングする も完了してください。この実験では、その実験で作成した別のゲートウェイと、上流認証の境界を再利用します。
この実験では、Cloudflare がホストする @cf/meta/llama-3.3-70b-instruct-fp8-fast モデルを、Standard Workers AI 課金で使用します。Workers Paid、Unified Billing、外部プロバイダーの認証情報は必要ありません。モデルに到達するリクエストは、小さなものを 3 件だけにしてください。共有の 1 日 Workers AI 割り当てが利用できない場合は、繰り返し再試行せずに停止してください。
セットアップでは、Node.js 22.22.0 とプロジェクトローカルの Wrangler 4.132.0 を /home/labex/project/ai-gateway-limits にインストールします。読み取り専用の確認処理を準備しますが、Wrangler の認証、ゲートウェイの作成、トークンの作成、モデル通信は行いません。LabEx は実験終了後に VM を破棄しますが、クラウドゲートウェイとトークンは削除してください。VM を破棄しても、リモートリソースは削除されないためです。
VM を認証して実験名を設定する
このステップでは、新しい VM を学習用アカウントに接続し、自分が管理するリソースに一意の名前を記録します。
各 LabEx 実験は、新しい VM で開始します。この VM を認証すると、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
表示されたリンクを開き、コードを入力して、対象の学習用アカウントを認証します。その後、構造化された ID 情報を確認します。
npx wrangler whoami --json
Wrangler 4.132.0 と loggedIn: true が表示されることを確認します。対象アカウントに表示された実際の 32 文字の ID で YOUR_ACCOUNT_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 秒間をさかのぼって確認します。その範囲内で 2 件のリクエストを受け付けた後、次のリクエストは Workers AI に到達する前に HTTP 429 で拒否されます。
Cloudflare Dashboard を開き、AI → AI Gateway → Create a custom gateway の順に選択します。保存した gatewayId を使用します。Collect Logs と Authenticated Gateway は有効のままにします。Rate Limit Requests を有効にし、Change を選択して、次の値を設定します。
- limit:
2リクエスト - interval:
20秒 - technique:
sliding
キャッシュと再試行は無効のままにします。Workers AI の課金方式は Standard のままにして、ゲートウェイを作成します。先にリクエストポリシーを作成すると、別のコストポリシーを追加する前に、安定したリソースを用意できます。
スコープ付きの支出制限を追加して読み取る
このステップでは、同じゲートウェイにコスト予算を追加し、その予算の対象となるリクエストを正確に制限します。
支出制限は予算であり、リクエストカウンターではありません。AI Gateway は、モデルの価格と使用量に基づいて完了した各リクエストのコストを推定し、一致するルールに加算します。この推定処理は結果整合性であるため、同時に発生したトラフィックによって、短時間だけ予算を超えることがあります。支出ルールが存在する場合でも、レート制限は有効です。
新しいゲートウェイの Settings タブを開きます。Spend Limits を有効にし、Add rule を選択して、次の 1 つのルールを設定します。
- cost limit:
$5 - window:
1 day - technique:
Sliding - provider filter:
workers-ai - model filter:
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 — Edit と AI Gateway — Run の 2 つを追加し、対象の学習用アカウントだけを含めます。Edit により、この実験で作成したゲートウェイを読み取り、後で正確に削除できます。Run は推論トラフィックを認証します。上流の Workers AI 認証情報は Wrangler が別に提供します。
概要を確認したら、トークンを作成します。Cloudflare は検証用コマンド内にトークンを 1 回だけ表示します。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
2 件のリクエスト、20 秒、スライディング方式のレートルールと、プロバイダーおよびモデルのフィルターを含む、有効な 5 ドル・1 日のコストルールが 1 件表示されることを確認します。この読み取り結果は設定を証明するものであり、予算が消費されたことを示すものではありません。
3 件の呼び出しでリクエスト拒否を確認する
このステップでは、3 件の小さなリクエストを使って、巨大なバーストを発生させずにリクエスト数ポリシーを確認します。
ここでは、非常に小さなリクエストを 3 件、順番に送信します。最初の 2 件は許可され、3 件目は 429 を受け取り、モデルには到達しないはずです。これは大量のトラフィックをバーストさせるよりも安全で、コストもかかりません。
この VM 用の短期間の 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
3 件の呼び出しを送信します。各リクエストには、ログで簡単に識別できるよう合成メタデータを付けます。支出ルール自体は、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 を開きます。レート制限が、2 件のリクエスト、20 秒、スライディング方式のままであることを確認します。Spend Limits では、1 件だけ表示されるルールを確認し、5 ドルのコスト、1 日のスライディングウィンドウ、プロバイダーとモデルのフィルターを確認します。

次に Logs を開きます。最初に成功した 2 件と、復旧後のリクエストが通常のログ反映後に表示されるはずです。3 件目の拒否リクエストは、プロバイダー推論の前に停止したため、別の形式で表示される場合があります。保存した HTTP ステータスが、レート制限を示す正式な証拠です。

ここで必要ないことにも注意してください。5 ドルを使う必要はありません。ルールを危険なほど小さい値に下げる必要も、コストによる拒否が発生するまでループする必要もありません。管理 API の読み取り結果によって支出ポリシーのスコープを確認し、3 件の呼び出しによる実験でリクエスト数の制御を別に確認できます。
使い捨てのゲートウェイを削除する
このステップでは、実験のインベントリに記録したゲートウェイだけを削除し、認証が利用できる状態のまま、その存在しないことを確認します。
管理トークンで対象リソースが正確に削除されたことを確認できるうちに、ゲートウェイを削除します。
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 トークンを失効させ、VM 内の 2 つのコピーを消去して、Wrangler を切断します。
Cloudflare Dashboard で My Profile → API Tokens を開きます。保存した正確な tokenName を見つけ、Actions を開いて Delete を選択します。確認画面の内容を確認し、そのトークンだけを削除します。ゲートウェイの削除はすでに確認できているため、ここでトークンを失効させても問題ありません。
一時トークンの 2 つのコピーを消去し、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: false と local token files removed が表示されることを確認します。Dashboard のセッションは別に管理されているため、ログインしたまま残ります。LabEx は実験終了時に、この一時 VM を保持せずに破棄します。
まとめ
AI Gateway の相補的な 2 つの制御を適用しました。2 件のリクエストを許可するスライディングウィンドウによって、少量の 3 件目のリクエストが HTTP 429 で拒否され、その後、ウィンドウが終了すると自動的にトラフィックが許可されました。別の 1 日 5 ドルの支出ルールは、Workers AI と 1 つのモデルにスコープを限定し、モデル使用量を無駄に消費せずに保存済みの設定を確認しました。
次の実験では、別のゲートウェイ信頼性制御である、制限付きフォールバックを使用します。制御されたプライマリモデルの障害を、互換性のある 2 つ目のモデルへルーティングします。一方、プライマリモデルが正常な場合は、最初のステップでリクエストが完了します。



