上周我第一次点开官方 Starter。三行命令,一个能计数、能实时同步的 Agent 就上线了。我当场决定,这一章就讲这个最快的路。
02.1 你需要什么
装好 Node 24+。有一个 Cloudflare 账号(免费层够跑通)。不用装任何 IDE 插件。不用写代码。
02.2 我们最终要做成什么
一个能打开链接就对话、点击按钮就改数字、多人同时看到变化、断电重启数字还在的计数器 Agent。
02.3 用 Starter 模板起项目
# 这一行拉取官方 agents-starter 模板
npm create cloudflare@latest -- --template cloudflare/agents-starter
cd my-agent
npm install
预期结果:目录里出现 src/server.ts(你的 Agent 代码)、src/client.tsx(前端)、wrangler.jsonc(配置)。
02.4 把 server.ts 换成计数器
import { Agent, routeAgentRequest, callable } from "agents";
// 定义状态的形状
type CounterState = { count: number };
export class Counter extends Agent<Env, CounterState> {
// 新实例的默认状态
initialState: CounterState = { count: 0 };
// @callable 标记的方法,客户端能直接调
@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;
}
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
// 路由请求到对应的 Agent 实例
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
}
};
02.5 在 wrangler.jsonc 里登记 Agent
{
"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"] }]
}
注意
Counter必须同时出现在durable_objects.bindings和migrations.new_sqlite_classes。漏一个,运行时报No such Durable Object class。这是新手第一坑。
02.6 启动,看它活过来
npm run dev
打开 http://localhost:5173。点按钮,数字变。开两个浏览器标签,一个加,另一个也跟着变。这就是实时同步。
标叔的经验
第一次看到两个标签页数字同步的那一刻,我明白了 Cloudflare Agents 的精髓——状态是"对象级"的,不是"请求级"的。
02.7 发生了什么
你点按钮时:客户端经 WebSocket 调 agent.stub.increment() → Agent 跑 increment(),setState() 把数字写进 SQLite → 状态广播给所有连接 → React 重渲染。
┌─────────────┐ ┌─────────────┐
│ Browser │◄───────►│ Agent │
│ (React) │ WS │ (Counter) │
└─────────────┘ └──────┬──────┘
│
┌──────▼──────┐
│ SQLite │
│ (State) │
└─────────────┘
关掉页面,再打开。数字还在。这就是休眠与唤醒。
装好第一个 Agent,下一章我们把开发环境配齐。