AgentSkillsCN

building-ai-agent-on-cloudflare

在Cloudflare平台上,使用Agents SDK构建AI智能体,支持状态管理、实时WebSocket通信、定时任务、工具集成,以及聊天功能。 生成可直接投入生产环境的智能体代码,并部署至Workers平台。 适用场景:当用户希望“构建智能体”“AI智能体”“聊天智能体”“有状态智能体”,或提及“Agents SDK”,需要“实时AI”“WebSocket AI”,或询问智能体的“状态管理”“定时任务”“工具调用”等问题时使用此功能。

SKILL.md
--- frontmatter
name: building-ai-agent-on-cloudflare
description: |
  Builds AI agents on Cloudflare using the Agents SDK with state management,
  real-time WebSockets, scheduled tasks, tool integration, and chat capabilities.
  Generates production-ready agent code deployed to Workers.

  Use when: user wants to "build an agent", "AI agent", "chat agent", "stateful
  agent", mentions "Agents SDK", needs "real-time AI", "WebSocket AI", or asks
  about agent "state management", "scheduled tasks", or "tool calling".

Building Cloudflare Agents

Creates AI-powered agents using Cloudflare's Agents SDK with persistent state, real-time communication, and tool integration.

When to Use

  • User wants to build an AI agent or chatbot
  • User needs stateful, real-time AI interactions
  • User asks about the Cloudflare Agents SDK
  • User wants scheduled tasks or background AI work
  • User needs WebSocket-based AI communication

Prerequisites

  • Cloudflare account with Workers enabled
  • Node.js 18+ and npm/pnpm/yarn
  • Wrangler CLI (npm install -g wrangler)

Quick Start

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

Agent runs at http://localhost:8787

Core Concepts

What is an Agent?

An Agent is a stateful, persistent AI service that:

  • Maintains state across requests and reconnections
  • Communicates via WebSockets or HTTP
  • Runs on Cloudflare's edge via Durable Objects
  • Can schedule tasks and call tools
  • Scales horizontally (each user/session gets own instance)

Agent Lifecycle

code
Client connects → Agent.onConnect() → Agent processes messages
                                    → Agent.onMessage()
                                    → Agent.setState() (persists + syncs)
Client disconnects → State persists → Client reconnects → State restored

Basic Agent Structure

typescript
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,
			}),
		);
	}
}

Entry Point Configuration

typescript
// 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 };

Clients connect via: wss://my-agent.workers.dev/agents/MyAgent/session-id

Wrangler Configuration

toml
name = "my-agent"
main = "src/index.ts"
compatibility_date = "2024-12-01"

[ai]
binding = "AI"

[durable_objects]
bindings = [{ name = "AGENT", class_name = "MyAgent" }]

[[migrations]]
tag = "v1"
new_classes = ["MyAgent"]

State Management

Reading State

typescript
// Current state is always available
const currentMessages = this.state.messages;
const userPrefs = this.state.preferences;

Updating State

typescript
// 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 Storage

For complex queries, use the embedded SQLite database:

typescript
// 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}%`}
`;

Scheduled Tasks

Agents can schedule future work:

typescript
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(),
  });
}

Schedule Options

typescript
// 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);

Chat Agent (AI-Powered)

For chat-focused agents, extend AIChatAgent:

typescript
import { AIChatAgent } from "agents/ai-chat-agent";

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;
	}
}

Features included:

  • Automatic message history
  • Resumable streaming (survives disconnects)
  • Built-in saveMessages() for persistence

Client Integration

React Hook

tsx
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

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!" }));

Common Patterns

See references/agent-patterns.md for:

  • Tool calling and function execution
  • Multi-agent orchestration
  • RAG (Retrieval Augmented Generation)
  • Human-in-the-loop workflows

Deployment

bash
# Deploy
npx wrangler deploy

# View logs
wrangler tail

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

Troubleshooting

See references/troubleshooting.md for common issues.

References