mcpField
B
building-ai-agent-on-cloudflare

building-ai-agent-on-cloudflare

github.com/cloudflareエージェントワークフロー3.2k3.7k 回インストール今日更新
リポジトリ

building-ai-agent-on-cloudflare について

Cloudflare Agents SDK でステートフルな AI エージェントを構築するためのドキュメント参照スキルです。SDK、Workers、プラットフォームの最新資料を確認し、状態管理、リアルタイム接続、定期タスク、チャットエージェントのパターンを案内します。

主な機能

  1. 01最新の SDK とプラットフォーム資料を案内
  2. 02エージェントの永続状態を扱う
  3. 03WebSocket と HTTP 通信を解説
  4. 04定期タスクとチャットエージェントのパターン
  5. 05サンプルとトラブルシューティングを案内

活用シーン

  1. 01ステートフルなチャットボットの構築
  2. 02定期またはバックグラウンドのエージェントタスク追加
  3. 03WebSocket ベースのエージェント通信の実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cloudflare/skills --skill building-ai-agent-on-cloudflare

インストール後、Claude Code で/building-ai-agent-on-cloudflareを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
agent-patterns.md
examples.md
state-patterns.md
troubleshooting.md

詳細

Cloudflare エージェントの構築

Agents SDK に関する情報が古くなっている可能性があります。エージェント構築のタスクでは、事前学習済みの知識よりも情報の取得を優先してください。

情報の取得元

情報源取得方法用途
Agents SDK ドキュメントhttps://github.com/cloudflare/agents/tree/main/docsSDK API、状態、ルーティング、スケジューリング
Cloudflare Agents ドキュメントhttps://developers.cloudflare.com/agents/プラットフォーム統合、デプロイ
Workers ドキュメント検索ツールまたは https://developers.cloudflare.com/workers/ランタイム API、バインディング、設定

使用するタイミング

  • ユーザーが AI エージェントやチャットボットの構築を希望している
  • ユーザーがステートフルなリアルタイム AI インタラクションを必要としている
  • ユーザーが Cloudflare Agents SDK について質問している
  • ユーザーがスケジュールされたタスクやバックグラウンドでの AI 処理を希望している
  • ユーザーが WebSocket ベースの AI 通信を必要としている

前提条件

  • Workers が有効な Cloudflare アカウント
  • Node.js 18 以降と npm/pnpm/yarn
  • Wrangler CLI(npm install -g wrangler)

クイックスタート

npm create cloudflare@latest -- my-agent --template=cloudflare/agents-starter
cd my-agent
npm start

エージェントは http://localhost:8787 で実行されます。

基本概念

エージェントとは?

エージェントは、次の機能を備えたステートフルで永続的な AI サービスです。

  • リクエストや再接続をまたいで状態を維持する
  • WebSocket または HTTP で通信する
  • Durable Objects を介して Cloudflare のエッジで動作する
  • タスクをスケジュールし、ツールを呼び出す
  • 水平スケーリングする(各ユーザー/セッションに独自のインスタンスが割り当てられます)
エージェントのライフサイクル
Client connects → Agent.onConnect() → Agent processes messages
                                    → Agent.onMessage()
                                    → Agent.setState() (persists + syncs)
Client disconnects → State persists → Client reconnects → State restored

基本的なエージェント構成

import { Agent, Connection } from "agents";

interface Env {
  AI: Ai;  // Workers AI binding
}

interface State {
  messages: Array<{ role: string; content: string }>;
  preferences: Record<string, string>;
}

export class MyAgent extends Agent<Env, State> {
  // Initial state for new instances
  initialState: State = {
    messages: [],
    preferences: {},
  };

  // Called when agent starts or resumes
  async onStart() {
    console.log("Agent started with state:", this.state);
  }

  // Handle WebSocket connections
  async onConnect(connection: Connection) {
    connection.send(JSON.stringify({
      type: "welcome",
      history: this.state.messages,
    }));
  }

  // Handle incoming messages
  async onMessage(connection: Connection, message: string) {
    const data = JSON.parse(message);

    if (data.type === "chat") {
      await this.handleChat(connection, data.content);
    }
  }

  // Handle disconnections
  async onClose(connection: Connection) {
    console.log("Client disconnected");
  }

  // React to state changes
  onStateUpdate(state: State, source: string) {
    console.log("State updated by:", source);
  }

  private async handleChat(connection: Connection, userMessage: string) {
    // Add user message to history
    const messages = [
      ...this.state.messages,
      { role: "user", content: userMessage },
    ];

    // Call AI
    const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
      messages,
    });

    // Update state (persists and syncs to all clients)
    this.setState({
      ...this.state,
      messages: [
        ...messages,
        { role: "assistant", content: response.response },
      ],
    });

    // Send response
    connection.send(JSON.stringify({
      type: "response",
      content: response.response,
    }));
  }
}

エントリーポイントの設定

// src/index.ts
import { routeAgentRequest } from "agents";
import { MyAgent } from "./agent";

export default {
  async fetch(request: Request, env: Env) {
    // routeAgentRequest handles routing to /agents/:class/:name
    return (
      (await routeAgentRequest(request, env)) ||
      new Response("Not found", { status: 404 })
    );
  },
};

export { MyAgent };

クライアントは次の URL で接続します:wss://my-agent.workers.dev/agents/MyAgent/session-id

Wrangler の設定

{
  "name": "my-agent",
  "main": "src/index.ts",
  "compatibility_date": "2024-12-01",
  "ai": { "binding": "AI" },
  "durable_objects": {
    "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}

状態管理

状態の読み取り
// Current state is always available
const currentMessages = this.state.messages;
const userPrefs = this.state.preferences;
状態の更新
// setState persists AND syncs to all connected clients
this.setState({
  ...this.state,
  messages: [...this.state.messages, newMessage],
});

// Partial updates work too
this.setState({
  preferences: { ...this.state.preferences, theme: "dark" },
});
SQL ストレージ

複雑なクエリには、組み込みの SQLite データベースを使用します。

// Create tables
await this.sql`
  CREATE TABLE IF NOT EXISTS documents (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    content TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  )
`;

// Insert
await this.sql`
  INSERT INTO documents (title, content)
  VALUES (${title}, ${content})
`;

// Query
const docs = await this.sql`
  SELECT * FROM documents WHERE title LIKE ${`%${search}%`}
`;

スケジュールされたタスク

エージェントは、将来の処理をスケジュールできます。

async onMessage(connection: Connection, message: string) {
  const data = JSON.parse(message);

  if (data.type === "schedule_reminder") {
    // Schedule task for 1 hour from now
    const { id } = await this.schedule(3600, "sendReminder", {
      message: data.reminderText,
      userId: data.userId,
    });

    connection.send(JSON.stringify({ type: "scheduled", taskId: id }));
  }
}

// Called when scheduled task fires
async sendReminder(data: { message: string; userId: string }) {
  // Send notification, email, etc.
  console.log(`Reminder for ${data.userId}: ${data.message}`);

  // Can also update state
  this.setState({
    ...this.state,
    lastReminder: new Date().toISOString(),
  });
}
スケジュールのオプション
// Delay in seconds
await this.schedule(60, "taskMethod", { data });

// Specific date
await this.schedule(new Date("2025-01-01T00:00:00Z"), "taskMethod", { data });

// Cron expression (recurring)
await this.schedule("0 9 * * *", "dailyTask", {});  // 9 AM daily
await this.schedule("*/5 * * * *", "everyFiveMinutes", {});  // Every 5 min

// Manage schedules
const schedules = await this.getSchedules();
await this.cancelSchedule(taskId);

チャットエージェント(AI 搭載)

チャットに特化したエージェントを作成するには、AIChatAgent を継承します。

import { AIChatAgent } from "@cloudflare/ai-chat";

export class ChatBot extends AIChatAgent<Env> {
  // Called for each user message
  async onChatMessage(message: string) {
    const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
      messages: [
        { role: "system", content: "You are a helpful assistant." },
        ...this.messages,  // Automatic history management
        { role: "user", content: message },
      ],
      stream: true,
    });

    // Stream response back to client
    return response;
  }
}

次の機能が含まれています。

  • メッセージ履歴の自動管理
  • ストリーミングの再開(切断後も継続)
  • 永続化のための組み込み saveMessages()

クライアントとの統合

React フック
import { useAgent } from "agents/react";

function Chat() {
  const { state, send, connected } = useAgent({
    agent: "my-agent",
    name: userId,  // Agent instance ID
  });

  const sendMessage = (text: string) => {
    send(JSON.stringify({ type: "chat", content: text }));
  };

  return (
    <div>
      {state.messages.map((msg, i) => (
        <div key={i}>{msg.role}: {msg.content}</div>
      ))}
      <input onKeyDown={(e) => e.key === "Enter" && sendMessage(e.target.value)} />
    </div>
  );
}
Vanilla JavaScript
const ws = new WebSocket("wss://my-agent.workers.dev/agents/MyAgent/user123");

ws.onopen = () => {
  console.log("Connected to agent");
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("Received:", data);
};

ws.send(JSON.stringify({ type: "chat", content: "Hello!" }));

よく使われるパターン

よく使われるパターンについては、references/agent-patterns.md を参照してください。

  • ツール呼び出しと関数の実行
  • マルチエージェントのオーケストレーション
  • RAG(検索拡張生成)
  • ヒューマン・イン・ザ・ループのワークフロー

デプロイ

# Deploy
npx wrangler deploy

# View logs
wrangler tail

# Test endpoint
curl https://my-agent.workers.dev/agents/MyAgent/test-user

トラブルシューティング

よくある問題については、references/troubleshooting.md を参照してください。

参考資料

コメント