05.1 先给结论
Cloudflare Agents 的状态,存在每个 Agent 实例私有的 SQLite 里。它自动持久化、跨客户端实时同步、重启后还在。
这点比 EdgeOne 的"平台托管记忆"更底层——你拿到的不是黑盒记忆,而是一整张能写 SQL 的表。
05.2 三种操作
export class ChatAgent extends Agent<Env, { messages: any[]; count: number }> {
// 1. 初始状态:新实例的默认值
initialState = { messages: [], count: 0 };
// 2. 读状态
onRequest() {
return Response.json(this.state);
}
// 3. 改状态:自动落盘 + 广播
addMessage(msg: any) {
this.setState({ ...this.state, messages: [...this.state.messages, msg] });
}
}
05.3 状态不是普通变量
setState 会:写进 SQLite、广播给所有连接、触发 onStateChanged。直接改 this.state 不生效。
// 对的
this.setState({ count: this.state.count + 1 });
// 错的:改动不会落盘,也不会广播
this.state.count = this.state.count + 1;
| 维度 | this.state 直改 |
this.setState() |
标叔的结论 |
|---|---|---|---|
| 持久化 | 否 | 是 | 永远用 setState |
| 广播 | 否 | 是 | setState 才同步 |
| 类型安全 | 有(泛型) | 有(泛型) | 都用泛型 |
05.4 直接写 SQL
状态是 JSON 存的。要复杂查询?直接用 this.sql,模板标签,类型安全。
type User = { id: string; name: string };
const [user] = this.sql<User>`SELECT * FROM users WHERE id = ${userId}`;
标叔的经验
小状态用setState,结构化数据用this.sql。我做一个游戏房 Agent,玩家列表用 setState,排行榜用 SQL 表。各司其职。
05.5 校验状态
敏感状态,加一道关卡。validateStateChange 在落盘前跑,抛错就拒绝。
validateStateChange(next: GameState) {
if (next.score < 0) throw new Error("score cannot be negative");
}
状态这块是 Cloudflare Agents 的立身之本。下一章讲工具——让 Agent 真的能"动手"。