mcpField
C
cloudflare-agents

cloudflare-agents

github.com/jezwebAgent 工作流1.1k326 次安装3 周前更新
代码仓库

关于 cloudflare-agents

面向开发者的 Cloudflare Agents SDK 技能指南,用于在 Workers 和 Durable Objects 上构建有状态、实时运行的 Agent。它提供持久化状态、调度、多 Agent 协作和 MCP 支持,但不提供 AI 推理。

主要功能

  1. 01构建有状态的 Agent
  2. 02实时 WebSocket 通信
  3. 03SQLite 状态持久化
  4. 04任务调度与多 Agent 协作
  5. 05支持构建 MCP 服务

适用场景

  1. 01实现需要持久状态的 Agent
  2. 02构建实时双向聊天应用
  3. 03安排周期性或延迟任务
  4. 04构建支持 MCP 工具执行的 Agent

MCP 相关

Agents SDK 支持实现 MCP 服务,可用于有状态的工具执行。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jezweb/claude-skills --skill cloudflare-agents

安装后在 Claude Code 中输入/cloudflare-agents确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
.claude-plugin/
plugin.json
rules/
cloudflare-agents.md
templates/
basic-agent.ts
browser-agent.ts
calling-agents-worker.ts
chat-agent-streaming.ts
hitl-agent.ts
mcp-server-basic.ts
rag-agent.ts
react-useagent-client.tsx
scheduled-agent.ts
simple-chat-no-agents-sdk.ts
state-sync-agent.ts
websocket-agent.ts
workflow-agent.ts

详细介绍

Cloudflare Agents SDK

状态:生产就绪 ✅ 最后更新:2026-01-09 依赖项:cloudflare-worker-base(推荐) 最新版本:[email protected]、@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-streamable 传输、任务队列和电子邮件集成
  • 2025 年 4 月:支持 MCP(MCPAgent 类),从 agents 导入 context
  • 2025 年 3 月:包更名(agents-sdk → agents)
可恢复流式传输([email protected]+)

AIChatAgent 现在支持可恢复流式传输,客户端可以重新连接并继续接收流式响应,而不会丢失数据。这解决了关键的实际场景:

  • 长时间运行的 AI 响应超过连接超时
  • 用户处于不稳定的网络环境中(移动网络、飞机 Wi-Fi)
  • 用户在对话过程中切换设备
  • 用户离开页面后又返回的后台任务
  • 多个客户端需要保持同步的实时协作

核心能力:流在刷新页面、连接中断后仍会保留,并可在打开的标签页和设备间同步。

实现方式(AIChatAgent 中自动处理):

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

无需更改代码,只需使用 [email protected] 或更高版本的 AIChatAgent。

来源:Agents SDK v0.2.24 更新日志


什么是 Cloudflare Agents?

Cloudflare Agents SDK 支持构建由 AI 驱动的自主 Agent,并在 Cloudflare Workers + Durable Objects 上运行。Agent 可以:

  • 通过 WebSockets 和 Server-Sent Events 实时通信
  • 使用内置 SQLite 数据库持久化状态(每个 Agent 最多 1GB)
  • 使用延迟、指定日期或 cron 表达式安排任务
  • 通过触发异步 Cloudflare Workflows 运行工作流
  • 使用 Browser Rendering API + Puppeteer 浏览网页
  • 使用 Vectorize 向量数据库 + Workers AI 嵌入实现 RAG
  • 构建实现 Model Context Protocol 的 MCP 服务
  • 支持人机协同审核与批准模式
  • 在全球扩展至数百万个独立 Agent 实例

每个 Agent 实例都是一个全球唯一、有状态的微型服务,可运行数秒、数分钟或数小时。


你需要 Agents SDK 吗?

请先停下来:使用 Agents SDK 之前,先问问自己是否真的需要它。

以下情况仅使用 Vercel AI SDK(更简单):
  • ✅ 构建基础聊天界面
  • ✅ Server-Sent Events(SSE)流式传输已满足需求(单向:服务器 → 客户端)
  • ✅ 无需持久化 Agent 状态(或使用 D1/KV 单独管理)
  • ✅ 单用户、单对话场景
  • ✅ 只需要 AI 响应,不需要复杂工作流或计划任务

这适用于 80% 的聊天应用。 对于这些场景,可直接在 Workers 上使用 Vercel AI SDK,它更简单、所需基础设施更少,还能自动处理流式传输。

示例(无需 Agents SDK):

// 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.
}

结果:代码量从 500 行减少到 100 行。无需设置 Durable Objects,无需处理 WebSocket 复杂性,也无需迁移。


在以下场景中使用 Agents SDK:
  • ✅ WebSocket 连接(真正的双向实时通信)
  • ✅ Durable Objects(全局唯一、有状态的 Agent 实例)
  • ✅ 内置状态持久化(每个 Agent 最多可使用 1GB 的 SQLite 存储)
  • ✅ 多 Agent 协调(Agent 之间相互调用和通信)
  • ✅ 计划任务(延迟、cron 表达式、定期作业)
  • ✅ 人在回路的工作流(审批关卡、审核流程)
  • ✅ 长时间运行的 Agent(后台处理、自主工作流)
  • ✅ MCP 服务,支持有状态的工具执行

这类场景约占应用的 20%——只有在需要 Agents SDK 提供的基础设施时才使用它。


关键认知:Agents SDK 是什么,不是什么

Agents SDK 是:

  • 🏗️ 用于 WebSocket 连接、Durable Objects 和状态管理的基础设施层
  • 🔧 用于构建有状态、自主 Agent 的框架
  • 📦 带有生命周期方法的 Durable Objects封装层

Agents SDK 不是:

  • ❌ AI 推理提供商(你需要自行选择:AI SDK、Workers AI、OpenAI 等)
  • ❌ 流式响应处理器(使用 AI SDK 自动解析)
  • ❌ 大模型集成(这是另一项独立的工作)

可以这样理解:

  • Agents SDK = 建筑(WebSocket、状态、房间)
  • AI SDK / Workers AI = AI 大脑(推理、思考、响应)

你可以将它们搭配使用(大多数情况下推荐这样做),也可以直接使用 Workers AI(前提是你愿意手动处理 SSE 解析)。


决策流程图
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 SDKAgents SDK + AI SDK
设置复杂度🟢 低(npm install 即可)🔴 较高(Durable Objects、迁移、绑定)
代码量🟢 约 100 行🟡 约 500 行以上
流式传输✅ 自动(SSE)✅ 自动(AI SDK)或手动(Workers AI)
状态管理⚠️ 手动(D1/KV)✅ 内置(SQLite)
WebSocket❌ 需手动设置✅ 内置
React Hooks✅ useChat、useCompletion⚠️ 需要自定义 Hooks
多 Agent❌ 不支持✅ 内置(routeAgentRequest)
计划任务❌ 外部实现(Queue/Workflow)✅ 内置(this.schedule)
适用场景简单聊天、补全复杂的有状态工作流

还不确定?

从 AI SDK 开始。 如果之后发现需要 WebSocket 或 Durable Objects,随时可以迁移到 Agents SDK。之后再添加基础设施,比移除它更容易。

对于大多数开发者:如果你要构建聊天界面,且没有 WebSocket、多 Agent 协调或计划任务方面的特定需求,请直接使用 AI SDK。这样能更快交付,复杂度也更低。

只有在确认需要其基础设施功能时,才使用 Agents SDK。


快速开始(10 分钟)

1. 使用模板搭建项目
npm create cloudflare@latest my-agent -- \
  --template=cloudflare/agents-starter \
  --ts \
  --git \
  --deploy false

此操作会创建:

  • 完整的 Agent 项目结构
  • TypeScript 配置
  • 带有 Durable Objects 绑定的 wrangler.jsonc
  • 示例聊天 Agent 实现
  • 带有 useAgent Hook 的 React 客户端
2. 或添加到现有 Worker
cd my-existing-worker
npm install agents

然后创建一个 Agent 类:

// src/index.ts
import { Agent, AgentNamespace } from "agents";

export class MyAgent extends Agent {
  async onRequest(request: Request): Promise<Response> {
    return new Response("Hello from Agent!");
  }
}

export default MyAgent;
3. 配置 Durable Objects 绑定

创建或更新 wrangler.jsonc:

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-agent",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-21",
  "compatibility_flags": ["nodejs_compat"],
  "durable_objects": {
    "bindings": [
      {
        "name": "MyAgent",        // MUST match class name
        "class_name": "MyAgent"   // MUST match exported class
      }
    ]
  },
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": ["MyAgent"]  // CRITICAL: Enables SQLite storage
    }
  ]
}

关键配置规则:

  • ✅ name 和 class_name 必须相同
  • ✅ new_sqlite_classes 必须包含在首次迁移中(之后无法再添加)
  • ✅ Agent 类必须导出(否则绑定会失败)
  • ✅ 迁移标记不能重复使用(每次迁移都需要唯一标记)
4. 部署
npx wrangler@latest deploy

你的 Agent 现已运行于:https://my-agent.<subdomain>.workers.dev


架构概览:各部分如何协同工作

了解每种工具的作用,有助于避免混淆并选择合适的组合。

技术栈
┌─────────────────────────────────────────────────────────┐
│                    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
各工具提供的功能
1. Agents SDK(此 Skill)

用途:为有状态、实时的 Agent 提供基础设施

提供:

  • ✅ WebSocket 连接管理(双向实时通信)
  • ✅ Durable Objects 封装器(全局唯一的 Agent 实例)
  • ✅ 内置状态持久化(SQLite,最大支持 1 GB)
  • ✅ 生命周期方法(onStart、onConnect、onMessage、onClose)
  • ✅ 任务调度(使用 this.schedule() 设置 cron 或延迟)
  • ✅ 多 Agent 协调(routeAgentRequest())
  • ✅ 客户端库(useAgent、AgentClient、agentFetch)

不提供:

  • ❌ AI 推理(不调用大模型)
  • ❌ 流式响应解析(需自行实现)
  • ❌ 提供商集成(OpenAI、Anthropic 等)

可以把它看作:建筑和基础设施(房间、门、管道),但不包括住户(AI)。


2. Vercel AI SDK(AI 场景推荐)

用途:自动处理流式传输的 AI 推理

提供:

  • ✅ 自动处理流式响应(为你解析 SSE)
  • ✅ 支持多个提供商(OpenAI、Anthropic、Google 等)
  • ✅ React Hooks(useChat、useCompletion、useAssistant)
  • ✅ 跨提供商的统一 API
  • ✅ 工具调用/函数调用
  • ✅ 可在 Cloudflare Workers 上运行 ✅

示例:

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();

与 Agents SDK 配合使用的场景:

  • ✅ 大多数聊天应用
  • ✅ 需要 React Hooks 时
  • ✅ 使用多个 AI 提供商时
  • ✅ 希望通过简洁、抽象化的方式调用 AI 时

与 Agents SDK 组合使用:

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

3. Workers AI(AI 场景的替代方案)

用途:Cloudflare 平台内的 AI 推理

提供:

  • ✅ 高性价比推理(包含在 Workers 订阅中)
  • ✅ 无需外部 API 密钥
  • ✅ 模型:LLaMA 3、Qwen、Mistral、嵌入模型等
  • ✅ 在 Cloudflare 网络上运行(低延迟)

不提供:

  • ❌ 自动解析流式传输(返回原始 SSE 格式)
  • ❌ React Hooks
  • ❌ 多提供商抽象

需要手动解析:

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

适用场景:

  • ✅ 成本至关重要(嵌入模型、高调用量)
  • ✅ 需要 Cloudflare 专属模型
  • ✅ 愿意手动处理 SSE 解析
  • ✅ 不允许使用外部依赖

权衡:节省费用,但需要花时间手动解析。


推荐组合
选项 A:Agents SDK + Vercel AI SDK(推荐 ⭐)

适用场景:需要 WebSocket/状态管理,同时希望简洁地集成 AI

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

优点:

  • ✅ 最佳开发体验
  • ✅ 自动处理流式传输
  • ✅ 使用 Agents SDK 提供 WebSocket 和状态管理
  • ✅ 代码简洁、易于维护

缺点:

  • ⚠️ 需要外部 API 密钥
  • ⚠️ AI 提供商会产生额外费用

选项 B:Agents SDK + Workers AI

适用场景:需要 WebSocket/状态管理,同时成本至关重要

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

优点:

  • ✅ 高性价比
  • ✅ 无需外部依赖
  • ✅ 使用 Agents SDK 提供 WebSocket 和状态管理

缺点:

  • ❌ 手动解析 SSE,增加复杂性
  • ❌ 模型选择有限
  • ❌ 需要维护更多代码

选项 C:仅使用 Vercel AI SDK(不使用 Agents)

适用场景:不需要 WebSocket 或 Durable Objects

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

优点:

  • ✅ 实现方式最简单
  • ✅ 代码最少
  • ✅ 实现速度快
  • ✅ 内置 React Hooks

缺点:

  • ❌ 不支持 WebSocket(仅支持 SSE)
  • ❌ 不支持 Durable Objects 状态
  • ❌ 不支持多 Agent 协调

最适合:80% 的聊天应用


决策矩阵
需求推荐技术栈复杂度成本
简单聊天,无状态管理仅 AI SDK🟢 低$$(AI 提供商)
聊天 + WebSocket + 状态管理Agents SDK + AI SDK🟡 中$$$(基础设施 + AI)
聊天 + WebSocket + 预算有限Agents SDK + Workers AI🔴 高$(仅基础设施)
多 Agent 工作流Agents SDK + AI SDK🔴 高$$$(基础设施 + AI)
带工具的 MCP 服务Agents SDK(McpAgent)🟡 中$(仅基础设施)

关键要点

**Agents SDK 是基础设施,而非 AI。**你需要将它与 AI 推理工具结合使用:

  • 获得最佳开发体验:Agents SDK + Vercel AI SDK ⭐
  • 节省成本:Agents SDK + Workers AI(接受手动解析)
  • 简单易用:只使用 AI SDK(如果你不需要 WebSocket/状态)

本技能的其余部分聚焦于 Agents SDK(基础设施层)。关于 AI 推理模式,请参阅 ai-sdk-core 或 cloudflare-workers-ai 技能。


配置(wrangler.jsonc)

关键必需配置:

{
  "durable_objects": {
    "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
  },
  "migrations": [
    { "tag": "v1", "new_sqlite_classes": ["MyAgent"] }  // MUST be in first migration
  ]
}

常见可选绑定:ai、vectorize、browser、workflows、d1_databases、r2_buckets

关键迁移规则:

  • ✅ new_sqlite_classes 必须位于标签 "v1" 中(无法向已部署的类添加 SQLite)
  • ✅ name 和 class_name 必须完全一致
  • ✅ 迁移是原子的(所有实例会同时更新)
  • ✅ 每个标签都必须唯一,不能编辑或移除之前的标签

参阅:https://developers.cloudflare.com/agents/api-reference/configuration/


Agent 核心模式

Agent 类基础知识——扩展 Agent<Env, State> 并实现生命周期方法:

  • onStart()——初始化 Agent
  • onRequest()——处理 HTTP 请求
  • onConnect/onMessage/onClose()——处理 WebSocket
  • onStateUpdate()——响应状态变化

关键属性:

  • this.env——环境绑定(AI、DB 等)
  • this.state——当前 Agent 状态(只读)
  • this.setState()——更新持久化状态
  • this.sql——内置 SQLite 数据库
  • this.name——Agent 实例标识符
  • this.schedule()——安排未来任务

参阅:Agent 官方 API 文档:https://developers.cloudflare.com/agents/api-reference/agents-api/


WebSocket 与实时通信

Agents 支持 WebSocket,可实现双向实时通信。适用于以下场景:

  • 客户端可以在服务端持续推送内容时发送消息
  • Agent 主动发送消息(通知、更新)
  • 需要长连接和状态

基本模式:

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 替代方案:对于单向服务端 → 客户端流式传输(更简单,基于 HTTP),请使用服务器发送事件,而非 WebSocket。

参阅:https://developers.cloudflare.com/agents/api-reference/websockets/


状态管理

两种状态机制:

  1. this.setState(newState)——可序列化为 JSON 的状态(最大 1GB)

    • 自动持久化,并同步到 WebSocket 客户端
    • 用于:用户偏好、会话数据、小型数据集
  2. this.sql——内置 SQLite 数据库(最大 1GB)

    • 标记模板字面量可防止 SQL 注入
    • 用于:关系型数据、大型数据集、复杂查询

状态规则:

  • ✅ 仅支持可序列化为 JSON 的数据(对象、数组、原始值、null)
  • ✅ 重启后仍会保留,并立即保持一致
  • ❌ 不支持函数或循环引用
  • ❌ 总上限为 1GB(状态与 SQL 合计)

SQL 模式:

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
状态类型安全注意事项

关键:为状态方法提供类型参数,并不会验证结果是否符合你的类型定义。在 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
  }
}

预防措施:为关键状态操作添加运行时验证:

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

参阅:https://developers.cloudflare.com/agents/api-reference/store-and-sync-state/


安排任务

Agents 可以使用 this.schedule() 安排未来运行的任务。

延迟(秒)
export class MyAgent extends Agent {
  async onRequest(request: Request): Promise<Response> {
    // Schedule task to run in 60 seconds
    const { id } = await this.schedule(60, "checkStatus", { requestId: "123" });

    return Response.json({ scheduledTaskId: id });
  }

  // This method will be called in 60 seconds
  async checkStatus(data: { requestId: string }) {
    console.log('Checking status for request:', data.requestId);
    // Perform check, update state, send notification, etc.
  }
}
指定日期
export class MyAgent extends Agent {
  async scheduleReminder(reminderDate: string) {
    const date = new Date(reminderDate);

    const { id } = await this.schedule(date, "sendReminder", {
      message: "Time for your appointment!"
    });

    return id;
  }

  async sendReminder(data: { message: string }) {
    console.log('Sending reminder:', data.message);
    // Send email, push notification, etc.
  }
}
Cron 表达式
export class MyAgent extends Agent {
  async setupRecurringTasks() {
    // Every 10 minutes
    await this.schedule("*/10 * * * *", "checkUpdates", {});

    // Every day at 8 AM
    await this.schedule("0 8 * * *", "dailyReport", {});

    // Every Monday at 9 AM
    await this.schedule("0 9 * * 1", "weeklyReport", {});

    // Every hour on the hour
    await this.schedule("0 * * * *", "hourlyCheck", {});
  }

  async checkUpdates(data: any) {
    console.log('Checking for updates...');
  }

  async dailyReport(data: any) {
    console.log('Generating daily report...');
  }

  async weeklyReport(data: any) {
    console.log('Generating weekly report...');
  }

  async hourlyCheck(data: any) {
    console.log('Running hourly check...');
  }
}
管理计划任务
export class MyAgent extends Agent {
  async manageSchedules() {
    // Get all scheduled tasks
    const allTasks = this.getSchedules();
    console.log('Total tasks:', allTasks.length);

    // Get specific task by ID
    const taskId = "some-task-id";
    const task = await this.getSchedule(taskId);

    if (task) {
      console.log('Task:', task.callback, 'at', new Date(task.time));
      console.log('Payload:', task.payload);
      console.log('Type:', task.type);  // "scheduled" | "delayed" | "cron"

      // Cancel the task
      const cancelled = await this.cancelSchedule(taskId);
      console.log('Cancelled:', cancelled);
    }

    // Get tasks in time range
    const upcomingTasks = this.getSchedules({
      timeRange: {
        start: new Date(),
        end: new Date(Date.now() + 24 * 60 * 60 * 1000)  // Next 24 hours
      }
    });

    console.log('Upcoming tasks:', upcomingTasks.length);

    // Filter by type
    const cronTasks = this.getSchedules({ type: "cron" });
    const delayedTasks = this.getSchedules({ type: "delayed" });
  }
}

计划任务限制:

  • 每个任务对应一行 SQL 数据库记录(每个任务最大 2 MB)
  • 任务总量限制为:(task_size * count) + other_state < 1GB
  • Cron 任务会持续运行,直到被明确取消
  • 回调方法必须存在于 Agent 类中(否则会抛出错误)

关键错误:如果回调方法不存在:

// ❌ BAD: Method doesn't exist
await this.schedule(60, "nonExistentMethod", {});

// ✅ GOOD: Method exists
await this.schedule(60, "existingMethod", {});

async existingMethod(data: any) {
  // Implementation
}

运行工作流

Agent 可以触发异步的 Cloudflare Workflows。

工作流绑定配置

wrangler.jsonc:

{
  "workflows": [
    {
      "name": "MY_WORKFLOW",
      "class_name": "MyWorkflow"
    }
  ]
}

如果 Workflow 位于不同的脚本中:

{
  "workflows": [
    {
      "name": "EMAIL_WORKFLOW",
      "class_name": "EmailWorkflow",
      "script_name": "email-workflows"  // Different project
    }
  ]
}
触发工作流
import { Agent } from "agents";
import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep } from "cloudflare:workers";

interface Env {
  MY_WORKFLOW: Workflow;
  MyAgent: AgentNamespace<MyAgent>;
}

export class MyAgent extends Agent<Env> {
  async onRequest(request: Request): Promise<Response> {
    const userId = new URL(request.url).searchParams.get('userId');

    // Trigger a workflow immediately
    const instance = await this.env.MY_WORKFLOW.create({
      id: `user-${userId}`,
      params: { userId, action: "process" }
    });

    // Or schedule a delayed workflow trigger
    await this.schedule(300, "runWorkflow", { userId });

    return Response.json({ workflowId: instance.id });
  }

  async runWorkflow(data: { userId: string }) {
    const instance = await this.env.MY_WORKFLOW.create({
      id: `delayed-${data.userId}`,
      params: data
    });

    // Monitor workflow status periodically
    await this.schedule("*/5 * * * *", "checkWorkflowStatus", { id: instance.id });
  }

  async checkWorkflowStatus(data: { id: string }) {
    // Check workflow status (see Workflows docs for details)
    console.log('Checking workflow:', data.id);
  }
}

// Workflow definition (can be in same or different file/project)
export class MyWorkflow extends WorkflowEntrypoint<Env> {
  async run(event: WorkflowEvent<{ userId: string }>, step: WorkflowStep) {
    // Workflow implementation
    const result = await step.do('process-data', async () => {
      return { processed: true };
    });

    return result;
  }
}
Agent 与工作流
功能Agent工作流
用途交互式,面向用户后台处理
持续时间数秒到数小时数分钟到数小时
状态SQLite 数据库基于步骤的检查点
交互WebSockets、HTTP无直接交互
重试手动每个步骤自动重试
使用场景聊天、实时 UIETL、批处理

最佳实践:使用 Agent 协调多个工作流。Agent 可以触发、监控工作流并响应其结果,同时保持与用户的交互。


浏览网页

Agent 可以使用 Browser Rendering 进行网页抓取和自动化:

绑定:将 "browser": { "binding": "BROWSER" } 添加到 wrangler.jsonc 软件包:@cloudflare/puppeteer 使用场景:网页抓取、截图,以及在 Agent 工作流中自动浏览网页

参见:cloudflare-browser-rendering 技能,了解完整的 Puppeteer + Workers 集成指南。


检索增强生成(RAG)

Agent 可以使用 Vectorize(向量数据库)+ Workers AI(嵌入)实现 RAG:

模式:摄取文档 → 生成嵌入 → 存储到 Vectorize → 查询 → 检索上下文 → 传递给 AI

绑定:

  • "ai": { "binding": "AI" } - 用于生成嵌入的 Workers AI
  • "vectorize": { "bindings": [{ "binding": "VECTORIZE", "index_name": "my-vectors" }] } - 向量搜索

典型工作流:

  1. 使用 Workers AI 生成嵌入(@cf/baai/bge-base-en-v1.5)
  2. 将向量插入或更新至 Vectorize(this.env.VECTORIZE.upsert(vectors))
  3. 查询相似向量(this.env.VECTORIZE.query(queryVector, { topK: 5 }))
  4. 在 AI 提示词中使用检索到的上下文

参见:cloudflare-vectorize 技能,了解完整的 RAG 实现指南。


使用 AI 模型

Agent 可以通过以下方式调用 AI 模型:

  • Vercel AI SDK(推荐):支持多家提供商、自动流式传输和工具调用
  • Workers AI:Cloudflare 的平台内推理(成本效益高,需手动解析)

架构说明:Agents SDK 提供基础设施(WebSockets、状态、调度)。AI 推理属于单独的一层——使用 AI SDK 作为“大脑”。

参见:

  • ai-sdk-core 技能,了解完整的 AI SDK 集成模式
  • cloudflare-workers-ai 技能,了解 Workers AI 流式解析

调用 Agent

两种主要模式:

  1. routeAgentRequest(request, env) - 通过 URL 模式 /agents/:agent/:name 自动路由

    • 示例:/agents/my-agent/user-123 路由到 MyAgent 实例“user-123”
  2. getAgentByName<Env, T>(env.AgentBinding, instanceName) - 自定义路由

    • 返回 Agent 存根,用于调用方法或传递请求
    • 示例:const agent = getAgentByName(env.MyAgent, 'user-${userId}')

多 Agent 通信:

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

重要安全事项:务必在创建或访问 Agent 之前,先在 Worker 中完成身份验证。Agent 应假定调用者已获授权。

参见:https://developers.cloudflare.com/agents/api-reference/calling-agents/


客户端 API

浏览器/React 集成:

  • AgentClient(来自 agents/client)- 用于浏览器的 WebSocket 客户端
  • agentFetch(来自 agents/client)- 向 Agent 发送 HTTP 请求
  • useAgent(来自 agents/react)- 用于 WebSocket 连接和状态同步的 React Hook
  • useAgentChat(来自 agents/ai-react)- 预构建的聊天 UI Hook

所有客户端库都会自动处理:WebSocket 连接、状态同步和重新连接逻辑。

参见:https://developers.cloudflare.com/agents/api-reference/client-apis/


模型上下文协议(MCP)

使用 Agents SDK 构建 MCP 服务。

MCP 服务设置
npm install @modelcontextprotocol/sdk agents
基本 MCP 服务
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

export class MyMCP extends McpAgent {
  server = new McpServer({ name: "Demo", version: "1.0.0" });

  async init() {
    // Define a tool
    this.server.tool(
      "add",
      "Add two numbers together",
      {
        a: z.number().describe("First number"),
        b: z.number().describe("Second number")
      },
      async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }]
      })
    );
  }
}
有状态 MCP 服务
type State = { counter: number };

export class StatefulMCP extends McpAgent<Env, State> {
  server = new McpServer({ name: "Counter", version: "1.0.0" });

  initialState: State = { counter: 0 };

  async init() {
    // Resource
    this.server.resource(
      "counter",
      "mcp://resource/counter",
      (uri) => ({
        contents: [{ uri: uri.href, text: String(this.state.counter) }]
      })
    );

    // Tool
    this.server.tool(
      "increment",
      "Increment the counter",
      { amount: z.number() },
      async ({ amount }) => {
        this.setState({
          ...this.state,
          counter: this.state.counter + amount
        });

        return {
          content: [{
            type: "text",
            text: `Counter is now ${this.state.counter}`
          }]
        };
      }
    );
  }
}
MCP 传输配置
import { Hono } from 'hono';

const app = new Hono();

// Modern streamable HTTP transport (recommended)
app.mount('/mcp', MyMCP.serve('/mcp').fetch, { replaceRequest: false });

// Legacy SSE transport (deprecated)
app.mount('/sse', MyMCP.serveSSE('/sse').fetch, { replaceRequest: false });

export default app;

传输方式对比:

  • /mcp:流式 HTTP(现代方式,推荐)
  • /sse:服务器发送事件(旧版,已弃用)
MCP 协议版本支持

Agents SDK 支持多个 MCP 协议版本。从 [email protected] 起,版本验证较为宽松,可接受更新的协议版本:

  • 支持的版本:2024-11-05、2025-11-25 及未来版本
  • 错误(0.3.x 之前):Error: Unsupported MCP protocol version: 2025-11-25
  • 已修复:版本验证现在接受所有非过旧的协议版本

这与 MCP 社区转向无状态传输的方向一致。如果遇到协议版本错误,请更新到 [email protected] 或更高版本。

来源:GitHub Issue #769

使用 OAuth 的 MCP
import { OAuthProvider } from '@cloudflare/workers-oauth-provider';

export default new OAuthProvider({
  apiHandlers: {
    '/sse': MyMCP.serveSSE('/sse'),
    '/mcp': MyMCP.serve('/mcp')
  },
  // OAuth configuration
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  // ... other OAuth settings
});
测试 MCP 服务
# Run MCP inspector
npx @modelcontextprotocol/inspector@latest

# Connect to: http://localhost:8788/mcp

Cloudflare 的 MCP 服务:查看参考资料中的生产环境示例。


关键规则

务必做到 ✅
  1. 导出 Agent 类 - 必须导出,绑定才能生效
  2. 在 v1 迁移中包含 new_sqlite_classes - 之后无法再添加 SQLite
  3. 使绑定名称与类名一致 - 防止出现“找不到绑定”错误
  4. 在 Worker 中而非 Agent 中进行身份验证 - 安全最佳实践
  5. 使用带标签的模板字面量编写 SQL - 防止 SQL 注入
  6. 处理 WebSocket 断开连接 - 状态会保留,连接不会
  7. 确认已存在计划任务回调 - 如果方法缺失,会抛出错误
  8. 对用户专属 Agent 使用 idFromName() - 对持久状态绝不要使用 newUniqueId()(参见 Issue #23)
  9. 检查状态大小限制 - 每个 Agent 总计最多 1GB
  10. 监控任务负载大小 - 每个计划任务最多 2MB
  11. 正确使用工作流绑定 - 必须在 wrangler.jsonc 中配置
  12. 插入数据前创建 Vectorize 索引 - 元数据过滤所必需
  13. 关闭浏览器实例 - 防止资源泄漏
  14. 使用 setState() 实现持久化 - 不要只修改 this.state
  15. 先在本地测试迁移 - 迁移是原子操作,无法回滚
  16. 精简 WebSocket 消息历史记录 - 累积负载保持在 1MB 以内(参见 Issue #17)
  17. 在运行时验证状态结构 - TypeScript 类型不会强制执行运行时验证(参见 State Type Safety)
绝不要做 ❌
  1. 不要向现有的已部署类添加 SQLite - 必须在首次迁移中添加
  2. 不要逐步部署迁移 - 只能原子部署
  3. 不要跳过 Worker 中的身份验证 - 访问 Agent 前务必先进行身份验证
  4. 不要手动拼接 SQL 字符串 - 使用带标签的模板字面量
  5. 不要让每个 Agent 的状态超过 1GB - 硬性限制
  6. 不要为不存在的回调安排任务 - 会导致运行时错误
  7. 不要对用户专属 Agent 使用 newUniqueId() - 状态无法持久化(参见 Issue #23)
  8. 不要将 SSE 用于 MCP - 已弃用,请使用 /mcp 传输方式
  9. 不要忘记浏览器绑定 - 网页浏览必需
  10. 不要直接修改 this.state - 改用 setState()
  11. 不要让 WebSocket 负载超过 1MB - 连接会崩溃(参见 Issue #17)
  12. 不要依赖 TypeScript 类型验证状态 - 添加运行时检查(参见 State Type Safety)

避免已知问题

此技能可避免 23 个已记录的问题:

问题 1:迁移不是原子操作

错误:“Cannot gradually deploy migration” 来源:https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/ 原因:迁移会同时应用于所有实例 预防方法:将迁移与代码更改分开部署,使用 npx wrangler versions deploy

问题 2:缺少 new_sqlite_classes

错误:"Cannot enable SQLite on existing class" 来源:https://developers.cloudflare.com/agents/api-reference/configuration/ 原因:必须在首次迁移中启用 SQLite 预防措施:在标签为 "v1" 的迁移中加入 new_sqlite_classes

问题 3:未导出 Agent 类

错误:"Binding not found" 或 "Cannot access undefined" 来源:https://developers.cloudflare.com/agents/api-reference/agents-api/ 原因:Durable Objects 要求导出类 预防措施:export class MyAgent extends Agent(包含 export 关键字)

问题 4:绑定名称不匹配

错误:"Binding 'X' not found" 来源:https://developers.cloudflare.com/agents/api-reference/configuration/ 原因:绑定名称必须与类名完全一致 预防措施:确保 wrangler.jsonc 中的 name 和 class_name 完全一致

问题 5:不了解全局唯一性

错误:Agent 实例行为异常 来源:https://developers.cloudflare.com/agents/api-reference/agents-api/ 原因:相同名称始终会返回同一个全局 Agent 实例 预防措施:使用唯一标识符(userId、sessionId)作为实例名称

问题 6:WebSocket 状态未持久化

错误:断开连接后连接状态丢失 来源:https://developers.cloudflare.com/agents/api-reference/websockets/ 原因:WebSocket 连接不会持久化,但 Agent 状态会 预防措施:通过 setState() 将重要数据存储在 Agent 状态中,而不是连接状态中

问题 7:计划任务回调不存在/长时间 AI 请求超时

错误:"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 问题 #600 原因:this.schedule() 调用了未定义的方法;或者,由于 blockConcurrencyWhile 包装器,AI 请求超过 30 秒时计划回调会失败(已在 [email protected] 中通过 PR #653 修复) 预防措施:安排任务前,确保回调方法已存在。对于长时间运行的 AI 请求,请更新到 [email protected] 或更高版本。

历史问题(0.2.x 之前):计划回调被 blockConcurrencyWhile 包装,该包装器会强制执行 30 秒的限制。AI 请求超过此时长时会失败,即使这些请求是有效的异步操作。

// ✅ 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 }]
    });
  }
}
问题 8:超出状态大小限制

错误:"Maximum database size exceeded" 来源:https://developers.cloudflare.com/agents/api-reference/store-and-sync-state/ 原因:Agent 状态和计划任务总计超过 1GB 预防措施:监控状态大小;对于大型数据,请使用外部存储(D1、R2)

问题 9:计划任务过大

错误:"Task payload exceeds 2MB" 来源:https://developers.cloudflare.com/agents/api-reference/schedule-tasks/ 原因:每个任务都映射到数据库行,大小限制为 2MB 预防措施:尽量精简任务负载,将大型数据存储在 Agent 状态/SQL 中

问题 10:缺少工作流绑定

错误:"Cannot read property 'create' of undefined" 来源:https://developers.cloudflare.com/agents/api-reference/run-workflows/ 原因:wrangler.jsonc 中未配置工作流绑定 预防措施:使用 this.env.WORKFLOW 前,先添加工作流绑定

问题 11:需要 Browser 绑定

错误:"BROWSER binding undefined" 来源:https://developers.cloudflare.com/agents/api-reference/browse-the-web/ 原因:Browser Rendering 需要显式绑定 预防措施:在 wrangler.jsonc 中添加 "browser": { "binding": "BROWSER" }

问题 12:未找到 Vectorize 索引

错误:"Index does not exist" 来源:https://developers.cloudflare.com/agents/api-reference/rag/ 原因:使用前必须创建 Vectorize 索引 预防措施:部署 Agent 前运行 wrangler vectorize create

问题 13:MCP 传输方式混淆

错误:“SSE 传输方式已弃用” 来源:https://developers.cloudflare.com/agents/model-context-protocol/transport/ 原因:SSE 传输方式已属旧版,建议使用可流式传输的 HTTP 预防措施:使用 /mcp 端点和 MyMCP.serve('/mcp'),而非 /sse

问题 14:绕过身份验证

错误:安全漏洞 来源:https://developers.cloudflare.com/agents/api-reference/calling-agents/ 原因:在 Agent 中而非 Worker 中进行身份验证 预防措施:调用 getAgentByName() 前,务必在 Worker 中进行身份验证

问题 15:实例命名错误

错误:用户间数据泄露 来源:https://developers.cloudflare.com/agents/api-reference/calling-agents/ 原因:实例命名不当,导致访问错误的 Agent 预防措施:使用带命名空间的名称,例如 user-${userId},并验证所有权

问题 16:Workers AI 流式传输需要手动解析

错误:“Cannot read property 'response' of undefined”或 AI 响应为空 来源:https://developers.cloudflare.com/workers-ai/platform/streaming/ 原因:Workers AI 以 Server-Sent Events(SSE)格式将流式响应作为 Uint8Array 返回,而非普通对象 预防措施:使用 TextDecoder + SSE 解析模式(参见上文“Workers AI(AI 的替代方案)”部分)

问题 - 直接访问流块会失败:

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
}

解决方案 - 手动解析 SSE 格式:

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

更好的替代方案:使用 Vercel AI SDK 自动处理:

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 ✅

适合接受手动解析的情况:

  • 成本至关重要(Workers AI 更便宜)
  • 不允许使用外部依赖
  • 愿意维护 SSE 解析代码

适合改用 AI SDK 的情况:

  • 开发者时间比计算成本更重要
  • 希望自动处理流式传输
  • 需要支持多个提供商
问题 17:WebSocket 负载大小限制(1MB)

错误:Error: internal error; reference = [reference ID] 来源:GitHub Issue #119 原因:当累计消息负载超过约 1 MB 时,WebSocket 连接会失败。连续 5–6 次工具调用返回大量数据(例如,每次超过 200KB)后,负载会超出限制,连接因“internal error”而崩溃。 预防措施:在客户端精简消息历史,确保大小不超过 950KB

问题:包括大型工具结果在内的所有消息都会回传给客户端和大模型,以便继续对话,导致累计负载不断增长。

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

更好的解决方案(提议):在服务端管理上下文,只向客户端发送消息摘要,而非完整的工具结果。

问题 18:使用 needsApproval 工具时出现重复的助手消息

错误:出现具有相同 toolCallId 的重复消息,原始消息卡在 input-available 状态 来源:GitHub Issue #790 原因:对工具使用 needsApproval: true 时,系统会创建重复的助手消息,而不是更新原始消息。客户端批准后,服务端生成的消息(状态为 input-available)不会转换为 approval-responded。 预防措施:请注意这是已知限制。问题修复前,在 UI 中跟踪这两条消息的 ID。

// Current behavior ([email protected])
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"

临时解决方法:在 UI 中处理这两条消息,或在问题解决前避免使用 needsApproval。

问题 19:客户端工具执行时出现重复消息(已在 0.2.31+ 中修复)

错误:Duplicate item found with id rs_xxx(OpenAI API 拒绝请求) 来源:GitHub Issue #728 修复版本:[email protected]+ 原因:使用 useAgentChat 搭配缺少服务端 execute 函数的客户端工具时,agents 库会创建共享相同推理 ID 的重复助手消息,导致 OpenAI API 拒绝请求。 预防措施:更新到 [email protected] 或更高版本

历史问题(0.2.31 之前):客户端工具执行会创建新消息,而不是更新现有消息,导致原始消息一直处于未完成状态,并产生重复的 providerMetadata.openai.itemId 值。

// ✅ Fixed in 0.2.31+ - no changes needed
// Just ensure you're on [email protected] or later
问题 20:异步查询未遵循缓存 TTL(已修复)

错误:即使设置了 cacheTtl,令牌过期后仍出现 401 Unauthorized 错误 来源:GitHub Issue #725 修复版本:查看 agents 发布说明 原因:useAgent 钩子的缓存存在问题:每个 cacheKey 只计算一次 queryPromise,并永久保留,即使 TTL 已过期也是如此。useMemo 实现未将时间纳入依赖项,因此 TTL 从未生效。 预防措施:更新到最新版本的 agents

历史解决方法(修复前):

// 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);
}, []);
问题 21:DO 休眠后 jsonSchemaValidator 失效(已修复)

错误:TypeError: validator.getValidator is not a function 来源:GitHub Issue #663 修复版本:查看 agents 发布说明 原因:Durable Object 休眠并恢复后,Agents SDK 会使用 JSON.stringify() 序列化 MCP 连接选项,将 CfWorkerJsonSchemaValidator 等类实例转换为没有方法的普通对象。通过 JSON.parse() 恢复后,验证器会丢失其方法。 预防措施:更新到最新版本的 agents(验证器现已内置)

历史问题(修复前):

// ❌ Before fix - manual validator caused errors
import { CfWorkerJsonSchemaValidator } from '@modelcontextprotocol/sdk/cloudflare-worker';

const mcpAgent = new McpAgent({
  client: {
    jsonSchemaValidator: new CfWorkerJsonSchemaValidator(), // Got serialized to {}
  }
});

当前方案(已修复):

// ✅ Now automatic - no manual validator needed
const mcpAgent = new McpAgent({
  // SDK handles validator internally
});
问题 22:WorkerTransport 在休眠后丢失 ClientCapabilities(已在 0.3.5+ 中修复)

错误:Error: Client does not support form elicitation 来源:GitHub Issue #777 修复版本:[email protected]+ 原因:在无服务器环境中将 WorkerTransport 与 MCP 服务搭配使用时,由于 TransportState 接口只存储 sessionId 和 initialized 状态,而不存储 clientCapabilities,客户端能力无法在 Durable Object 的休眠周期之间持久保存。 预防措施:更新到 [email protected] 或更高版本

历史问题(0.3.5 之前):

// Client advertised elicitation capability during handshake,
// but after hibernation, capability info was lost
await server.elicitInput({ /* form */ }); // ❌ Error: capabilities lost

解决方案(已在 0.3.5 中修复):

// TransportState now includes clientCapabilities
interface TransportState {
  sessionId: string;
  initialized: boolean;
  clientCapabilities?: ClientCapabilities; // ✅ Now persisted
}
问题 23:idFromName() 与 newUniqueId() 的关键用法

错误:状态从不持久保存,每次请求都会创建新的 Agent 实例 来源:Cloudflare 博客 - 使用 OpenAI 构建 Agent 原因:如果使用 newUniqueId() 而不是 idFromName(),每次都会获得一个新的 Agent 实例,内存/状态也永远不会持久保存。这是常见的早期错误,会在不易察觉的情况下破坏有状态能力。 预防措施:用户专属的 Agent 一律使用 idFromName(),不要使用 newUniqueId()

// ❌ 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);
  }
}

重要性:

  • newUniqueId():每次调用都会生成随机的唯一 ID → 新的 Agent 实例
  • idFromName(string):根据字符串生成确定性 ID → 相同输入对应同一个 Agent

经验法则:99% 的情况下都使用 idFromName()。只有确实需要一次性、临时的 Agent 实例时,才使用 newUniqueId()。


依赖项

必需
  • cloudflare-worker-base - 基础框架(Hono、Vite、Workers 配置)
可选(按功能)
  • cloudflare-workers-ai - 用于调用 Workers AI 模型
  • cloudflare-vectorize - 用于使用 Vectorize 实现 RAG
  • cloudflare-d1 - 用于存储 Agent 状态之外的其他持久化数据
  • cloudflare-r2 - 用于文件存储
  • cloudflare-queues - 用于消息队列
NPM 包
  • agents - Agents SDK(必需)
  • @modelcontextprotocol/sdk - 用于构建 MCP 服务
  • @cloudflare/puppeteer - 用于网页浏览
  • ai - 用于调用模型的 AI SDK
  • @ai-sdk/openai - OpenAI 模型
  • @ai-sdk/anthropic - Anthropic 模型

官方文档


捆绑资源

模板(templates/)
  • wrangler-agents-config.jsonc - 完整的配置示例
  • basic-agent.ts - 最精简的 HTTP Agent
  • websocket-agent.ts - WebSocket 处理程序
  • state-sync-agent.ts - 状态管理模式
  • scheduled-agent.ts - 任务调度
  • workflow-agent.ts - 工作流集成
  • browser-agent.ts - 网页浏览
  • rag-agent.ts - RAG 实现
  • chat-agent-streaming.ts - 流式聊天
  • calling-agents-worker.ts - Agent 路由
  • react-useagent-client.tsx - React 客户端
  • mcp-server-basic.ts - MCP 服务
  • hitl-agent.ts - 人机协作
参考资料(references/)
  • agent-class-api.md - 完整的 Agent 类参考
  • client-api-reference.md - 浏览器客户端 API
  • state-management-guide.md - 状态与 SQL 深入指南
  • websockets-sse.md - WebSocket 与 SSE 对比
  • scheduling-api.md - 任务调度详情
  • workflows-integration.md - 工作流指南
  • browser-rendering.md - 网页浏览模式
  • rag-patterns.md - RAG 最佳实践
  • mcp-server-guide.md - MCP 服务开发
  • mcp-tools-reference.md - MCP 工具 API
  • hitl-patterns.md - 人机协作工作流
  • best-practices.md - 生产环境模式
示例(examples/)
  • chat-bot-complete.md - 完整的聊天 Agent
  • multi-agent-workflow.md - Agent 编排
  • scheduled-reports.md - 定期任务
  • browser-scraper-agent.md - 网页抓取
  • rag-knowledge-base.md - RAG 系统
  • mcp-remote-server.md - 生产环境 MCP 服务

最后验证时间:2026-01-21 包版本:[email protected] 合规性:符合 Cloudflare Agents SDK 官方文档 变更:根据社区调研新增 7 个问题(WebSocket 负载限制、状态类型安全、idFromName 陷阱),并更新至 [email protected]

评论

支持 Markdown