cloudflare-agents について
Cloudflare Agents SDKは、Cloudflare WorkersとDurable Objects上でステートフルなAIエージェントを構築する開発者向けSDKです。状態の永続化やリアルタイム通信に加え、タスクのスケジュールやMCPサーバーの実装に対応します。
主な機能
- 01Durable Objects上でのエージェント構築
- 02WebSocketsとSSEによるリアルタイム通信
- 03SQLiteによる状態の永続化
- 04遅延・日時・cronによるタスク実行
- 05非同期Cloudflare Workflowsの起動
- 06MCPサーバーの構築
活用シーン
- 01リアルタイムチャットエージェントの構築
- 02定期チェックやリマインダーの設定
- 03対話型エージェントとバックグラウンド処理の連携
- 04人による確認を含むプロセスの実装
MCP 対応
Model Context Protocolを実装するMCPサーバーを構築し、MCPクライアントに接続できます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill cloudflare-agentsインストール後、Claude Code で/cloudflare-agentsを入力して読み込まれたか確認します。
同梱ファイルREADME.mdSKILL.json
詳細
Cloudflare Agents SDK
ステータス:本番環境で利用可能 ✅ 最終更新日:2025-10-21 依存関係:cloudflare-worker-base(推奨) 最新バージョン:agents@latest、@modelcontextprotocol/sdk@latest 本番環境でのテスト済み:Cloudflare 独自の MCP サーバー(https://github.com/cloudflare/mcp-server-cloudflare)
Cloudflare Agents とは?
Cloudflare Agents SDK を使用すると、Cloudflare Workers + Durable Objects 上で動作する、AI を活用した自律型エージェントを構築できます。エージェントは次のことができます。
- WebSocket と Server-Sent Events を介したリアルタイム通信
- 組み込みの SQLite データベース(エージェントあたり最大 1GB)を使用した状態の永続化
- 遅延時間、指定日、または cron 式を使用したタスクのスケジュール
- Cloudflare Workflows を非同期で起動したワークフローの実行
- Browser Rendering API + Puppeteer を使用したWeb の閲覧
- Vectorize ベクトルデータベース + Workers AI の埋め込みを使用したRAG の実装
- Model Context Protocol を実装したMCP サーバーの構築
- レビューと承認のための人間参加型パターンのサポート
- 世界中で数百万の独立したエージェントインスタンスにスケール
各エージェントインスタンスは、数秒、数分、または数時間動作できる、グローバルに一意なステートフルのマイクロサーバーです。
クイックスタート(10 分)
1. テンプレートでプロジェクトをスキャフォールディングする
npm create cloudflare@latest my-agent -- \
--template=cloudflare/agents-starter \
--ts \
--git \
--deploy false
作成されるもの:
- 完全なエージェントプロジェクト構成
- TypeScript の設定
- Durable Objects バインディングを含む wrangler.jsonc
- チャットエージェントの実装例
- useAgent フックを備えた React クライアント
2. または既存の Worker に追加する
cd my-existing-worker
npm install agents
続いて、Agent クラスを作成します。
// src/index.ts
import { Agent, AgentNamespace } from "agents";
export class MyAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
return new Response("Hello from Agent!");
}
}
export default MyAgent;
3. Durable Objects バインディングを設定する
wrangler.jsonc を作成または更新します。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-agent",
"main": "src/index.ts",
"compatibility_date": "2025-10-21",
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [
{
"name": "MyAgent", // MUST match class name
"class_name": "MyAgent" // MUST match exported class
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["MyAgent"] // CRITICAL: Enables SQLite storage
}
]
}
重要な設定ルール:
- ✅
nameとclass_nameは必ず同一にする必要があります - ✅
new_sqlite_classesは最初のマイグレーションに必ず含める必要があります(後から追加できません) - ✅ Agent クラスは必ずエクスポートする必要があります(そうしないとバインディングが失敗します)
- ✅ マイグレーションタグは再利用できません(各マイグレーションに一意のタグが必要です)
4. デプロイする
npx wrangler@latest deploy
エージェントは次の場所で実行されています:https://my-agent.<subdomain>.workers.dev
設定の詳細
wrangler.jsonc の完全な例
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-agent",
"main": "src/index.ts",
"account_id": "YOUR_ACCOUNT_ID",
"compatibility_date": "2025-10-21",
"compatibility_flags": ["nodejs_compat"],
// Durable Objects configuration (REQUIRED)
"durable_objects": {
"bindings": [
{
"name": "MyAgent",
"class_name": "MyAgent"
}
]
},
// Migrations (REQUIRED)
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["MyAgent"] // Enables state persistence
}
],
// Optional: Workers AI binding (for AI model calls)
"ai": {
"binding": "AI"
},
// Optional: Vectorize binding (for RAG)
"vectorize": {
"bindings": [
{
"binding": "VECTORIZE",
"index_name": "my-agent-vectors"
}
]
},
// Optional: Browser Rendering binding (for web browsing)
"browser": {
"binding": "BROWSER"
},
// Optional: Workflows binding (for async workflows)
"workflows": [
{
"name": "MY_WORKFLOW",
"class_name": "MyWorkflow",
"script_name": "my-workflow-script" // If in different project
}
],
// Optional: D1 binding (for additional persistent data)
"d1_databases": [
{
"binding": "DB",
"database_name": "my-agent-db",
"database_id": "your-database-id"
}
],
// Optional: R2 binding (for file storage)
"r2_buckets": [
{
"binding": "BUCKET",
"bucket_name": "my-agent-files"
}
],
// Optional: Environment variables
"vars": {
"ENVIRONMENT": "production"
},
// Optional: Secrets (set with: wrangler secret put KEY)
// OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.
// Observability
"observability": {
"enabled": true
}
}
マイグレーションのベストプラクティス
アトミックなデプロイ:マイグレーションはアトミックな操作であり、段階的にデプロイすることはできません。
{
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["MyAgent"] // Initial: enable SQLite
},
{
"tag": "v2",
"renamed_classes": [
{"from": "MyAgent", "to": "MyRenamedAgent"}
]
},
{
"tag": "v3",
"deleted_classes": ["OldAgent"]
},
{
"tag": "v4",
"transferred_classes": [
{
"from": "AgentInOldScript",
"from_script": "old-worker",
"to": "AgentInNewScript"
}
]
}
]
}
マイグレーションのルール:
- ✅ 各マイグレーションには一意の
tagが必要です - ✅ デプロイ済みの既存クラスで SQLite を有効にすることはできません(最初のマイグレーションに含める必要があります)
- ✅ デプロイ時にマイグレーションが順番に適用されます
- ✅ 以前のマイグレーションタグを編集または削除することはできません
- ❌ 新しいマイグレーションを段階的にデプロイしないでください(アトミックなデプロイのみ)
環境ごとのマイグレーション
{
"migrations": [{"tag": "v1", "new_sqlite_classes": ["MyAgent"]}],
"env": {
"staging": {
"migrations": [
{"tag": "v1", "new_sqlite_classes": ["MyAgent"]},
{"tag": "v2-staging", "renamed_classes": [{"from": "MyAgent", "to": "StagingAgent"}]}
]
}
}
}
Agent クラス API
Agent クラスは Agents SDK の基盤です。これを拡張してエージェントを作成します。
基本的な Agent 構造
import { Agent } from "agents";
interface Env {
// Environment variables and bindings
OPENAI_API_KEY: string;
AI: Ai;
VECTORIZE: Vectorize;
DB: D1Database;
}
interface State {
// Your agent's persistent state
counter: number;
messages: string[];
lastUpdated: Date | null;
}
export class MyAgent extends Agent<Env, State> {
// Optional: Set initial state (first time agent is created)
initialState: State = {
counter: 0,
messages: [],
lastUpdated: null
};
// Optional: Called when agent instance starts or wakes from hibernation
async onStart() {
console.log('Agent started:', this.name, 'State:', this.state);
}
// Handle HTTP requests
async onRequest(request: Request): Promise<Response> {
return Response.json({ message: "Hello from Agent", state: this.state });
}
// Handle WebSocket connections (optional)
async onConnect(connection: Connection, ctx: ConnectionContext) {
console.log('Client connected:', connection.id);
// Connections are automatically accepted
}
// Handle WebSocket messages (optional)
async onMessage(connection: Connection, message: WSMessage) {
if (typeof message === 'string') {
connection.send(`Echo: ${message}`);
}
}
// Handle WebSocket errors (optional)
async onError(connection: Connection, error: unknown): Promise<void> {
console.error('Connection error:', error);
}
// Handle WebSocket close (optional)
async onClose(connection: Connection, code: number, reason: string, wasClean: boolean): Promise<void> {
console.log('Connection closed:', code, reason);
}
// Called when state is updated from any source (optional)
onStateUpdate(state: State, source: "server" | Connection) {
console.log('State updated:', state, 'Source:', source);
}
// Custom methods (call from any handler)
async customMethod(data: any) {
this.setState({
...this.state,
counter: this.state.counter + 1,
lastUpdated: new Date()
});
}
}
Agent のプロパティへのアクセス
Agent の任意のメソッド内で:
export class MyAgent extends Agent<Env, State> {
async someMethod() {
// Access environment variables and bindings
const apiKey = this.env.OPENAI_API_KEY;
const ai = this.env.AI;
// Access current state (read-only)
const counter = this.state.counter;
// Update state (persisted automatically)
this.setState({ ...this.state, counter: counter + 1 });
// Access SQL database
const results = await this.sql`SELECT * FROM users`;
// Get agent instance name
const instanceName = this.name; // e.g., "user-123"
// Schedule tasks
await this.schedule(60, "runLater", { data: "example" });
// Call other methods
await this.customMethod({ foo: "bar" });
}
}
HTTP と Server-Sent Events
HTTP リクエストの処理
export class MyAgent extends Agent<Env> {
async onRequest(request: Request): Promise<Response> {
const url = new URL(request.url);
const method = request.method;
if (method === "POST" && url.pathname === "/increment") {
const counter = (this.state.counter || 0) + 1;
this.setState({ ...this.state, counter });
return Response.json({ counter });
}
if (method === "GET" && url.pathname === "/status") {
return Response.json({ state: this.state, name: this.name });
}
return new Response("Not Found", { status: 404 });
}
}
Server-Sent Events(SSE)ストリーミング
export class MyAgent extends Agent<Env> {
async onRequest(request: Request): Promise<Response> {
const stream = new ReadableStream({
async start(controller) {
const encoder = new TextEncoder();
// Send events to client
controller.enqueue(encoder.encode('data: {"message": "Starting"}\n\n'));
await new Promise(resolve => setTimeout(resolve, 1000));
controller.enqueue(encoder.encode('data: {"message": "Processing"}\n\n'));
await new Promise(resolve => setTimeout(resolve, 1000));
controller.enqueue(encoder.encode('data: {"message": "Complete"}\n\n'));
controller.close();
}
});
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
}
});
}
}
SSE と WebSockets の比較:
| 機能 | SSE | WebSockets |
|---|---|---|
| 方向 | サーバー → クライアントのみ | 双方向 |
| プロトコル | HTTP | ws:// または wss:// |
| 再接続 | 自動 | 手動 |
| バイナリデータ | 制限あり | 完全にサポート |
| 用途 | ストリーミング応答、通知 | チャット、リアルタイムコラボレーション |
推奨:ほとんどのエージェントアプリケーションでは WebSockets を使用してください(全二重通信が可能で、長時間のセッションに適しています)。
WebSockets
WebSocket の完全な例
import { Agent, Connection, ConnectionContext, WSMessage } from "agents";
interface ChatState {
messages: Array<{ id: string; text: string; sender: string; timestamp: number }>;
participants: string[];
}
export class ChatAgent extends Agent<Env, ChatState> {
initialState: ChatState = {
messages: [],
participants: []
};
async onConnect(connection: Connection, ctx: ConnectionContext) {
// Access original HTTP request for auth
const authHeader = ctx.request.headers.get('Authorization');
const userId = ctx.request.headers.get('X-User-ID') || 'anonymous';
// Connections are automatically accepted
// Optionally close connection if unauthorized:
// if (!authHeader) {
// connection.close(401, "Unauthorized");
// return;
// }
// Add to participants
this.setState({
...this.state,
participants: [...this.state.participants, userId]
});
// Send welcome message
connection.send(JSON.stringify({
type: 'welcome',
message: 'Connected to chat',
participants: this.state.participants
}));
}
async onMessage(connection: Connection, message: WSMessage) {
if (typeof message === 'string') {
try {
const data = JSON.parse(message);
if (data.type === 'chat') {
// Add message to state
const newMessage = {
id: crypto.randomUUID(),
text: data.text,
sender: data.sender || 'anonymous',
timestamp: Date.now()
};
this.setState({
...this.state,
messages: [...this.state.messages, newMessage]
});
// Broadcast to this connection (state sync will broadcast to all)
connection.send(JSON.stringify({
type: 'message_added',
message: newMessage
}));
}
} catch (e) {
connection.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
}
}
}
async onError(connection: Connection, error: unknown): Promise<void> {
console.error('WebSocket error:', error);
// Optionally log to external monitoring
}
async onClose(connection: Connection, code: number, reason: string, wasClean: boolean): Promise<void> {
console.log(`Connection ${connection.id} closed:`, code, reason, wasClean);
// Clean up connection-specific state if needed
}
}
接続の管理
export class MyAgent extends Agent {
async onMessage(connection: Connection, message: WSMessage) {
// Connection properties
const connId = connection.id; // Unique connection ID
const connState = connection.state; // Connection-specific state
// Update connection state (not agent state)
connection.setState({ ...connection.state, lastActive: Date.now() });
// Send to this connection only
connection.send("Message to this client");
// Close connection programmatically
connection.close(1000, "Goodbye");
}
}
状態管理
setState() の使用
interface UserState {
name: string;
email: string;
preferences: { theme: string; notifications: boolean };
loginCount: number;
lastLogin: Date | null;
}
export class UserAgent extends Agent<Env, UserState> {
initialState: UserState = {
name: "",
email: "",
preferences: { theme: "dark", notifications: true },
loginCount: 0,
lastLogin: null
};
async onRequest(request: Request): Promise<Response> {
if (request.method === "POST" && new URL(request.url).pathname === "/login") {
// Update state
this.setState({
...this.state,
loginCount: this.state.loginCount + 1,
lastLogin: new Date()
});
// State is automatically persisted and synced to connected clients
return Response.json({ success: true, state: this.state });
}
return Response.json({ state: this.state });
}
onStateUpdate(state: UserState, source: "server" | Connection) {
console.log('State updated:', state);
console.log('Source:', source); // "server" or Connection object
// React to state changes
if (state.loginCount > 10) {
console.log('Frequent user!');
}
}
}
状態のルール:
- ✅ 状態は JSON でシリアライズ可能です(オブジェクト、配列、文字列、数値、ブール値、null)
- ✅ エージェントの再起動後も状態は保持されます
- ✅ エージェント内では状態がすぐに一貫します
- ✅ 状態は接続中の WebSocket クライアントに自動的に同期されます
- ❌ 状態に関数や循環参照を含めることはできません
- ❌ 状態の合計サイズはデータベースサイズによって制限されます(エージェントあたり最大 1GB)
SQL データベースの使用
各エージェントには、this.sql からアクセスできる SQLite データベースが組み込まれています。
export class MyAgent extends Agent {
async onStart() {
// Create tables on first start
await this.sql`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`;
await this.sql`
CREATE INDEX IF NOT EXISTS idx_email ON users(email)
`;
}
async addUser(name: string, email: string) {
// Insert with prepared statement (prevents SQL injection)
const result = await this.sql`
INSERT INTO users (name, email)
VALUES (${name}, ${email})
`;
return result;
}
async getUser(email: string) {
// Query returns array of results
const users = await this.sql`
SELECT * FROM users WHERE email = ${email}
`;
return users[0] || null;
}
async getAllUsers() {
const users = await this.sql`
SELECT * FROM users ORDER BY created_at DESC
`;
return users;
}
async updateUser(id: number, name: string) {
await this.sql`
UPDATE users SET name = ${name} WHERE id = ${id}
`;
}
async deleteUser(id: number) {
await this.sql`
DELETE FROM users WHERE id = ${id}
`;
}
}
SQL のベストプラクティス:
- ✅ タグ付きテンプレートリテラルを使用します(SQL インジェクションを防止します)
- ✅ 頻繁にクエリするカラムにはインデックスを作成します
- ✅ 複数の関連する操作にはトランザクションを使用します
- ✅ クエリ結果は常に配列です(1 行の場合も同様です)
- ❌ SQL 文字列を手動で構築しないでください
- ❌ データベースのサイズ上限が 1GB であることに注意してください
タスクのスケジュール設定
エージェントは this.schedule() を使用して、将来実行するタスクをスケジュールできます。
遅延(秒)
export class MyAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
// Schedule task to run in 60 seconds
const { id } = await this.schedule(60, "checkStatus", { requestId: "123" });
return Response.json({ scheduledTaskId: id });
}
// This method will be called in 60 seconds
async checkStatus(data: { requestId: string }) {
console.log('Checking status for request:', data.requestId);
// Perform check, update state, send notification, etc.
}
}
特定の日付
export class MyAgent extends Agent {
async scheduleReminder(reminderDate: string) {
const date = new Date(reminderDate);
const { id } = await this.schedule(date, "sendReminder", {
message: "Time for your appointment!"
});
return id;
}
async sendReminder(data: { message: string }) {
console.log('Sending reminder:', data.message);
// Send email, push notification, etc.
}
}
Cron 式
export class MyAgent extends Agent {
async setupRecurringTasks() {
// Every 10 minutes
await this.schedule("*/10 * * * *", "checkUpdates", {});
// Every day at 8 AM
await this.schedule("0 8 * * *", "dailyReport", {});
// Every Monday at 9 AM
await this.schedule("0 9 * * 1", "weeklyReport", {});
// Every hour on the hour
await this.schedule("0 * * * *", "hourlyCheck", {});
}
async checkUpdates(data: any) {
console.log('Checking for updates...');
}
async dailyReport(data: any) {
console.log('Generating daily report...');
}
async weeklyReport(data: any) {
console.log('Generating weekly report...');
}
async hourlyCheck(data: any) {
console.log('Running hourly check...');
}
}
スケジュール済みタスクの管理
export class MyAgent extends Agent {
async manageSchedules() {
// Get all scheduled tasks
const allTasks = this.getSchedules();
console.log('Total tasks:', allTasks.length);
// Get specific task by ID
const taskId = "some-task-id";
const task = await this.getSchedule(taskId);
if (task) {
console.log('Task:', task.callback, 'at', new Date(task.time));
console.log('Payload:', task.payload);
console.log('Type:', task.type); // "scheduled" | "delayed" | "cron"
// Cancel the task
const cancelled = await this.cancelSchedule(taskId);
console.log('Cancelled:', cancelled);
}
// Get tasks in time range
const upcomingTasks = this.getSchedules({
timeRange: {
start: new Date(),
end: new Date(Date.now() + 24 * 60 * 60 * 1000) // Next 24 hours
}
});
console.log('Upcoming tasks:', upcomingTasks.length);
// Filter by type
const cronTasks = this.getSchedules({ type: "cron" });
const delayedTasks = this.getSchedules({ type: "delayed" });
}
}
スケジュール設定の制約:
- 各タスクは SQL データベースの 1 行に対応します(タスクあたり最大 2 MB)
- タスクの合計数は次の条件によって制限されます:
(task_size * count) + other_state < 1GB - Cron タスクは明示的にキャンセルするまで実行され続けます
- コールバックメソッドは Agent クラスに存在する必要があります(存在しない場合はエラーが発生します)
重大なエラー:コールバックメソッドが存在しない場合:
// ❌ BAD: Method doesn't exist
await this.schedule(60, "nonExistentMethod", {});
// ✅ GOOD: Method exists
await this.schedule(60, "existingMethod", {});
async existingMethod(data: any) {
// Implementation
}
ワークフローの実行
エージェントは非同期の Cloudflare Workflows をトリガーできます。
ワークフローのバインディング設定
wrangler.jsonc:
{
"workflows": [
{
"name": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
]
}
ワークフローが別のスクリプトにある場合:
{
"workflows": [
{
"name": "EMAIL_WORKFLOW",
"class_name": "EmailWorkflow",
"script_name": "email-workflows" // Different project
}
]
}
ワークフローのトリガー
import { Agent } from "agents";
import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep } from "cloudflare:workers";
interface Env {
MY_WORKFLOW: Workflow;
MyAgent: AgentNamespace<MyAgent>;
}
export class MyAgent extends Agent<Env> {
async onRequest(request: Request): Promise<Response> {
const userId = new URL(request.url).searchParams.get('userId');
// Trigger a workflow immediately
const instance = await this.env.MY_WORKFLOW.create({
id: `user-${userId}`,
params: { userId, action: "process" }
});
// Or schedule a delayed workflow trigger
await this.schedule(300, "runWorkflow", { userId });
return Response.json({ workflowId: instance.id });
}
async runWorkflow(data: { userId: string }) {
const instance = await this.env.MY_WORKFLOW.create({
id: `delayed-${data.userId}`,
params: data
});
// Monitor workflow status periodically
await this.schedule("*/5 * * * *", "checkWorkflowStatus", { id: instance.id });
}
async checkWorkflowStatus(data: { id: string }) {
// Check workflow status (see Workflows docs for details)
console.log('Checking workflow:', data.id);
}
}
// Workflow definition (can be in same or different file/project)
export class MyWorkflow extends WorkflowEntrypoint<Env> {
async run(event: WorkflowEvent<{ userId: string }>, step: WorkflowStep) {
// Workflow implementation
const result = await step.do('process-data', async () => {
return { processed: true };
});
return result;
}
}
エージェントとワークフロー
| 機能 | エージェント | ワークフロー |
|---|---|---|
| 目的 | インタラクティブで、ユーザー向け | バックグラウンド処理 |
| 期間 | 数秒から数時間 | 数分から数時間 |
| 状態 | SQLite データベース | ステップベースのチェックポイント |
| インタラクション | WebSocket、HTTP | 直接のインタラクションなし |
| 再試行 | 手動 | 各ステップで自動 |
| ユースケース | チャット、リアルタイム UI | ETL、バッチ処理 |
ベストプラクティス:複数のワークフローを連携させるにはエージェントを使用します。エージェントはユーザーとのインタラクションを維持しながら、ワークフローをトリガー、監視し、その結果に応答できます。
Web の閲覧
エージェントは Browser Rendering を使用して Web を閲覧できます。
Browser Rendering バインディング
wrangler.jsonc:
{
"browser": {
"binding": "BROWSER"
}
}
インストール
npm install @cloudflare/puppeteer
Web スクレイピングの例
import { Agent } from "agents";
import puppeteer from "@cloudflare/puppeteer";
interface Env {
BROWSER: Fetcher;
OPENAI_API_KEY: string;
}
export class BrowserAgent extends Agent<Env> {
async browse(urls: string[]) {
const responses = [];
for (const url of urls) {
const browser = await puppeteer.launch(this.env.BROWSER);
const page = await browser.newPage();
await page.goto(url);
await page.waitForSelector("body");
const bodyContent = await page.$eval("body", el => el.innerHTML);
// Extract data with AI
const data = await this.extractData(bodyContent);
responses.push({ url, data });
await browser.close();
}
return responses;
}
async extractData(html: string): Promise<any> {
// Use OpenAI or Workers AI to extract structured data
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{
role: 'user',
content: `Extract product info from HTML: ${html.slice(0, 4000)}`
}],
response_format: { type: "json_object" }
})
});
const result = await response.json();
return JSON.parse(result.choices[0].message.content);
}
async onRequest(request: Request): Promise<Response> {
const url = new URL(request.url).searchParams.get('url');
if (!url) {
return new Response("Missing url parameter", { status: 400 });
}
const results = await this.browse([url]);
return Response.json(results);
}
}
スクリーンショットの取得
export class ScreenshotAgent extends Agent<Env> {
async captureScreenshot(url: string): Promise<Buffer> {
const browser = await puppeteer.launch(this.env.BROWSER);
const page = await browser.newPage();
await page.goto(url);
const screenshot = await page.screenshot({ fullPage: true });
await browser.close();
return screenshot;
}
}
検索拡張生成(RAG)
Vectorize と Workers AI の埋め込みを使用して RAG を実装します。
Vectorize バインディング
wrangler.jsonc:
{
"ai": {
"binding": "AI"
},
"vectorize": {
"bindings": [
{
"binding": "VECTORIZE",
"index_name": "my-agent-vectors"
}
]
}
}
インデックスの作成
npx wrangler vectorize create my-agent-vectors \
--dimensions=768 \
--metric=cosine
RAG の完全な実装
import { Agent } from "agents";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
interface Env {
AI: Ai;
VECTORIZE: Vectorize;
OPENAI_API_KEY: string;
}
export class RAGAgent extends Agent<Env> {
// Ingest documents
async ingestDocuments(documents: Array<{ id: string; text: string; metadata: any }>) {
const vectors = [];
for (const doc of documents) {
// Generate embedding with Workers AI
const { data } = await this.env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: [doc.text]
});
vectors.push({
id: doc.id,
values: data[0],
metadata: { ...doc.metadata, text: doc.text }
});
}
// Insert into Vectorize
await this.env.VECTORIZE.upsert(vectors);
return { ingested: vectors.length };
}
// Query knowledge base
async queryKnowledge(userQuery: string, topK: number = 5) {
// Generate query embedding
const { data } = await this.env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: [userQuery]
});
// Search Vectorize
const results = await this.env.VECTORIZE.query(data[0], { topK });
// Extract relevant documents
const context = results.matches.map(match => match.metadata.text).join('\n\n');
return context;
}
// RAG Chat
async chat(userMessage: string) {
// Retrieve relevant context
const context = await this.queryKnowledge(userMessage);
// Generate response with context
const { text } = await generateText({
model: openai('gpt-4o-mini'),
messages: [
{
role: 'system',
content: `You are a helpful assistant. Use the following context to answer questions:\n\n${context}`
},
{
role: 'user',
content: userMessage
}
]
});
return { response: text, context };
}
async onRequest(request: Request): Promise<Response> {
const { message } = await request.json();
const result = await this.chat(message);
return Response.json(result);
}
}
メタデータのフィルタリング
// Create metadata indexes BEFORE inserting vectors
await this.env.VECTORIZE.createMetadataIndex("category");
await this.env.VECTORIZE.createMetadataIndex("language");
// Query with filters
const results = await this.env.VECTORIZE.query(queryVector, {
topK: 10,
filter: {
category: { $eq: "documentation" },
language: { $eq: "en" }
}
});
参照:Vectorize の完全なガイドについては、cloudflare-vectorize スキルをご覧ください。
AI モデルの使用
AI SDK(Vercel)
npm install ai @ai-sdk/openai @ai-sdk/anthropic
import { Agent } from "agents";
import { generateText, streamText } from "ai";
import { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
export class AIAgent extends Agent {
// Simple text generation
async generateResponse(prompt: string) {
const { text } = await generateText({
model: openai('gpt-4o-mini'),
prompt
});
return text;
}
// Streaming response
async streamResponse(prompt: string): Promise<Response> {
const result = streamText({
model: anthropic('claude-sonnet-4-5'),
prompt
});
return result.toTextStreamResponse();
}
// Structured output
async extractData(text: string) {
const { object } = await generateObject({
model: openai('gpt-4o-mini'),
schema: z.object({
name: z.string(),
email: z.string().email(),
age: z.number().optional()
}),
prompt: `Extract user info from: ${text}`
});
return object;
}
}
Workers AI
interface Env {
AI: Ai;
}
export class WorkersAIAgent extends Agent<Env> {
async generateText(prompt: string) {
const response = await this.env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [{ role: 'user', content: prompt }]
});
return response;
}
async generateImage(prompt: string) {
const response = await this.env.AI.run('@cf/black-forest-labs/flux-1-schnell', {
prompt
});
return response;
}
}
参照:Workers AI の完全なガイドについては、cloudflare-workers-ai スキルをご覧ください。
エージェントの呼び出し
routeAgentRequest の使用
URL パターン /agents/:agent/:name に基づいて、エージェントにリクエストを自動的にルーティングします。
import { Agent, AgentNamespace, routeAgentRequest } from 'agents';
interface Env {
MyAgent: AgentNamespace<MyAgent>;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Routes to: /agents/my-agent/user-123
const response = await routeAgentRequest(request, env);
if (response) {
return response;
}
return new Response("Not Found", { status: 404 });
}
} satisfies ExportedHandler<Env>;
export class MyAgent extends Agent<Env> {
async onRequest(request: Request): Promise<Response> {
return Response.json({ agent: this.name });
}
}
URL パターン:/agents/my-agent/user-123
my-agent= kebab-case のクラス名user-123= エージェントのインスタンス名
getAgentByName の使用
カスタムルーティング、または Workers からエージェントを呼び出す場合:
import { Agent, AgentNamespace, getAgentByName } from 'agents';
interface Env {
MyAgent: AgentNamespace<MyAgent>;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const userId = new URL(request.url).searchParams.get('userId') || 'anonymous';
// Get or create agent instance
const agent = getAgentByName<Env, MyAgent>(env.MyAgent, `user-${userId}`);
// Pass request to agent
return (await agent).fetch(request);
}
} satisfies ExportedHandler<Env>;
export class MyAgent extends Agent<Env> {
// Agent implementation
}
エージェントメソッドの直接呼び出し
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const agent = getAgentByName<Env, MyAgent>(env.MyAgent, 'user-123');
// Call custom methods on agent using RPC
const result = await (await agent).customMethod({ data: "example" });
return Response.json({ result });
}
}
export class MyAgent extends Agent<Env> {
async customMethod(params: { data: string }): Promise<any> {
return { processed: params.data };
}
}
マルチエージェント通信
interface Env {
AgentA: AgentNamespace<AgentA>;
AgentB: AgentNamespace<AgentB>;
}
export class AgentA extends Agent<Env> {
async processData(data: any) {
// Call another agent
const agentB = getAgentByName<Env, AgentB>(this.env.AgentB, 'processor-1');
const result = await (await agentB).analyze(data);
return result;
}
}
export class AgentB extends Agent<Env> {
async analyze(data: any) {
return { analyzed: true, data };
}
}
認証パターン
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Authenticate BEFORE invoking agent
const authHeader = request.headers.get('Authorization');
if (!authHeader) {
return new Response("Unauthorized", { status: 401 });
}
const userId = await verifyToken(authHeader);
if (!userId) {
return new Response("Forbidden", { status: 403 });
}
// Only create/access agent for authenticated users
const agent = getAgentByName<Env, MyAgent>(env.MyAgent, `user-${userId}`);
return (await agent).fetch(request);
}
}
重要:認証は常に Worker で行い、Agent では行わないでください。Agent は呼び出し元が認可済みであることを前提とします。
クライアント API
AgentClient(ブラウザー)
import { AgentClient } from "agents/client";
// Connect to agent instance
const client = new AgentClient({
agent: "chat-agent", // Class name in kebab-case
name: "room-123", // Instance name
host: window.location.host
});
client.onopen = () => {
console.log("Connected");
client.send(JSON.stringify({ type: "join", user: "alice" }));
};
client.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Received:", data);
};
client.onclose = () => {
console.log("Disconnected");
};
agentFetch(HTTP リクエスト)
import { agentFetch } from "agents/client";
async function getData() {
const response = await agentFetch(
{ agent: "my-agent", name: "user-123" },
{
method: "GET",
headers: { "Authorization": `Bearer ${token}` }
}
);
const data = await response.json();
return data;
}
useAgent フック(React)
import { useAgent } from "agents/react";
import { useState } from "react";
function ChatUI() {
const [messages, setMessages] = useState([]);
const connection = useAgent({
agent: "chat-agent",
name: "room-123",
onMessage: (event) => {
const data = JSON.parse(event.data);
if (data.type === 'message') {
setMessages(prev => [...prev, data.message]);
}
},
onOpen: () => console.log("Connected"),
onClose: () => console.log("Disconnected")
});
const sendMessage = (text: string) => {
connection.send(JSON.stringify({ type: 'chat', text }));
};
return (
<div>
{messages.map((msg, i) => <div key={i}>{msg.text}</div>)}
<button onClick={() => sendMessage("Hello")}>Send</button>
</div>
);
}
状態の同期
import { useAgent } from "agents/react";
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const agent = useAgent({
agent: "counter-agent",
name: "my-counter",
onStateUpdate: (newState) => {
setCount(newState.counter);
}
});
const increment = () => {
agent.setState({ counter: count + 1 });
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
useAgentChat フック
import { useAgentChat } from "agents/ai-react";
function ChatInterface() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgentChat({
agent: "ai-chat-agent",
name: "chat-session-123"
});
return (
<div>
<div>
{messages.map((msg, i) => (
<div key={i}>
<strong>{msg.role}:</strong> {msg.content}
</div>
))}
</div>
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={handleInputChange}
placeholder="Type a message..."
disabled={isLoading}
/>
<button type="submit" disabled={isLoading}>
{isLoading ? "Thinking..." : "Send"}
</button>
</form>
</div>
);
}
モデルコンテキストプロトコル(MCP)
Agents SDK を使用して MCP サーバーを構築します。
MCP サーバーのセットアップ
npm install @modelcontextprotocol/sdk agents
基本的な MCP サーバー
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
export class MyMCP extends McpAgent {
server = new McpServer({ name: "Demo", version: "1.0.0" });
async init() {
// Define a tool
this.server.tool(
"add",
"Add two numbers together",
{
a: z.number().describe("First number"),
b: z.number().describe("Second number")
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
}
}
ステートフルな MCP サーバー
type State = { counter: number };
export class StatefulMCP extends McpAgent<Env, State> {
server = new McpServer({ name: "Counter", version: "1.0.0" });
initialState: State = { counter: 0 };
async init() {
// Resource
this.server.resource(
"counter",
"mcp://resource/counter",
(uri) => ({
contents: [{ uri: uri.href, text: String(this.state.counter) }]
})
);
// Tool
this.server.tool(
"increment",
"Increment the counter",
{ amount: z.number() },
async ({ amount }) => {
this.setState({
...this.state,
counter: this.state.counter + amount
});
return {
content: [{
type: "text",
text: `Counter is now ${this.state.counter}`
}]
};
}
);
}
}
MCP トランスポートの設定
import { Hono } from 'hono';
const app = new Hono();
// Modern streamable HTTP transport (recommended)
app.mount('/mcp', MyMCP.serve('/mcp').fetch, { replaceRequest: false });
// Legacy SSE transport (deprecated)
app.mount('/sse', MyMCP.serveSSE('/sse').fetch, { replaceRequest: false });
export default app;
トランスポートの比較:
- /mcp:ストリーミング可能な HTTP(モダンで、推奨)
- /sse:Server-Sent Events(レガシー、非推奨)
OAuth を使用した MCP
import { OAuthProvider } from '@cloudflare/workers-oauth-provider';
export default new OAuthProvider({
apiHandlers: {
'/sse': MyMCP.serveSSE('/sse'),
'/mcp': MyMCP.serve('/mcp')
},
// OAuth configuration
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
// ... other OAuth settings
});
MCP サーバーのテスト
# Run MCP inspector
npx @modelcontextprotocol/inspector@latest
# Connect to: http://localhost:8788/mcp
Cloudflare の MCP サーバー:本番環境での例については、リファレンスを参照してください。
パターンと概念
チャットエージェント(AIChatAgent)
import { AIChatAgent } from "agents/ai-chat-agent";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export class MyChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
const result = streamText({
model: openai('gpt-4o-mini'),
messages: this.messages,
onFinish
});
return result.toTextStreamResponse();
}
// Optional: Customize message persistence
async onStateUpdate(state, source) {
console.log('Chat state updated:', this.messages.length, 'messages');
}
}
Human-in-the-Loop(HITL)
export class ApprovalAgent extends Agent {
async processRequest(data: any) {
// Process automatically
const processed = await this.autoProcess(data);
// If confidence low, request human review
if (processed.confidence < 0.8) {
this.setState({
...this.state,
pendingReview: {
data: processed,
requestedAt: Date.now(),
status: 'pending'
}
});
// Send notification to human
await this.notifyHuman(processed);
return { status: 'pending_review', id: processed.id };
}
// High confidence, proceed automatically
return this.complete(processed);
}
async approveReview(id: string, approved: boolean) {
const pending = this.state.pendingReview;
if (approved) {
await this.complete(pending.data);
} else {
await this.reject(pending.data);
}
this.setState({
...this.state,
pendingReview: null
});
}
}
ツールの概念
ツールを使うと、エージェントは外部サービスと連携できます。
export class ToolAgent extends Agent {
// Tool: Search flights
async searchFlights(from: string, to: string, date: string) {
const response = await fetch(`https://api.flights.com/search`, {
method: 'POST',
body: JSON.stringify({ from, to, date })
});
return response.json();
}
// Tool: Book flight
async bookFlight(flightId: string, passengers: any[]) {
const response = await fetch(`https://api.flights.com/book`, {
method: 'POST',
body: JSON.stringify({ flightId, passengers })
});
return response.json();
}
// Tool: Send confirmation email
async sendEmail(to: string, subject: string, body: string) {
// Use email service
return { sent: true };
}
// Orchestrate tools
async bookTrip(params: any) {
const flights = await this.searchFlights(params.from, params.to, params.date);
const booking = await this.bookFlight(flights[0].id, params.passengers);
await this.sendEmail(params.email, "Booking Confirmed", `Booking ID: ${booking.id}`);
return booking;
}
}
マルチエージェントのオーケストレーション
interface Env {
ResearchAgent: AgentNamespace<ResearchAgent>;
WriterAgent: AgentNamespace<WriterAgent>;
EditorAgent: AgentNamespace<EditorAgent>;
}
export class OrchestratorAgent extends Agent<Env> {
async createArticle(topic: string) {
// 1. Research agent gathers information
const researcher = getAgentByName<Env, ResearchAgent>(
this.env.ResearchAgent,
`research-${topic}`
);
const research = await (await researcher).research(topic);
// 2. Writer agent creates draft
const writer = getAgentByName<Env, WriterAgent>(
this.env.WriterAgent,
`writer-${topic}`
);
const draft = await (await writer).write(research);
// 3. Editor agent reviews
const editor = getAgentByName<Env, EditorAgent>(
this.env.EditorAgent,
`editor-${topic}`
);
const final = await (await editor).edit(draft);
return final;
}
}
重要なルール
必ず実施すること ✅
- Agent クラスをエクスポートする - バインディングを機能させるにはエクスポートが必要です
- v1 マイグレーションに new_sqlite_classes を含める - SQLite は後から追加できません
- バインディング名をクラス名と一致させる - 「binding not found」エラーを防ぎます
- Agent ではなく Worker で認証する - セキュリティ上のベストプラクティスです
- SQL にはタグ付きテンプレートリテラルを使う - SQL インジェクションを防ぎます
- WebSocket の切断を処理する - 状態は保持されますが、接続は保持されません
- スケジュール済みタスクのコールバックが存在することを確認する - メソッドがない場合はエラーが発生します
- グローバルに一意なインスタンス名を使う - 同じ名前はグローバルで同じエージェントを指します
- 状態のサイズ制限を確認する - エージェントごとの合計上限は 1GB です
- タスクのペイロードサイズを監視する - スケジュール済みタスクごとの上限は 2MB です
- ワークフローバインディングを正しく使う - wrangler.jsonc で設定する必要があります
- 挿入前に Vectorize インデックスを作成する - メタデータのフィルタリングに必要です
- ブラウザーのインスタンスを閉じる - リソースリークを防ぎます
- 永続化には setState() を使う - this.state を変更するだけでは不十分です
- まずローカルでマイグレーションをテストする - マイグレーションはアトミックであり、ロールバックできません
絶対にしないこと ❌
- デプロイ済みの既存クラスに SQLite を追加しない - 最初のマイグレーションに含める必要があります
- マイグレーションを段階的にデプロイしない - アトミックにのみ実行できます
- Worker での認証を省略しない - エージェントにアクセスする前に必ず認証してください
- SQL 文字列を手動で構築しない - タグ付きテンプレートを使ってください
- エージェントごとに 1GB を超える状態を保存しない - 厳格な上限です
- 存在しないコールバックを指定してタスクをスケジュールしない - 実行時エラーになります
- 同じ名前なら別のエージェントだと思い込まない - グローバルに一意です
- MCP に SSE を使わない - 非推奨です。/mcp トランスポートを使ってください
- ブラウザーバインディングを忘れない - ウェブ閲覧に必要です
- this.state を直接変更しない - 代わりに setState() を使ってください
既知の問題の防止
このスキルは、文書化されている 15 件以上の問題を防ぎます。
問題 1:マイグレーションがアトミックでない
エラー:「Cannot gradually deploy migration」
ソース:https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/
理由:マイグレーションはすべてのインスタンスに同時に適用されます
防止策:コード変更とは独立してマイグレーションをデプロイし、npx wrangler versions deploy を使います
問題 2:new_sqlite_classes がない
エラー:「Cannot enable SQLite on existing class」
ソース:https://developers.cloudflare.com/agents/api-reference/configuration/
理由:最初のマイグレーションで SQLite を有効にする必要があります
防止策:タグ「v1」のマイグレーションに new_sqlite_classes を含めます
問題 3:Agent クラスがエクスポートされていない
エラー:「Binding not found」または「Cannot access undefined」
ソース:https://developers.cloudflare.com/agents/api-reference/agents-api/
理由:Durable Objects ではクラスのエクスポートが必要です
防止策:export class MyAgent extends Agent(export キーワードを付ける)を使います
問題 4:バインディング名が一致しない
エラー:「Binding 'X' not found」
ソース:https://developers.cloudflare.com/agents/api-reference/configuration/
理由:バインディング名はクラス名と完全に一致する必要があります
防止策:wrangler.jsonc で name と class_name が同一であることを確認します
問題 5:グローバルな一意性が理解されていない
エラー:エージェントのインスタンスで予期しない動作が発生する ソース:https://developers.cloudflare.com/agents/api-reference/agents-api/ 理由:同じ名前を指定すると、常にグローバルで同じエージェントインスタンスが返されます 防止策:インスタンス名には一意の識別子(userId、sessionId)を使います
Issue 6: WebSocket の状態が永続化されない
エラー: 切断後に接続状態が失われます 参照元: https://developers.cloudflare.com/agents/api-reference/websockets/ 原因: WebSocket 接続は永続化されませんが、エージェントの状態は永続化されます 予防策: 接続状態ではなく、setState() を使って重要なデータをエージェントの状態に保存してください
Issue 7: スケジュールされたタスクのコールバックが存在しない
エラー: 「Agent にメソッド X が存在しません」 参照元: https://developers.cloudflare.com/agents/api-reference/schedule-tasks/ 原因: this.schedule() が定義されていないメソッドを呼び出します 予防策: スケジュールする前に、コールバックメソッドが存在することを確認してください
Issue 8: 状態のサイズ制限を超過
エラー: 「データベースの最大サイズを超過しました」 参照元: https://developers.cloudflare.com/agents/api-reference/store-and-sync-state/ 原因: エージェントの状態とスケジュールされたタスクの合計が 1GB を超えています 予防策: 状態のサイズを監視し、大きなデータには外部ストレージ(D1、R2)を使用してください
Issue 9: スケジュールされたタスクが大きすぎる
エラー: 「タスクのペイロードが 2MB を超えています」 参照元: https://developers.cloudflare.com/agents/api-reference/schedule-tasks/ 原因: 各タスクは、2MB の制限があるデータベース行に対応します 予防策: タスクのペイロードを最小限に抑え、大きなデータはエージェントの状態または SQL に保存してください
Issue 10: Workflow バインディングが未設定
エラー: 「undefined のプロパティ 'create' を読み取れません」 参照元: https://developers.cloudflare.com/agents/api-reference/run-workflows/ 原因: wrangler.jsonc で Workflow バインディングが設定されていません 予防策: this.env.WORKFLOW を使用する前に Workflow バインディングを追加してください
Issue 11: Browser バインディングが必要
エラー: 「BROWSER バインディングが undefined です」
参照元: https://developers.cloudflare.com/agents/api-reference/browse-the-web/
原因: Browser Rendering には明示的なバインディングが必要です
予防策: wrangler.jsonc に "browser": { "binding": "BROWSER" } を追加してください
Issue 12: Vectorize インデックスが見つからない
エラー: 「インデックスが存在しません」
参照元: https://developers.cloudflare.com/agents/api-reference/rag/
原因: 使用する前に Vectorize インデックスを作成する必要があります
予防策: エージェントをデプロイする前に wrangler vectorize create を実行してください
Issue 13: MCP トランスポートの混同
エラー: 「SSE トランスポートは非推奨です」
参照元: https://developers.cloudflare.com/agents/model-context-protocol/transport/
原因: SSE トランスポートはレガシーであり、ストリーミング可能な HTTP が推奨されています
予防策: /sse ではなく、MyMCP.serve('/mcp') を使って /mcp エンドポイントを使用してください
Issue 14: 認証のバイパス
エラー: セキュリティ上の脆弱性 参照元: https://developers.cloudflare.com/agents/api-reference/calling-agents/ 原因: Worker ではなく Agent 内で認証を行っています 予防策: getAgentByName() を呼び出す前に、必ず Worker で認証してください
Issue 15: インスタンス名のエラー
エラー: ユーザー間のデータ漏えい
参照元: https://developers.cloudflare.com/agents/api-reference/calling-agents/
原因: インスタンス名の付け方が不適切なため、別のエージェントへのアクセスが可能になっています
予防策: user-${userId} のような名前空間付きの名前を使用し、所有権を検証してください
依存関係
必須
- cloudflare-worker-base - 基盤(Hono、Vite、Workers のセットアップ)
任意(機能別)
- cloudflare-workers-ai - Workers AI のモデル呼び出し用
- cloudflare-vectorize - Vectorize を使った RAG 用
- cloudflare-d1 - エージェントの状態以外の追加の永続ストレージ用
- cloudflare-r2 - ファイルストレージ用
- cloudflare-queues - メッセージキュー用
NPM パッケージ
agents- Agents SDK(必須)@modelcontextprotocol/sdk- MCP サーバーの構築用@cloudflare/puppeteer- ウェブブラウジング用ai- モデル呼び出し用の AI SDK@ai-sdk/openai- OpenAI モデル@ai-sdk/anthropic- Anthropic モデル
公式ドキュメント
- Agents SDK: https://developers.cloudflare.com/agents/
- API リファレンス: https://developers.cloudflare.com/agents/api-reference/
- Durable Objects: https://developers.cloudflare.com/durable-objects/
- Workflows: https://developers.cloudflare.com/workflows/
- Vectorize: https://developers.cloudflare.com/vectorize/
- Browser Rendering: https://developers.cloudflare.com/browser-rendering/
- Model Context Protocol: https://modelcontextprotocol.io/
- Cloudflare MCP Servers: https://github.com/cloudflare/mcp-server-cloudflare
同梱リソース
テンプレート(templates/)
wrangler-agents-config.jsonc- 設定の完全な例basic-agent.ts- 最小構成の HTTP エージェントwebsocket-agent.ts- WebSocket ハンドラーstate-sync-agent.ts- 状態管理のパターンscheduled-agent.ts- タスクのスケジューリングworkflow-agent.ts- ワークフローとの連携browser-agent.ts- Web ブラウジングrag-agent.ts- RAG の実装chat-agent-streaming.ts- ストリーミングチャットcalling-agents-worker.ts- エージェントのルーティングreact-useagent-client.tsx- React クライアントmcp-server-basic.ts- MCP サーバーhitl-agent.ts- Human-in-the-loop
リファレンス(references/)
agent-class-api.md- Agent クラスの完全なリファレンスclient-api-reference.md- ブラウザークライアント APIstate-management-guide.md- 状態と SQL の詳細ガイドwebsockets-sse.md- WebSocket と SSE の比較scheduling-api.md- タスクスケジューリングの詳細workflows-integration.md- Workflows ガイドbrowser-rendering.md- Web ブラウジングのパターンrag-patterns.md- RAG のベストプラクティスmcp-server-guide.md- MCP サーバー開発mcp-tools-reference.md- MCP ツール APIhitl-patterns.md- Human-in-the-loop ワークフローbest-practices.md- 本番環境向けのパターン
例(examples/)
chat-bot-complete.md- 完全なチャットエージェントmulti-agent-workflow.md- エージェントのオーケストレーションscheduled-reports.md- 定期タスクbrowser-scraper-agent.md- Web スクレイピングrag-knowledge-base.md- RAG システムmcp-remote-server.md- 本番環境向け MCP サーバー
最終確認日: 2025-10-21 パッケージバージョン: agents@latest 準拠基準: Cloudflare Agents SDK 公式ドキュメント