第19章: Vectorize によるエッジRAGパイプライン(実践チュートリアル)
外部のベクトルデータベース(Pinecone等)やOpenAIのAPIキーを一切使わず、Cloudflareのネイティブベクトルデータベース Vectorize と Workers AI だけで、完全エッジ完結・プライバシー安全・超低遅延なRAG(検索拡張生成)システム をゼロから構築します。
本チュートリアルのゴール
- Vectorize インデックスの作成(CLI)
- テキストのベクトル化(Embedding)とVectorizeへの登録
- ユーザーの質問に基づくセマンティック類似検索(Cosine Similarity)
- 検索されたドキュメントをコンテキストとしてLLM(Llama 3)へ渡し、正確な回答を生成するエンドツーエンドRAGパイプライン
【エッジRAGの流れ】[ ユーザーの質問: "Cloudflare R2の料金は?" ] ↓[ Workers AI: テキストをベクトル化 (768次元) ] ↓[ Vectorize: 類似するドキュメントを上位3件検索 ] ↓[ Workers AI (Llama 3): ドキュメントを元に正確な日本語回答を生成 ] ↓[ ユーザーへレスポンス ]Step 1: ベクトルインデックスの作成(CLI)
Embeddingモデル(@cf/baai/bge-base-en-v1.5)の次元数(768次元)に合わせてインデックスを作成します。
npx wrangler vectorize create faq-rag-index \ --dimensions=768 \ --metric=cosine出力例:
✅ Successfully created Vectorize index 'faq-rag-index'Step 2: wrangler.jsonc の設定
{ "name": "edge-rag-service", "main": "src/index.ts", "compatibility_date": "2024-09-01", "compatibility_flags": [ "nodejs_compat" ], "ai": { "binding": "AI" }, "vectorize": [ { "binding": "VECTORIZE", "index_name": "faq-rag-index" } ]}型定義を更新します。
npx wrangler typesStep 3: 完全なRAGパイプラインコード(src/index.ts)
import { Hono } from 'hono';
type Bindings = { AI: Ai; VECTORIZE: VectorizeIndex;};
const app = new Hono<{ Bindings: Bindings }>();
// 1. ドキュメント(ナレッジ)の登録APIapp.post('/api/knowledge', async (c) => { const { id, title, content } = await c.req.json<{ id: string; title: string; content: string }>();
// テキストを768次元のベクトルへ変換 const { data } = await c.env.AI.run('@cf/baai/bge-base-en-v1.5', { text: [content], }); const vector = data[0];
// Vectorizeへメタデータ付きで登録 await c.env.VECTORIZE.upsert([ { id: id, values: vector, metadata: { title, content }, }, ]);
return c.json({ success: true, message: `ナレッジ「${title}」を登録しました` });});
// 2. RAG質問応答API(検索 + LLM生成)app.post('/api/ask', async (c) => { const { question } = await c.req.json<{ question: string }>(); if (!question) return c.json({ error: '質問を入力してください' }, 400);
// ① 質問文をベクトル化 const { data } = await c.env.AI.run('@cf/baai/bge-base-en-v1.5', { text: [question], }); const questionVector = data[0];
// ② Vectorizeで最も関連性の高いドキュメント上位2件を検索 const matches = await c.env.VECTORIZE.query(questionVector, { topK: 2, returnValues: false, returnMetadata: 'all', });
// 検索されたドキュメントのテキストをコンテキストとして結合 const contextDocs = matches.matches .map((m: any) => `【${m.metadata?.title}】: ${m.metadata?.content}`) .join('\n\n');
// ③ コンテキストをプロンプトに埋め込んでLlama 3に回答させる const prompt = `あなたは親切なテクニカルサポートです。以下の参考資料のみに基づいて、ユーザーの質問に日本語で簡潔に回答してください。
参考資料:${contextDocs}
ユーザーの質問:${question}
回答:`;
const aiResponse: any = await c.env.AI.run('@cf/meta/llama-3-8b-instruct', { prompt: prompt, max_tokens: 500, });
return c.json({ answer: aiResponse.response, references: matches.matches.map((m: any) => ({ title: m.metadata?.title, score: m.score, })), });});
export default app;Step 4: 動作検証(curlテスト)
# ローカルサーバー起動(Miniflare)npx wrangler dev1. ナレッジの登録
curl -X POST http://localhost:8787/api/knowledge \ -H "Content-Type: application/json" \ -d '{ "id": "doc_1", "title": "Cloudflare R2の転送量料金", "content": "Cloudflare R2はS3互換のオブジェクトストレージです。最大の特徴は下り転送量(Egress)が完全無料(0円)である点です。保存容量は月10GBまで無料です。" }'2. RAGで質問を投げる
curl -X POST http://localhost:8787/api/ask \ -H "Content-Type: application/json" \ -d '{"question": "R2から画像ファイルをたくさんダウンロードした場合、転送量料金はいくらですか?"}'レスポンス例:
{ "answer": "Cloudflare R2では下り転送量(Egress)が完全無料(0円)のため、画像ファイルをどれだけダウンロードしても転送量料金は発生しません。", "references": [ { "title": "Cloudflare R2の転送量料金", "score": 0.892 } ]}外部APIのコストもトークン漏洩の心配も一切なく、最先端のエッジAI検索基盤が完成します。
まとめ
- Vectorize: 秒間数万クエリのベクトル類似度検索をエッジで実行。
- Workers AI: Embedding生成とLLM推論を外部APIキー不要・従量無料枠内で実行。
- 完全プライベート: 社内ドキュメントが外部の他社APIに流出するリスクをゼロに抑えられます。
💡 用語解説コラム
[!NOTE] RAG (Retrieval-Augmented Generation / 検索拡張生成)
LLMに最新ドキュメントや社内データをベクトル検索させて回答させる手法。AIの嘘(ハルシネーション)を防ぎ、最新情報に基づいた回答が可能になります。
[!NOTE] コサイン類似度 (Cosine Similarity)
2つのベクトルが向いている方向の一致度(-1〜1)を測る指標。テキスト同士の意味的な近さを判定する最も代表的な計算手法です。