ゲートウェイ経由の推論ルーティング

CloudflareBeginner
オンラインで実践に進む

はじめに

Workers AI コースでは、アプリケーションから Cloudflare がホストするモデルへプロンプトを直接送信しました。この方法でも動作しますが、利用が拡大するアプリケーションでは、モデルへのトラフィックを監視・制御するための一貫した場所も必要になります。Cloudflare AI Gateway はそのチェックポイントです。呼び出し元は名前付きゲートウェイにリクエストを送り、ゲートウェイが Workers AI などのアップストリームモデルプロバイダーへリクエストを転送します。

この実験では、次の 3 つの役割を明確に分けます。

  • 呼び出し元は LabEx VM 上の curl です。
  • ゲートウェイは、呼び出し元がアクセスできるか確認し、リクエストを記録します。
  • アップストリームプロバイダーは Workers AI です。リクエストによってモデルを実行できるか確認します。

後者 2 つの確認では、別々の認証情報を使います。cf-aig-authorization は呼び出し元を AI Gateway に対して認証します。通常の Authorization ヘッダーは、ゲートウェイから Workers AI へのリクエストを認証します。有効なゲートウェイトークンが、Workers AI の認証情報として自動的に使われるわけではありません。また、Workers AI の認証情報があっても、認証付きゲートウェイを迂回することはできません。

この実験では、Cloudflare Dashboard で使い捨ての認証付きゲートウェイを 1 つ作成し、スコープを限定した AI Gateway トークンを作成します。その後、Cloudflare がホストする Llama 3.3 モデルへ短いリクエストを送り、生成されたログを確認します。次に、ゲートウェイの認証情報だけを無効な値に置き換え、どの境界でリクエストが拒否されるかを確認します。最後に、ゲートウェイとそのトークンを削除してリクエストを認証できない状態にし、Wrangler からログアウトします。

このコースに直接参加した場合は、まず LabEx を Cloudflare アカウントに接続する を完了してください。この実験では、LabEx VM のターミナル、Wrangler のデバイス認証、アカウント確認、明示的なアカウント ID の指定を学びます。Workers AI 推論の実験も、役立つ前提実験です。

AI Gateway は Free プランで利用でき、基本的なログ記録はアカウントの制限内で無料です。選択する @cf/meta/llama-3.3-70b-instruct-fp8-fast モデルは、Standard billing で共有 Workers AI 無料割り当てを利用できます。Workers Paid と Unified Billing は必要ありません。アカウントでその日の Workers AI 割り当てを利用できない場合は、何度も再試行せずに停止してください。

セットアップでは、Node.js 22.22.0 とプロジェクト専用の Wrangler 4.132.0 を /home/labex/project/ai-gateway-route にインストールします。読み取り専用の独立した評価機能を提供しますが、Wrangler の認証、トークンやゲートウェイの作成、推論の送信、Cloudflare アカウントの変更は行いません。LabEx は実験終了後にこの一時 VM を保存しません。ただし、クリーンアップを完了してから VM が破棄されるよう、クラウド上のトークンと VM 内のコピーは明示的に削除します。

VM を認証し、管理対象の名前を記録する

このステップでは、新しい VM を学習用アカウントに接続し、この実験のリソースを明確に識別できる名前を保存します。

Wrangler のデバイスログインでは Workers AI を認証できますが、後で使用する AI Gateway 呼び出し元用の認証情報は別途作成する必要があります。これらの認証情報を分けておくと、信頼境界を確認しやすくなります。

用意されたプロジェクトへ移動し、固定された CLI バージョンを確認します。

cd /home/labex/project/ai-gateway-route
npx wrangler --version

4.132.0 と表示されることを確認します。アカウント識別情報と Workers AI へのアクセス権を指定して、デバイス認証を開始します。

npx wrangler login --device --browser=false --scopes account:read user:read ai:write

表示されたリンクを開き、コードを入力して、使用する学習用アカウントを認証します。その後、構造化された ID 情報を確認します。

npx wrangler whoami --json

loggedIn: true であることを確認します。重複しないゲートウェイ ID と、それに関連するトークン名を作成します。YOUR_ACCOUNT_ID を、使用するアカウントに表示された実際の 32 文字の ID に置き換えてください。

GATEWAY_ID="labex-c09-g01-$(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

ランダムな接尾辞によって名前の重複を防ぎます。状態ファイルには認証情報ではなくリソース識別子が含まれます。以降のコマンドは、この実験が所有する正確なリソースを対象にできます。

認証付きゲートウェイと呼び出し元トークンを作成する

このステップでは、チェックポイントとなるゲートウェイと、そのゲートウェイを呼び出して確認できる認証情報を作成します。

Cloudflare Dashboard を開き、AI → AI Gateway → Create gateway → Custom gateway を選択します。ゲートウェイ名には .labex/state.jsongatewayId を使用します。次の設定を維持してください。

  • request logging: on
  • gateway authentication: on
  • cache, rate limits, spend limits, retries: off
  • Workers AI billing: Standard

Standard billing を使用すると、Workers AI の使用量は通常の割り当てで処理されます。Unified Billing は別の支払い経路であり、この初心者向け実験の対象外です。

Cloudflare が新しいリソースを開いたら、パンくずリストと選択中の Overview タブを使い、アカウント全体のゲートウェイ一覧ではなく、今回作成した使い捨てゲートウェイを開いていることを確認します。

一意の ID と、最初のリクエストがまだないことを示すメトリクスが表示された新しいゲートウェイの Overview

作成後、Settings を開きます。表示されたゲートウェイ ID が保存した ID と完全に一致し、ログ記録と認証が有効になっていることを確認します。

次に、Create an AI Gateway authentication token を選択します。保存した tokenName を名前に指定し、使用する学習用アカウントだけを選択して、次の権限を追加します。

  • AI Gateway — Run は、呼び出し元が認証済みゲートウェイに入るために必要です。
  • AI Gateway — Edit は、管理 API を通じて AI Gateway リソースを読み取り、削除するために必要です。

このトークンに Workers AI の権限は追加しないでください。Workers AI は、Wrangler の別の短期認証情報によって認証されます。

AI Gateway Run と Edit にスコープを限定したトークン権限フォーム

アカウントと権限を確認してから、トークンを作成します。Cloudflare はトークンの値を一度だけ表示します。トークンを表示せずに安全に保存してください。

bash -c '
while :; do
  read -rsp "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
'

用意されたターミナルは対話型 zsh を使用しています。そのため、このブロックでは Bash の非表示 read プロンプトを使うために、短時間だけ Bash サブプロセスを起動します。空の値を貼り付けると、コマンドがシェルに戻る前に拒否されます。トークンはサブプロセスと、アクセス権を制限したファイルにだけ保持されます。

トークンは設定やコマンド出力に含めません。認証付き管理 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" \
  | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const b=JSON.parse(s),g=b.result||{};console.log(JSON.stringify({success:b.success,id:g.id,collect_logs:g.collect_logs,authentication:g.authentication},null,2))})'
unset GATEWAY_TOKEN

所有している ID が表示され、collect_logsauthentication の両方が true になっていることを確認します。秘密情報は表示されません。

認証、ログ、Standard billing が表示されたゲートウェイの Settings ビュー

Workers AI のリクエストをゲートウェイ経由で 1 件送信する

このステップでは、Workers AI に直接送信する代わりに、ゲートウェイを経由して小さなリクエストを 1 件送信します。

プロバイダー固有のゲートウェイ URL には、アカウント、ゲートウェイ、プロバイダー、モデルが含まれます。2 つの認証ヘッダーは意図的に分けて使用します。

caller → cf-aig-authorization → AI Gateway → Authorization → Workers AI model

Wrangler の現在の短期 Workers AI トークンを構造化データとして取得し、リクエストを送信します。このコマンドは JSON レスポンスだけをディスクに書き込み、どちらの認証情報も表示しません。

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=$(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))')
curl --http1.1 -fsS \
  -H "cf-aig-authorization: Bearer $GATEWAY_TOKEN" \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"In one sentence, explain why an AI gateway is useful.","max_tokens":64}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL" \
  > .labex/valid-response.json
unset GATEWAY_TOKEN UPSTREAM_TOKEN
node -e 'const b=require("./.labex/valid-response.json"); console.log(b.result?.response ?? b.result)'

生成は決定的ではないため、文章は異なる場合があります。評価では、所有するゲートウェイを経由してプロバイダーが成功し、空でない結果を返したことだけを確認します。

ゲートウェイ認証の境界を切り分ける

このステップでは、有効な Workers AI の認証情報を維持したまま、ゲートウェイの認証情報だけを置き換えます。

制御された負のテストでは、一度に 1 つの条件だけを変更します。両方の認証情報が無効だと、HTTP エラーがどのシステムによって返されたのか判断できません。ここでは Wrangler の有効なアップストリームトークンを維持し、cf-aig-authorization には明らかに無効な値を指定します。

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'
UPSTREAM_TOKEN=$(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))')
STATUS=$(curl --http1.1 -sS -o .labex/invalid-response.json -w '%{http_code}' \
  -H 'cf-aig-authorization: Bearer deliberately-invalid' \
  -H "Authorization: Bearer $UPSTREAM_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"prompt":"This request must not reach the model.","max_tokens":8}' \
  "https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/workers-ai/$MODEL")
unset UPSTREAM_TOKEN
printf '%s\n' "$STATUS" | tee .labex/invalid-status.txt

401 または 403 が表示されることを確認します。レスポンス本文は表示しないでください。ステータスだけで十分な証拠になり、エラー出力を抑えることでリクエストの詳細が漏れる可能性を減らせます。

リクエストをゲートウェイログに結び付ける

このステップでは、可観測性を使って実行時の動作と、ゲートウェイに表示される記録を結び付けます。

可観測性(Observability)とは、呼び出し元からリクエストが送信された後に、システムが何をしたか説明できるだけの証拠を収集することです。ゲートウェイログには、モデルへ再度リクエストを送信しなくても、プロバイダー、モデル、ステータス、レイテンシ、トークン使用量などを記録できます。ログが表示されるまで少し時間がかかる場合があります。

認証付き管理 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/logs?per_page=50" \
  > .labex/logs.json
unset GATEWAY_TOKEN
node - <<'NODE'
const body = require('./.labex/logs.json')
const model = '@cf/meta/llama-3.3-70b-instruct-fp8-fast'
const matches = (body.result || []).filter(row =>
  row.provider === 'workers-ai' && row.model === model
)
console.log(matches.map(row => ({
  id: row.id,
  provider: row.provider,
  model: row.model,
  success: row.success,
  created_at: row.created_at
})))
if (!matches.some(row => row.success === true)) process.exit(2)
NODE

provider: "workers-ai"、指定したモデル、success: true を含むエントリが 1 件表示されることを確認します。そのエントリがない状態でコマンドが終了した場合は、推論リクエストを追加で送信せず、約 20 秒待って同じ読み取り専用ブロックを再実行してください。

Dashboard でゲートウェイの Logs ビューを開きます。@cf/meta/llama-3.3-70b-instruct-fp8-fast に対する成功した Workers AI の行を見つけます。詳細パネルを開く前に、成功、プロバイダー、モデルを確認してください。

成功した Workers AI リクエストが強調表示されたゲートウェイの Logs テーブル

正確な所要時間、トークン数、生成テキストは変わる可能性があります。これらは今回のリクエストの値であり、完全に再現する目標値ではありません。ログを見つけやすくするためだけに、認証情報や個人情報をプロンプトへ入力しないでください。

モデル、ステータス、レイテンシ、トークン使用量が表示されたログ詳細パネル

使い捨てゲートウェイを削除する

このステップでは、管理用認証情報がまだ利用できる状態で、クラウド上のリソースを削除します。

クリーンアップでは、所有する正確な ID を対象にし、認証付きインベントリによって削除を確認する必要があります。ログアウトやネットワーク障害によってページが表示されないことは、削除の証拠にはなりません。

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 が表示されることを確認します。2 回目のリクエストでは、有効な認証情報でゲートウェイ一覧を取得し、所有する ID が残っている場合は失敗します。アカウント内の他のゲートウェイは変更されません。

トークンを削除してログアウトする

このステップでは、使用した順序とは逆の順序で、独立した 2 つの認証情報を削除します。

Cloudflare Dashboard で My Profile → API Tokens を開きます。.labex/state.json に保存されている正確なトークン名を探し、その Actions メニューを開いて Delete を選択します。確認内容を確認し、そのトークンだけを削除してください。トークンを削除すると、アクセス権は直ちに取り消されます。ゲートウェイはすでに削除済みなので、ここで削除して問題ありません。

ローカルコピーを削除し、Wrangler の VM 用の別の認証を終了します。

shred -u .labex/gateway-token
npx wrangler logout
npx wrangler whoami --json || true

loggedIn: false を含む構造化された出力が表示されることを確認します。Dashboard のブラウザーセッションは別のものであり、ログイン状態のままです。最後にローカルの状態を確認します。

test ! -e .labex/gateway-token && echo "local gateway token removed"

このメッセージは、VM 内のコピーが存在しないことを示します。LabEx の Check ボタンは、ローカルファイルと Wrangler のログアウトを独立して再確認します。評価用バックエンドスクリプトは、意図的に学習者のプロジェクトには含まれていません。

これで、ゲートウェイの削除、呼び出し元・管理用トークンの削除、ローカルトークンの消去、新しい VM の切断が完了しました。実験を終了すると、LabEx はこの一時 VM を保存せずに破棄します。ただし、クラウド側のクリーンアップは必要です。VM を破棄するだけでは、Cloudflare トークンを無効化したりゲートウェイを削除したりできないためです。

まとめ

認証付き Cloudflare AI Gateway を作成し、実際の Workers AI 推論をそのゲートウェイ経由でルーティングしました。ゲートウェイの認証とアップストリームモデルの認証を分離し、1 つの認証情報だけを変更して、どの境界がリクエストを拒否するかを特定しました。また、成功したリクエストをゲートウェイログに結び付けました。最後に、認証付きのリソース一覧で削除を確認してからトークンを削除し、VM からログアウトしました。

次の実験では、この可観測なリクエスト経路を基に進めます。秘密ではない小さなメタデータを追加し、意図的な失敗を追跡し、リクエストがどこで失敗したかを推測ではなくゲートウェイの証拠から判断します。