【2026年版】Cloudflare Workers AI活用ガイド:エッジでAI推論を実行する方法

Tech Trends AI
- 6 minutes read - 1186 wordsはじめに:エッジAI推論の新たな選択肢
AI推論をプロダクション環境で運用する際、レイテンシとコストは最大の課題です。従来のクラウドベースの推論では、ユーザーから離れたリージョンにリクエストが送られることで数百ミリ秒のレイテンシが発生し、GPUインスタンスの常時起動によるコストも無視できません。
Cloudflare Workers AIは、Cloudflareのグローバルエッジネットワーク上でAIモデルを直接実行できるプラットフォームです。世界300以上の拠点にGPUが配備されており、ユーザーに最も近いエッジでAI推論を実行できます。
本記事では、Workers AIのセットアップから主要なAIタスクの実装、パフォーマンス最適化、本番運用までを実践的に解説します。
Cloudflare Workers AIの概要
アーキテクチャと特徴
| 特徴 | 説明 |
|---|---|
| グローバルエッジ | 300以上の拠点でGPU推論が可能 |
| サーバーレス | インフラ管理不要、リクエスト単位の課金 |
| 低レイテンシ | ユーザー最寄りのエッジで推論実行 |
| 事前最適化モデル | 量子化・最適化済みモデルが利用可能 |
| 統合エコシステム | Workers、D1、R2、Vectorize等と連携 |
| 従量課金 | 無料枠あり、使った分だけ課金 |
対応モデルと料金体系
| カテゴリ | モデル例 | 無料枠(日) | 料金目安 |
|---|---|---|---|
| テキスト生成(LLM) | Llama 3.1 8B, Mistral 7B | 10,000ニューロン | $0.011/1Kニューロン |
| テキスト埋め込み | bge-base-en, bge-large-en | 10,000ニューロン | $0.011/1Kニューロン |
| 画像分類 | ResNet-50 | 10,000ニューロン | $0.011/1Kニューロン |
| 画像生成 | Stable Diffusion XL | 10,000ニューロン | $0.011/1Kニューロン |
| 音声認識 | Whisper | 10,000ニューロン | $0.011/1Kニューロン |
| 翻訳 | m2m100 | 10,000ニューロン | $0.011/1Kニューロン |
| 要約 | bart-large-cnn | 10,000ニューロン | $0.011/1Kニューロン |
環境セットアップ
プロジェクトの初期化
# Wrangler CLIのインストール
npm install -g wrangler
# プロジェクト作成
wrangler init my-ai-worker
cd my-ai-worker
# Workers AIバインディングの設定
wrangler.tomlの設定
name = "my-ai-worker"
main = "src/index.ts"
compatibility_date = "2026-01-01"
[ai]
binding = "AI"
# D1データベース(オプション)
[[d1_databases]]
binding = "DB"
database_name = "my-ai-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# Vectorizeインデックス(RAG用)
[[vectorize]]
binding = "VECTORIZE_INDEX"
index_name = "my-embeddings"
# R2ストレージ(画像保存等)
[[r2_buckets]]
binding = "R2_BUCKET"
bucket_name = "my-ai-assets"
# 環境変数
[vars]
ENVIRONMENT = "production"
MAX_TOKENS = "512"
主要AIタスクの実装
1. テキスト生成(LLM推論)
import { Ai } from '@cloudflare/ai';
export interface Env {
AI: any;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
const { prompt, system_prompt } = await request.json() as {
prompt: string;
system_prompt?: string;
};
const messages = [
{
role: 'system',
content: system_prompt || 'あなたは親切で有能なAIアシスタントです。',
},
{
role: 'user',
content: prompt,
},
];
// Llama 3.1 8B Instructモデルで推論
const response = await ai.run(
'@cf/meta/llama-3.1-8b-instruct',
{
messages,
max_tokens: 512,
temperature: 0.7,
top_p: 0.9,
}
);
return Response.json({
success: true,
result: response,
});
},
};
2. ストリーミングレスポンス
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
const { prompt } = await request.json() as { prompt: string };
// ストリーミングモードで推論
const stream = await ai.run(
'@cf/meta/llama-3.1-8b-instruct',
{
messages: [
{ role: 'system', content: '日本語で回答してください。' },
{ role: 'user', content: prompt },
],
max_tokens: 1024,
stream: true,
}
);
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
},
};
3. テキスト埋め込み(Embedding)生成
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
const { texts } = await request.json() as { texts: string[] };
// BGEモデルで埋め込みベクトル生成
const embeddings = await ai.run(
'@cf/baai/bge-base-en-v1.5',
{
text: texts,
}
);
return Response.json({
success: true,
embeddings: embeddings.data,
dimensions: embeddings.data[0].length,
});
},
};
4. 画像分類
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
// 画像データを取得
const imageBuffer = await request.arrayBuffer();
// ResNet-50で画像分類
const result = await ai.run(
'@cf/microsoft/resnet-50',
{
image: [...new Uint8Array(imageBuffer)],
}
);
return Response.json({
success: true,
classifications: result,
});
},
};
5. 音声文字起こし(Whisper)
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
const audioBuffer = await request.arrayBuffer();
// Whisperで音声をテキストに変換
const result = await ai.run(
'@cf/openai/whisper',
{
audio: [...new Uint8Array(audioBuffer)],
}
);
return Response.json({
success: true,
text: result.text,
segments: result.segments,
});
},
};
RAGシステムの構築
Vectorize + Workers AIによるRAG
Cloudflareのエコシステムを活用して、完全なRAGパイプラインをエッジで構築できます。
import { Ai } from '@cloudflare/ai';
interface Env {
AI: any;
VECTORIZE_INDEX: VectorizeIndex;
DB: D1Database;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
const url = new URL(request.url);
// ドキュメント登録エンドポイント
if (url.pathname === '/api/documents' && request.method === 'POST') {
return handleDocumentIngestion(request, env, ai);
}
// 質問応答エンドポイント
if (url.pathname === '/api/query' && request.method === 'POST') {
return handleQuery(request, env, ai);
}
return new Response('Not Found', { status: 404 });
},
};
async function handleDocumentIngestion(
request: Request, env: Env, ai: Ai
): Promise<Response> {
const { documents } = await request.json() as {
documents: { id: string; text: string; metadata: any }[];
};
// 埋め込みベクトル生成
const embeddings = await ai.run('@cf/baai/bge-base-en-v1.5', {
text: documents.map(d => d.text),
});
// Vectorizeに保存
const vectors = documents.map((doc, i) => ({
id: doc.id,
values: embeddings.data[i],
metadata: {
text: doc.text,
...doc.metadata,
},
}));
await env.VECTORIZE_INDEX.upsert(vectors);
// D1にもドキュメントを保存
const stmt = env.DB.prepare(
'INSERT OR REPLACE INTO documents (id, text, metadata) VALUES (?, ?, ?)'
);
await env.DB.batch(
documents.map(doc =>
stmt.bind(doc.id, doc.text, JSON.stringify(doc.metadata))
)
);
return Response.json({
success: true,
indexed: documents.length,
});
}
async function handleQuery(
request: Request, env: Env, ai: Ai
): Promise<Response> {
const { question, top_k = 5 } = await request.json() as {
question: string;
top_k?: number;
};
// 質問を埋め込みベクトルに変換
const queryEmbedding = await ai.run('@cf/baai/bge-base-en-v1.5', {
text: [question],
});
// ベクトル検索
const searchResults = await env.VECTORIZE_INDEX.query(
queryEmbedding.data[0],
{
topK: top_k,
returnMetadata: true,
}
);
// 検索結果からコンテキストを構築
const context = searchResults.matches
.map(match => match.metadata?.text || '')
.join('\n\n');
// LLMで回答を生成
const answer = await ai.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [
{
role: 'system',
content: `以下のコンテキストに基づいて質問に回答してください。
コンテキストに含まれない情報については「情報が見つかりません」と回答してください。
コンテキスト:
${context}`,
},
{ role: 'user', content: question },
],
max_tokens: 1024,
temperature: 0.3,
});
return Response.json({
success: true,
answer: answer.response,
sources: searchResults.matches.map(m => ({
id: m.id,
score: m.score,
text: m.metadata?.text,
})),
});
}
パフォーマンス最適化
他プラットフォームとの比較
| 指標 | Workers AI | AWS Lambda + SageMaker | Google Cloud Run |
|---|---|---|---|
| コールドスタート | なし(常時稼働) | 数秒〜数十秒 | 数秒 |
| レイテンシ(P50) | 50〜200ms | 200〜500ms | 150〜400ms |
| グローバル展開 | 自動(300+拠点) | リージョン選択が必要 | リージョン選択が必要 |
| 最小課金単位 | リクエスト単位 | 秒単位 | 秒単位 |
| GPU管理 | 不要 | 必要 | 必要 |
| モデルカスタマイズ | 限定的 | 自由 | 自由 |
キャッシュ戦略
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ai = new Ai(env.AI);
const { prompt } = await request.json() as { prompt: string };
// Cache APIを使用してAI推論結果をキャッシュ
const cache = caches.default;
const cacheKey = new Request(
`https://ai-cache/${encodeURIComponent(prompt)}`,
{ method: 'GET' }
);
let cachedResponse = await cache.match(cacheKey);
if (cachedResponse) {
return cachedResponse;
}
// キャッシュミス時にAI推論を実行
const result = await ai.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [
{ role: 'user', content: prompt },
],
max_tokens: 512,
});
const response = Response.json({
success: true,
result: result,
cached: false,
});
// レスポンスをキャッシュ(1時間)
response.headers.set('Cache-Control', 'public, max-age=3600');
await cache.put(cacheKey, response.clone());
return response;
},
};
レート制限の実装
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// クライアントIPでレート制限
const clientIP = request.headers.get('CF-Connecting-IP') || 'unknown';
// KVを使ったシンプルなレート制限
const rateLimitKey = `rate:${clientIP}`;
const currentCount = parseInt(
await env.KV.get(rateLimitKey) || '0'
);
if (currentCount >= 60) { // 1分あたり60リクエスト
return new Response(
JSON.stringify({ error: 'Rate limit exceeded' }),
{
status: 429,
headers: {
'Content-Type': 'application/json',
'Retry-After': '60',
},
}
);
}
// カウントをインクリメント
await env.KV.put(rateLimitKey, String(currentCount + 1), {
expirationTtl: 60,
});
// AI推論処理...
const ai = new Ai(env.AI);
const result = await ai.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [{ role: 'user', content: 'Hello' }],
});
return Response.json({ success: true, result });
},
};
デプロイとCI/CD
GitHub Actionsによる自動デプロイ
name: Deploy Workers AI
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy
ステージング環境の設定
# wrangler.toml
[env.staging]
name = "my-ai-worker-staging"
vars = { ENVIRONMENT = "staging", MAX_TOKENS = "256" }
[env.production]
name = "my-ai-worker"
vars = { ENVIRONMENT = "production", MAX_TOKENS = "512" }
# ステージングにデプロイ
wrangler deploy --env staging
# 本番にデプロイ
wrangler deploy --env production
ユースケース別アーキテクチャ
チャットボットアプリケーション
[ユーザー] → [Cloudflare CDN]
↓
[Workers AI]
├── テキスト生成(Llama 3.1)
├── 文脈検索(Vectorize + BGE)
└── 会話履歴(D1 / KV)
↓
[ストリーミングレスポンス]
コンテンツモデレーション
[ユーザー投稿] → [Workers]
├── テキスト分類(有害コンテンツ検知)
├── 画像分類(不適切画像検知)
└── 結果をD1に記録
↓
[承認 / 拒否 / レビュー]
多言語カスタマーサポート
[多言語入力] → [Workers AI]
├── 言語検出
├── 翻訳(m2m100)
├── FAQ検索(Vectorize)
└── 回答生成(Llama 3.1)
↓
[多言語レスポンス]
制約事項と注意点
| 制約 | 詳細 | 対策 |
|---|---|---|
| モデルサイズ | 大規模モデルは非対応(70B以上) | 8B/7Bクラスのモデルを利用 |
| カスタムモデル | 現時点では事前提供モデルのみ | ファインチューニング機能の活用 |
| 実行時間 | Workerの実行時間制限あり | ストリーミングで対応 |
| コンテキスト長 | モデルにより異なる | 入力の前処理で調整 |
| リージョン指定 | エッジの自動選択のため不可 | 特定リージョンが必要なら他を検討 |
まとめ
Cloudflare Workers AIは、エッジでAI推論を手軽に実行できる強力なプラットフォームです。
- 低レイテンシ:グローバルエッジネットワークでユーザーに近い場所で推論
- ゼロ運用負荷:サーバーレスでインフラ管理が不要
- 統合エコシステム:Vectorize、D1、R2等との組み合わせでRAGも構築可能
- コスト効率:従量課金で無料枠もあり、スモールスタートに最適
- 迅速なデプロイ:
wrangler deploy一発でグローバル展開
一方で、大規模モデルやカスタムモデルの利用には制約があるため、要件に応じてクラウドベースの推論サービスとの使い分けが重要です。まずはプロトタイプをWorkers AIで構築し、要件が明確になった段階で最適なインフラを選定するアプローチが推奨されます。