Cloudflare Agents 深度拆解:当 AI Agent 成为边缘一等公民——从 Durable Objects 持久状态、Agents SDK 到 Workflows 持久执行与 @cloudflare/computer 的全链路实战
2026 年,AI Agent 已经不再是「跑在笔记本上的脚本」。当 Agent 需要记住跨数天的对话、在数百万人同时在线时保持状态一致、还能调用浏览器和真实命令行时,传统的「无状态函数 + 外部数据库」组合就开始露怯了。Cloudflare 在 2025 年开源了 Agents SDK,又在 2026 年连续抛出 Agent Development Lifecycle、@cloudflare/computer 等重磅原语——它想做的,是把「有状态的 AI Agent」做成边缘平台上的一等公民。本文从底层存储模型、运行时架构,到可运行的 Agents SDK + Workflows 代码,再到生产级性能调优,进行全链路拆解。
一、背景介绍:为什么 Agent 需要「边缘态」
1.1 无状态浪潮留下的坑
过去十年,云原生把「无状态(stateless)」奉为圭臬。容器、函数、微服务,统统追求可以随时被杀掉、随时被调度的纯计算单元。这种范式对 Web API 极其友好——请求进来,处理,返回,上下文随进程一起消失。
但 AI Agent 的天性恰恰是有状态:
- 它需要记忆:上一轮对话说了什么,用户的偏好是什么,任务的进度到了哪一步;
- 它需要协调:多个工具调用之间要共享中间结果,多个并发请求要串行访问同一份资源;
- 它需要恢复:一个跑几分钟到几小时的任务,中途宕机、超时、限流了,得能从最后一个成功的检查点继续,而不是从头再来。
当这些需求叠加到「无状态函数」上时,工程师被迫自己拼接一套外部状态层:Redis 存会话、Postgres 存业务数据、消息队列做任务编排、再加一层锁服务解决并发。结果是——你 80% 的代码都在和「状态一致性」搏斗,只有 20% 在解决真正的业务问题。
1.2 为什么是边缘,而不是中心机房
把 Agent 放在传统云上,最大的痛是延迟和冷启动:
- 一个来自东京的用户,请求要漂洋过海到
us-east-1的机房,Round Trip 就是一两百毫秒起步; - Serverless 函数冷启动动辄几百毫秒到几秒,而 Agent 的推理本身就要等模型吐字,叠加起来体感极慢;
- 数据合规要求数据留在本地司法辖区,集中式部署天然违规。
Cloudfloudflare 的卖点恰好命中这两点:全球 300+ 个 PoP(入网点),代码以 V8 Isolate 方式运行,冷启动 < 1ms(不是毫秒级「预热」,而是几乎没有冷启动),并且原生支持「请求落到离用户最近的节点」。
但光有边缘计算还不够。边缘节点的核心难题是:计算无处不在,可状态该放哪儿? 如果每个 PoP 都是无状态的,那状态就只能回源到中心数据库,边缘的低延迟优势瞬间被一次跨洲 DB 查询抹平。
Cloudflare 的答案就是 Durable Objects:一个「地址唯一、单实例、强一致」的计算+存储单元,把状态锚定在某一个确定的位置,同时让计算结果尽可能靠近用户。
1.3 Cloudflare 与 LangChain / Vercel AI SDK 的根本区别
很多同学会问:我用 LangChain.js 或者 Vercel AI SDK 不也能写 Agent 吗?区别在于状态归谁管:
- LangChain / Vercel AI SDK 是「客户端框架」:它们管的是「怎么调模型、怎么组 prompt、怎么串 tool」。至于状态存在哪、并发怎么协调、宕机怎么恢复——你自己想办法(通常是一个外部的 memory store)。
- Cloudflare Agents 是「运行时 + 状态层」:它把 Agent 直接建在 Durable Objects 之上,
this.state就是持久化的内存,单实例模型天然解决了并发写冲突,WebSocket hibernation 让百万连接不再烧钱,Workflows 负责长任务的持久执行。
一句话:前者给你乐高积木,后者直接给你一座带地基的房子。 这就是为什么 Cloudflare 在 2026 年的宣传里反复强调「Agent 是一等公民,而不是你自己拼出来的上层应用」。
二、核心概念:把 Agent 拆成四块积木
要在边缘上跑 Agent,Cloudflare 提供了一组彼此咬合的原语。我们逐一拆开。
2.1 Workers:V8 Isolate 上的无冷启动计算
Workers 是 Cloudflare 的计算底座。它和你熟悉的 Node.js / Docker 函数最大的不同是运行单元不是容器,而是 V8 Isolate:
- 每个 Isolate 是 V8 引擎里的一个独立上下文,启动只需微秒级,没有容器镜像加载;
- 同一台物理机的上百个 Isolate 共享同一个 V8 实例,内存开销极低;
- 计费按 CPU 时间(实际消耗的计算),而不是 wall-clock 挂钟时间,空闲等待(比如等模型流式返回)不怎么花钱。
代价是受限的运行时:没有原生文件系统、不能用 process、不能用动态 require、CPU 时间 有硬上限(免费版每请求 10ms,付费版可到 30s 级 CPU + 更长的 duration)。对 Agent 来说,这意味着「重活」(跑浏览器、编译、长进程)不能只靠 Isolate,这正是后面 @cloudflare/computer 要补的洞。
2.2 Durable Objects:状态的地基
Durable Objects(简称 DO)是整套 Agent 架构的「定海神针」。它的三个核心特性:
① 单实例强一致。 每个 DO 由「命名空间 + ID」唯一确定,Cloudflare 保证全局只有一个活跃的该实例。所有对该对象的请求,无论来自哪个 PoP,都会被路由到这同一个实例上串行执行。这意味着你不需要分布式锁——DO 本身就是锁。这是 Agent 协调能力的来源。
② SQLite 存储。 现代 DO 的存储后端是事务型 SQLite(this.ctx.storage 的底层)。你可以像写关系表一样 INSERT/SELECT,ACID 保证。Agents SDK 把这套存储封装成了 this.state(自动持久化的结构化状态)和 this.sql(直接跑 SQL)。
③ WebSocket Hibernation(休眠)。 这是 DO 最被低估的能力。传统 WebSocket 服务,每个连接都拽着一个进程/线程不撒手,10 万连接就是 10 万份内存占用。DO 的 Hibernation API 允许连接休眠:消息到来时 Isolate 可以被整体驱逐,只在有新消息时唤醒。一个 DO 实例轻松扛住海量休眠连接,醒来时再从存储里恢复上下文。
2.3 Agents SDK:把 DO 包装成「Agent」
@cloudflare/agents(npm 上的 agents 包)是一个薄而关键的上层封装:它让你继承一个 Agent 类,而这个类本质就是一个 Durable Object,但额外提供了一套 Agent 友好的生命周期与状态接口。
关键接口一览:
| 能力 | API | 说明 |
|---|---|---|
| 持久化状态 | this.state / this.setState(partial) | 结构化状态,自动落盘到 DO 的 SQLite |
| 关系存储 | this.sql\...`` | 直接在 DO 存储里跑 SQL |
| 连接管理 | this.broadcast() / this.getConnection() | 向所有 WebSocket 连接广播 |
| 定时唤醒 | this.scheduleAlarm() / this.ctx.waitUntil | 类似 cron,用于定时任务、心跳 |
| 生命周期 | onStart / onConnect / onMessage / onDisconnect / onClose | 事件钩子 |
| 工具调用 | 内置 tool / MCP 集成 | 让 Agent 调用外部工具或 MCP server |
最妙的是:你写的 Agent 子类,既是「业务逻辑」,又是「Durable Object 定义」。Cloudflare 的运行时自动把它路由成单实例、强一致、可休眠的 Agent。你不用碰一行分布式协调代码。
2.4 Workflows:长任务的「持久执行」
Agent 经常要干「多步、长时、不容失败」的活儿:调研 → 起草 → 评审 → 发布,任何一步崩了都得从断点续跑。Workflows 就是为这种场景设计的持久执行引擎。
它的心智模型非常简单:一个 Workflow 由若干 step 组成,每个 step 是「可独立重试的最小单元」。Workflows 引擎会在每个 step 完成后持久化状态,如果进程崩溃、网络中断或代码报错,它会从最后一个成功的 step 自动恢复,而不是从头重跑。你不需要自己写状态机、不需要外挂数据库记录进度。
const outline = await step.do("research", async () => { /* 调用 LLM 做调研 */ });
const draft = await step.do("draft", async () => { /* 基于 outline 起草 */ });
const review = await step.do("review", async () => { /* 评审并打回或放行 */ });
注意 step.do 的 handler 必须是幂等的——因为引擎可能在重试时多次调用它(虽然它保证最终只提交一次结果,但执行可能被重放)。这是用 Workflows 的第一条铁律。
2.5 周边绑定:AI / Vectorize / R2 / KV
Agent 要干活,还得有「感官」和「手脚」,Cloudflare 用 binding(绑定) 把这些能力挂到 Worker 上:
- Workers AI:直接
env.AI.run("@cf/...", {...})调用托管模型(Llama、Phi、嵌入模型等),免运维、按量计费; - Vectorize:托管的向量数据库,给 RAG 提供语义检索;
- R2:零出口费用的对象存储,存大文件、知识库、产物;
- KV:全球低延迟键值缓存,适合存「读多写少」的配置/会话索引。
2.6 @cloudflare/computer:给 Agent 一台「真机」
2026 年 Cloudflare 推出的 @cloudflare/computer,是补齐 Agent 能力版图的最后一块。它的核心洞察是:Agent 需要的不是一个容器,而是一台「计算机」——能开浏览器、能跑 shell、能装依赖、能操作真实 GUI。
@cloudflare/computer 是一个 Agent 运行时,它动态地在「快但受限的 Isolate」和「完整但重的 Linux 容器」之间编排:轻量推理和路由走 Isolate(毫秒级、几乎零成本),需要浏览器自动化、代码编译、长进程的重活则调度到全功能容器。Agent 于是同时拥有了「边缘的速度」和「主机的完整能力」。下文会给出它的集成思路。
三、架构分析:一个请求是怎么变成「有状态的 Agent」的
3.1 路由全景
全球用户请求
│
Cloudfloudflare 边缘网络 (300+ PoP)
│ (就近接入,<1ms 冷启动)
▼
Worker (路由层 / index.ts)
│ 根据 room/topic 算出 DO id
▼
Durable Object 单实例 (Agents SDK 的 Agent 子类)
┌─────────────────────────────────┐
│ this.state ← 自动持久化的状态 │
│ this.sql ← SQLite 关系存储 │
│ WebSocket 连接池 (可休眠) │
│ Alarm / 定时任务 │
└─────────────────────────────────┘
│ │ │
env.AI.run() Vectorize 查询 R2/KV 读写
(Workers AI) (语义检索) (知识库/缓存)
│
长任务 → Workflows (持久执行: research→draft→review)
│
重活 → @cloudflare/computer (Isolate↔容器编排)
3.2 协调模型:一个 Agent = 一个 DO 实例 = 一个线程
这是理解整套架构的钥匙。每个逻辑上的 Agent(比如「房间 A 的对话助手」「用户 X 的长期记忆体」)都映射到一个唯一的 Durable Object 实例。Cloudflare 保证这个实例全局唯一且串行执行。于是:
- 多用户同时给「房间 A」发消息 → 全部被路由到同一个 DO 实例 → 天然串行,没有并发写冲突;
- Agent 的 memory 就是
this.state,读写都在单线程内进行,不需要任何锁; - 状态变更通过 SQLite 事务持久化,进程挂了重启后从存储恢复,memory 不丢。
对比一下传统方案:你要在 Redis + Postgres 之上自己实现「同一房间请求串行化」,通常得用分布式锁(Redlock 之类的),而 Redlock 在真实网络分区下并不绝对安全。Cloudflare 直接把这个问题从「工程难题」降级成了「架构默认」。
3.3 状态存储:SQLite 才是真相
很多人以为 this.state 是个内存变量。其实它的真相是:DO 的 SQLite 存储里的一张表。当你 this.setState(partial) 时,Agents SDK 会把结构化状态序列化后写入事务型存储;唤醒时再读回来。
这意味着你可以对 Agent 的状态做真正的 SQL 查询。比如一个客服 Agent,你可以:
-- 查这个用户最近 7 天的高优先级会话
SELECT * FROM messages
WHERE role = 'user'
AND created_at > datetime('now', '-7 days')
ORDER BY created_at DESC;
this.sql 标签模板直接在这个 SQLite 上执行,ACID、事务、索引一应俱全。这是把 Agent 从「玩具」推向「生产系统」的关键——你的 Agent 记忆是可查询、可分析、可治理的数据,而不是一团腌在内存里的 JSON。
3.4 长连接与休眠:百万 WebSocket 不烧钱
实时 Agent(比如边想边吐字的聊天界面)离不开 WebSocket。DO 的 Hibernation 机制让这件事变得便宜:
- 客户端连上来,DO
acceptWebSocket接住; - 没有消息的空闲期,Isolate 可以被整体驱逐,但连接由 Cloudfloudflare 边缘维持;
- 新消息到达,对应 DO 实例被唤醒,从存储恢复上下文,处理并
getWebSockets().forEach广播。
这样你付的钱是「被唤醒时处理消息的 CPU」,而不是「24 小时养着 10 万个进程」。对实时协作、直播字幕、多人 Agent 会话这类场景,这是成本结构的质变。
3.5 Workflows 在架构中的定位
DO / Agent 擅长「有状态、长连接、低延迟」;Workflows 擅长「长时、多步、必须不丢」。二者是互补层:
- Agent 收到一个「帮我写一份竞品分析报告」的大任务 → 不直接在 DO 里跑(怕超时、怕中途崩)→ 转交给 Workflows;
- Workflows 用
step把任务拆成调研/起草/评审,每步持久化,任何失败自动从断点续跑; - 每步内部可以回调 Agent / 调 Workers AI / 读写 R2,形成「Agent 管状态、Workflow 管流程」的分工。
四、代码实战:从零搭一个边缘智能体
下面我们动手实现一个**「带长期记忆的多人聊天 Agent」+「竞品分析长任务 Workflow」**,并给出 @cloudflare/computer 的集成思路。所有代码面向 Cloudflare Workers + Agents SDK + Workflows。
4.1 工程骨架与 wrangler.toml
name = "edge-agent-demo"
main = "src/index.ts"
compatibility_date = "2025-08-01"
workers_dev = true
# 把 Agent 同时作为 Durable Object 和 Agent 命名空间暴露
[[durable_objects.bindings]]
name = "ChatAgent"
class_name = "ChatAgent"
[[migrations]]
tag = "v1"
new_classes = ["ChatAgent"]
# 让 DO 自动选择离用户/离存储最近的部署位置,降低延迟
[[durable_objects.bindings]]
name = "ChatAgent"
class_name = "ChatAgent"
# 在代码中通过 binding 的 smart_placement 控制;此处给出 DO 级别的提示
# Workers AI 绑定
[ai]
binding = "AI"
# 向量库(用于 RAG 检索)
[[vectorize.bindings]]
name = "VECTORIZE"
index_name = "knowledge-base"
# R2 对象存储(存放长文档/产物)
[[r2_buckets.bindings]]
name = "DOCS"
bucket_name = "edge-agent-docs"
# Workflows 绑定
[[workflows]]
name = "research-workflow"
binding = "RESEARCH_WORKFLOW"
class_name = "ResearchWorkflow"
注意:
smart_placement = "smart"也可以写在 DO 绑定上,让 Cloudfloudflare 自动把实例调度到「离其存储与调用方最近」的位置,对跨大洲的低延迟至关重要。
4.2 一个有长期记忆的 Agent(Agents SDK)
// src/chat-agent.ts
import { Agent, type Connection } from "agents";
interface ChatMessage {
role: "user" | "assistant" | "system";
content: string;
ts: number;
}
interface ChatState {
room: string;
messages: ChatMessage[];
}
export class ChatAgent extends Agent<Env, ChatState> {
// 初始状态,首次创建实例时写入存储
initialState: ChatState = { room: "default", messages: [] };
// 新连接建立
async onConnect(connection: Connection) {
// 把当前历史推给刚连上的客户端,实现「断线重连不丢上下文」
connection.send(
JSON.stringify({ type: "history", messages: this.state.messages })
);
}
// 收到一条消息
async onMessage(connection: Connection, raw: string) {
const { text } = JSON.parse(raw) as { text: string };
// 1) 写入持久化状态(自动落盘到 DO 的 SQLite)
this.setState({
...this.state,
messages: [
...this.state.messages,
{ role: "user", content: text, ts: Date.now() },
],
});
// 2) 调用 Workers AI 做推理( Messages 格式)
const resp = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
messages: this.state.messages.map((m) => ({
role: m.role,
content: m.content,
})),
max_tokens: 512,
temperature: 0.7,
});
const reply = (resp as { response: string }).response;
// 3) 把回复也持久化,并广播给房间内所有连接(含休眠连接)
this.setState({
...this.state,
messages: [
...this.state.messages,
{ role: "assistant", content: reply, ts: Date.now() },
],
});
this.broadcast(JSON.stringify({ type: "message", role: "assistant", content: reply }));
}
// 定时任务:每天凌晨清理 30 天前的历史,避免存储无限膨胀
async scheduled(controller: ScheduledController) {
this.sql`
DELETE FROM messages
WHERE ts < ${Date.now() - 30 * 24 * 3600 * 1000}
`;
}
}
这段代码看似简单,背后却藏着整套架构红利:
this.setState的写入是事务型、自动持久化的,进程被杀也不丢;this.broadcast通过 DO 的 WebSocket 连接池广播,休眠连接也会被唤醒投递;onConnect里回放历史,天然支持「刷新页面 / 断线重连后记忆还在」;scheduled定时清理,配合 DO 的 Alarm 能力,无需外部 cron 服务。
4.3 直接在 DO 存储上跑 SQL:把记忆变成可查询数据
上面 scheduled 里用到的 this.sql 就是 DO 的 SQLite。你也可以在任何方法里做分析型查询,比如统计一个房间今天的高频话题:
async topTopicsToday(): Promise<string[]> {
const rows = this.sql<{ topic: string; cnt: number }>`
SELECT json_extract(content, '$.topic') AS topic, COUNT(*) AS cnt
FROM messages
WHERE role = 'user'
AND ts > ${Date.now() - 24 * 3600 * 1000}
GROUP BY topic
ORDER BY cnt DESC
LIMIT 10
`;
return rows.map((r) => r.topic);
}
this.sql 是标签模板函数,参数用 ${} 插值会被安全地参数化,天然防 SQL 注入。json_extract 是 SQLite 内置的 JSON 函数,说明 DO 存储就是正经的 SQLite,不是什么阉割版 KV。
4.4 底层透视:Durable Objects 的 Hibernatable WebSocket
如果你想绕开 Agents SDK、直接吃透 DO 的休眠能力,可以手写一个 Room 类(Agents SDK 的连接管理底层就是这套):
// src/room.ts
export class Room extends DurableObject<Env> {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/ws") {
const pair = new WebSocketPair();
// 关键:acceptWebSocket 让这个连接进入「可休眠」状态
this.ctx.acceptWebSocket(pair[1]);
return new Response(null, { status: 101, webSocket: pair[0] });
}
return new Response("not found", { status: 404 });
}
// 休眠期间连接不占 Isolate;新消息到达才唤醒实例
async webSocketMessage(ws: WebSocket, message: string) {
// 唤醒后从存储恢复房间状态(示意)
const state = (await this.ctx.storage.get("state")) ?? { users: [] };
// 广播给该 DO 下所有连接(包括其他休眠连接)
for (const c of this.ctx.getWebSockets()) {
c.send(JSON.stringify({ from: "server", message }));
}
}
async webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean) {
ws.close(code, reason);
}
}
acceptWebSocket / getWebSockets / webSocketMessage / webSocketClose 这套 Hibernatable API,是支撑「百万长连接不烧钱」的底层机制。Agents SDK 帮你封装了它,但你理解了底层,才能在出问题时精准排障。
4.5 Workflows:把「竞品分析」做成持久执行的长任务
下面这个 Workflow 演示「调研 → 起草 → 评审」三步,任何一步崩了都能从断点恢复:
// src/research-workflow.ts
import { WorkflowEntrypoint, type WorkflowStep, type WorkflowEvent } from "cloudflare:workers";
type Params = { topic: string; depth: "lite" | "full" };
export class ResearchWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
const { topic, depth } = event.params;
// Step 1: 调研(可能要调多次模型 / 抓网页,慢且易失败)
const research = await step.do("research", async () => {
const r = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
prompt: `针对「${topic}」做一份结构化调研大纲,列出关键维度与数据源。`,
max_tokens: 1024,
});
return (r as { response: string }).response;
});
// Step 2: 起草(依赖 Step1 的结果)
const draft = await step.do("draft", async () => {
const r = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
prompt: `基于以下调研大纲撰写竞品分析草稿:\n${research}`,
max_tokens: 2048,
});
return (r as { response: string }).response;
});
// Step 3: 评审(用另一个模型做 critique,可打回)
const review = await step.do("review", async () => {
const r = await this.env.AI.run("@cf/microsoft/phi-3-mini-4k-instruct", {
prompt: `评审以下草稿的事实准确性与结构,给出通过/打回结论:\n${draft}`,
max_tokens: 512,
});
return (r as { response: string }).response;
});
// 落库:把最终产物存进 R2,供前端拉取
const key = `reports/${topic}-${Date.now()}.md`;
await this.env.DOCS.put(key, `# ${topic}\n\n${draft}\n\n---\n评审:${review}`);
return { topic, research, draft, review, storedKey: key };
}
}
触发方式(在 Worker 里):
// src/index.ts
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// 触发长任务
if (url.pathname === "/analyze" && request.method === "POST") {
const { topic } = await request.json();
const instance = await env.RESEARCH_WORKFLOW.create({
params: { topic, depth: "full" },
});
return Response.json({ workflowId: instance.id });
}
// 把 WebSocket 请求路由到唯一 Agent 实例(按 room 算 id)
if (url.pathname.startsWith("/ws")) {
const room = url.searchParams.get("room") ?? "lobby";
const id = env.ChatAgent.idFromName(room); // 同 room → 同实例 → 强一致
return env.ChatAgent.get(id).fetch(request);
}
return new Response("Edge Agent Demo");
},
};
注意 env.ChatAgent.idFromName(room) 这一行:它把「房间名」映射成「确定性的 DO id」,从而保证同一个房间的所有请求都落到同一个单实例上。这就是前面说的「一个 Agent = 一个 DO 实例」在工程上的落点。
4.6 给 Agent 一台真机:@cloudflare/computer 集成思路
当 Agent 需要「打开浏览器截图」「跑一段要编译的代码」「操作真实 GUI」时,纯 Isolate 无能为力。@cloudflare/computer 的思路是:轻活走 Isolate,重活调度到全功能 Linux 容器,对 Agent 暴露统一的「计算机」接口。
// src/computer-agent.ts (示意:集成思路,具体 API 以官方文档为准)
import { Computer } from "@cloudflare/computer";
export class BrowserAgent extends Agent<Env, ChatState> {
private computer?: Computer;
private getComputer() {
if (!this.computer) {
// 把「计算机运行时」绑定挂到 Agent 上
this.computer = new Computer(this.env.COMPUTER);
}
return this.computer;
}
async onMessage(_conn: Connection, raw: string) {
const { task } = JSON.parse(raw);
// 1) 推理阶段在 Isolate 里完成(毫秒级、零成本)
const plan = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
prompt: `把任务「${task}」拆解成浏览器操作序列`,
max_tokens: 512,
});
// 2) 执行阶段:需要真实浏览器 → 交给 computer 运行时调度到容器
const session = await this.getComputer().session.create({ image: "browser" });
const result = await session.run(async (vm) => {
const page = await vm.browser.open("https://example.com");
await page.click("#login");
return await page.screenshot();
});
this.broadcast(JSON.stringify({ type: "screenshot", data: result }));
}
}
这里展示的是架构意图:Agent 不再被 Isolate 的能力边界困住——推理与路由的「快」留在边缘,浏览器/编译/长进程的「重」下沉到容器,二者由 computer 运行时无缝编排。对「能逛网页、能点按钮、能跑代码」的自主 Agent 来说,这是从 demo 走向生产力的关键一步。
五、性能优化:把边缘 Agent 榨到极致
代码能跑只是第一步。生产环境里,Agent 要在高并发、长连接、模型慢响应的压力下保持廉价和稳定。下面是经过实战检验的优化清单。
5.1 让 DO 待在「对的位置」:Smart Placement
默认情况下,DO 实例创建在哪个 PoP 是「就近创建时所在节点」。如果你的 Agent 既要读 R2/KV(有固定存储位置),又要服务全球用户,位置选错就意味着每次请求都跨大洲。开启 smart_placement:
[durable_objects]
smart_placement = "smart"
Cloudfloudflare 会动态把实例调度到「离其依赖存储与调用方综合最近」的位置,通常能把 P99 延迟砍掉一大截。
5.2 用 Hibernation 扛长连接,而不是堆进程
再次强调:别用「每个连接一个常驻 Isolate」的思路。统一走 acceptWebSocket / Agents SDK 的连接池,让空闲连接休眠。一个 DO 实例扛 10 万休眠连接的成本,远低于 10 万个常驻 Worker。
5.3 用 Alarm 代替轮询
很多同学用「每 5 秒发一个请求来触发检查」的轮询模式——这在边缘上既贵又蠢。改用 DO Alarm:
// 设定 1 小时后唤醒做一次性检查
await this.ctx.storage.setAlarm(Date.now() + 3600_000);
// 引擎会在到点时调用 agent 的 alarm() 钩子
async alarm() {
// 做定时任务,无需外部 cron
}
Alarm 由平台精确触发,不占持续计算,是做心跳、过期清理、定时摘要的最佳原语。
5.4 状态写入要批量、要事务
Agent 记忆频繁更新时,别一条条 setState。把多个相关变更合并成一次事务写入,既减少存储往返,又保证一致性:
// 好的做法:一次合并更新
this.setState({
messages: [...this.state.messages, userMsg, assistantMsg],
lastActive: Date.now(),
});
// 避免:两次独立写,中间崩溃会丢一半
this.setState({ messages: [...] });
this.setState({ lastActive: Date.now() }); // 若此处崩溃,状态不一致
5.5 把「读多写少」的东西塞进 KV / Cache API
Agent 的「系统提示词」「用户画像摘要」「工具目录」这类几乎不变、却被每次请求读取的数据,不该每次都从 DO 存储或模型里拉。用 Workers KV 或 Cache API 做一层边缘缓存:
// 用 Cache API 缓存一次昂贵的检索结果,TTL 60s
const cache = caches.default;
const cacheKey = new Request(`https://cache.local/tools-catalog`);
let catalog = await cache.match(cacheKey);
if (!catalog) {
catalog = await buildToolCatalog(); // 昂贵操作
await cache.put(cacheKey, new Response(JSON.stringify(catalog), {
headers: { "Cache-Control": "max-age=60" },
}));
}
5.6 Workflow 的 step 必须幂等 + 加超时
Workflows 会在失败时重放 step 的 handler,所以:
- 不要在 step 里做「副作用不可重入」的事(比如无脑
INSERT一条订单)。需要幂等就带幂等键去重; - 给外部调用设超时,避免一个慢 API 把整个 Workflow 拖死:
const draft = await step.do("draft", {
retries: { limit: 3, delay: "5s", backoff: "exponential" },
timeout: "2m",
}, async () => { /* ... */ });
5.7 流式输出,别等模型吐完再回
Agent 聊天体验的关键不是「快」,而是「立刻有反馈」。Workers AI 支持流式,配合 WebSocket 逐 token 广播:
const stream = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
messages, stream: true,
});
for await (const chunk of (stream as ReadableStream)) {
this.broadcast(JSON.stringify({ type: "token", delta: chunk }));
}
用户看到的是「边想边打字」的体感,而不是「转圈 5 秒后啪一下全出来」。
5.8 生产级调优清单(直接抄)
- DO 开启
smart_placement = "smart" - 长连接统一走 hibernation,禁止常驻 Isolate 轮询
- 定时任务用 Alarm,不用外部 cron
- 状态变更合并成单次事务写入
- 系统提示 / 工具目录 / 用户画像 → KV + Cache API 缓存
- Workflow step 幂等 + 显式超时 + 指数退避
- 模型输出走流式逐 token 广播
- 大文件 / 知识库走 R2,别塞进 DO 存储
- 用
wrangler tail+wrangler dev的结构化 trace 做故障定位 - 监控 DO 存储用量与 CPU 时间,设预算告警
六、总结与展望:边缘 Agent 的下半场
6.1 这套架构到底适合谁
强烈适合:
- 需要长期记忆、跨会话一致的 Agent(客服、个人助理、协作工具);
- 实时多人场景(直播字幕、协作白板里的 AI、游戏内 NPC);
- 追求全球低延迟且不想养一堆中心数据库的产品;
- 长任务、不容失败的自动化(报告生成、数据管道、内容审核流)。
要三思的:
- 你极度厌恶厂商锁定:这套能力深度绑定 Cloudfloudflare,迁移成本不低;
- 你的负载是纯 CPU 重计算(视频转码、大规模训练),DO 的 CPU 上限和 Isolate 限制会卡脖子——这类更适合
@cloudflare/computer的容器通道或干脆回传统云; - 你需要跨多个强一致存储做分布式事务:DO 是单实例单存储的强一致,跨 DO 的协调得自己设计(消息 + 最终一致)。
6.2 2026 年的信号:Cloudfloudflare 在赌「Agent 全生命周期」
把 2026 年的几则官方动态串起来,能看出 Cloudfloudflare 的野心不止于「跑 Agent」,而是承包 Agent 的整个生命周期:
- Agent Development Lifecycle:把「编写 → 评审 → 部署 → 维护」做成 Cloudfloudflare 原生原语;
wrangler dev现在能为每个本地请求产出结构化 trace,你的 coding agent 只要调一个 API 就能精确定位「哪一步失败、为什么失败」,无需部署即可排障; - @cloudfloudflare/computer:给 Agent 一台真机,弥合 Isolate 与完整 Linux 容器之间的能力鸿沟;
- Software Factory:Cloudfloudflare 展示用「跑在 GitHub Actions 里的隔离 AI 子 Agent」把 Astro 项目的 open issue 数干到接近零——自动复现 bug、验证补丁、发预览版本。
这背后是一条清晰的产品哲学:未来的 Agent 不该是开发者手搓的上层应用,而应该是平台提供的、带状态、带记忆、带真机、带可观测性的基础设施。 你专注于「Agent 该做什么」,平台负责「Agent 怎么稳稳地活着」。
6.3 写在最后
回到开头那个问题:当 AI Agent 需要记忆、需要协调、需要从断点恢复时,无状态函数为什么不够用?答案现在已经很清楚——不是不够「算」,而是不够「稳」和不够「近」。Cloudfloudflare 用 Durable Objects 把状态钉死在确定的位置,用 Agents SDK 把「有状态」变成默认,用 Workflows 把「长任务」变成持久执行,再用 @cloudfloudflare/computer 把「真机能力」补齐。
对程序员来说,这意味着你终于可以少写 80% 的状态胶水代码,把精力放回真正创造价值的地方。当然,代价是更深地拥抱一个生态。但至少在「让 Agent 稳稳跑在全球边缘」这件事上,Cloudfloudflare 目前给出的,是工程上最自洽、也最省力的一套答案。
技术的尽头不是更复杂的架构,而是让复杂的事情变得理所当然。边缘上的 Agent,正在朝这个方向走。