- AI Gateway の役割 — ログ・分析・キャッシュ・レート制限・フォールバックを 1 つの中継点で担う仕組み
- ゲートウェイの作成(
defaultの自動作成)と、REST API・プロバイダ別エンドポイント・Workers バインディングという 3 つの接続方法 - Workers AI の呼び出しを AI Gateway 経由に切り替え、ダッシュボードでログ・トークン数・コストを観察する方法
- Agents SDK(
agentsパッケージ)の Agent クラス — 永続状態・スケジュール実行・WebSocket useAgentフックでブラウザからエージェントに接続し、状態をリアルタイム同期する方法
AI Gateway とは — AI 呼び出しの中継点
第 11 章では env.AI.run() で Workers AI を直接呼びました。アプリを本番運用に近づけると、すぐに次の疑問が出てきます。誰がどれだけ AI を呼んでいるのか。トークンコストは月いくらか。同じプロンプトに毎回課金するのは無駄ではないか。プロバイダ障害時に別モデルへ切り替えられるか。AI Gateway は、アプリと AI プロバイダの間に挟まるプロキシ層としてこれらをまとめて解決するサービスです。導入は接続先を 1 行変えるだけで、全プランで利用できます。
| 機能 | できること |
|---|---|
| Analytics | リクエスト数・トークン数・コスト・エラー数・キャッシュ率をダッシュボードや GraphQL で集計 |
| Logging | 個々のリクエストのプロンプト・レスポンス・トークン数・コスト・所要時間・ステータスを保存して閲覧 |
| Caching | 同一リクエストへの応答を Cloudflare のキャッシュから返し、レイテンシとプロバイダ課金を削減 |
| Rate limiting | ゲートウェイ単位でリクエスト数を制限(固定 / スライディングウィンドウ、超過時は 429) |
| リトライ・フォールバック | エラーやタイムアウト時に別モデル・別プロバイダへ切り替え(現在は Dynamic Routing で構成) |
| マルチプロバイダ | Workers AI・OpenAI・Anthropic・Google AI Studio・AWS Bedrock など多数のプロバイダに対応 |
コア機能(ダッシュボード分析・キャッシュ・レート制限)は無料です。ログの保存件数はプランで異なり、2026-08 時点で Workers Free はアカウント全体で 10 万件、Workers Paid はゲートウェイあたり 1,000 万件です。上限到達時は古いログの自動削除を有効にするか、保存を停止するかを選べます。コスト表示はトークン数からの推定値であり、正確な請求額はプロバイダ側のダッシュボードで確認します。
ゲートウェイの作成 — default は自動で作られる
ゲートウェイは明示的に作らなくても使い始められます。ゲートウェイ ID を省略するか default を指定して認証済みリクエストを送ると、アカウントに default という名前のゲートウェイが自動作成されます。自動作成された default ゲートウェイの初期設定は次のとおりです。
| 設定 | 初期値 |
|---|---|
| Authentication(認証) | On |
| Log collection(ログ収集) | On |
| Caching(キャッシュ) | Off(TTL 0) |
| Rate limiting | Off |
| Workers AI billing | Standard billing |
自動作成されるのは ID が default の場合だけで、それ以外の名前を使うには、ダッシュボードの AI → AI Gateway → Create Gateway(名前は 64 文字まで)か、AI Gateway - Read / Edit 権限の API トークンで REST API から事前に作成します。用途ごと(本番 / 検証、アプリ別など)にゲートウェイを分けると、分析やレート制限を独立して管理できます。
プロバイダ接続 — 3 つの入口と Universal Endpoint
アプリから AI Gateway を通す方法は 3 つあります。
| 入口 | エンドポイント / 書き方 | 向いている場面 |
|---|---|---|
| REST API | api.cloudflare.com の OpenAI 互換エンドポイント | プロバイダの API キー管理を Cloudflare に寄せたいとき |
| プロバイダ別エンドポイント | gateway.ai.cloudflare.com/v1/.../{provider} | 既存の OpenAI / Anthropic SDK のコードを最小変更で通したいとき |
| Workers バインディング | env.AI.run() の第 3 引数に gateway を渡す | Worker 内から Workers AI やサードパーティモデルを呼ぶとき |
REST API は、Cloudflare の API トークンだけで Workers AI もサードパーティモデルも同じ形式で呼べる入口です。モデル名は openai/gpt-4.1-mini のような {プロバイダ}/{モデル} 形式、Workers AI は @cf/ 接頭辞で指定します。Workers AI モデルを呼ぶ場合のみ、どのゲートウェイを通すかを示す cf-aig-gateway-id ヘッダが必須です(サードパーティモデルは省略すると default が使われます)。
curl -X POST "https://api.cloudflare.com/client/v4/accounts/<YOUR_ACCOUNT_ID>/ai/v1/chat/completions" \
--header "Authorization: Bearer <YOUR_API_TOKEN>" \
--header "cf-aig-gateway-id: default" \
--header "Content-Type: application/json" \
--data '{
"model": "@cf/meta/llama-3.1-8b-instruct",
"messages": [
{ "role": "user", "content": "What is Cloudflare?" }
]
}'
<YOUR_ACCOUNT_ID> は npx wrangler whoami で表示されるアカウント ID に、<YOUR_API_TOKEN> は npx wrangler auth token で取得できるトークン(または AI Gateway - Read / Edit と Workers AI - Read 権限を付けて作成した API トークン)に置き換えます。
プロバイダ別エンドポイントは、各プロバイダの API スキーマをそのまま維持しつつ AI Gateway の機能を追加する入口です。SDK の base URL を差し替えるだけで移行できます。
| プロバイダ | 差し替え後の base URL |
|---|---|
| OpenAI | https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/openai |
| Anthropic | https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/anthropic |
| Workers AI | @cf/ モデルを REST API またはバインディング経由で(上記・後述) |
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "<YOUR_OPENAI_API_KEY>",
// 認証付きゲートウェイでは cf-aig-authorization ヘッダも付ける
defaultHeaders: {
"cf-aig-authorization": "Bearer <YOUR_CF_API_TOKEN>",
},
baseURL:
"https://gateway.ai.cloudflare.com/v1/<YOUR_ACCOUNT_ID>/<YOUR_GATEWAY_ID>/openai",
});
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello, world!" }],
});
プロバイダへの認証は 3 通りから選べます。リクエストヘッダで自分の API キーを渡す方法のほか、BYOK(プロバイダのキーを Cloudflare に保管し、実行時に AI Gateway が自動付与)と、Unified Billing(プリペイドの AI Gateway クレジットで支払い、プロバイダのキー自体が不要になる方式。クレジット購入時に 5% の手数料、推論単価はプロバイダと同額。2026-08 時点)があります。
Universal Endpoint とフォールバック
かつての AI Gateway では、https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id} という単一 URL に「プロバイダ名 + エンドポイント + ペイロード」の配列を POST し、先頭から順に試して失敗したら次に切り替える Universal Endpoint がフォールバックの手段でした。どのステップが応答したかはレスポンスヘッダ cf-aig-step(0 = 1 番目のモデル、1 = 2 番目にフォールバック…)で確認できます。
Universal Endpoint は非推奨(2026-08 時点)。既存の統合は動き続けますが、新規開発では単一モデルの呼び出しに REST API(OpenAI 互換)を、フォールバック・リトライ・条件付きルーティングには Dynamic Routing(ダッシュボードのビジュアルエディタまたは JSON でルーティングフローを定義し、dynamic/{route} というモデル名で呼び出す機能)を使います。
dynamic/{route} という名前だけなので、コードは触らずに済みます。応答元を知るヘッダも別物で、cf-aig-step は Universal Endpoint 専用です。Agents SDK — ステートフルなエージェントの実行基盤
章の後半は視点を変えて、AI アプリの「実行基盤」を扱います。チャットボットやタスク実行エージェントは、リクエストごとに消える Worker と違い会話や作業の状態を持ち続ける必要があります。Agents SDK(npm の agents パッケージ)は、第 8 章で学んだ Durable Objects の上に構築されたフレームワークで、エージェント 1 インスタンスに永続的なアイデンティティ・組み込み SQLite・WebSocket 接続・スケジュール実行を与えます。
エージェントは Agent クラスを継承して定義し、routeAgentRequest() でルーティングします。同じ名前でアクセスすれば常に同じインスタンスに到達するため(ユーザー ID やチケット番号をインスタンス名にする)、セッションストアを別に用意する必要がありません。主なライフサイクルメソッドは次のとおりです。
| メソッド | 呼ばれるタイミング |
|---|---|
onStart() | インスタンスの起動時・ハイバネーションからの復帰時 |
onRequest(request) | HTTP リクエストごと |
onConnect(connection, ctx) | WebSocket 接続の確立時 |
onMessage(connection, message) | WebSocket メッセージの受信ごと |
onStateChanged(state, source) | 状態の変更時(サーバー起点・クライアント起点の両方) |
状態管理は initialState プロパティと this.setState() で行います。状態は SQLite に自動永続化されて再起動やハイバネーションを生き延び、変更は接続中の全 WebSocket クライアントへ即座にブロードキャストされます。表形式のデータは this.sql タグ付きテンプレートで SQLite を直接クエリすることもできます。
this.setState() から出る濃い 3 本が、1 回の呼び出しで同時に走る経路です。永続化とブロードキャストが分かれていないため、セッションストアも pub/sub も別に用意せずに、ボタンを押していない側のタブまで表示が揃います。細い矢印はクライアント発の RPC、破線は起動時の読み戻しで、どちらも setState() とは別のタイミングで動きます。スケジュール実行は 4 つのモードがあり、Durable Object のアラームを使って指定時刻にエージェントを起こします。
// 30 秒後に 1 回実行
await this.schedule(30, "sendReminder", { message: "Check your email" });
// 指定時刻に 1 回実行
await this.schedule(new Date("2026-09-01T09:00:00Z"), "sendReminder", { message: "報告締切" });
// cron 式で毎日 8:00 に実行
await this.schedule("0 8 * * *", "dailyDigest", { userId: "user-123" });
// 30 秒間隔で繰り返し実行(秒単位の粒度・重複実行防止つき)
await this.scheduleEvery(30, "poll", { source: "api" });
第 2 引数はコールバックとして呼ぶメソッド名、第 3 引数はそのメソッドに渡されるペイロードです。cron と scheduleEvery() は同一引数での重複登録を防ぐ冪等設計なので、onStart() 内で安全にセットアップできます。
クライアント接続は React なら agents/react の useAgent フック、素の JavaScript なら agents/client の AgentClient を使います。どちらも WebSocket で接続し、onStateUpdate コールバックで状態変更を受け取り、サーバー側で @callable() デコレータを付けたメソッドを agent.stub.メソッド名() として型安全に呼び出せます。エージェント内から AI モデルを呼ぶときは第 11 章と同じ this.env.AI.run() が使え、gateway オプションを渡せばその呼び出しも AI Gateway で観測できます。制限値は 2026-08 時点で、インスタンスあたり状態 1 GB、CPU 時間 30 秒(HTTP リクエスト・WebSocket メッセージ・スケジュール実行のたびにリフレッシュ)です。
Workers AI を呼ぶ最小の Worker を作り、gateway オプション 1 つで AI Gateway 経由に切り替えて、ダッシュボードでログとコストを観察します。所要 15 分。
Workers AI の推論はローカル開発(wrangler dev)でも実際に Cloudflare アカウント上のモデルを呼び出し、使用量に応じた課金が発生します。
- プロジェクトを作成します(Hello World example → Worker only → TypeScript を選択。デプロイは No)。
npm create cloudflare@latest -- hello-aig cd hello-aig - wrangler.jsonc に AI バインディングを追加します。
{ "name": "hello-aig", "main": "src/index.ts", "compatibility_date": "2026-08-10", "ai": { "binding": "AI" } } src/index.tsを次の内容に置き換えます。gateway.idに"default"を指定するだけで、この呼び出しが AI Gateway を通るようになります(default ゲートウェイは初回リクエスト時に自動作成されます)。export interface Env { AI: Ai; } export default { async fetch(request, env): Promise<Response> { const response = await env.AI.run( "@cf/meta/llama-3.1-8b-instruct-fast", { prompt: "What is the origin of the phrase Hello, World", }, { gateway: { id: "default", // これだけで AI Gateway 経由になる }, }, ); return new Response(JSON.stringify(response), { headers: { "Content-Type": "application/json" }, }); }, } satisfies ExportedHandler<Env>;npx wrangler devで起動し、表示されたhttp://localhost:8787をブラウザで数回開きます。{"response":"A fascinating question!..."}のような JSON が返れば成功です。- ダッシュボードで AI → AI Gateway → default を開き、Logs タブを確認します。リクエストごとに、送ったプロンプト・モデルの応答・プロバイダ・トークン数(In / Out)・推定コスト・所要時間が記録されています。
Analytics タブではリクエスト数・トークン消費・エラー率の推移がグラフで見られます。コードの変更は実質 1 行(gateway オプションの追加)だけで、AI 呼び出しの可観測性が手に入りました。
REST API 経由で同じリクエストを 2 回送り、キャッシュヘッダの効果をレスポンスヘッダで確認します。所要 10 分。
- アカウント ID とトークンを環境変数にセットします。
export ACCOUNT_ID=$(npx wrangler whoami | grep -oE '[0-9a-f]{32}') export CF_TOKEN=$(npx wrangler auth token)取得できない場合はダッシュボードでアカウント ID を確認し、
AI Gateway - Read / EditとWorkers AI - Read権限の API トークンを作成してください。 cf-aig-cache-ttlヘッダ(60 秒以上、最長 1 か月)を付けて同じリクエストを 2 回送り、cf-aig-cache-statusヘッダを確認します。for i in 1 2; do curl -si -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/ai/v1/chat/completions" \ --header "Authorization: Bearer $CF_TOKEN" \ --header "cf-aig-gateway-id: default" \ --header "cf-aig-cache-ttl: 3600" \ --header "Content-Type: application/json" \ --data '{ "model": "@cf/meta/llama-3.1-8b-instruct", "messages": [{ "role": "user", "content": "say hello in one word" }] }' | grep -i "cf-aig-cache-status" done- 期待される出力は 1 回目が
cf-aig-cache-status: MISS、2 回目がcf-aig-cache-status: HITです。2 回目はプロバイダに到達していないため応答も高速で、課金も発生しません。 - ダッシュボードの Logs でも 2 件目に Cached のマークが付いていることを確認します。逆にキャッシュを確実に避けたいリクエストには
cf-aig-skip-cache: trueヘッダを付けます。
Agents SDK のスターターからカウンターエージェントを作り、永続状態が複数のブラウザタブへリアルタイム同期される様子を確認します。所要 20 分。
- スターターテンプレートからプロジェクトを作成し、起動します。
npm create cloudflare@latest -- --template cloudflare/agents-starter cd agents-starter npm install npm run dev src/server.tsを次の内容に置き換えます。@callable()を付けたメソッドがクライアントから呼べる API になります。import { Agent, routeAgentRequest, callable } from "agents"; export type CounterState = { count: number; }; export class CounterAgent extends Agent<Env, CounterState> { initialState: CounterState = { count: 0 }; @callable() increment() { this.setState({ count: this.state.count + 1 }); return this.state.count; } @callable() reset() { this.setState({ count: 0 }); } } export default { async fetch(request: Request, env: Env, ctx: ExecutionContext) { return ( (await routeAgentRequest(request, env)) ?? new Response("Not found", { status: 404 }) ); }, } satisfies ExportedHandler<Env>;- wrangler.jsonc にエージェントを登録します。
class_nameはエクスポートしたクラス名と完全一致させ、new_sqlite_classesで状態永続化用の SQLite を有効にします。{ "name": "my-agent", "main": "src/server.ts", "compatibility_date": "2026-08-10", "compatibility_flags": ["nodejs_compat"], "durable_objects": { "bindings": [ { "name": "CounterAgent", "class_name": "CounterAgent" } ] }, "migrations": [ { "tag": "v1", "new_sqlite_classes": ["CounterAgent"] } ] } src/client.tsxをuseAgentを使う実装に置き換えます。import "./styles.css"; import { createRoot } from "react-dom/client"; import { useState } from "react"; import { useAgent } from "agents/react"; import type { CounterAgent, CounterState } from "./server"; export default function App() { const [count, setCount] = useState(0); const agent = useAgent<CounterAgent, CounterState>({ agent: "CounterAgent", onStateUpdate: (state) => setCount(state.count), }); return ( <div> <h1>Counter Agent</h1> <p>{count}</p> <button onClick={() => agent.stub.increment()}>+</button> <button onClick={() => agent.stub.reset()}>Reset</button> </div> ); } const root = createRoot(document.getElementById("root")!); root.render(<App />);http://localhost:5173をブラウザタブ 2 つで開き、片方で「+」を押します。もう片方のタブのカウントも即座に増えれば成功です。裏では、クライアントのstub.increment()が WebSocket RPC でエージェントに届き、setState()が SQLite へ永続化と全クライアントへのブロードキャストを同時に行っています。開発サーバーを再起動してもカウントが残っていることも確認しましょう。- 仕上げに
npm run deployでデプロイすると、エージェントは Cloudflare のグローバルネットワーク上で動き、クライアントが誰もいない間はハイバネーションしてコストがかかりません。
つまずきポイント
Workers AI モデルの REST API 呼び出しで cf-aig-gateway-id を忘れる。サードパーティモデルはヘッダ省略時に default ゲートウェイへ自動ルーティングされますが、@cf/ 接頭辞の Workers AI モデルではこのヘッダが常に必須です。また自動作成されるのは ID が default のときだけで、他の名前のゲートウェイは事前作成が必要です。
gateway.ai.cloudflare.com のプロバイダ別エンドポイントで認証エラーになる。自動作成された default ゲートウェイは Authentication が On のため、プロバイダの API キーに加えて cf-aig-authorization: Bearer <CF_API_TOKEN> ヘッダが必要です。付け忘れるとプロバイダ以前にゲートウェイで拒否されます。
キャッシュが効かない・HIT にならない。キャッシュキーはプロバイダ・エンドポイント・モデル・認証ヘッダ・リクエストボディ全体のハッシュで、完全一致したリクエストだけが HIT します。メッセージが 1 文字でも違えば別エントリです。対応するのはテキストと画像の応答のみで、キャッシュは揮発的(同時に同じリクエストが来ると 2 件目が MISS になることがある)です。cf-aig-cache-ttl の最小値は 60 秒です。
Agents で「No such Durable Object class」や @callable() の構文エラーが出る。前者は wrangler.jsonc の migrations に new_sqlite_classes を書き忘れたのが原因です。後者(SyntaxError: Invalid or unexpected token)は 2 点で解消します — vite.config.ts のプラグインに agents/vite を追加し(Vite 8 の変換系は TC39 デコレータ未対応のため)、tsconfig は agents/tsconfig を extends する(target: ES2021 を含む推奨設定。スターターは両方設定済み)。なお experimentalDecorators: true は設定してはいけません — Agents SDK は TC39 標準デコレータを使うため、互換性のない変換が適用されて @callable() が実行時に静かに壊れます。
理解度チェック
Q1. REST API 経由で Workers AI モデルを AI Gateway に通すとき、必須のヘッダは?
cf-aig-gateway-id です。@cf/ 接頭辞の Workers AI モデルでは常に必要です。サードパーティモデルの場合は省略でき、そのときは default ゲートウェイが使われます(存在しなければ初回の認証済みリクエストで自動作成)。
Q2. レスポンスがキャッシュから返されたかどうかは、どうやって確認する?
レスポンスヘッダ cf-aig-cache-status を見ます。HIT ならキャッシュから、MISS ならプロバイダから返された応答です。ダッシュボードのログでも Cached のフィルタで確認できます。
Q3. Universal Endpoint は現在どういう位置づけ?新規開発では何を使う?
非推奨です(既存統合は継続動作)。新規では、単一モデルの呼び出しには OpenAI 互換の REST API を、フォールバック・リトライ・条件付きルーティングには Dynamic Routing を使います。
Q4. Agent クラスで this.setState() を呼ぶと何が起きる?
状態がインスタンス内蔵の SQLite に永続化され(再起動・ハイバネーションを生き延びる)、同時に接続中の全 WebSocket クライアントへブロードキャストされます。クライアント側では useAgent の onStateUpdate コールバックが発火します。
まとめと次章へ
- AI Gateway はアプリと AI プロバイダの間に挟まるプロキシ層で、ログ・分析・キャッシュ・レート制限・フォールバックを提供する。コア機能は無料
- ゲートウェイ ID
defaultは初回の認証済みリクエストで自動作成される。接続方法は REST API・プロバイダ別エンドポイント(base URL 差し替え)・Workers バインディング(gatewayオプション)の 3 つ - キャッシュはリクエスト完全一致で判定され、
cf-aig-cache-ttl/cf-aig-skip-cache/cf-aig-cache-keyヘッダでリクエスト単位の制御ができる - Universal Endpoint は非推奨(応答したステップは
cf-aig-stepヘッダで確認)。フォールバックは Dynamic Routing で構成し、実際に応答したモデルはcf-aig-model/cf-aig-providerヘッダで確認する - Agents SDK は Durable Objects ベースのエージェント基盤。
setState()による永続状態と全クライアント同期、schedule()の 4 モード、@callable()+useAgentの型安全な RPC が柱
AI 編はここまでです。次章からは守りと運用編に入り、Turnstile・WAF・レート制限で bot と攻撃からアプリを守る方法を学びます。