Cloudflare Agents 从入门到精通
附录

§05 对话状态:每个 Agent 自带 SQLite,断线续跑

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 真的能"动手"。