cloudflare-agents
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare Agents SDK
Cloudflare Agents SDK
Status: Production Ready ✅
Last Updated: 2026-01-09
Dependencies: cloudflare-worker-base (recommended)
Latest Versions: agents@0.3.3, @modelcontextprotocol/sdk@latest
Production Tested: Cloudflare's own MCP servers (https://github.com/cloudflare/mcp-server-cloudflare)
Recent Updates (2025-2026):
- Jan 2026: Agents SDK v0.3.6 with callable methods fix, protocol version support updates
- Nov 2025: Agents SDK v0.2.24+ with resumable streaming (streams persist across disconnects, page refreshes, and sync across tabs/devices), MCP client improvements, schedule fixes
- Sept 2025: AI SDK v5 compatibility, automatic message migration
- Aug 2025: MCP Elicitation support, http-streamable transport, task queues, email integration
- April 2025: MCP support (MCPAgent class), from agents
import { context } - March 2025: Package rename (agents-sdk → agents)
状态:已就绪可用于生产环境 ✅
最后更新:2026-01-09
依赖项:cloudflare-worker-base(推荐)
最新版本:agents@0.3.3, @modelcontextprotocol/sdk@latest
生产环境验证:Cloudflare官方MCP服务器(https://github.com/cloudflare/mcp-server-cloudflare)
近期更新(2025-2026):
- 2026年1月:Agents SDK v0.3.6,修复可调用方法问题,更新协议版本支持
- 2025年11月:Agents SDK v0.2.24+,新增可恢复式流式传输(流式连接在断开、页面刷新、多标签/设备同步时仍能保留),优化MCP客户端,修复调度问题
- 2025年9月:兼容AI SDK v5,支持自动消息迁移
- 2025年8月:支持MCP Elicitation,新增HTTP流式传输、任务队列、邮件集成
- 2025年4月:支持MCP(新增MCPAgent类),可从agents中
import { context } - 2025年3月:包重命名(agents-sdk → agents)
Resumable Streaming (agents@0.2.24+)
可恢复式流式传输(agents@0.2.24+)
AIChatAgent now supports resumable streaming, enabling clients to reconnect and continue receiving streamed responses without data loss. This solves critical real-world scenarios:
- Long-running AI responses that exceed connection timeout
- Users on unreliable networks (mobile, airplane WiFi)
- Users switching between devices mid-conversation
- Background tasks where users navigate away and return
- Real-time collaboration where multiple clients need to stay in sync
Key capability: Streams persist across page refreshes, broken connections, and sync across open tabs and devices.
Implementation (automatic in AIChatAgent):
typescript
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return streamText({
model: openai('gpt-4o-mini'),
messages: this.messages,
onFinish
}).toTextStreamResponse();
// ✅ Stream automatically resumable
// - Client disconnects? Stream preserved
// - Page refresh? Stream continues
// - Multiple tabs? All stay in sync
}
}No code changes needed - just use AIChatAgent with agents@0.2.24 or later.
Source: Agents SDK v0.2.24 Changelog
AIChatAgent现在支持可恢复式流式传输,客户端重新连接后可继续接收流式响应,不会丢失数据。这解决了以下关键实际场景问题:
- 超过连接超时的长时AI响应
- 网络不稳定的用户(移动网络、飞机WiFi)
- 对话中途切换设备的用户
- 用户离开后返回的后台任务
- 多客户端需要保持同步的实时协作场景
核心能力:流式连接可在页面刷新、连接中断、多标签/设备间同步保留。
实现方式(AIChatAgent中自动生效):
typescript
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return streamText({
model: openai('gpt-4o-mini'),
messages: this.messages,
onFinish
}).toTextStreamResponse();
// ✅ 流自动可恢复
// - 客户端断开?流会保留
// - 页面刷新?流会继续
// - 多标签页面?全部保持同步
}
}无需修改代码 - 只需使用agents@0.2.24或更高版本的AIChatAgent即可。
What is Cloudflare Agents?
什么是Cloudflare Agents?
The Cloudflare Agents SDK enables building AI-powered autonomous agents that run on Cloudflare Workers + Durable Objects. Agents can:
- Communicate in real-time via WebSockets and Server-Sent Events
- Persist state with built-in SQLite database (up to 1GB per agent)
- Schedule tasks using delays, specific dates, or cron expressions
- Run workflows by triggering asynchronous Cloudflare Workflows
- Browse the web using Browser Rendering API + Puppeteer
- Implement RAG with Vectorize vector database + Workers AI embeddings
- Build MCP servers implementing the Model Context Protocol
- Support human-in-the-loop patterns for review and approval
- Scale to millions of independent agent instances globally
Each agent instance is a globally unique, stateful micro-server that can run for seconds, minutes, or hours.
Cloudflare Agents SDK用于构建运行在Cloudflare Workers + Durable Objects上的AI驱动自主Agent。Agent具备以下能力:
- 实时双向通信:通过WebSocket和Server-Sent Events实现
- 状态持久化:内置SQLite数据库(每个Agent最多1GB)
- 任务调度:支持延迟执行、指定日期或cron表达式
- 工作流运行:触发异步Cloudflare Workflows
- 网页浏览:使用Browser Rendering API + Puppeteer
- RAG实现:结合Vectorize向量数据库 + Workers AI嵌入
- MCP服务器构建:实现Model Context Protocol
- 人在回路模式:支持审核与批准流程
- 全球百万级扩展:支持独立Agent实例的全球大规模扩展
每个Agent实例都是全局唯一的有状态微服务,可运行数秒、数分钟或数小时。
Do You Need Agents SDK?
是否需要Agents SDK?
STOP: Before using Agents SDK, ask yourself if you actually need it.
注意:在使用Agents SDK之前,请先确认你是否真的需要它。
Use JUST Vercel AI SDK (Simpler) When:
仅使用Vercel AI SDK(更简单)的场景:
- ✅ Building a basic chat interface
- ✅ Server-Sent Events (SSE) streaming is sufficient (one-way: server → client)
- ✅ No persistent agent state needed (or you manage it separately with D1/KV)
- ✅ Single-user, single-conversation scenarios
- ✅ Just need AI responses, no complex workflows or scheduling
This covers 80% of chat applications. For these cases, use Vercel AI SDK directly on Workers - it's simpler, requires less infrastructure, and handles streaming automatically.
Example (no Agents SDK needed):
typescript
// worker.ts - Simple chat with AI SDK only
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
export default {
async fetch(request: Request, env: Env) {
const { messages } = await request.json();
const result = streamText({
model: openai('gpt-4o-mini'),
messages
});
return result.toTextStreamResponse(); // Automatic SSE streaming
}
}
// client.tsx - React with built-in hooks
import { useChat } from 'ai/react';
function ChatPage() {
const { messages, input, handleSubmit } = useChat({ api: '/api/chat' });
// Done. No Agents SDK needed.
}Result: 100 lines of code instead of 500. No Durable Objects setup, no WebSocket complexity, no migrations.
- ✅ 构建基础聊天界面
- ✅ Server-Sent Events (SSE)流式传输已足够(单向:服务器→客户端)
- ✅ 不需要持久化Agent状态(或通过D1/KV单独管理)
- ✅ 单用户、单对话场景
- ✅ 仅需要AI响应,无需复杂工作流或调度
这覆盖了80%的聊天应用场景。对于这些场景,直接在Workers上使用Vercel AI SDK即可 - 它更简单,所需基础设施更少,且自动处理流式传输。
示例(无需Agents SDK):
typescript
// worker.ts - 仅使用AI SDK的简单聊天
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
export default {
async fetch(request: Request, env: Env) {
const { messages } = await request.json();
const result = streamText({
model: openai('gpt-4o-mini'),
messages
});
return result.toTextStreamResponse(); // 自动SSE流式传输
}
}
// client.tsx - 带有内置钩子的React客户端
import { useChat } from 'ai/react';
function ChatPage() {
const { messages, input, handleSubmit } = useChat({ api: '/api/chat' });
// 完成。无需Agents SDK。
}结果:只需约100行代码,而非500行。无需Durable Objects配置、WebSocket复杂度或迁移操作。
Use Agents SDK When You Need:
需要使用Agents SDK的场景:
- ✅ WebSocket connections (true bidirectional real-time communication)
- ✅ Durable Objects (globally unique, stateful agent instances)
- ✅ Built-in state persistence (SQLite storage up to 1GB per agent)
- ✅ Multi-agent coordination (agents calling and communicating with each other)
- ✅ Scheduled tasks (delays, cron expressions, recurring jobs)
- ✅ Human-in-the-loop workflows (approval gates, review processes)
- ✅ Long-running agents (background processing, autonomous workflows)
- ✅ MCP servers with stateful tool execution
This is ~20% of applications - when you need the infrastructure that Agents SDK provides.
- ✅ WebSocket连接(真正的双向实时通信)
- ✅ Durable Objects(全局唯一的有状态Agent实例)
- ✅ 内置状态持久化(每个Agent最多1GB的SQLite存储)
- ✅ 多Agent协同(Agent之间可调用与通信)
- ✅ 任务调度(延迟执行、cron表达式、周期性任务)
- ✅ 人在回路工作流(审批 gate、审核流程)
- ✅ 长时运行Agent(后台处理、自主工作流)
- ✅ MCP服务器:支持有状态工具执行
这约占20%的应用场景 - 当你需要Agents SDK提供的基础设施能力时使用。
Key Understanding: What Agents SDK IS vs IS NOT
核心认知:Agents SDK能做什么 vs 不能做什么
Agents SDK IS:
- 🏗️ Infrastructure layer for WebSocket connections, Durable Objects, and state management
- 🔧 Framework for building stateful, autonomous agents
- 📦 Wrapper around Durable Objects with lifecycle methods
Agents SDK IS NOT:
- ❌ AI inference provider (you bring your own: AI SDK, Workers AI, OpenAI, etc.)
- ❌ Streaming response handler (use AI SDK for automatic parsing)
- ❌ LLM integration (that's a separate concern)
Think of it this way:
- Agents SDK = The building (WebSockets, state, rooms)
- AI SDK / Workers AI = The AI brain (inference, reasoning, responses)
You can use them together (recommended for most cases), or use Workers AI directly (if you're willing to handle manual SSE parsing).
Agents SDK能做:
- 🏗️ 基础设施层:管理WebSocket连接、Durable Objects与状态
- 🔧 开发框架:用于构建有状态的自主Agent
- 📦 Durable Objects封装:提供生命周期方法
Agents SDK不能做:
- ❌ AI推理提供商:你需要自行引入(AI SDK、Workers AI、OpenAI等)
- ❌ 流式响应处理器:使用AI SDK进行自动解析
- ❌ LLM集成:这是独立的关注点
可以这样理解:
- Agents SDK = 建筑(WebSocket、状态、房间)
- AI SDK / Workers AI = AI大脑(推理、决策、响应)
你可以将它们结合使用(大多数场景推荐),也可以直接使用Workers AI(如果你愿意手动处理SSE解析)。
Decision Flowchart
决策流程图
Building an AI application?
│
├─ Need WebSocket bidirectional communication? ───────┐
│ (Client sends while server streams, agent-initiated messages)
│
├─ Need Durable Objects stateful instances? ──────────┤
│ (Globally unique agents with persistent memory)
│
├─ Need multi-agent coordination? ────────────────────┤
│ (Agents calling/messaging other agents)
│
├─ Need scheduled tasks or cron jobs? ────────────────┤
│ (Delayed execution, recurring tasks)
│
├─ Need human-in-the-loop workflows? ─────────────────┤
│ (Approval gates, review processes)
│
└─ If ALL above are NO ─────────────────────────────→ Use AI SDK directly
(Much simpler approach)
If ANY above are YES ────────────────────────────→ Use Agents SDK + AI SDK
(More infrastructure, more power)是否在构建AI应用?
│
├─ 是否需要WebSocket双向通信? ───────┐
│ (客户端发送消息时服务器同时流式传输,Agent主动发起消息)
│
├─ 是否需要Durable Objects有状态实例? ──────────┤
│ (全局唯一、带持久化记忆的Agent)
│
├─ 是否需要多Agent协同? ────────────────────┤
│ (Agent之间调用/通信)
│
├─ 是否需要任务调度或cron任务? ────────────────┤
│ (延迟执行、周期性任务)
│
├─ 是否需要人在回路工作流? ─────────────────┤
│ (审批 gate、审核流程)
│
└─ 如果以上全否 ─────────────────────────────→ 直接使用AI SDK
(更简单的方案)
如果以上任一为是 ────────────────────────────→ 使用Agents SDK + AI SDK
(更多基础设施,更强能力)Architecture Comparison
架构对比
| Feature | AI SDK Only | Agents SDK + AI SDK |
|---|---|---|
| Setup Complexity | 🟢 Low (npm install, done) | 🔴 Higher (Durable Objects, migrations, bindings) |
| Code Volume | 🟢 ~100 lines | 🟡 ~500+ lines |
| Streaming | ✅ Automatic (SSE) | ✅ Automatic (AI SDK) or manual (Workers AI) |
| State Management | ⚠️ Manual (D1/KV) | ✅ Built-in (SQLite) |
| WebSockets | ❌ Manual setup | ✅ Built-in |
| React Hooks | ✅ useChat, useCompletion | ⚠️ Custom hooks needed |
| Multi-agent | ❌ Not supported | ✅ Built-in (routeAgentRequest) |
| Scheduling | ❌ External (Queue/Workflow) | ✅ Built-in (this.schedule) |
| Use Case | Simple chat, completions | Complex stateful workflows |
| 特性 | 仅使用AI SDK | Agents SDK + AI SDK |
|---|---|---|
| 配置复杂度 | 🟢 低(npm安装即可) | 🔴 较高(Durable Objects、迁移、绑定) |
| 代码量 | 🟢 ~100行 | 🟡 ~500+行 |
| 流式传输 | ✅ 自动(SSE) | ✅ 自动(AI SDK)或手动(Workers AI) |
| 状态管理 | ⚠️ 手动(D1/KV) | ✅ 内置(SQLite) |
| WebSocket | ❌ 需手动配置 | ✅ 内置 |
| React钩子 | ✅ useChat, useCompletion | ⚠️ 需要自定义钩子 |
| 多Agent | ❌ 不支持 | ✅ 内置(routeAgentRequest) |
| 任务调度 | ❌ 需外部工具(Queue/Workflow) | ✅ 内置(this.schedule) |
| 适用场景 | 简单聊天、补全 | 复杂有状态工作流 |
Still Not Sure?
仍不确定?
Start with AI SDK. You can always migrate to Agents SDK later if you discover you need WebSockets or Durable Objects. It's easier to add infrastructure later than to remove it.
For most developers: If you're building a chat interface and don't have specific requirements for WebSockets, multi-agent coordination, or scheduled tasks, use AI SDK directly. You'll ship faster and with less complexity.
Proceed with Agents SDK only if you've identified a specific need for its infrastructure capabilities.
从AI SDK开始。如果之后发现需要WebSocket或Durable Objects,再迁移到Agents SDK。后期添加基础设施比移除更容易。
对于大多数开发者:如果你正在构建聊天界面,且没有WebSocket、多Agent协同或任务调度的特定需求,请直接使用AI SDK。你将更快交付,且复杂度更低。
仅当你明确需要其基础设施能力时,再使用Agents SDK。
Quick Start (10 Minutes)
快速开始(10分钟)
1. Scaffold Project with Template
1. 使用模板搭建项目
bash
npm create cloudflare@latest my-agent -- \
--template=cloudflare/agents-starter \
--ts \
--git \
--deploy falseWhat this creates:
- Complete Agent project structure
- TypeScript configuration
- wrangler.jsonc with Durable Objects bindings
- Example chat agent implementation
- React client with useAgent hook
bash
npm create cloudflare@latest my-agent -- \
--template=cloudflare/agents-starter \
--ts \
--git \
--deploy false创建的内容:
- 完整的Agent项目结构
- TypeScript配置
- 带有Durable Objects绑定的wrangler.jsonc
- 示例聊天Agent实现
- 带有useAgent钩子的React客户端
2. Or Add to Existing Worker
2. 或添加到现有Worker项目
bash
cd my-existing-worker
npm install agentsThen create an Agent class:
typescript
// 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;bash
cd my-existing-worker
npm install agents然后创建Agent类:
typescript
// 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. Configure Durable Objects Binding
3. 配置Durable Objects绑定
Create or update :
wrangler.jsoncjsonc
{
"$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
}
]
}CRITICAL Configuration Rules:
- ✅ and
nameMUST be identicalclass_name - ✅ MUST be in first migration (cannot add later)
new_sqlite_classes - ✅ Agent class MUST be exported (or binding will fail)
- ✅ Migration tags CANNOT be reused (each migration needs unique tag)
创建或更新:
wrangler.jsoncjsonc
{
"$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", // 必须与类名匹配
"class_name": "MyAgent" // 必须与导出的类名匹配
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["MyAgent"] // 关键:启用SQLite存储
}
]
}关键配置规则:
- ✅ 和
name必须完全相同class_name - ✅ 必须在首次迁移中添加(之后无法添加)
new_sqlite_classes - ✅ Agent类 必须导出(否则绑定会失败)
- ✅ 迁移标签 不能重复使用(每个迁移需要唯一标签)
4. Deploy
4. 部署
bash
npx wrangler@latest deployYour agent is now running at:
https://my-agent.<subdomain>.workers.devbash
npx wrangler@latest deploy你的Agent现在运行在:
https://my-agent.<subdomain>.workers.devArchitecture Overview: How the Pieces Fit Together
架构概述:各组件如何配合
Understanding what each tool does prevents confusion and helps you choose the right combination.
了解每个工具的作用可避免混淆,帮助你选择正确的组合。
The Stack
技术栈
┌─────────────────────────────────────────────────────────┐
│ Your Application │
│ │
│ ┌────────────────┐ ┌──────────────────────┐ │
│ │ Agents SDK │ │ AI Inference │ │
│ │ (Infra Layer) │ + │ (Brain Layer) │ │
│ │ │ │ │ │
│ │ • WebSockets │ │ Choose ONE: │ │
│ │ • Durable Objs │ │ • Vercel AI SDK ✅ │ │
│ │ • State (SQL) │ │ • Workers AI ⚠️ │ │
│ │ • Scheduling │ │ • OpenAI Direct │ │
│ │ • Multi-agent │ │ • Anthropic Direct │ │
│ └────────────────┘ └──────────────────────┘ │
│ ↓ ↓ │
│ Manages connections Generates responses │
│ and state and handles streaming │
└─────────────────────────────────────────────────────────┘
↓
Cloudflare Workers + Durable Objects┌─────────────────────────────────────────────────────────┐
│ 你的应用程序 │
│ │
│ ┌────────────────┐ ┌──────────────────────┐ │
│ │ Agents SDK │ │ AI推理层 │ │
│ │ (基础设施层) │ + │ (大脑层) │ │
│ │ │ │ │ │
│ │ • WebSocket │ │ 选择其中一个: │ │
│ │ • Durable Objs │ │ • Vercel AI SDK ✅ │ │
│ │ • 状态(SQL) │ │ • Workers AI ⚠️ │ │
│ │ • 任务调度 │ │ • OpenAI Direct │ │
│ │ • 多Agent协同 │ │ • Anthropic Direct │ │
│ └────────────────┘ └──────────────────────┘ │
│ ↓ ↓ │
│ 管理连接与状态 生成响应并处理流式传输 │
└─────────────────────────────────────────────────────────┘
↓
Cloudflare Workers + Durable ObjectsWhat Each Tool Provides
各工具提供的能力
1. Agents SDK (This Skill)
1. Agents SDK(本技能)
Purpose: Infrastructure for stateful, real-time agents
Provides:
- ✅ WebSocket connection management (bidirectional real-time)
- ✅ Durable Objects wrapper (globally unique agent instances)
- ✅ Built-in state persistence (SQLite up to 1GB)
- ✅ Lifecycle methods (,
onStart,onConnect,onMessage)onClose - ✅ Task scheduling (with cron/delays)
this.schedule() - ✅ Multi-agent coordination ()
routeAgentRequest() - ✅ Client libraries (,
useAgent,AgentClient)agentFetch
Does NOT Provide:
- ❌ AI inference (no LLM calls)
- ❌ Streaming response parsing (bring your own)
- ❌ Provider integrations (OpenAI, Anthropic, etc.)
Think of it as: The building and infrastructure (rooms, doors, plumbing) but NOT the residents (AI).
目的:为有状态实时Agent提供基础设施
提供的能力:
- ✅ WebSocket连接管理(双向实时)
- ✅ Durable Objects封装(全局唯一Agent实例)
- ✅ 内置状态持久化(SQLite最多1GB)
- ✅ 生命周期方法(,
onStart,onConnect,onMessage)onClose - ✅ 任务调度(支持cron/延迟)
this.schedule() - ✅ 多Agent协同()
routeAgentRequest() - ✅ 客户端库(,
useAgent,AgentClient)agentFetch
不提供的能力:
- ❌ AI推理(无LLM调用)
- ❌ 流式响应解析:需自行引入
- ❌ 提供商集成(OpenAI、Anthropic等)
可以理解为:建筑与基础设施(房间、门、管道),而非住户(AI)。
2. Vercel AI SDK (Recommended for AI)
2. Vercel AI SDK(推荐用于AI)
Purpose: AI inference with automatic streaming
Provides:
- ✅ Automatic streaming response handling (SSE parsing done for you)
- ✅ Multi-provider support (OpenAI, Anthropic, Google, etc.)
- ✅ React hooks (,
useChat,useCompletion)useAssistant - ✅ Unified API across providers
- ✅ Tool calling / function calling
- ✅ Works on Cloudflare Workers ✅
Example:
typescript
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = streamText({
model: openai('gpt-4o-mini'),
messages: [...]
});
// Returns SSE stream - no manual parsing needed
return result.toTextStreamResponse();When to use with Agents SDK:
- ✅ Most chat applications
- ✅ When you want React hooks
- ✅ When you use multiple AI providers
- ✅ When you want clean, abstracted AI calls
Combine with Agents SDK:
typescript
import { AIChatAgent } from "agents/ai-chat-agent";
import { streamText } from "ai";
export class MyAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
// Agents SDK provides: WebSocket, state, this.messages
// AI SDK provides: Automatic streaming, provider abstraction
return streamText({
model: openai('gpt-4o-mini'),
messages: this.messages // Managed by Agents SDK
}).toTextStreamResponse();
}
}目的:带自动流式传输的AI推理
提供的能力:
- ✅ 自动流式响应处理(SSE解析已完成)
- ✅ 多提供商支持(OpenAI、Anthropic、Google等)
- ✅ React钩子(,
useChat,useCompletion)useAssistant - ✅ 跨提供商统一API
- ✅ 工具调用/函数调用
- ✅ 支持Cloudflare Workers ✅
示例:
typescript
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
const result = streamText({
model: openai('gpt-4o-mini'),
messages: [...]
});
// 返回SSE流 - 无需手动解析
return result.toTextStreamResponse();何时与Agents SDK结合使用:
- ✅ 大多数聊天应用
- ✅ 想要使用React钩子
- ✅ 使用多个AI提供商
- ✅ 想要简洁、抽象的AI调用
与Agents SDK结合示例:
typescript
import { AIChatAgent } from "agents/ai-chat-agent";
import { streamText } from "ai";
export class MyAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
// Agents SDK提供:WebSocket、状态、this.messages
// AI SDK提供:自动流式传输、提供商抽象
return streamText({
model: openai('gpt-4o-mini'),
messages: this.messages, // Agents SDK管理历史记录
onFinish
}).toTextStreamResponse();
}
}3. Workers AI (Alternative for AI)
3. Workers AI(AI的替代选择)
Purpose: Cloudflare's on-platform AI inference
Provides:
- ✅ Cost-effective inference (included in Workers subscription)
- ✅ No external API keys needed
- ✅ Models: LLaMA 3, Qwen, Mistral, embeddings, etc.
- ✅ Runs on Cloudflare's network (low latency)
Does NOT Provide:
- ❌ Automatic streaming parsing (returns raw SSE format)
- ❌ React hooks
- ❌ Multi-provider abstraction
Manual parsing required:
typescript
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [...],
stream: true
});
// Returns raw SSE format - YOU must parse
for await (const chunk of response) {
const text = new TextDecoder().decode(chunk); // Uint8Array → string
if (text.startsWith('data: ')) { // Check SSE format
const data = JSON.parse(text.slice(6)); // Parse JSON
if (data.response) { // Extract .response field
fullResponse += data.response;
}
}
}When to use:
- ✅ Cost is critical (embeddings, high-volume)
- ✅ Need Cloudflare-specific models
- ✅ Willing to handle manual SSE parsing
- ✅ No external dependencies allowed
Trade-off: Save money, spend time on manual parsing.
目的:Cloudflare平台内置的AI推理
提供的能力:
- ✅ 高性价比推理(包含在Workers订阅中)
- ✅ 无需外部API密钥
- ✅ 模型支持:LLaMA 3、Qwen、Mistral、嵌入等
- ✅ 在Cloudflare网络运行(低延迟)
不提供的能力:
- ❌ 自动流式解析:返回原始SSE格式
- ❌ React钩子
- ❌ 多提供商抽象
需要手动解析:
typescript
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [...],
stream: true
});
// 返回原始SSE格式 - 你必须自行解析
for await (const chunk of response) {
const text = new TextDecoder().decode(chunk); // Uint8Array → 字符串
if (text.startsWith('data: ')) { // 检查SSE格式
const data = JSON.parse(text.slice(6)); // 解析JSON
if (data.response) { // 提取.response字段
fullResponse += data.response;
}
}
}何时使用:
- ✅ 成本至关重要(嵌入、高流量场景)
- ✅ 需要Cloudflare特定模型
- ✅ 愿意处理手动SSE解析
- ✅ 不允许外部依赖
权衡:节省成本,但需花费时间处理手动解析。
Recommended Combinations
推荐组合
Option A: Agents SDK + Vercel AI SDK (Recommended ⭐)
选项A:Agents SDK + Vercel AI SDK(推荐 ⭐)
Use when: You need WebSockets/state AND want clean AI integration
typescript
import { AIChatAgent } from "agents/ai-chat-agent";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return streamText({
model: openai('gpt-4o-mini'),
messages: this.messages, // Agents SDK manages history
onFinish
}).toTextStreamResponse();
}
}Pros:
- ✅ Best developer experience
- ✅ Automatic streaming
- ✅ WebSockets + state from Agents SDK
- ✅ Clean, maintainable code
Cons:
- ⚠️ Requires external API keys
- ⚠️ Additional cost for AI provider
适用场景:需要WebSocket/状态,且想要简洁的AI集成
typescript
import { AIChatAgent } from "agents/ai-chat-agent";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return streamText({
model: openai('gpt-4o-mini'),
messages: this.messages, // Agents SDK管理历史记录
onFinish
}).toTextStreamResponse();
}
}优点:
- ✅ 最佳开发者体验
- ✅ 自动流式传输
- ✅ Agents SDK提供WebSocket + 状态
- ✅ 代码简洁、可维护
缺点:
- ⚠️ 需要外部API密钥
- ⚠️ AI提供商产生额外成本
Option B: Agents SDK + Workers AI
选项B:Agents SDK + Workers AI
Use when: You need WebSockets/state AND cost is critical
typescript
import { Agent } from "agents";
export class BudgetAgent extends Agent<Env> {
async onMessage(connection, message) {
const response = await this.env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [...],
stream: true
});
// Manual SSE parsing required (see Workers AI section above)
for await (const chunk of response) {
// ... manual parsing ...
}
}
}Pros:
- ✅ Cost-effective
- ✅ No external dependencies
- ✅ WebSockets + state from Agents SDK
Cons:
- ❌ Manual SSE parsing complexity
- ❌ Limited model selection
- ❌ More code to maintain
适用场景:需要WebSocket/状态,且成本至关重要
typescript
import { Agent } from "agents";
export class BudgetAgent extends Agent<Env> {
async onMessage(connection, message) {
const response = await this.env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [...],
stream: true
});
// 需要手动解析SSE(见上方Workers AI章节)
for await (const chunk of response) {
// ... 手动解析 ...
}
}
}优点:
- ✅ 高性价比
- ✅ 无外部依赖
- ✅ Agents SDK提供WebSocket + 状态
缺点:
- ❌ 手动SSE解析复杂度高
- ❌ 模型选择有限
- ❌ 需维护更多代码
Option C: Just Vercel AI SDK (No Agents)
选项C:仅使用Vercel AI SDK(无需Agents)
Use when: You DON'T need WebSockets or Durable Objects
typescript
// worker.ts - Simple Workers route
export default {
async fetch(request: Request, env: Env) {
const { messages } = await request.json();
const result = streamText({
model: openai('gpt-4o-mini'),
messages
});
return result.toTextStreamResponse();
}
}
// client.tsx - Built-in React hooks
import { useChat } from 'ai/react';
function Chat() {
const { messages, input, handleSubmit } = useChat({ api: '/api/chat' });
return <form onSubmit={handleSubmit}>...</form>;
}Pros:
- ✅ Simplest approach
- ✅ Least code
- ✅ Fast to implement
- ✅ Built-in React hooks
Cons:
- ❌ No WebSockets (only SSE)
- ❌ No Durable Objects state
- ❌ No multi-agent coordination
Best for: 80% of chat applications
适用场景:不需要WebSocket或Durable Objects
typescript
// worker.ts - 简单的Workers路由
export default {
async fetch(request: Request, env: Env) {
const { messages } = await request.json();
const result = streamText({
model: openai('gpt-4o-mini'),
messages
});
return result.toTextStreamResponse();
}
}
// client.tsx - 内置React钩子
import { useChat } from 'ai/react';
function Chat() {
const { messages, input, handleSubmit } = useChat({ api: '/api/chat' });
return <form onSubmit={handleSubmit}>...</form>;
}优点:
- ✅ 最简单的方案
- ✅ 代码量最少
- ✅ 快速实现
- ✅ 内置React钩子
缺点:
- ❌ 无WebSocket(仅SSE)
- ❌ 无Durable Objects状态
- ❌ 无多Agent协同
最适合:80%的聊天应用场景
Decision Matrix
决策矩阵
| Your Needs | Recommended Stack | Complexity | Cost |
|---|---|---|---|
| Simple chat, no state | AI SDK only | 🟢 Low | $$ (AI provider) |
| Chat + WebSockets + state | Agents SDK + AI SDK | 🟡 Medium | $$$ (infra + AI) |
| Chat + WebSockets + budget | Agents SDK + Workers AI | 🔴 High | $ (infra only) |
| Multi-agent workflows | Agents SDK + AI SDK | 🔴 High | $$$ (infra + AI) |
| MCP server with tools | Agents SDK (McpAgent) | 🟡 Medium | $ (infra only) |
| 需求 | 推荐技术栈 | 复杂度 | 成本 |
|---|---|---|---|
| 简单聊天、无状态 | 仅AI SDK | 🟢 低 | $$(AI提供商) |
| 聊天 + WebSocket + 状态 | Agents SDK + AI SDK | 🟡 中 | $$$(基础设施 + AI) |
| 聊天 + WebSocket + 低成本 | Agents SDK + Workers AI | 🔴 高 | $(仅基础设施) |
| 多Agent工作流 | Agents SDK + AI SDK | 🔴 高 | $$$(基础设施 + AI) |
| 带工具的MCP服务器 | Agents SDK(McpAgent) | 🟡 中 | $(仅基础设施) |
Key Takeaway
核心要点
Agents SDK is infrastructure, not AI. You combine it with AI inference tools:
- For best DX: Agents SDK + Vercel AI SDK ⭐
- For cost savings: Agents SDK + Workers AI (accept manual parsing)
- For simplicity: Just AI SDK (if you don't need WebSockets/state)
The rest of this skill focuses on Agents SDK (the infrastructure layer). For AI inference patterns, see the or skills.
ai-sdk-corecloudflare-workers-aiAgents SDK是基础设施,而非AI。你需要将它与AI推理工具结合使用:
- 最佳开发者体验:Agents SDK + Vercel AI SDK ⭐
- 成本优先:Agents SDK + Workers AI(接受手动解析)
- 最简单方案:仅AI SDK(如果不需要WebSocket/状态)
本技能的剩余部分将聚焦于Agents SDK(基础设施层)。关于AI推理模式,请查看或技能。
ai-sdk-corecloudflare-workers-aiConfiguration (wrangler.jsonc)
配置(wrangler.jsonc)
Critical Required Configuration:
jsonc
{
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] } // MUST be in first migration
]
}Common Optional Bindings: , , , , ,
aivectorizebrowserworkflowsd1_databasesr2_bucketsCRITICAL Migration Rules:
- ✅ MUST be in tag "v1" (cannot add SQLite to existing deployed class)
new_sqlite_classes - ✅ and
nameMUST match exactlyclass_name - ✅ Migrations are atomic (all instances updated simultaneously)
- ✅ Each tag must be unique, cannot edit/remove previous tags
关键必填配置:
jsonc
{
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] } // 必须在首次迁移中添加
]
}常见可选绑定:, , , , ,
aivectorizebrowserworkflowsd1_databasesr2_buckets关键迁移规则:
- ✅ 必须在标签"v1"中添加(无法为已部署的类添加SQLite)
new_sqlite_classes - ✅ 和
name必须完全匹配class_name - ✅ 迁移是原子操作(所有实例同时更新)
- ✅ 每个标签必须唯一,无法编辑/移除之前的标签
Core Agent Patterns
核心Agent模式
Agent Class Basics - Extend with lifecycle methods:
Agent<Env, State>- - Agent initialization
onStart() - - Handle HTTP requests
onRequest() - - WebSocket handling
onConnect/onMessage/onClose() - - React to state changes
onStateUpdate()
Key Properties:
- - Environment bindings (AI, DB, etc.)
this.env - - Current agent state (read-only)
this.state - - Update persisted state
this.setState() - - Built-in SQLite database
this.sql - - Agent instance identifier
this.name - - Schedule future tasks
this.schedule()
See: Official Agent API docs at https://developers.cloudflare.com/agents/api-reference/agents-api/
Agent类基础 - 继承并实现生命周期方法:
Agent<Env, State>- - Agent初始化
onStart() - - 处理HTTP请求
onRequest() - - WebSocket处理
onConnect/onMessage/onClose() - - 响应状态变化
onStateUpdate()
核心属性:
- - 环境绑定(AI、数据库等)
this.env - - 当前Agent状态(只读)
this.state - - 更新持久化状态
this.setState() - - 内置SQLite数据库
this.sql - - Agent实例标识符
this.name - - 调度未来任务
this.schedule()
参考:官方Agent API文档 https://developers.cloudflare.com/agents/api-reference/agents-api/
WebSockets & Real-Time Communication
WebSocket与实时通信
Agents support WebSockets for bidirectional real-time communication. Use when you need:
- Client can send messages while server streams
- Agent-initiated messages (notifications, updates)
- Long-lived connections with state
Basic Pattern:
typescript
export class ChatAgent extends Agent<Env, State> {
async onConnect(connection: Connection, ctx: ConnectionContext) {
// Auth check, add to participants, send welcome
}
async onMessage(connection: Connection, message: WSMessage) {
// Process message, update state, broadcast response
}
}SSE Alternative: For one-way server → client streaming (simpler, HTTP-based), use Server-Sent Events instead of WebSockets.
Agents支持WebSocket实现双向实时通信。在以下场景使用:
- 客户端可在服务器流式传输时发送消息
- Agent主动发起消息(通知、更新)
- 带状态的长连接
基础模式:
typescript
export class ChatAgent extends Agent<Env, State> {
async onConnect(connection: Connection, ctx: ConnectionContext) {
// 权限检查、添加参与者、发送欢迎消息
}
async onMessage(connection: Connection, message: WSMessage) {
// 处理消息、更新状态、广播响应
}
}SSE替代方案:对于单向服务器→客户端流式传输(更简单、基于HTTP),使用Server-Sent Events而非WebSocket。
State Management
状态管理
Two State Mechanisms:
-
- JSON-serializable state (up to 1GB)
this.setState(newState)- Automatically persisted, syncs to WebSocket clients
- Use for: User preferences, session data, small datasets
-
- Built-in SQLite database (up to 1GB)
this.sql- Tagged template literals prevent SQL injection
- Use for: Relational data, large datasets, complex queries
State Rules:
- ✅ JSON-serializable only (objects, arrays, primitives, null)
- ✅ Persists across restarts, immediately consistent
- ❌ No functions or circular references
- ❌ 1GB total limit (state + SQL combined)
SQL Pattern:
typescript
await this.sql`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, email TEXT)`
await this.sql`INSERT INTO users (email) VALUES (${userEmail})` // ← Prepared statement
const users = await this.sql`SELECT * FROM users WHERE email = ${email}` // ← Returns array两种状态机制:
-
- JSON可序列化状态(最多1GB)
this.setState(newState)- 自动持久化,同步到WebSocket客户端
- 适用场景:用户偏好、会话数据、小型数据集
-
- 内置SQLite数据库(最多1GB)
this.sql- 标签模板字面量防止SQL注入
- 适用场景:关系型数据、大型数据集、复杂查询
状态规则:
- ✅ 仅支持JSON可序列化类型(对象、数组、基本类型、null)
- ✅ 跨重启持久化,立即一致
- ❌ 不支持函数或循环引用
- ❌ 总限制1GB(状态 + SQL)
SQL模式:
typescript
await this.sql`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, email TEXT)`
await this.sql`INSERT INTO users (email) VALUES (${userEmail})` // ← 预编译语句
const users = await this.sql`SELECT * FROM users WHERE email = ${email}` // ← 返回数组State Type Safety Gotcha
状态类型安全陷阱
CRITICAL: Providing a type parameter to state methods does NOT validate that the result matches your type definition. In TypeScript, properties (fields) that do not exist or conform to the type you provided will be dropped silently.
typescript
interface MyState {
count: number;
name: string;
}
export class MyAgent extends Agent<Env, MyState> {
initialState = { count: 0, name: "default" };
async increment() {
// TypeScript allows this, but runtime may differ
const currentState = this.state; // Type is MyState
// If state was corrupted/modified externally:
// { count: "invalid", otherField: 123 }
// TypeScript still shows it as MyState
// count field doesn't match (string vs number)
// otherField is dropped silently
}
}Prevention: Add runtime validation for critical state operations:
typescript
// Validate state shape at runtime
function validateState(state: unknown): state is MyState {
return (
typeof state === 'object' &&
state !== null &&
'count' in state &&
typeof (state as MyState).count === 'number' &&
'name' in state &&
typeof (state as MyState).name === 'string'
);
}
async increment() {
if (!validateState(this.state)) {
console.error('State validation failed', this.state);
// Reset to valid state
await this.setState(this.initialState);
return;
}
// Safe to use
const newCount = this.state.count + 1;
await this.setState({ ...this.state, count: newCount });
}关键注意:为状态方法提供类型参数并不保证运行时结果与类型定义匹配。在TypeScript中,不存在或不符合类型的属性会被静默丢弃。
typescript
interface MyState {
count: number;
name: string;
}
export class MyAgent extends Agent<Env, MyState> {
initialState = { count: 0, name: "default" };
async increment() {
// TypeScript允许此操作,但运行时可能不同
const currentState = this.state; // 类型为MyState
// 如果状态被外部损坏/修改:
// { count: "invalid", otherField: 123 }
// TypeScript仍将其显示为MyState
// count字段类型不匹配(字符串 vs 数字)
// otherField被静默丢弃
}
}预防措施:为关键状态操作添加运行时验证:
typescript
// 运行时验证状态结构
function validateState(state: unknown): state is MyState {
return (
typeof state === 'object' &&
state !== null &&
'count' in state &&
typeof (state as MyState).count === 'number' &&
'name' in state &&
typeof (state as MyState).name === 'string'
);
}
async increment() {
if (!validateState(this.state)) {
console.error('状态验证失败', this.state);
// 重置为有效状态
await this.setState(this.initialState);
return;
}
// 安全使用
const newCount = this.state.count + 1;
await this.setState({ ...this.state, count: newCount });
}Schedule Tasks
任务调度
Agents can schedule tasks to run in the future using .
this.schedule()Agents可使用调度未来任务。
this.schedule()Delay (Seconds)
延迟执行(秒)
typescript
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.
}
}typescript
export class MyAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
// 调度60秒后运行的任务
const { id } = await this.schedule(60, "checkStatus", { requestId: "123" });
return Response.json({ scheduledTaskId: id });
}
// 此方法将在60秒后被调用
async checkStatus(data: { requestId: string }) {
console.log('检查请求状态:', data.requestId);
// 执行检查、更新状态、发送通知等
}
}Specific Date
指定日期执行
typescript
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.
}
}typescript
export class MyAgent extends Agent {
async scheduleReminder(reminderDate: string) {
const date = new Date(reminderDate);
const { id } = await this.schedule(date, "sendReminder", {
message: "你的预约时间到了!"
});
return id;
}
async sendReminder(data: { message: string }) {
console.log('发送提醒:', data.message);
// 发送邮件、推送通知等
}
}Cron Expressions
Cron表达式
typescript
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...');
}
}typescript
export class MyAgent extends Agent {
async setupRecurringTasks() {
// 每10分钟一次
await this.schedule("*/10 * * * *", "checkUpdates", {});
// 每天上午8点
await this.schedule("0 8 * * *", "dailyReport", {});
// 每周一上午9点
await this.schedule("0 9 * * 1", "weeklyReport", {});
// 每小时整点
await this.schedule("0 * * * *", "hourlyCheck", {});
}
async checkUpdates(data: any) {
console.log('检查更新...');
}
async dailyReport(data: any) {
console.log('生成每日报告...');
}
async weeklyReport(data: any) {
console.log('生成每周报告...');
}
async hourlyCheck(data: any) {
console.log('执行每小时检查...');
}
}Managing Scheduled Tasks
管理调度任务
typescript
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" });
}
}Scheduling Constraints:
- Each task maps to a SQL database row (max 2 MB per task)
- Total tasks limited by:
(task_size * count) + other_state < 1GB - Cron tasks continue running until explicitly cancelled
- Callback method MUST exist on Agent class (throws error if missing)
CRITICAL ERROR: If callback method doesn't exist:
typescript
// ❌ BAD: Method doesn't exist
await this.schedule(60, "nonExistentMethod", {});
// ✅ GOOD: Method exists
await this.schedule(60, "existingMethod", {});
async existingMethod(data: any) {
// Implementation
}typescript
export class MyAgent extends Agent {
async manageSchedules() {
// 获取所有调度任务
const allTasks = this.getSchedules();
console.log('总任务数:', allTasks.length);
// 通过ID获取特定任务
const taskId = "some-task-id";
const task = await this.getSchedule(taskId);
if (task) {
console.log('任务:', task.callback, '执行时间:', new Date(task.time));
console.log('负载:', task.payload);
console.log('类型:', task.type); // "scheduled" | "delayed" | "cron"
// 取消任务
const cancelled = await this.cancelSchedule(taskId);
console.log('已取消:', cancelled);
}
// 获取时间范围内的任务
const upcomingTasks = this.getSchedules({
timeRange: {
start: new Date(),
end: new Date(Date.now() + 24 * 60 * 60 * 1000) // 未来24小时
}
});
console.log('即将执行的任务数:', upcomingTasks.length);
// 按类型筛选
const cronTasks = this.getSchedules({ type: "cron" });
const delayedTasks = this.getSchedules({ type: "delayed" });
}
}调度限制:
- 每个任务对应SQL数据库中的一行(每个任务最多2MB)
- 总任务数限制:
(任务大小 * 数量) + 其他状态 < 1GB - Cron任务会持续运行,直到显式取消
- 回调方法必须存在于Agent类中(如果不存在会抛出错误)
关键错误:如果回调方法不存在:
typescript
// ❌ 错误:方法不存在
await this.schedule(60, "nonExistentMethod", {});
// ✅ 正确:方法存在
await this.schedule(60, "existingMethod", {});
async existingMethod(data: any) {
// 实现代码
}Run Workflows
运行工作流
Agents can trigger asynchronous Cloudflare Workflows.
Agents可触发异步Cloudflare Workflows。
Workflow Binding Configuration
工作流绑定配置
wrangler.jsoncjsonc
{
"workflows": [
{
"name": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
]
}If Workflow is in a different script:
jsonc
{
"workflows": [
{
"name": "EMAIL_WORKFLOW",
"class_name": "EmailWorkflow",
"script_name": "email-workflows" // Different project
}
]
}wrangler.jsoncjsonc
{
"workflows": [
{
"name": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
]
}如果工作流在其他脚本中:
jsonc
{
"workflows": [
{
"name": "EMAIL_WORKFLOW",
"class_name": "EmailWorkflow",
"script_name": "email-workflows" // 不同项目
}
]
}Triggering a Workflow
触发工作流
typescript
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;
}
}typescript
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');
// 立即触发工作流
const instance = await this.env.MY_WORKFLOW.create({
id: `user-${userId}`,
params: { userId, action: "process" }
});
// 或调度延迟触发的工作流
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
});
// 定期监控工作流状态
await this.schedule("*/5 * * * *", "checkWorkflowStatus", { id: instance.id });
}
async checkWorkflowStatus(data: { id: string }) {
// 检查工作流状态(详情见Workflows文档)
console.log('检查工作流:', data.id);
}
}
// 工作流定义(可在同一文件/项目或不同文件/项目中)
export class MyWorkflow extends WorkflowEntrypoint<Env> {
async run(event: WorkflowEvent<{ userId: string }>, step: WorkflowStep) {
// 工作流实现
const result = await step.do('process-data', async () => {
return { processed: true };
});
return result;
}
}Agents vs Workflows
Agents vs Workflows
| Feature | Agents | Workflows |
|---|---|---|
| Purpose | Interactive, user-facing | Background processing |
| Duration | Seconds to hours | Minutes to hours |
| State | SQLite database | Step-based checkpoints |
| Interaction | WebSockets, HTTP | No direct interaction |
| Retry | Manual | Automatic per step |
| Use Case | Chat, real-time UI | ETL, batch processing |
Best Practice: Use Agents to coordinate multiple Workflows. Agents can trigger, monitor, and respond to Workflow results while maintaining user interaction.
| 特性 | Agents | Workflows |
|---|---|---|
| 目的 | 交互式、面向用户 | 后台处理 |
| 持续时间 | 秒到小时 | 分钟到小时 |
| 状态 | SQLite数据库 | 基于步骤的检查点 |
| 交互 | WebSocket、HTTP | 无直接交互 |
| 重试 | 手动 | 按步骤自动重试 |
| 适用场景 | 聊天、实时UI | ETL、批处理 |
最佳实践:使用Agents协调多个Workflows。Agents可触发、监控并响应Workflow结果,同时保持用户交互。
Browse the Web
网页浏览
Agents can use Browser Rendering for web scraping and automation:
Binding: Add to wrangler.jsonc
Package:
Use Case: Web scraping, screenshots, automated browsing within agent workflows
"browser": { "binding": "BROWSER" }@cloudflare/puppeteerSee: skill for complete Puppeteer + Workers integration guide.
cloudflare-browser-renderingAgents可使用Browser Rendering进行网页抓取与自动化:
绑定:在wrangler.jsonc中添加
包:
适用场景:网页抓取、截图、Agent工作流中的自动化浏览
"browser": { "binding": "BROWSER" }@cloudflare/puppeteer参考:技能提供完整的Puppeteer + Workers集成指南。
cloudflare-browser-renderingRetrieval Augmented Generation (RAG)
检索增强生成(RAG)
Agents can implement RAG using Vectorize (vector database) + Workers AI (embeddings):
Pattern: Ingest docs → generate embeddings → store in Vectorize → query → retrieve context → pass to AI
Bindings:
- - Workers AI for embeddings
"ai": { "binding": "AI" } - - Vector search
"vectorize": { "bindings": [{ "binding": "VECTORIZE", "index_name": "my-vectors" }] }
Typical Workflow:
- Generate embeddings with Workers AI ()
@cf/baai/bge-base-en-v1.5 - Upsert vectors to Vectorize ()
this.env.VECTORIZE.upsert(vectors) - Query similar vectors ()
this.env.VECTORIZE.query(queryVector, { topK: 5 }) - Use retrieved context in AI prompt
See: skill for complete RAG implementation guide.
cloudflare-vectorizeAgents可使用Vectorize(向量数据库) + Workers AI(嵌入)实现RAG:
模式:导入文档 → 生成嵌入 → 存储到Vectorize → 查询 → 检索上下文 → 传递给AI
绑定:
- - Workers AI用于生成嵌入
"ai": { "binding": "AI" } - - 向量搜索
"vectorize": { "bindings": [{ "binding": "VECTORIZE", "index_name": "my-vectors" }] }
典型工作流:
- 使用Workers AI生成嵌入()
@cf/baai/bge-base-en-v1.5 - 将向量插入Vectorize()
this.env.VECTORIZE.upsert(vectors) - 查询相似向量()
this.env.VECTORIZE.query(queryVector, { topK: 5 }) - 在AI提示词中使用检索到的上下文
参考:技能提供完整的RAG实现指南。
cloudflare-vectorizeUsing AI Models
使用AI模型
Agents can call AI models using:
- Vercel AI SDK (recommended): Multi-provider, automatic streaming, tool calling
- Workers AI: Cloudflare's on-platform inference (cost-effective, manual parsing)
Architecture Note: Agents SDK provides infrastructure (WebSockets, state, scheduling). AI inference is a separate layer - use AI SDK for the "brain".
See:
- skill for complete AI SDK integration patterns
ai-sdk-core - skill for Workers AI streaming parsing
cloudflare-workers-ai
Agents可通过以下方式调用AI模型:
- Vercel AI SDK(推荐):多提供商、自动流式传输、工具调用
- Workers AI:Cloudflare平台内置推理(高性价比、手动解析)
架构说明:Agents SDK提供基础设施(WebSocket、状态、调度)。AI推理是独立层 - 使用AI SDK作为“大脑”。
参考:
- 技能提供完整的AI SDK集成模式
ai-sdk-core - 技能提供Workers AI流式解析指南
cloudflare-workers-ai
Calling Agents
调用Agents
Two Main Patterns:
-
- Auto-route via URL pattern
routeAgentRequest(request, env)/agents/:agent/:name- Example: routes to MyAgent instance "user-123"
/agents/my-agent/user-123
- Example:
-
- Custom routing
getAgentByName<Env, T>(env.AgentBinding, instanceName)- Returns agent stub for calling methods or passing requests
- Example:
const agent = getAgentByName(env.MyAgent, 'user-${userId}')
Multi-Agent Communication:
typescript
export class AgentA extends Agent<Env> {
async processData(data: any) {
const agentB = getAgentByName<Env, AgentB>(this.env.AgentB, 'processor-1');
return await (await agentB).analyze(data);
}
}CRITICAL Security: Always authenticate in Worker BEFORE creating/accessing agents. Agents should assume the caller is authorized.
两种主要模式:
-
- 通过URL模式
routeAgentRequest(request, env)自动路由/agents/:agent/:name- 示例:路由到MyAgent实例"user-123"
/agents/my-agent/user-123
- 示例:
-
- 自定义路由
getAgentByName<Env, T>(env.AgentBinding, instanceName)- 返回Agent存根,用于调用方法或传递请求
- 示例:
const agent = getAgentByName(env.MyAgent, 'user-${userId}')
多Agent通信:
typescript
export class AgentA extends Agent<Env> {
async processData(data: any) {
const agentB = getAgentByName<Env, AgentB>(this.env.AgentB, 'processor-1');
return await (await agentB).analyze(data);
}
}关键安全注意:在Worker中始终先认证,再创建/访问Agents。Agents应假设调用者已授权。
Client APIs
客户端API
Browser/React Integration:
- (from
AgentClient) - WebSocket client for browseragents/client - (from
agentFetch) - HTTP requests to agentsagents/client - (from
useAgent) - React hook for WebSocket connections + state syncagents/react - (from
useAgentChat) - Pre-built chat UI hookagents/ai-react
All client libraries automatically handle: WebSocket connections, state synchronization, reconnection logic.
浏览器/React集成:
- (来自
AgentClient) - 浏览器WebSocket客户端agents/client - (来自
agentFetch) - 向Agents发送HTTP请求agents/client - (来自
useAgent) - WebSocket连接 + 状态同步的React钩子agents/react - (来自
useAgentChat) - 预构建聊天UI钩子agents/ai-react
所有客户端库自动处理:WebSocket连接、状态同步、重连逻辑。
Model Context Protocol (MCP)
Model Context Protocol (MCP)
Build MCP servers using the Agents SDK.
使用Agents SDK构建MCP服务器。
MCP Server Setup
MCP服务器设置
bash
npm install @modelcontextprotocol/sdk agentsbash
npm install @modelcontextprotocol/sdk agentsBasic MCP Server
基础MCP服务器
typescript
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) }]
})
);
}
}typescript
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() {
// 定义工具
this.server.tool(
"add",
"将两个数字相加",
{
a: z.number().describe("第一个数字"),
b: z.number().describe("第二个数字")
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
}
}Stateful MCP Server
有状态MCP服务器
typescript
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}`
}]
};
}
);
}
}typescript
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() {
// 资源
this.server.resource(
"counter",
"mcp://resource/counter",
(uri) => ({
contents: [{ uri: uri.href, text: String(this.state.counter) }]
})
);
// 工具
this.server.tool(
"increment",
"增加计数器值",
{ amount: z.number() },
async ({ amount }) => {
this.setState({
...this.state,
counter: this.state.counter + amount
});
return {
content: [{
type: "text",
text: `计数器当前值为 ${this.state.counter}`
}]
};
}
);
}
}MCP Transport Configuration
MCP传输配置
typescript
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;Transport Comparison:
- /mcp: Streamable HTTP (modern, recommended)
- /sse: Server-Sent Events (legacy, deprecated)
typescript
import { Hono } from 'hono';
const app = new Hono();
// 现代流式HTTP传输(推荐)
app.mount('/mcp', MyMCP.serve('/mcp').fetch, { replaceRequest: false });
// 传统SSE传输(已废弃)
app.mount('/sse', MyMCP.serveSSE('/sse').fetch, { replaceRequest: false });
export default app;传输对比:
- /mcp:流式HTTP(现代、推荐)
- /sse:Server-Sent Events(传统、已废弃)
MCP Protocol Version Support
MCP协议版本支持
The Agents SDK supports multiple MCP protocol versions. As of agents@0.3.x, version validation is permissive to accept newer protocol versions:
- Supported versions: ,
2024-11-05, and future versions2025-11-25 - Error (before 0.3.x):
Error: Unsupported MCP protocol version: 2025-11-25 - Fixed: Version validation now accepts any non-ancient protocol version
This aligns with the MCP community's move to stateless transports. If you encounter protocol version errors, update to agents@0.3.x or later.
Source: GitHub Issue #769
Agents SDK支持多个MCP协议版本。在agents@0.3.x及以上版本中,版本验证已放宽,可接受更新的协议版本:
- 支持版本:,
2024-11-05及未来版本2025-11-25 - 旧版本错误(0.3.x之前):
Error: Unsupported MCP protocol version: 2025-11-25 - 修复:版本验证现在接受所有非过时的协议版本
这与MCP社区向无状态传输的转变保持一致。如果遇到协议版本错误,请升级到agents@0.3.x或更高版本。
MCP with OAuth
MCP与OAuth结合
typescript
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
});typescript
import { OAuthProvider } from '@cloudflare/workers-oauth-provider';
export default new OAuthProvider({
apiHandlers: {
'/sse': MyMCP.serveSSE('/sse'),
'/mcp': MyMCP.serve('/mcp')
},
// OAuth配置
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
// ... 其他OAuth设置
});Testing MCP Server
测试MCP服务器
bash
undefinedbash
undefinedRun MCP inspector
运行MCP检查器
npx @modelcontextprotocol/inspector@latest
npx @modelcontextprotocol/inspector@latest
Connect to: http://localhost:8788/mcp
**Cloudflare's MCP Servers**: See [reference](https://developers.cloudflare.com/agents/model-context-protocol/mcp-servers-for-cloudflare/) for production examples.
---
**Cloudflare的MCP服务器**:查看[参考文档](https://developers.cloudflare.com/agents/model-context-protocol/mcp-servers-for-cloudflare/)获取生产示例。
---Critical Rules
关键规则
Always Do ✅
始终要做 ✅
- Export Agent class - Must be exported for binding to work
- Include new_sqlite_classes in v1 migration - Cannot add SQLite later
- Match binding name to class name - Prevents "binding not found" errors
- Authenticate in Worker, not Agent - Security best practice
- Use tagged template literals for SQL - Prevents SQL injection
- Handle WebSocket disconnections - State persists, connections don't
- Verify scheduled task callback exists - Throws error if method missing
- Use idFromName() for user-specific agents - NEVER use newUniqueId() for persistent state (see Issue #23)
- Check state size limits - Max 1GB total per agent
- Monitor task payload size - Max 2MB per scheduled task
- Use workflow bindings correctly - Must be configured in wrangler.jsonc
- Create Vectorize indexes before inserting - Required for metadata filtering
- Close browser instances - Prevent resource leaks
- Use setState() for persistence - Don't just modify this.state
- Test migrations locally first - Migrations are atomic, can't rollback
- Prune WebSocket message history - Stay under 1MB cumulative payload (see Issue #17)
- Validate state shape at runtime - TypeScript types don't enforce runtime validation (see State Type Safety)
- 导出Agent类 - 必须导出才能使绑定生效
- 在v1迁移中包含new_sqlite_classes - 之后无法添加SQLite
- 绑定名称与类名匹配 - 防止“绑定未找到”错误
- 在Worker中认证,而非Agent中 - 安全最佳实践
- 使用标签模板字面量编写SQL - 防止SQL注入
- 处理WebSocket断开 - 状态持久化,但连接不持久
- 验证调度任务的回调存在 - 如果方法缺失会抛出错误
- 对用户特定Agent使用idFromName() - 绝不要对持久化状态使用newUniqueId()(见Issue #23)
- 检查状态大小限制 - 每个Agent最多1GB
- 监控任务负载大小 - 每个调度任务最多2MB
- 正确使用工作流绑定 - 必须在wrangler.jsonc中配置
- 插入前创建Vectorize索引 - 元数据过滤必需
- 关闭浏览器实例 - 防止资源泄漏
- 使用setState()进行持久化 - 不要直接修改this.state
- 先在本地测试迁移 - 迁移是原子操作,无法回滚
- 清理WebSocket消息历史 - 累计负载保持在1MB以下(见Issue #17)
- 运行时验证状态结构 - TypeScript类型不强制执行运行时验证(见状态类型安全部分)
Never Do ❌
绝不要做 ❌
- Don't add SQLite to existing deployed class - Must be in first migration
- Don't gradually deploy migrations - Atomic only
- Don't skip authentication in Worker - Always auth before agent access
- Don't construct SQL strings manually - Use tagged templates
- Don't exceed 1GB state per agent - Hard limit
- Don't schedule tasks with non-existent callbacks - Runtime error
- Don't use newUniqueId() for user-specific agents - State won't persist (see Issue #23)
- Don't use SSE for MCP - Deprecated, use /mcp transport
- Don't forget browser binding - Required for web browsing
- Don't modify this.state directly - Use setState() instead
- Don't let WebSocket payloads exceed 1MB - Connection will crash (see Issue #17)
- Don't trust TypeScript types for state validation - Add runtime checks (see State Type Safety)
- 不要为已部署的类添加SQLite - 必须在首次迁移中添加
- 不要逐步部署迁移 - 仅支持原子操作
- 不要在Worker中跳过认证 - 访问Agent前始终先认证
- 不要手动构造SQL字符串 - 使用标签模板
- 不要超过每个Agent 1GB的状态限制 - 硬限制
- 不要调度不存在回调的任务 - 运行时错误
- 不要对用户特定Agent使用newUniqueId() - 状态不会持久化(见Issue #23)
- 不要对MCP使用SSE - 已废弃,使用/mcp传输
- 不要忘记浏览器绑定 - 网页浏览必需
- 不要直接修改this.state - 使用setState()替代
- 不要让WebSocket负载超过1MB - 连接会崩溃(见Issue #17)
- 不要依赖TypeScript类型进行状态验证 - 添加运行时检查(见状态类型安全部分)
Known Issues Prevention
已知问题预防
This skill prevents 23 documented issues:
本技能可预防23种已记录的问题:
Issue 1: Migrations Not Atomic
Issue 1:迁移非原子操作
Error: "Cannot gradually deploy migration"
Source: https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/
Why: Migrations apply to all instances simultaneously
Prevention: Deploy migrations independently of code changes, use
npx wrangler versions deploy错误:"Cannot gradually deploy migration"
来源:https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/
原因:迁移会同时应用到所有实例
预防:独立于代码变更部署迁移,使用
npx wrangler versions deployIssue 2: Missing new_sqlite_classes
Issue 2:缺少new_sqlite_classes
Error: "Cannot enable SQLite on existing class"
Source: https://developers.cloudflare.com/agents/api-reference/configuration/
Why: SQLite must be enabled in first migration
Prevention: Include in tag "v1" migration
new_sqlite_classes错误:"Cannot enable SQLite on existing class"
来源:https://developers.cloudflare.com/agents/api-reference/configuration/
原因:必须在首次迁移中启用SQLite
预防:在标签"v1"的迁移中包含
new_sqlite_classesIssue 3: Agent Class Not Exported
Issue 3:Agent类未导出
Error: "Binding not found" or "Cannot access undefined"
Source: https://developers.cloudflare.com/agents/api-reference/agents-api/
Why: Durable Objects require exported class
Prevention: (with export keyword)
export class MyAgent extends Agent错误:"Binding not found"或"Cannot access undefined"
来源:https://developers.cloudflare.com/agents/api-reference/agents-api/
原因:Durable Objects要求类必须导出
预防:(包含export关键字)
export class MyAgent extends AgentIssue 4: Binding Name Mismatch
Issue 4:绑定名称不匹配
Error: "Binding 'X' not found"
Source: https://developers.cloudflare.com/agents/api-reference/configuration/
Why: Binding name must match class name exactly
Prevention: Ensure and are identical in wrangler.jsonc
nameclass_name错误:"Binding 'X' not found"
来源:https://developers.cloudflare.com/agents/api-reference/configuration/
原因:绑定名称必须与类名完全匹配
预防:确保wrangler.jsonc中的和完全相同
nameclass_nameIssue 5: Global Uniqueness Not Understood
Issue 5:未理解全局唯一性
Error: Unexpected behavior with agent instances
Source: https://developers.cloudflare.com/agents/api-reference/agents-api/
Why: Same name always returns same agent instance globally
Prevention: Use unique identifiers (userId, sessionId) for instance names
错误:Agent实例行为不符合预期
来源:https://developers.cloudflare.com/agents/api-reference/agents-api/
原因:相同名称始终返回同一个全局Agent实例
预防:使用唯一标识符(userId、sessionId)作为实例名称
Issue 6: WebSocket State Not Persisted
Issue 6:WebSocket状态未持久化
Error: Connection state lost after disconnect
Source: https://developers.cloudflare.com/agents/api-reference/websockets/
Why: WebSocket connections don't persist, but agent state does
Prevention: Store important data in agent state via setState(), not connection state
错误:断开连接后连接状态丢失
来源:https://developers.cloudflare.com/agents/api-reference/websockets/
原因:WebSocket连接不持久,但Agent状态持久
预防:通过setState()将重要数据存储在Agent状态中,而非连接状态
Issue 7: Scheduled Task Callback Doesn't Exist / Long AI Requests Timeout
Issue 7:调度任务回调不存在 / 长时AI请求超时
Error: "Method X does not exist on Agent" or "IoContext timed out due to inactivity" or "A call to blockConcurrencyWhile() waited for too long"
Source: https://developers.cloudflare.com/agents/api-reference/schedule-tasks/ and GitHub Issue #600
Why: this.schedule() calls method that isn't defined, OR scheduled callbacks failed when AI requests exceeded 30 seconds due to wrapper (fixed in agents@0.2.x via PR #653)
Prevention: Ensure callback method exists before scheduling. For long-running AI requests, update to agents@0.2.x or later.
blockConcurrencyWhileHistorical issue (before 0.2.x): Scheduled callbacks were wrapped in , which enforced a 30-second limit. AI requests exceeding this would fail even though they were valid async operations.
blockConcurrencyWhiletypescript
// ✅ Fixed in 0.2.x - schedule callbacks can now run for their full duration
export class MyAgent extends Agent<Env> {
async onRequest(request: Request) {
await this.schedule(60, "processAIRequest", { query: "..." });
}
async processAIRequest(data: { query: string }) {
// This can now take > 30s without timeout
const result = await streamText({
model: openai('gpt-4o'),
messages: [{ role: 'user', content: data.query }]
});
}
}错误:"Method X does not exist on Agent"或"IoContext timed out due to inactivity"或"A call to blockConcurrencyWhile() waited for too long"
来源:https://developers.cloudflare.com/agents/api-reference/schedule-tasks/和[GitHub Issue #600](https://github.com/cloudflare/agents/issues/600)
原因:this.schedule()调用了未定义的方法,或者调度回调在AI请求超过30秒时失败(agents@0.2.x中通过PR #653修复)
预防:调度前确保回调方法存在。对于长时AI请求,升级到agents@0.2.x或更高版本。
历史问题(0.2.x之前):调度回调被包装,强制执行30秒限制。即使是有效的异步操作,超过此时间的AI请求也会失败。
blockConcurrencyWhiletypescript
// ✅ 0.2.x中已修复 - 调度回调现在可运行完整时长
export class MyAgent extends Agent<Env> {
async onRequest(request: Request) {
await this.schedule(60, "processAIRequest", { query: "..." });
}
async processAIRequest(data: { query: string }) {
// 现在可运行超过30秒而不会超时
const result = await streamText({
model: openai('gpt-4o'),
messages: [{ role: 'user', content: data.query }]
});
}
}Issue 8: State Size Limit Exceeded
Issue 8:状态大小超出限制
Error: "Maximum database size exceeded"
Source: https://developers.cloudflare.com/agents/api-reference/store-and-sync-state/
Why: Agent state + scheduled tasks exceed 1GB
Prevention: Monitor state size, use external storage (D1, R2) for large data
错误:"Maximum database size exceeded"
来源:https://developers.cloudflare.com/agents/api-reference/store-and-sync-state/
原因:Agent状态 + 调度任务超过1GB
预防:监控状态大小,对大数据使用外部存储(D1、R2)
Issue 9: Scheduled Task Too Large
Issue 9:调度任务过大
Error: "Task payload exceeds 2MB"
Source: https://developers.cloudflare.com/agents/api-reference/schedule-tasks/
Why: Each task maps to database row with 2MB limit
Prevention: Keep task payloads minimal, store large data in agent state/SQL
错误:"Task payload exceeds 2MB"
来源:https://developers.cloudflare.com/agents/api-reference/schedule-tasks/
原因:每个任务对应数据库中的一行,限制2MB
预防:保持任务负载最小,将大数据存储在Agent状态/SQL中
Issue 10: Workflow Binding Missing
Issue 10:工作流绑定缺失
Error: "Cannot read property 'create' of undefined"
Source: https://developers.cloudflare.com/agents/api-reference/run-workflows/
Why: Workflow binding not configured in wrangler.jsonc
Prevention: Add workflow binding before using this.env.WORKFLOW
错误:"Cannot read property 'create' of undefined"
来源:https://developers.cloudflare.com/agents/api-reference/run-workflows/
原因:未在wrangler.jsonc中配置工作流绑定
预防:使用this.env.WORKFLOW前添加工作流绑定
Issue 11: Browser Binding Required
Issue 11:缺少浏览器绑定
Error: "BROWSER binding undefined"
Source: https://developers.cloudflare.com/agents/api-reference/browse-the-web/
Why: Browser Rendering requires explicit binding
Prevention: Add to wrangler.jsonc
"browser": { "binding": "BROWSER" }错误:"BROWSER binding undefined"
来源:https://developers.cloudflare.com/agents/api-reference/browse-the-web/
原因:Browser Rendering需要显式绑定
预防:在wrangler.jsonc中添加
"browser": { "binding": "BROWSER" }Issue 12: Vectorize Index Not Found
Issue 12:Vectorize索引未找到
Error: "Index does not exist"
Source: https://developers.cloudflare.com/agents/api-reference/rag/
Why: Vectorize index must be created before use
Prevention: Run before deploying agent
wrangler vectorize create错误:"Index does not exist"
来源:https://developers.cloudflare.com/agents/api-reference/rag/
原因:必须先创建Vectorize索引才能使用
预防:部署Agent前运行
wrangler vectorize createIssue 13: MCP Transport Confusion
Issue 13:MCP传输混淆
Error: "SSE transport deprecated"
Source: https://developers.cloudflare.com/agents/model-context-protocol/transport/
Why: SSE transport is legacy, streamable HTTP is recommended
Prevention: Use endpoint with , not
/mcpMyMCP.serve('/mcp')/sse错误:"SSE transport deprecated"
来源:https://developers.cloudflare.com/agents/model-context-protocol/transport/
原因:SSE传输已过时,推荐使用流式HTTP
预防:使用的/mcp端点,而非/sse
MyMCP.serve('/mcp')Issue 14: Authentication Bypass
Issue 14:认证绕过
Error: Security vulnerability
Source: https://developers.cloudflare.com/agents/api-reference/calling-agents/
Why: Authentication done in Agent instead of Worker
Prevention: Always authenticate in Worker before calling getAgentByName()
错误:安全漏洞
来源:https://developers.cloudflare.com/agents/api-reference/calling-agents/
原因:在Agent中而非Worker中进行认证
预防:调用getAgentByName()前始终在Worker中认证
Issue 15: Instance Naming Errors
Issue 15:实例命名错误
Error: Cross-user data leakage
Source: https://developers.cloudflare.com/agents/api-reference/calling-agents/
Why: Poor instance naming allows access to wrong agent
Prevention: Use namespaced names like , validate ownership
user-${userId}错误:跨用户数据泄露
来源:https://developers.cloudflare.com/agents/api-reference/calling-agents/
原因:实例命名不当导致访问错误的Agent
预防:使用命名空间名称如,验证所有权
user-${userId}Issue 16: Workers AI Streaming Requires Manual Parsing
Issue 16:Workers AI流式传输需要手动解析
Error: "Cannot read property 'response' of undefined" or empty AI responses
Source: https://developers.cloudflare.com/workers-ai/platform/streaming/
Why: Workers AI returns streaming responses as in Server-Sent Events (SSE) format, not plain objects
Prevention: Use + SSE parsing pattern (see "Workers AI (Alternative for AI)" section above)
Uint8ArrayTextDecoderThe problem - Attempting to access stream chunks directly fails:
typescript
const response = await env.AI.run(model, { stream: true });
for await (const chunk of response) {
console.log(chunk.response); // ❌ undefined - chunk is Uint8Array, not object
}The solution - Parse SSE format manually:
typescript
const response = await env.AI.run(model, { stream: true });
for await (const chunk of response) {
const text = new TextDecoder().decode(chunk); // Step 1: Uint8Array → string
if (text.startsWith('data: ')) { // Step 2: Check SSE format
const jsonStr = text.slice(6).trim(); // Step 3: Extract JSON from "data: {...}"
if (jsonStr === '[DONE]') break; // Step 4: Handle termination
const data = JSON.parse(jsonStr); // Step 5: Parse JSON
if (data.response) { // Step 6: Extract .response field
fullResponse += data.response;
}
}
}Better alternative: Use Vercel AI SDK which handles this automatically:
typescript
import { streamText } from 'ai';
import { createCloudflare } from '@ai-sdk/cloudflare';
const cloudflare = createCloudflare();
const result = streamText({
model: cloudflare('@cf/meta/llama-3-8b-instruct', { binding: env.AI }),
messages
});
// No manual parsing needed ✅When to accept manual parsing:
- Cost is critical (Workers AI is cheaper)
- No external dependencies allowed
- Willing to maintain SSE parsing code
When to use AI SDK instead:
- Value developer time over compute cost
- Want automatic streaming
- Need multi-provider support
错误:"Cannot read property 'response' of undefined"或空AI响应
来源:https://developers.cloudflare.com/workers-ai/platform/streaming/
原因:Workers AI以Server-Sent Events (SSE)格式返回流式响应的,而非普通对象
预防:使用 + SSE解析模式(见上方“Workers AI(AI的替代选择)”章节)
Uint8ArrayTextDecoder问题 - 直接访问流块会失败:
typescript
const response = await env.AI.run(model, { stream: true });
for await (const chunk of response) {
console.log(chunk.response); // ❌ undefined - chunk是Uint8Array,而非对象
}解决方案 - 手动解析SSE格式:
typescript
const response = await env.AI.run(model, { stream: true });
for await (const chunk of response) {
const text = new TextDecoder().decode(chunk); // 步骤1:Uint8Array → 字符串
if (text.startsWith('data: ')) { // 步骤2:检查SSE格式
const jsonStr = text.slice(6).trim(); // 步骤3:从"data: {...}"中提取JSON
if (jsonStr === '[DONE]') break; // 步骤4:处理终止信号
const data = JSON.parse(jsonStr); // 步骤5:解析JSON
if (data.response) { // 步骤6:提取.response字段
fullResponse += data.response;
}
}
}更好的替代方案:使用Vercel AI SDK自动处理:
typescript
import { streamText } from 'ai';
import { createCloudflare } from '@ai-sdk/cloudflare';
const cloudflare = createCloudflare();
const result = streamText({
model: cloudflare('@cf/meta/llama-3-8b-instruct', { binding: env.AI }),
messages
});
// 无需手动解析 ✅何时接受手动解析:
- 成本至关重要(Workers AI更便宜)
- 不允许外部依赖
- 愿意维护SSE解析代码
何时使用AI SDK替代:
- 更看重开发者时间而非计算成本
- 想要自动流式传输
- 需要多提供商支持
Issue 17: WebSocket Payload Size Limit (1MB)
Issue 17:WebSocket负载大小限制(1MB)
Error:
Source: GitHub Issue #119
Why: WebSocket connections fail when cumulative message payload exceeds approximately 1 MB. After 5-6 tool calls returning large data (e.g., 200KB+ each), the payload exceeds the limit and the connection crashes with "internal error".
Prevention: Prune message history client-side to stay under 950KB
Error: internal error; reference = [reference ID]The problem: All messages—including large tool results—are streamed back to the client and LLM for continued conversations, causing cumulative payload growth.
typescript
// Workaround: Prune old messages client-side
function pruneMessages(messages: Message[]): Message[] {
let totalSize = 0;
const pruned = [];
// Keep recent messages until we hit size limit
for (let i = messages.length - 1; i >= 0; i--) {
const msgSize = JSON.stringify(messages[i]).length;
if (totalSize + msgSize > 950_000) break; // 950KB limit
pruned.unshift(messages[i]);
totalSize += msgSize;
}
return pruned;
}
// Use before sending to agent
const prunedMessages = pruneMessages(allMessages);Better solution (proposed): Server-side context management where only message summaries are sent to the client, not full tool results.
错误:
来源:GitHub Issue #119
原因:当累计消息负载超过约1MB时,WebSocket连接会失败。在5-6次返回大数据的工具调用(如200KB+)后,负载会超过限制,连接会因“内部错误”崩溃。
预防:在客户端清理旧消息,保持在950KB以下
Error: internal error; reference = [reference ID]问题:所有消息(包括大型工具结果)都会流式传输回客户端和LLM以继续对话,导致累计负载增长。
typescript
// 解决方法:在客户端清理旧消息
function pruneMessages(messages: Message[]): Message[] {
let totalSize = 0;
const pruned = [];
// 保留最近的消息直到达到大小限制
for (let i = messages.length - 1; i >= 0; i--) {
const msgSize = JSON.stringify(messages[i]).length;
if (totalSize + msgSize > 950_000) break; // 950KB限制
pruned.unshift(messages[i]);
totalSize += msgSize;
}
return pruned;
}
// 发送到Agent前使用
const prunedMessages = pruneMessages(allMessages);更好的解决方案(提议):服务器端上下文管理,仅将消息摘要发送到客户端,而非完整工具结果。
Issue 18: Duplicate Assistant Messages with needsApproval Tools
Issue 18:使用needsApproval工具时出现重复助手消息
Error: Duplicate messages with identical , original stuck in state
Source: GitHub Issue #790
Why: When using on tools, the system creates duplicate assistant messages instead of updating the original one. The server-generated message (state ) never transitions to when client approves.
Prevention: Understand this is a known limitation. Track both message IDs in your UI until fixed.
toolCallIdinput-availableneedsApproval: trueinput-availableapproval-respondedtypescript
// Current behavior (agents@0.3.3)
export class MyAgent extends AIChatAgent<Env> {
tools = {
sensitiveAction: tool({
needsApproval: true, // ⚠️ Causes duplicate messages
execute: async (args) => {
return { result: "action completed" };
}
})
};
}
// Result: Two messages persist
// 1. Server message: ID "assistant_1768917665170_4mub00d32", state "input-available"
// 2. Client message: ID "oFwQwEpvLd8f1Gwd", state "approval-responded"Workaround: Handle both messages in your UI or avoid until this is resolved.
needsApproval错误:具有相同的重复消息,原始消息卡在状态
来源:GitHub Issue #790
原因:在工具上使用时,系统会创建重复的助手消息,而非更新原始消息。当客户端批准时,服务器生成的消息(状态)不会转换为。
预防:了解这是已知限制。在修复前在UI中跟踪两个消息ID。
toolCallIdinput-availableneedsApproval: trueinput-availableapproval-respondedtypescript
// 当前行为(agents@0.3.3)
export class MyAgent extends AIChatAgent<Env> {
tools = {
sensitiveAction: tool({
needsApproval: true, // ⚠️ 导致重复消息
execute: async (args) => {
return { result: "操作已完成" };
}
})
};
}
// 结果:两条消息保留
// 1. 服务器消息:ID "assistant_1768917665170_4mub00d32",状态 "input-available"
// 2. 客户端消息:ID "oFwQwEpvLd8f1Gwd",状态 "approval-responded"解决方法:在UI中处理两条消息,或在修复前避免使用。
needsApprovalIssue 19: Duplicate Messages with Client-Side Tool Execution (Fixed in 0.2.31+)
Issue 19:客户端工具执行时出现重复消息(0.2.31+已修复)
Error: (OpenAI API rejection)
Source: GitHub Issue #728
Fixed In: agents@0.2.31+
Why: When using with client-side tools lacking server-side execute functions, the agents library created duplicate assistant messages sharing identical reasoning IDs, triggering OpenAI API rejection.
Prevention: Update to agents@0.2.31 or later
Duplicate item found with id rs_xxxuseAgentChatHistorical issue (before 0.2.31): Client-side tool execution created new messages instead of updating existing ones, leaving the original stuck in incomplete state and causing duplicate values.
providerMetadata.openai.itemIdtypescript
// ✅ Fixed in 0.2.31+ - no changes needed
// Just ensure you're on agents@0.2.31 or later错误:(OpenAI API拒绝)
来源:GitHub Issue #728
修复版本:agents@0.2.31+
原因:当使用且客户端工具缺少服务器端执行函数时,agents库会创建具有相同推理ID的重复助手消息,触发OpenAI API拒绝。
预防:升级到agents@0.2.31或更高版本
Duplicate item found with id rs_xxxuseAgentChat历史问题(0.2.31之前):客户端工具执行会创建新消息而非更新现有消息,导致原始消息卡在未完成状态,并产生重复的值。
providerMetadata.openai.itemIdtypescript
// ✅ 0.2.31+已修复 - 无需修改
// 只需确保使用agents@0.2.31或更高版本Issue 20: Async Querying Cache TTL Not Honored (Fixed)
Issue 20:异步查询缓存TTL未生效(已修复)
Error: errors after token expiration despite setting
Source: GitHub Issue #725
Fixed In: Check agents release notes
Why: The hook had a caching problem where the queryPromise was computed once per and kept forever, even after TTL expired. The implementation didn't include time in dependencies, so TTL was never enforced.
Prevention: Update to latest agents version
401 UnauthorizedcacheTtluseAgentcacheKeyuseMemoHistorical workaround (before fix):
typescript
// Force cache invalidation by including token version in queryDeps
const [tokenVersion, setTokenVersion] = useState(0);
const { state } = useAgent({
query: async () => ({ token: await getJWT() }),
queryDeps: [tokenVersion], // ✅ Force new cache key
cacheTtl: 60_000,
});
// Manually refresh token before expiry
useEffect(() => {
const interval = setInterval(() => {
setTokenVersion(v => v + 1);
}, 50_000); // Refresh every 50s
return () => clearInterval(interval);
}, []);错误:令牌过期后出现错误,尽管设置了
来源:GitHub Issue #725
修复版本:查看agents发布说明
原因:钩子存在缓存问题,queryPromise会按计算一次并永久保留,即使TTL过期。实现未将时间包含在依赖项中,因此TTL从未生效。
预防:升级到最新agents版本
401 UnauthorizedcacheTtluseAgentcacheKeyuseMemo历史解决方法(修复前):
typescript
// 通过在queryDeps中包含令牌版本强制缓存失效
const [tokenVersion, setTokenVersion] = useState(0);
const { state } = useAgent({
query: async () => ({ token: await getJWT() }),
queryDeps: [tokenVersion], // ✅ 强制生成新缓存键
cacheTtl: 60_000,
});
// 在过期前手动刷新令牌
useEffect(() => {
const interval = setInterval(() => {
setTokenVersion(v => v + 1);
}, 50_000); // 每50秒刷新一次
return () => clearInterval(interval);
}, []);Issue 21: jsonSchemaValidator Breaks After DO Hibernation (Fixed)
Issue 21:DO休眠后jsonSchemaValidator失效(已修复)
Error:
Source: GitHub Issue #663
Fixed In: Check agents release notes
Why: When a Durable Object hibernated and restored, the Agents SDK serialized MCP connection options using , converting class instances like into plain objects without methods. Upon restoration via , the validator lost its methods.
Prevention: Update to latest agents version (validator now built-in)
TypeError: validator.getValidator is not a functionJSON.stringify()CfWorkerJsonSchemaValidatorJSON.parse()Historical issue (before fix):
typescript
// ❌ Before fix - manual validator caused errors
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/sdk/cloudflare-worker';
const mcpAgent = new McpAgent({
client: {
jsonSchemaValidator: new CfWorkerJsonSchemaValidator(), // Got serialized to {}
}
});Current approach (fixed):
typescript
// ✅ Now automatic - no manual validator needed
const mcpAgent = new McpAgent({
// SDK handles validator internally
});错误:
来源:GitHub Issue #663
修复版本:查看agents发布说明
原因:当Durable Object休眠并恢复时,Agents SDK使用序列化MCP连接选项,将等类实例转换为无方法的普通对象。通过恢复后,验证器丢失了方法。
预防:升级到最新agents版本(验证器现在内置)
TypeError: validator.getValidator is not a functionJSON.stringify()CfWorkerJsonSchemaValidatorJSON.parse()历史问题(修复前):
typescript
// ❌ 修复前 - 手动验证器会导致错误
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/sdk/cloudflare-worker';
const mcpAgent = new McpAgent({
client: {
jsonSchemaValidator: new CfWorkerJsonSchemaValidator(), // 被序列化为{}
}
});当前方案(已修复):
typescript
// ✅ 现在自动处理 - 无需手动验证器
const mcpAgent = new McpAgent({
// SDK内部处理验证器
});Issue 22: WorkerTransport ClientCapabilities Lost After Hibernation (Fixed in 0.3.5+)
Issue 22:WorkerTransport客户端能力在休眠后丢失(0.3.5+已修复)
Error:
Source: GitHub Issue #777
Fixed In: agents@0.3.5+
Why: When using with MCP servers in serverless environments, client capabilities failed to persist across Durable Object hibernation cycles because the interface only stored and status, not .
Prevention: Update to agents@0.3.5 or later
Error: Client does not support form elicitationWorkerTransportTransportStatesessionIdinitializedclientCapabilitiesHistorical issue (before 0.3.5):
typescript
// Client advertised elicitation capability during handshake,
// but after hibernation, capability info was lost
await server.elicitInput({ /* form */ }); // ❌ Error: capabilities lostSolution (fixed in 0.3.5):
typescript
// TransportState now includes clientCapabilities
interface TransportState {
sessionId: string;
initialized: boolean;
clientCapabilities?: ClientCapabilities; // ✅ Now persisted
}错误:
来源:GitHub Issue #777
修复版本:agents@0.3.5+
原因:在无服务器环境中使用与MCP服务器时,客户端能力无法在Durable Object休眠周期中持久化,因为接口仅存储和状态,不存储。
预防:升级到agents@0.3.5或更高版本
Error: Client does not support form elicitationWorkerTransportTransportStatesessionIdinitializedclientCapabilities历史问题(0.3.5之前):
typescript
// 客户端在握手时声明了elicitation能力,
// 但休眠后能力信息丢失
await server.elicitInput({ /* 表单 */ }); // ❌ 错误:能力丢失解决方案(0.3.5中修复):
typescript
// TransportState现在包含clientCapabilities
interface TransportState {
sessionId: string;
initialized: boolean;
clientCapabilities?: ClientCapabilities; // ✅ 现在会持久化
}Issue 23: idFromName() vs newUniqueId() Critical Pattern
Issue 23:idFromName() vs newUniqueId()关键模式
Error: State never persists, new agent instance every request
Source: Cloudflare blog - Building agents with OpenAI
Why: If you use instead of , you'll get a new agent instance each time, and your memory/state will never persist. This is a common early bug that silently kills statefulness.
Prevention: Always use for user-specific agents, never
newUniqueId()idFromName()idFromName()newUniqueId()typescript
// ❌ WRONG: Creates new agent every time (state never persists)
export default {
async fetch(request: Request, env: Env) {
const id = env.MyAgent.newUniqueId(); // New ID = new instance
const agent = env.MyAgent.get(id);
// State never persists - different instance each time
return agent.fetch(request);
}
}
// ✅ CORRECT: Same user = same agent = persistent state
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
const id = env.MyAgent.idFromName(userId); // Same ID for same user
const agent = env.MyAgent.get(id);
// State persists across requests for this user
return agent.fetch(request);
}
}Why It Matters:
- : Generates a random unique ID each call → new agent instance
newUniqueId() - : Deterministic ID from string → same agent for same input
idFromName(string)
Rule of thumb: Use for 99% of cases. Only use when you genuinely need a one-time, ephemeral agent instance.
idFromName()newUniqueId()错误:状态从未持久化,每次请求创建新Agent实例
来源:Cloudflare博客 - 使用OpenAI构建Agent
原因:如果使用而非,每次都会创建新Agent实例,内存/状态永远不会持久化。这是一个常见的早期错误,会无声地破坏状态性。
预防:始终对用户特定Agent使用idFromName(),绝不要使用newUniqueId()
newUniqueId()idFromName()typescript
// ❌ 错误:每次创建新Agent(状态从未持久化)
export default {
async fetch(request: Request, env: Env) {
const id = env.MyAgent.newUniqueId(); // 新ID = 新实例
const agent = env.MyAgent.get(id);
// 状态从未持久化 - 每次请求都是不同实例
return agent.fetch(request);
}
}
// ✅ 正确:同一用户 = 同一Agent = 持久化状态
export default {
async fetch(request: Request, env: Env) {
const userId = getUserId(request);
const id = env.MyAgent.idFromName(userId); // 同一用户对应同一ID
const agent = env.MyAgent.get(id);
// 该用户的请求间状态持久化
return agent.fetch(request);
}
}为什么重要:
- :每次调用生成随机唯一ID → 新Agent实例
newUniqueId() - :从字符串生成确定性ID → 同一输入对应同一Agent
idFromName(string)
经验法则:99%的场景使用。仅当你确实需要一次性临时Agent实例时才使用。
idFromName()newUniqueId()Dependencies
依赖项
Required
必需
- cloudflare-worker-base - Foundation (Hono, Vite, Workers setup)
- cloudflare-worker-base - 基础框架(Hono、Vite、Workers设置)
Optional (by feature)
可选(按功能)
- cloudflare-workers-ai - For Workers AI model calls
- cloudflare-vectorize - For RAG with Vectorize
- cloudflare-d1 - For additional persistent storage beyond agent state
- cloudflare-r2 - For file storage
- cloudflare-queues - For message queues
- cloudflare-workers-ai - 用于Workers AI模型调用
- cloudflare-vectorize - 用于基于Vectorize的RAG
- cloudflare-d1 - 用于Agent状态之外的额外持久化存储
- cloudflare-r2 - 用于文件存储
- cloudflare-queues - 用于消息队列
NPM Packages
NPM包
- - Agents SDK (required)
agents - - For building MCP servers
@modelcontextprotocol/sdk - - For web browsing
@cloudflare/puppeteer - - AI SDK for model calls
ai - - OpenAI models
@ai-sdk/openai - - Anthropic models
@ai-sdk/anthropic
- - Agents SDK(必需)
agents - - 用于构建MCP服务器
@modelcontextprotocol/sdk - - 用于网页浏览
@cloudflare/puppeteer - - AI SDK用于模型调用
ai - - OpenAI模型
@ai-sdk/openai - - Anthropic模型
@ai-sdk/anthropic
Official Documentation
官方文档
- Agents SDK: https://developers.cloudflare.com/agents/
- API Reference: 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
- 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服务器:https://github.com/cloudflare/mcp-server-cloudflare
Bundled Resources
捆绑资源
Templates (templates/)
模板(templates/)
- - Complete configuration example
wrangler-agents-config.jsonc - - Minimal HTTP agent
basic-agent.ts - - WebSocket handlers
websocket-agent.ts - - State management patterns
state-sync-agent.ts - - Task scheduling
scheduled-agent.ts - - Workflow integration
workflow-agent.ts - - Web browsing
browser-agent.ts - - RAG implementation
rag-agent.ts - - Streaming chat
chat-agent-streaming.ts - - Agent routing
calling-agents-worker.ts - - React client
react-useagent-client.tsx - - MCP server
mcp-server-basic.ts - - Human-in-the-loop
hitl-agent.ts
- - 完整配置示例
wrangler-agents-config.jsonc - - 最小HTTP Agent
basic-agent.ts - - WebSocket处理器
websocket-agent.ts - - 状态管理模式
state-sync-agent.ts - - 任务调度
scheduled-agent.ts - - 工作流集成
workflow-agent.ts - - 网页浏览
browser-agent.ts - - RAG实现
rag-agent.ts - - 流式聊天
chat-agent-streaming.ts - - Agent路由
calling-agents-worker.ts - - React客户端
react-useagent-client.tsx - - MCP服务器
mcp-server-basic.ts - - 人在回路
hitl-agent.ts
References (references/)
参考文档(references/)
- - Complete Agent class reference
agent-class-api.md - - Browser client APIs
client-api-reference.md - - State and SQL deep dive
state-management-guide.md - - WebSocket vs SSE comparison
websockets-sse.md - - Task scheduling details
scheduling-api.md - - Workflows guide
workflows-integration.md - - Web browsing patterns
browser-rendering.md - - RAG best practices
rag-patterns.md - - MCP server development
mcp-server-guide.md - - MCP tools API
mcp-tools-reference.md - - Human-in-the-loop workflows
hitl-patterns.md - - Production patterns
best-practices.md
- - 完整Agent类参考
agent-class-api.md - - 浏览器客户端API
client-api-reference.md - - 状态与SQL深度指南
state-management-guide.md - - WebSocket vs SSE对比
websockets-sse.md - - 任务调度详情
scheduling-api.md - - 工作流指南
workflows-integration.md - - 网页浏览模式
browser-rendering.md - - RAG最佳实践
rag-patterns.md - - MCP服务器开发
mcp-server-guide.md - - MCP工具API
mcp-tools-reference.md - - 人在回路工作流
hitl-patterns.md - - 生产模式
best-practices.md
Examples (examples/)
示例(examples/)
- - Full chat agent
chat-bot-complete.md - - Agent orchestration
multi-agent-workflow.md - - Recurring tasks
scheduled-reports.md - - Web scraping
browser-scraper-agent.md - - RAG system
rag-knowledge-base.md - - Production MCP server
mcp-remote-server.md
Last Verified: 2026-01-21
Package Versions: agents@0.3.6
Compliance: Cloudflare Agents SDK official documentation
Changes: Added 7 new issues from community research (WebSocket payload limits, state type safety, idFromName gotcha), updated to agents@0.3.6
- - 完整聊天Agent
chat-bot-complete.md - - Agent编排
multi-agent-workflow.md - - 周期性任务
scheduled-reports.md - - 网页抓取
browser-scraper-agent.md - - RAG知识库
rag-knowledge-base.md - - 生产MCP服务器
mcp-remote-server.md
最后验证:2026-01-21
包版本:agents@0.3.6
合规性:Cloudflare Agents SDK官方文档
变更:添加社区研究的7个新问题(WebSocket负载限制、状态类型安全、idFromName陷阱),更新到agents@0.3.6