ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Cloudflare agents 框架完全指南:在 Cloudflare 全球网络上构建持久化 AI Agent

Cloudflare agents 框架完全指南:在 Cloudflare 全球网络上构建持久化 AI Agent Cloudflare agents 框架完全指南在 Cloudflare 全球网络上构建持久化 AI Agent【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agentsagents是 Cloudflare 开源的 Agent 运行时与 SDK本仓库位于packages/agents它的核心承诺是构建会思考、会行动Build software that thinks and does的软件让 LLM 不再只是一次请求、一次返回的临时工具而是有记忆、能推理、可自主调度并主动行动的持久化实体。本指南以 packages/agents/README.md 为主线结合 源码实现 与 官方文档带你从零掌握如何用Agent类编写有状态的服务端智能体、如何用callable()暴露 RPC 方法、如何通过 React/原生 JS 客户端实时同步状态以及如何接入调度、子 Agent、Workflows、AI Chat 与 MCP 等进阶能力。为什么需要 Agent从无状态函数到持久智能体LLM 已经能推理、规划、使用工具但它们需要与之匹配的基础设施。传统 Serverless 是无状态且短暂的——一个函数从请求到返回生命周期即告终结而 Agent 是持久且有目的的实体From request handlers → to autonomous entities From stateless functions → to persistent intelligence Traditional serverless: Request → Response → Gone Agents: Thinking, remembering, acting — continuously二者的本质差异在于按活跃度计费Agent 在请求之间会休眠hibernate。你可以在单个 Worker 上拥有数百万个 Agent——每用户一个、每会话一个、每游戏房间一个——空闲时零成本被唤醒时才开始计费。持久状态基于 Cloudflare Durable Objects 构建Agent 运行在距离用户最近的全球节点状态在重启、部署甚至休眠后依然存活。这一设计直接回答了为什么是现在模型能力已经就绪而传统无服务器模型无法承载持续思考、跨请求记忆这类应用形态。快速上手创建项目与安装方式一从模板创建全新项目npm create cloudflarelatest -- --template cloudflare/agents-starter方式二加入现有项目npm install agentsREADME 中的示例大量使用callable()装饰器这需要工程配置配合Vite 项目必须继承agents/tsconfig并在vite.config.ts中加入agents/vite插件其他打包器必须支持 TC39 装饰器2023-11版本。详细配置见 将 Agents 加入现有项目。在 getting-started 文档 中给出了两份关键配置tsconfig.json—— 继承agents/tsconfig设置target: ES2021等推荐选项{ extends: agents/tsconfig }vite.config.ts—— 加入agents()插件处理 TC39 装饰器转换Vite 8 的 Oxc 转译器目前尚不支持装饰器因此必须依赖该插件import { cloudflare } from cloudflare/vite-plugin; import react from vitejs/plugin-react; import agents from agents/vite; import { defineConfig } from vite; export default defineConfig({ plugins: [agents(), react(), cloudflare()] });从 package.json 的exports字段可以看出agents包采用了多入口设计agents核心、agents/client原生 JS 客户端、agents/reactReact Hook、agents/vite、agents/tsconfig、agents/mcp、agents/mcp/server、agents/mcp/client、agents/voice、agents/channels、agents/workflows、agents/schedule、agents/agent-tools、agents/email等。这让打包器可以按需加载应用只加载真正用到的集成模块。快速示例一个带实时状态同步的计数器 Agent服务端定义 Agent 与可调用方法// server.ts import { Agent, callable } from agents; export type State { count: number }; export class CounterAgent extends AgentEnv, State { initialState: State { count: 0 }; callable() increment() { this.setState({ count: this.state.count 1 }); return this.state.count; } callable() decrement() { this.setState({ count: this.state.count - 1 }); return this.state.count; } }客户端React Hook 实时同步// client.tsx import { useAgent } from agents/react; import { useState } from react; import type { CounterAgent, State } from ./server; function Counter() { const [count, setCount] useState(0); const agent useAgentCounterAgent, State({ agent: counter-agent, name: my-counter, onStateUpdate: (state) setCount(state.count) }); return ( div span{count}/span button onClick{() agent.stub.increment()}/button button onClick{() agent.stub.decrement()}-/button /div ); }状态变更会自动同步到所有已连接的客户端方法调用就像调用本地函数一样简单。整个交互链路是客户端通过 WebSocket 调用agent.stub.increment()Agent执行increment()用setState()更新状态状态自动持久化到 SQLite广播推送给所有已连接客户端React组件重新渲染出最新的agent.state完整流程与排查指南如 Agent not found、状态不同步、Method X is not callable 等常见问题的解决方案见 Getting Started。注册 Agent 到 wrangler.jsonc{ name: my-agent, main: src/server.ts, compatibility_date: 2025-01-01, compatibility_flags: [nodejs_compat], durable_objects: { bindings: [ { name: Counter, class_name: Counter } ] }, migrations: [ { tag: v1, new_sqlite_classes: [Counter] } ] }Agent 使用SQLite 存储new_sqlite_classes因此每个命名实例都拥有独立的持久存储。你能构建什么典型应用场景应用场景为什么用 Agent多人游戏房间按房间隔离状态、实时同步、房间空置时休眠客服机器人记住对话历史、可升级转人工协作编辑器在线存在感、光标、文档状态审批工作流长时间运行、暂停等待人工输入、可持久化个人 AI 助手每用户记忆、通过 MCP 接入工具通知系统定时投递、用户偏好、重试逻辑状态管理持久化 实时广播状态跨请求持久化并同步到所有已连接客户端import { Agent, callable, type Connection } from agents; type State { items: string[] }; export class MyAgent extends AgentEnv, State { initialState: State { items: [] }; callable() addItem(item: string) { this.setState({ items: [...this.state.items, item] }); } onStateChanged(state: State, source: Connection | server) { // Called after state is persisted and broadcast } }从源码看Agent 的状态管理有一整套内部设计。在 src/index.ts 中状态存储在 DO 的 SQLite 内内部键如cf_state_row_id与用户状态键隔离连接状态中保留一批_cf_前缀的内部键CF_READONLY_KEY、CF_NO_PROTOCOL_KEY等setState时会被自动剥离/保留避免用户代码误操作内部状态错误广播会经过sanitizeErrorString截断与剥离控制字符最长 500 字符防止来自外部 MCP OAuth 提供商的不可信内容带来 XSS 风险。细节参考 State Management 文档。callable() 方法类型安全的 RPC用callable()装饰器向客户端暴露方法callable() async processOrder(orderId: string, items: Item[]) { // Full type safety - clients call this like a local function const result await this.validateAndProcess(orderId, items); return result; }// Client const result await agent.stub.processOrder(order-123, items);从 callable-decorator.ts 的源码可以看到装饰器背后的元数据机制CallableMetadata目前支持两个可选字段description方法功能描述与streaming方法是否支持流式响应装饰器通过WeakMapFunction, CallableMetadata注册方法元数据getCallableMetadata/isCallableMethod用于运行时识别可调用方法copyCallableMetadata保证框架包装方法后注册信息不丢失旧的unstable_callable已更名为callable会在下一个大版本移除。更多细节见 Callable Methods 文档。调度与后台任务调度Scheduling支持延迟执行、固定间隔与 cron 表达式// In 60 seconds this.schedule(60, sendReminder, { userId: 123 }); // Every hour this.scheduleEvery(3600, syncData); // Daily at 9am UTC this.schedule(0 9 * * *, dailyReport); // At a specific date this.schedule(new Date(2025-12-31), yearEndTask);从源码实现看schedules 模块 使用cron-schedule包解析 cron 表达式见 schedule-timing.ts并由 scheduler.ts 统一调度。调度器有一个hungScheduleTimeoutSeconds参数默认 30 秒如果一次周期性任务回调被认为卡死会被强制重置。如果你的回调合法地需要超过 30 秒应调大该值。参考 Scheduling 文档。后台任务Queue立即排队执行后台任务await this.queue(processUpload, { fileId: abc }); // Returns immediately, task runs in background从 src/index.ts 中QueueItem类型可以看出队列条目的结构id、payload、callbackAgent 上的方法名、created_at以及可选的retry: RetryOptions。任务项支持独立配置重试策略框架对schedule()、queue()、this.retry()提供了默认重试配置见下文配置一节。参考 Queue 文档。子 AgentSub-agents / Facets父 Agent 可以派生子 Durable Object称为 facet。每个子 Agent 拥有独立的 SQLite 存储并可并行运行但都统一挂在父 Agent 的 URL 下export class Inbox extends Agent { callable() async createChat() { const id crypto.randomUUID(); await this.subAgent(Chat, id); return id; } override async onBeforeSubAgent(_req, { className, name }) { if (!this.hasSubAgent(className, name)) { return new Response(Not found, { status: 404 }); } } } export class Chat extends Agent { async writePreview(text: string) { const inbox await this.parentAgent(Inbox); await inbox.savePreview(this.name, text); } }客户端通过useAgent({ sub: [...] })连接子 Agentconst inbox useAgent({ agent: Inbox, name: userId }); const chat useAgent({ agent: Inbox, name: userId, sub: [{ agent: Chat, name: chatId }] });路由后的 URL 形如/agents/inbox/{userId}/sub/chat/{chatId}。子 Agent 的 WebSocket 客户端可以使用相同的 URL 结构。父 Agent 始终是公开地址但子 Agent 依然能收到作用域限定在自己客户端上的onConnect、onMessage、onClose、broadcast()、getConnections()回调。父 Agent 的广播不会泄漏到定向子 Agent 的 socket当连接从休眠中恢复时子 Agent 的连接标签、只读状态和协议消息设置都会被保留。子 Agent URL 支持通过重复的/sub/{agent}/{name}段进行嵌套但受平台当前 facet 嵌套层数限制。路由实现细节可参考 sub-routing.ts导出buildAgentPath、routeSubAgentRequest、SUB_PREFIX等以及 Sub-agents 文档。Agent Tools把子 Agent 变成工具父聊天 Agent 可以把具备聊天能力的子 Agent 作为工具运行支持 Think Agent 与AIChatAgent子类。子 Agent 保留自己的消息、工具、SQLite 存储和可恢复的流父 Agent 广播agent-tool-event帧让 UI 可以内联渲染子 Agent 的时间线import { Think } from cloudflare/think; import { agentTool } from agents/agent-tools; import { z } from zod; export class Researcher extends ThinkEnv { getSystemPrompt() { return Research the requested topic and end with a concise summary.; } } export class Assistant extends ThinkEnv { getTools() { return { research: agentTool(Researcher, { description: Research one topic in depth., inputSchema: z.object({ query: z.string().min(3) }) }) }; } }inputSchema接受 AI SDK 支持的各类 schemaZod、Standard JSON Schema 兼容 schema、通过jsonSchema()传入的原始 JSON Schema以及 AI SDK 适配器暴露的 schema。例如使用ai-sdk/valibotAI SDK 6 用 v2AI SDK 7 用 v3import { valibotSchema } from ai-sdk/valibot; import * as v from valibot; const researchInput valibotSchema( v.object({ query: v.pipe(v.string(), v.minLength(3)) }) ); agentTool(Researcher, { description: Research one topic in depth., inputSchema: researchInput });注意工具输入除了运行时校验外还需要面向模型的 JSON Schema。因此仅做校验的 Standard Schema 是不够的必须使用其 Standard JSON Schema 扩展或 AI SDK 适配器。确定性扇出deterministic fan-out可以直接调用this.runAgentTool(Researcher, { input })。父 Agent 在重启后会协调并清理残留的子任务行把无法恢复的运行标记为interrupted而不是一直挂起。React 端用useAgentToolEvents({ agent })渲染保留并重放的子 Agent 时间线。AIChatAgent子任务以无头模式运行因此浏览器端客户端工具需要一个独立的桥接而服务端工具正常工作。完整指南见 Agent Tools。WebSocket 连接与邮件处理实时连接async onConnect(connection: Connection) { console.log(Client ${connection.id} connected); } async onMessage(connection: Connection, message: unknown) { // Handle incoming messages connection.send(JSON.stringify({ received: true })); } async onClose(connection: Connection) { console.log(Client ${connection.id} disconnected); }邮件收发Agent 可以接收并回复邮件import type { AgentEmail } from agents/email; async onEmail(email: AgentEmail) { const from email.from; const subject email.headers.get(subject); // Process incoming email }邮件头解析基于postal-mime、邮件构造基于mimetext见 package.json 依赖。邮件相关完整文档见 Email 文档。客户端 SDKReact Hookimport { useAgent } from agents/react; import { useState } from react; function App() { const [state, setState] useStateMyState | null(null); const agent useAgentMyState({ agent: my-agent, name: instance-name, onStateUpdate: (newState) setState(newState) }); return ( div pre{JSON.stringify(state, null, 2)}/pre button onClick{() agent.stub.doSomething()}Call Agent/button /div ); }原生 JavaScriptimport { AgentClient } from agents/client; const client new AgentClient({ agent: my-agent, name: instance-name, onStateUpdate: (state) console.log(State:, state) }); // Call methods const result await client.call(processData, [payload]); // Or use the stub const result await client.stub.processData(payload);useAgent通过 WebSocket 连接 Agentagent.state是响应式的状态变化触发组件重渲染agent.stub.methodName()调用服务端callable()方法。完整 API 参考见 Client SDK。Workflows 集成持久化多步任务对需要跨故障存活、且能暂停等待人工审批的多步任务可以集成 Cloudflare Workflowsimport { AgentWorkflow } from agents; export class OrderWorkflow extends AgentWorkflowOrderAgent, OrderParams { async run(event, step) { // Step 1: Validate (retries automatically on failure) const validated await step.do(validate, async () { return validateOrder(event.payload); }); // Step 2: Wait for human approval await this.reportProgress({ step: approval, status: pending }); const approval await this.waitForApproval(step, { timeout: 7 days }); // Step 3: Process the approved order await step.do(process, async () { return processOrder(validated, approval); }); } }Workflows 提供的能力持久化执行Durable execution—— 步骤失败自动重试状态跨故障保留人在回路Human-in-the-loop—— 通过waitForApproval()暂停等待审批长时任务—— 可以运行数天甚至数周进度追踪—— 通过reportProgress()向 Agent 汇报状态AgentWorkflow类在 workflows.ts 中定义。参考 Workflows 文档 与 Human in the Loop。AI Chat 集成持久会话与流式响应对于需要持久会话、流式响应和工具支持的 AI 聊天体验参见cloudflare/ai-chatimport { AIChatAgent } from cloudflare/ai-chat; import { createWorkersAI } from workers-ai-provider; import { convertToModelMessages, streamText } from ai; export class ChatAgent extends AIChatAgentEnv { async onChatMessage() { const workersai createWorkersAI({ binding: this.env.AI }); const result streamText({ model: workersai(cf/moonshotai/kimi-k2.7-code), messages: await convertToModelMessages(this.messages) }); return result.toUIMessageStreamResponse(); } }// Client import { useAgentChat } from cloudflare/ai-chat/react; const { messages, sendMessage } useAgentChat({ agent: useAgent({ agent: chat-agent }) });特性自动消息持久化可恢复流式响应断开连接后可以恢复服务端与客户端工具执行敏感工具的人工审批human-in-the-loopMCPModel Context ProtocolAgent 可以扮演 MCP 服务器向 AI 助手提供工具也可以扮演 MCP 客户端使用其他服务的工具。创建无状态 MCP 服务器import { McpServer } from modelcontextprotocol/server; import { createMcpHandler } from agents/mcp/server; import { z } from zod; function createServer() { const server new McpServer({ name: my-tools, version: 1.0.0 }); server.registerTool( lookup, { description: Look up data, inputSchema: { query: z.string() } }, async ({ query }) ({ content: [{ type: text, text: await lookup(query) }] }) ); return server; } export default { fetch(request, env, ctx) { return createMcpHandler(createServer)(request, env, ctx); } } satisfies ExportedHandler;只有当需要保留 Legacy 会话行为时才从agents/mcp使用McpAgent、createLegacyMcpHandler和WorkerTransport。使用 MCP 工具作为客户端// Connect to external MCP servers await this.addMcpServer( weather-service, https://weather-mcp.example.com/mcp, { transport: { type: streamable-http } } ); // Use with AI SDK const result await generateText({ model: openai(gpt-4o), tools: this.mcp.getAITools(), prompt: Whats the weather in Tokyo? });从 src/index.ts 中AddMcpServerOptions的源码可见addMcpServer支持丰富选项可选稳定id用于存储与工具名命名空间如 connector 风格的tool_github_create_pull_request、callbackHost/callbackPathOAuth 回调地址、agentsPrefix路由前缀默认agents、clientMCP 客户端选项、transport含headers认证头、传输类型sse | streamable-http | auto以及一个安全弱化的skipIssuerMetadataValidation兼容开关、retry连接与重连重试策略。normalizeServerId与MCP_SERVER_ID_MAX_LENGTH约束了服务器 ID 的规范化与长度上限。参考 MCP Client 文档 与 MCP Servers 文档。配置与路由在 wrangler.jsonc 中注册 Agent{ durable_objects: { bindings: [{ name: MyAgent, class_name: MyAgent }] }, migrations: [{ tag: v1, new_sqlite_classes: [MyAgent] }] }将请求路由到 Agentimport { routeAgentRequest } from agents; export default { async fetch(request: Request, env: Env) { return ( (await routeAgentRequest(request, env)) ?? new Response(Not found, { status: 404 }) ); } };路由与运行时选项源码级routeAgentRequest的实现位于 agent-routing.ts它的行为由AgentOptions控制prefix—— URL 前缀默认agents路由匹配形如/agents/{binding}/{name}的路径cors—— 设为true时启用默认宽松 CORS 头Access-Control-Allow-Origin: *、方法GET, POST, HEAD, OPTIONS、Max-Age: 86400带凭证的请求应显式传入HeadersInit指定具体 origin对匹配路由的 OPTIONS 预检请求会自动处理jurisdiction/locationHint—— Durable Object 的管辖区域与放置位置提示props—— 生命周期启动前注入的属性通过x-agents-lifecycle-props头编码传递onBeforeRequest/onBeforeConnect—— 路由前的拦截钩子可以改写请求或直接返回响应routingRetry—— 默认开启maxAttempts: 3、baseDelayMs: 100、maxDelayMs: 800指数退避 随机抖动仅对 Durable Object 标记为retryable的瞬时基础设施错误生效传false关闭。此外Agent 类本身有一组可通过static options覆盖的默认静态配置定义在 src/index.ts 的DEFAULT_AGENT_STATIC_OPTIONS选项默认值说明sendIdentityOnConnecttrue连接建立时是否向客户端发送身份信息agent 名称与实例名hungScheduleTimeoutSeconds30周期调度回调被认为卡死并被强制重置的超时秒keepAliveIntervalMs30000keepAlive()心跳 alarm 的间隔毫秒越低恢复越快但 alarm 越频繁retry{ maxAttempts: 3, baseDelayMs: 100, maxDelayMs: 3000 }schedule()、queue()、this.retry()的默认重试策略fiberRecoveryHookTimeoutMs10000框架内部 fiber 恢复钩子的超时fiberRecoveryScanDeadlineMs10000单次中断 fiber 恢复扫描的软截止时间fiberRecoveryMaxAgeMs8640000024h未管理的中断 fiber 行的最大恢复年龄防止反复抛错的钩子无限重试设为0可永久保留agentToolReattachNoProgressTimeoutMs120000部署/父恢复后重挂到仍在运行的 agent-tool 子任务的无进展预算每次收到转发 chunk 会重置agentToolReattachMaxWindowMsInfinity单次重挂的硬墙钟上限默认不设上限detachedMaxBudgetMs8640000024h分离后台agent-tool 运行的绝对预算上限detachedNoProgressBudgetMs36000001h分离运行报告过一次进度后、再次静默的放弃窗口maxAlarmMemoryLimitStrikes3连续因内存限制重置的 alarm 调用次数上限防止平台自动重试循环断路器总结与下一步agents把 Cloudflare Durable Objects、SQLite、WebSocket、调度器、Workflows 和 MCP 整合为一套面向 AI 智能体的运行时抽象让开发者用普通类的写法就能获得持久状态、实时同步、类型安全的远程方法调用、后台调度、子 Agent 编排与多通道通信。官方发布包内还包含完整的文档树docs/index.md。继续深入可以参考以下文档Getting Started · State Management · SchedulingCallable Methods · Durable Object Lifecycle · MCP IntegrationFull Documentation · Agent Class · Sub-agents · Workflows · Channels项目的完整开源许可见根目录 LICENSEMIT 协议。【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进