了解如何从 Workers 调用您的 Agents,包括如何即时创建 Agents、寻址它们以及将请求路由到 Agent 的特定实例。
Agents 是即时创建的,可以并发处理多个请求。每个 Agent 实例与其他实例隔离,可以维护自己的状态,并有唯一的地址。
您可以使用以下方式之一直接从 Worker 创建和运行 Agent 实例:
routeAgentRequest
助手:这将基于/agents/:agent/:name
URL 模式自动将请求映射到单个 Agent。:agent
的值将是您的 Agent 类名转换为kebab-case
,:name
的值将是您想要创建或检索的 Agent 实例的名称。getAgentByName
,如果该名称不存在 Agent 实例,它将创建一个新的 Agent 实例,或检索现有实例的句柄。
查看以下示例中的使用模式:
import { Agent, AgentNamespace, getAgentByName, routeAgentRequest,} from "agents";
export default { async fetch(request, env, ctx) { // 路由寻址 // 自动将 HTTP 请求和/或 WebSocket 连接路由到 /agents/:agent/:name // 最适合:使用 agents/react 的 useAgent 将 React 应用直接连接到 Agents return ( (await routeAgentRequest(request, env)) || Response.json({ msg: "no agent here" }, { status: 404 }) );
// 命名寻址 // 最适合:通过名称/ID 创建或检索 Agent 的便利方法。 // 带上您自己的路由、中间件和/或插入现有的 // 应用程序或框架。 let namedAgent = getAgentByName(env.MyAgent, "my-unique-agent-id"); // 将传入请求直接传递给您的 Agent let namedResp = (await namedAgent).fetch(request); return namedResp; },};
export class MyAgent extends Agent { // 您的 Agent 实现在这里}
import { Agent, AgentNamespace, getAgentByName, routeAgentRequest,} from "agents";
interface Env { // 在环境中定义您的 Agent // 将您的 Agent 类作为 TypeScript 类型参数传递,允许您调用 // 在您的 Agent 上定义的方法。 MyAgent: AgentNamespace<MyAgent>;}
export default { async fetch(request, env, ctx): Promise<Response> { // 路由寻址 // 自动将 HTTP 请求和/或 WebSocket 连接路由到 /agents/:agent/:name // 最适合:使用 agents/react 的 useAgent 将 React 应用直接连接到 Agents return ( (await routeAgentRequest(request, env)) || Response.json({ msg: "no agent here" }, { status: 404 }) );
// 命名寻址 // 最适合:通过名称/ID 创建或检索 Agent 的便利方法。 // 带上您自己的路由、中间件和/或插入现有的 // 应用程序或框架。 let namedAgent = getAgentByName<Env, MyAgent>( env.MyAgent, "my-unique-agent-id", ); // 将传入请求直接传递给您的 Agent let namedResp = (await namedAgent).fetch(request); return namedResp; },} satisfies ExportedHandler<Env>;
export class MyAgent extends Agent<Env> { // 您的 Agent 实现在这里}
使用 getAgentByName
时,您可以传递请求(包括 WebSocket)连接,并使用原生 JavaScript RPC(JSRPC)API 调用直接在 Agent 本身上定义的方法。
例如,一旦您有了 Agent 唯一实例的句柄(或"存根"),您可以在其上调用方法:
import { Agent, AgentNamespace, getAgentByName } from "agents";
export default { async fetch(request, env, ctx) { let namedAgent = getAgentByName(env.MyAgent, "my-unique-agent-id"); // 直接在 Agent 上调用方法,并传递原生 JavaScript 对象 let chatResponse = namedAgent.chat("你好!"); // 无需从 HTTP 请求或 WebSocket 序列化/反序列化 // 消息然后再返回 let agentState = getState(); // agentState 的类型是 UserHistory return namedResp; },};
export class MyAgent extends Agent { // 您的 Agent 实现在这里 async chat(prompt) { // 调用您喜欢的 LLM return "result"; }
async getState() { // 直接返回 Agent 的状态 return this.state; }
// 根据需要的其他方法!}
import { Agent, AgentNamespace, getAgentByName } from "agents";
interface Env { // 在环境中定义您的 Agent // 将您的 Agent 类作为 TypeScript 类型参数传递,允许您调用 // 在您的 Agent 上定义的方法。 MyAgent: AgentNamespace<MyAgent>;}
interface UserHistory { history: string[]; lastUpdated: Date;}
export default { async fetch(request, env, ctx): Promise<Response> { let namedAgent = getAgentByName<Env, MyAgent>( env.MyAgent, "my-unique-agent-id", ); // 直接在 Agent 上调用方法,并传递原生 JavaScript 对象 let chatResponse = namedAgent.chat("你好!"); // 无需从 HTTP 请求或 WebSocket 序列化/反序列化 // 消息然后再返回 let agentState = getState(); // agentState 的类型是 UserHistory return namedResp; },} satisfies ExportedHandler<Env>;
export class MyAgent extends Agent<Env, UserHistory> { // 您的 Agent 实现在这里 async chat(prompt: string) { // 调用您喜欢的 LLM return "result"; }
async getState() { // 直接返回 Agent 的状态 return this.state; }
// 根据需要的其他方法!}
使用 TypeScript 时,确保将您的 Agent 类作为 TypeScript 类型参数传递给 AgentNamespace 类型,以便正确推断类型:
interface Env { // 将您的 Agent 类作为 TypeScript 类型参数传递,允许您调用 // 在您的 Agent 上定义的方法。 MyAgent: AgentNamespace<CodeReviewAgent>;}
export class CodeReviewAgent extends Agent<Env, AgentState> { // Agent 方法在这里}
为您的 Agents 创建名称时,考虑 Agent 代表什么。一个唯一的用户?一个团队或公司?用于协作的房间或频道?
一致的命名方法允许您:
- 将传入请求直接定向到正确的 Agent
- 确定性地将新请求路由回该 Agent,无论客户端在世界的哪个地方。
- 避免依赖集中式会话存储或外部服务进行状态管理,因为每个 Agent 实例可以维护自己的状态。
对于给定的 Agent 定义(或下面代码中的"命名空间"),可以有数百万(或数千万)个该 Agent 的实例,每个都处理自己的请求、调用 LLM 并维护自己的状态。
例如,您可能为每个使用新的基于 AI 的代码编辑器的用户拥有一个 Agent。在这种情况下,您希望基于系统中的用户 ID 创建 Agents,这将允许该 Agent 处理该用户的所有请求。
它还确保 Agent 内的状态,包括聊天历史、语言偏好、模型配置和其他上下文可以与该用户特别关联,使状态管理变得更容易。
以下示例显示如何为请求中的每个 userId
创建唯一的 Agent:
import { Agent, AgentNamespace, getAgentByName, routeAgentRequest,} from "agents";
export default { async fetch(request, env, ctx) { let userId = new URL(request.url).searchParams.get("userId") || "anonymous"; // 使用允许您路由到请求、WebSockets 或在 Agent 上调用方法的标识符 // 您也可以在这里放置身份验证逻辑 - 例如,仅为已知用户创建或检索 Agents。 let namedAgent = getAgentByName(env.MyAgent, "my-unique-agent-id"); return (await namedAgent).fetch(request); },};
export class MyAgent extends Agent { // 您可以在 Agent 内的任何方法中通过 this.name 访问 Agent 的名称 async onStartup() { console.log(`agent ${this.name} ready!`); }}
import { Agent, AgentNamespace, getAgentByName, routeAgentRequest,} from "agents";
interface Env { MyAgent: AgentNamespace<MyAgent>;}
export default { async fetch(request, env, ctx): Promise<Response> { let userId = new URL(request.url).searchParams.get("userId") || "anonymous"; // 使用允许您路由到请求、WebSockets 或在 Agent 上调用方法的标识符 // 您也可以在这里放置身份验证逻辑 - 例如,仅为已知用户创建或检索 Agents。 let namedAgent = getAgentByName<Env, MyAgent>( env.MyAgent, "my-unique-agent-id", ); return (await namedAgent).fetch(request); },} satisfies ExportedHandler<Env>;
export class MyAgent extends Agent<Env> { // 您可以在 Agent 内的任何方法中通过 this.name 访问 Agent 的名称 async onStartup() { console.log(`agent ${this.name} ready!`); }}
根据您的 Agents 目标,将 userId
替换为 teamName
、channel
、companyName
- 和/或配置身份验证以确保仅为已知的、经过身份验证的用户创建 Agents。
使用 Agents SDK 构建和部署 Agents 时,您通常希望在将请求传递给 Agent 之前验证客户端,以便限制 Agent 将调用谁、为特定 Agents 授权特定用户,和/或限制谁可以访问 Agent 公开的管理或调试 API。
作为最佳实践:
- 在调用 Agent 之前,在您的 Workers 代码中处理身份验证。
- 使用
routeAgentRequest
助手时使用内置钩子 -onBeforeConnect
和onBeforeRequest
- 在使用其他方法调用 Agent 之前,使用您首选的路由器(如 Hono)和身份验证中间件或提供商来应用自定义身份验证方案。
本指南前面记录的 routeAgentRequest
助手公开了两个有用的钩子(onBeforeConnect
、onBeforeRequest
),允许您在创建或检索 Agent 之前应用自定义逻辑:
import { Agent, AgentNamespace, routeAgentRequest } from "agents";
export default { async fetch(request, env, ctx) { // Use the onBeforeConnect and onBeforeRequest hooks to authenticate clients // or run logic before handling a HTTP request or WebSocket. return ( (await routeAgentRequest(request, env, { // Run logic before a WebSocket client connects onBeforeConnect: (request) => { // Your code/auth code here // You can return a Response here - e.g. a HTTP 403 Not Authorized - // which will stop further request processing and will NOT invoke the // Agent. // return Response.json({"error": "not authorized"}, { status: 403 }) }, // Run logic before a HTTP client clients onBeforeRequest: (request) => { // Your code/auth code here // Returning nothing will result in the call to the Agent continuing }, // Prepend a prefix for how your Agents are named here prefix: "name-prefix-here", })) || Response.json({ msg: "no agent here" }, { status: 404 }) ); },};
import { Agent, AgentNamespace, routeAgentRequest } from "agents";
interface Env { MyAgent: AgentNamespace<MyAgent>;}
export default { async fetch(request, env, ctx): Promise<Response> { // Use the onBeforeConnect and onBeforeRequest hooks to authenticate clients // or run logic before handling a HTTP request or WebSocket. return ( (await routeAgentRequest(request, env, { // Run logic before a WebSocket client connects onBeforeConnect: (request) => { // Your code/auth code here // You can return a Response here - e.g. a HTTP 403 Not Authorized - // which will stop further request processing and will NOT invoke the // Agent. // return Response.json({"error": "not authorized"}, { status: 403 }) }, // Run logic before a HTTP client clients onBeforeRequest: (request) => { // Your code/auth code here // Returning nothing will result in the call to the Agent continuing }, // Prepend a prefix for how your Agents are named here prefix: "name-prefix-here", })) || Response.json({ msg: "no agent here" }, { status: 404 }) ); },} satisfies ExportedHandler<Env>;
如果使用 getAgentByName
或底层 Durable Objects 路由 API,则应在调用 getAgentByName
之前验证传入请求或 WebSocket 连接。
例如,如果您使用 Hono ↗,您可以在调用 Agent 之前在中间件中进行身份验证:
import { Agent, AgentNamespace, getAgentByName } from "agents";import { Hono } from "hono";
const app = new Hono();
app.use("/code-review/*", async (c, next) => { // Perform auth here // e.g. validate a Bearer token, a JWT, use your preferred auth library // return Response.json({ msg: 'unauthorized' }, { status: 401 }); await next(); // continue on if valid});
app.get("/code-review/:id", async (c) => { const id = c.req.param("teamId"); if (!id) return Response.json({ msg: "missing id" }, { status: 400 });
// Call the Agent, creating it with the name/identifier from the ":id" segment // of our URL const agent = await getAgentByName(c.env.MyAgent, id);
// Pass the request to our Agent instance return await agent.fetch(c.req.raw);});
import { Agent, AgentNamespace, getAgentByName } from "agents";import { Hono } from "hono";
const app = new Hono<{ Bindings: Env }>();
app.use("/code-review/*", async (c, next) => { // Perform auth here // e.g. validate a Bearer token, a JWT, use your preferred auth library // return Response.json({ msg: 'unauthorized' }, { status: 401 }); await next(); // continue on if valid});
app.get("/code-review/:id", async (c) => { const id = c.req.param("teamId"); if (!id) return Response.json({ msg: "missing id" }, { status: 400 });
// Call the Agent, creating it with the name/identifier from the ":id" segment // of our URL const agent = await getAgentByName<Env, MyAgent>(c.env.MyAgent, id);
// Pass the request to our Agent instance return await agent.fetch(c.req.raw);});
这确保我们仅创建已验证用户的 Agents,并允许您验证 Agent 名称是否符合您首选的命名方案,然后再创建实例。
- 查看 API 文档 以了解如何定义
- 构建聊天 Agent 使用 Agents SDK 并将其部署到 Workers。
- 了解如何使用 WebSockets 构建交互式 Agents 并从您的 Agent 流式传输数据。
- 或组织异步工作流 从您的 Agent 通过组合 Agents SDK 和 工作流。
- @2025 Cloudflare Ubitools
- Cf Repo