每个 Agent 都有内置的状态管理功能,包括内置存储和 Agent 与前端应用程序之间的同步。
Agent 内的状态具有以下特性:
- 在 Agent 重启时持久化:数据永久存储在 Agent 内。
- 自动序列化/反序列化:您可以存储任何 JSON 可序列化的数据。
- 在 Agent 内立即一致:读取您自己的写入。
- 并发更新的线程安全
- 快速:状态与 Agent 运行的位置位于同一位置。读取和写入不需要穿越网络。
Agent 状态存储在嵌入每个单独 Agent 实例内的 SQL 数据库中:您可以使用更高级别的 this.setState
API(推荐)与其交互,它允许您同步状态并在状态更改时触发事件,或直接使用 this.sql
查询数据库。
每个 Agent 都有内置的状态管理功能。您可以直接使用 this.setState
设置和更新 Agent 的状态:
import { Agent } from "agents";
export class MyAgent extends Agent { // 响应事件更新状态 async incrementCounter() { this.setState({ ...this.state, counter: this.state.counter + 1, }); }
// 处理传入消息 async onMessage(message) { if (message.type === "update") { this.setState({ ...this.state, ...message.data, }); } }
// 处理状态更新 onStateUpdate(state, source) { console.log("状态已更新", state); }}
import { Agent } from "agents";
export class MyAgent extends Agent { // 响应事件更新状态 async incrementCounter() { this.setState({ ...this.state, counter: this.state.counter + 1, }); }
// 处理传入消息 async onMessage(message) { if (message.type === "update") { this.setState({ ...this.state, ...message.data, }); } }
// 处理状态更新 onStateUpdate(state, source: "server" | Connection) { console.log("状态已更新", state); }}
如果您使用 TypeScript,您还可以通过将类型作为 类型参数 ↗ 传递给 Agent
类定义的第二个类型参数来为您的 Agent 状态提供类型。
import { Agent } from "agents";
// 为您的 Agent 状态定义类型// 传入您的 Agent 状态的类型export class MyAgent extends Agent { // 这允许 this.setState 和 onStateUpdate 方法 // 被类型化: async onStateUpdate(state) { console.log("状态已更新", state); }
async someOtherMethod() { this.setState({ ...this.state, price: this.state.price + 10, }); }}
import { Agent } from "agents";
interface Env {}
// 为您的 Agent 状态定义类型interface FlightRecord { id: string; departureIata: string; arrival: Date; arrivalIata: string; price: number;}
// 传入您的 Agent 状态的类型export class MyAgent extends Agent<Env, FlightRecord> { // 这允许 this.setState 和 onStateUpdate 方法 // 被类型化: async onStateUpdate(state: FlightRecord) { console.log("状态已更新", state); }
async someOtherMethod() { this.setState({ ...this.state, price: this.state.price + 10, }); }}
您还可以通过 Agent
类上的 initialState
属性为 Agent 设置初始状态:
class MyAgent extends Agent { // 设置默认的初始状态 initialState = { counter: 0, text: "", color: "#3B82F6", };
doSomething() { console.log(this.state); // {counter: 0, text: "", color: "#3B82F6"},如果您还没有设置状态 }}
type State = { counter: number; text: string; color: string;};
class MyAgent extends Agent<Env, State> { // 设置默认的初始状态 initialState = { counter: 0, text: "", color: "#3B82F6", };
doSomething() { console.log(this.state); // {counter: 0, text: "", color: "#3B82F6"},如果您还没有设置状态 }}
任何初始状态都会同步到通过useAgent
hook连接的客户端。
客户端可以连接到 Agent 并使用作为 agents/react
一部分提供的 React hooks 与其状态保持同步。
React 应用程序可以调用 useAgent
通过 WebSockets 连接到命名的 Agent
import { useState } from "react";import { useAgent } from "agents/react";
function StateInterface() { const [state, setState] = useState({ counter: 0 });
const agent = useAgent({ agent: "thinking-agent", name: "my-agent", onStateUpdate: (newState) => setState(newState), });
const increment = () => { agent.setState({ counter: state.counter + 1 }); };
return ( <div> <div>计数: {state.counter}</div> <button onClick={increment}>增加</button> </div> );}
import { useState } from "react";import { useAgent } from "agents/react";
function StateInterface() { const [state, setState] = useState({ counter: 0 });
const agent = useAgent({ agent: "thinking-agent", name: "my-agent", onStateUpdate: (newState) => setState(newState), });
const increment = () => { agent.setState({ counter: state.counter + 1 }); };
return ( <div> <div>计数: {state.counter}</div> <button onClick={increment}>增加</button> </div> );}
状态同步系统:
- 自动将 Agent 的状态同步到所有连接的客户端
- 优雅地处理客户端断开连接和重新连接
- 提供立即的本地更新
- 支持多个同时的客户端连接
常见用例:
- 实时协作功能
- 多窗口/选项卡同步
- 跨多个设备的实时更新
- 在客户端之间维护一致的 UI 状态
- 当新客户端连接时,它们自动从 Agent 接收当前状态,确保所有客户端都从最新数据开始。
每个单独的 Agent 实例都有自己的 SQL(SQLite)数据库,运行在与 Agent 本身相同的上下文中。这意味着在您的 Agent 内插入或查询数据实际上是零延迟的:Agent 不必跨越大陆或世界来访问自己的数据。
您可以通过 this.sql
在 Agent 的任何方法中访问 SQL API。SQL API 接受模板字符串,并且
export class MyAgent extends Agent { async onRequest(request) { let userId = new URL(request.url).searchParams.get("userId");
// 'users' 这里只是一个例子:您可以创建任意表并在每个 Agent 的数据库中 // 使用 SQL(SQLite 语法)定义您自己的架构。 let user = await this.sql`SELECT * FROM users WHERE id = ${userId}`; return Response.json(user); }}
export class MyAgent extends Agent<Env> { async onRequest(request: Request) { let userId = new URL(request.url).searchParams.get("userId");
// 'users' 这里只是一个例子:您可以创建任意表并在每个 Agent 的数据库中 // 使用 SQL(SQLite 语法)定义您自己的架构。 let user = await this.sql`SELECT * FROM users WHERE id = ${userId}`; return Response.json(user); }}
您还可以为查询提供一个 TypeScript 类型参数 ↗,它将用于推断结果的类型:
type User = { id: string; name: string; email: string;};
export class MyAgent extends Agent<Env> { async onRequest(request: Request) { let userId = new URL(request.url).searchParams.get("userId"); // Supply the type paramter to the query when calling this.sql // This assumes the results returns one or more User rows with "id", "name", and "email" columns const user = await this.sql<User>`SELECT * FROM users WHERE id = ${userId}`; return Response.json(user); }}
您不需要指定数组类型 (User[]
或 Array<User>
),因为 this.sql
将始终返回指定类型的数组。
提供类型参数不会验证结果是否匹配您的类型定义。在 TypeScript 中,不存在的属性(字段)或不符合您提供的类型定义的属性将被删除。如果您需要验证传入的事件,我们建议使用库,例如 zod ↗ 或您自己的验证逻辑。
The SQL API exposed to an Agent is similar to the one within Durable Objects: Durable Object SQL methods available on this.ctx.storage.sql
. You can use the same SQL queries with the Agent's database, create tables, and query data, just as you would with Durable Objects or D1.
You can combine the state and SQL APIs in your Agent with its ability to call AI models to include historical context within your prompts to a model. Modern Large Language Models (LLMs) often have very large context windows (up to millions of tokens), which allows you to pull relevant context into your prompt directly.
For example, you can use an Agent's built-in SQL database to pull history, query a model with it, and append to that history ahead of the next call to the model:
export class ReasoningAgent extends Agent { async callReasoningModel(prompt) { let result = this .sql`SELECT * FROM history WHERE user = ${prompt.userId} ORDER BY timestamp DESC LIMIT 1000`; let context = []; for await (const row of result) { context.push(row.entry); }
const client = new OpenAI({ apiKey: this.env.OPENAI_API_KEY, });
// Combine user history with the current prompt const systemPrompt = prompt.system || "You are a helpful assistant."; const userPrompt = `${prompt.user}\n\nUser history:\n${context.join("\n")}`;
try { const completion = await client.chat.completions.create({ model: this.env.MODEL || "o3-mini", messages: [ { role: "system", content: systemPrompt }, { role: "user", content: userPrompt }, ], temperature: 0.7, max_tokens: 1000, });
// Store the response in history this .sql`INSERT INTO history (timestamp, user, entry) VALUES (${new Date()}, ${prompt.userId}, ${completion.choices[0].message.content})`;
return completion.choices[0].message.content; } catch (error) { console.error("Error calling reasoning model:", error); throw error; } }}
export class ReasoningAgent extends Agent<Env> { async callReasoningModel(prompt: Prompt) { let result = this .sql<History>`SELECT * FROM history WHERE user = ${prompt.userId} ORDER BY timestamp DESC LIMIT 1000`; let context = []; for await (const row of result) { context.push(row.entry); }
const client = new OpenAI({ apiKey: this.env.OPENAI_API_KEY, });
// Combine user history with the current prompt const systemPrompt = prompt.system || "You are a helpful assistant."; const userPrompt = `${prompt.user}\n\nUser history:\n${context.join("\n")}`;
try { const completion = await client.chat.completions.create({ model: this.env.MODEL || "o3-mini", messages: [ { role: "system", content: systemPrompt }, { role: "user", content: userPrompt }, ], temperature: 0.7, max_tokens: 1000, });
// Store the response in history this .sql`INSERT INTO history (timestamp, user, entry) VALUES (${new Date()}, ${prompt.userId}, ${completion.choices[0].message.content})`;
return completion.choices[0].message.content; } catch (error) { console.error("Error calling reasoning model:", error); throw error; } }}
This works because each instance of an Agent has its own database, the state stored in that database is private to that Agent: whether it's acting on behalf of a single user, a room or channel, or a deep research tool. By default, you don't have to manage contention or reach out over the network to a centralized database to retrieve and store state.
- Review the API documentation for the Agents class to learn how to define them.
- Build a chat Agent using the Agents SDK and deploy it to Workers.
- Learn more using WebSockets to build interactive Agents and stream data back from your Agent.
- Orchestrate asynchronous workflows from your Agent by combining the Agents SDK and Workflows.
- @2025 Cloudflare Ubitools
- Cf Repo