ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

在 Cloudflare Agents 上构建 A2A 协议服务器:Agent Card 发现、JSON-RPC 传输与 SSE 流式示例全解析

在 Cloudflare Agents 上构建 A2A 协议服务器:Agent Card 发现、JSON-RPC 传输与 SSE 流式示例全解析 在 Cloudflare Agents 上构建 A2A 协议服务器Agent Card 发现、JSON-RPC 传输与 SSE 流式示例全解析【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents本教程以examples/a2a示例为蓝本讲解如何把一个基于 Cloudflare Agents 框架构建的 AI Agent 暴露为标准 A2AAgent-to-Agent协议服务器并配套一个浏览器端的 A2A 客户端 UI。读完本文你将掌握 A2A Agent Card 发现机制、基于a2a-js/sdk的 JSON-RPC 传输与 SSE 流式推送、以及用 Durable Object SQLite 持久化任务状态的完整实战方案。示例概览Cloudflare Agent 如何成为 A2A 服务器examples/a2a是 Cloudflare Agents 仓库中一个端到端的 A2A 示例它的核心思路非常清晰复用 SDK 而不是手写协议。服务器端使用a2a-js/sdk提供的DefaultRequestHandler与JsonRpcTransportHandler组装协议处理链开发者只需要关心两件事——任务怎么执行实现AgentExecutor和任务状态存哪里实现TaskStore。该示例集中展示了以下五项能力与 README 一一对应Agent Card 发现在/.well-known/agent-card.json提供标准化的 Agent 元数据协议版本、能力、技能、端点 URL 等任何 A2A 客户端都能先发现、再交互JSON-RPC 传输通过a2a-js/sdk服务器端实现message/send与message/stream两种方法SSE 流式推送message/stream的返回以text/event-stream形式实时推送任务状态更新用户能看到提交 → 工作中 → 完成的全过程DO-backed TaskStore使用 Durable Object SQLite 作为任务持久化存储任务状态跨请求可恢复Workers AI 真实推理AI 响应由 Cloudflare Workers AI 提供Agent Card 描述中标注为 GLM 4.7 Flash而server.ts源码实际调用的是cf/moonshotai/kimi-k2.7-code模型。快速运行三行命令跑通完整链路在examples/a2a目录下执行npm install npm startnpm start实际运行的是vite dev见 package.json通过cloudflare/vite-plugin在本地同时拉起 Worker 与前端静态资源。启动后打开 http://localhost:5173 即可使用聊天 UI。任何 A2A 客户端都可以先通过 Agent Card 发现这个 Agentcurl http://localhost:5173/.well-known/agent-card.json该端点同时支持.well-known/agent-card.json与.well-known/agent.json两个路径见 server.ts返回的 Agent Card 带有Access-Control-Allow-Origin: *头便于跨域客户端读取。Agent Card 中的url字段指向http://localhost:5173/a2a即 JSON-RPC 端点。生产部署使用npm run deploy等价于vite build wrangler deploy。关键模式DefaultRequestHandler AgentExecutor不手写协议这是整个示例最值得借鉴的设计。A2A 协议本身包含 JSON-RPC 信封、方法分发、参数校验、SSE 流式封装等一系列样板逻辑手写很容易出错。示例直接使用 SDK 的服务器端组件把协议层与业务层解耦const handler new DefaultRequestHandler(agentCard, taskStore, executor); const transport new JsonRpcTransportHandler(handler);DefaultRequestHandler接收三个参数Agent Card协议元数据、TaskStore任务持久化实现、AgentExecutor实际执行任务的业务逻辑。它负责解析 JSON-RPC 请求、分发到message/send/message/stream/message/cancel等方法JsonRpcTransportHandler负责处理 JSON-RPC 2.0 信封与序列化业务方只需实现AgentExecutor接口通过ExecutionEventBus发布生命周期事件。在 MyA2A 构造函数 中可以看到三者的组装方式export class MyA2A extends AgentEnv { constructor(ctx: DurableObjectState, env: Env) { super(ctx, env); const taskStore new DurableObjectTaskStore(ctx.storage.sql); const executor new AIAgentExecutor(() this.env); this.handler new DefaultRequestHandler(agentCard, taskStore, executor); this.transport new JsonRpcTransportHandler(this.handler); } }MyA2A继承自agents框架的AgentEnv基类因此天然具备 Durable Object 的持久化能力ctx.storage.sql可以直接拿来做任务存储。AgentExecutor用事件总线表达任务生命周期AIAgentExecutor完整展示了 A2A 任务的状态机流转。它利用ExecutionEventBus依次发布submitted→working→ AI 响应消息→completed事件class AIAgentExecutor implements AgentExecutor { async execute(ctx: RequestContext, bus: ExecutionEventBus) { // 新任务先发布 submitted 状态 if (!task) { bus.publish({ id: taskId, contextId, history: [userMessage], kind: task, status: { state: submitted, timestamp: ... } }); } // 发布 working 状态 bus.publish({ kind: status-update, status: { state: working, ... }, ... }); // 调用 Workers AI const result await generateText({ model, messages }); // 发布 agent 回复消息 bus.publish({ kind: message, role: agent, parts: [{ kind: text, text: result.text }], ... }); // 发布 completed 状态final: true携带回复消息 bus.publish({ kind: status-update, final: true, status: { state: completed, message: responseMessage }, ... }); bus.finished(); } cancelTask async (): Promisevoid {}; }要点在于status-update事件的final: true标记任务终结同时可携带message字段把最终回复一并推送bus.finished()通知执行流结束。cancelTask在示例中是空实现生产环境中应在此实现任务取消逻辑。AI 调用workers-ai-provider Vercel AI SDKAI 推理部分没有直接调用 Workers AI 的 REST API而是用workers-ai-provider把它适配为 Vercel AI SDK 的模型接口再交给generateTextconst workersai createWorkersAI({ binding: this.getEnv().AI }); const result await generateText({ model: workersai(cf/moonshotai/kimi-k2.7-code), instructions: You are a helpful AI assistant. Keep responses concise and clear., messages: [{ role: user, content: userText }] });用户消息中的文本通过过滤parts中kind text的部分拼接而成见 server.ts这也体现了 A2AMessage多模态 parts 结构的使用方式。任务持久化Durable Object SQLite 版 TaskStoreA2A 协议要求任务状态可查询、可恢复因此TaskStore必须有真实的存储后端。示例给出了一个仅 20 余行的最小实现DurableObjectTaskStore见 server.ts直接构建在 Durable Object 的 SQLite 之上class DurableObjectTaskStore implements TaskStore { constructor(private sql: SqlStorage) { this.sql.exec( CREATE TABLE IF NOT EXISTS a2a_tasks ( id TEXT PRIMARY KEY, data TEXT NOT NULL ) ); } async save(task: Task): Promisevoid { this.sql.exec( INSERT OR REPLACE INTO a2a_tasks (id, data) VALUES (?, ?), task.id, JSON.stringify(task) ); } async load(taskId: string): PromiseTask | undefined { const rows [...this.sql.exec(SELECT data FROM a2a_tasks WHERE id ?, taskId)]; if (rows.length 0) return undefined; return JSON.parse(rows[0].data as string) as Task; } }整个 Task 对象被整体序列化为 JSON 存入单表id为主键、INSERT OR REPLACE实现幂等更新。schema 在构造函数中通过CREATE TABLE IF NOT EXISTS自举创建无需额外的迁移脚本。得益于 Durable Object 的持久化特性即使 Worker 重启任务状态也能从 SQLite 中恢复——这正是 Agent Card 中stateTransitionHistory: true能力声明的基础。路由与传输Agent 内部如何分发请求MyA2A的onRequest方法是协议入口完整覆盖三条路径见 server.tsAgent Card 发现GET /.well-known/agent-card.json或/.well-known/agent.json返回handler.getAgentCard()CORS 预检OPTIONS请求返回允许POST, OPTIONS与Content-Type头的响应头JSON-RPC 端点POST请求交给transport.handle(body)。handle的返回值有两种情况需要分别处理非流式结果直接Response.json(result)返回异步可迭代结果message/stream的场景将异步生成器逐个事件编码为 SSE 格式id: ...\ndata: ...\n\n通过TransformStream以text/event-stream响应头返回并设置Cache-Control: no-cache防止中间层缓存。顶层 Worker 入口则负责把 A2A 相关路径路由到 Durable Object 实例export default { async fetch(request: Request, env: Env) { const url new URL(request.url); if (url.pathname.startsWith(/.well-known/) || url.pathname /a2a) { const agent await getAgentByName(env.MyA2A, default); return agent.fetch(request); } return new Response(Not found, { status: 404 }); } } satisfies ExportedHandlerEnv;getAgentByName是agents框架提供的路由助手实现位于 packages/agents/src/agent-routing.ts它根据命名空间与实例名返回初始化后的 Agent stub这里把 default 单例实例作为 A2A 服务器的承载者。其余请求直接 404静态资源则由 Vite 插件托管。浏览器端 A2A 客户端零 SDK 依赖的轻量实现client.tsx展示了一个不打包 SDK、直接用 fetch 实现的 A2A 客户端非常适合理解协议本质。整个客户端分为三层1. Agent Card 发现组件挂载后先请求同源的/.well-known/agent-card.jsonasync function fetchAgentCard(baseUrl: string): PromiseAgentCard { const res await fetch(${baseUrl}/.well-known/agent-card.json); if (!res.ok) throw new Error(Failed to fetch agent card: ${res.status}); return res.json(); }拿到 Agent Card 后UI 会渲染协议版本徽章、Streaming 能力徽章、skills 列表以及 JSON-RPC 端点 URL见 client.tsx。2. 非流式发送 message/sendsendMessage构造标准 JSON-RPC 2.0 信封调用message/send方法const res await fetch(url, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ jsonrpc: 2.0, id: crypto.randomUUID(), method: message/send, params: { message } }) });3. 流式接收 message/streamstreamMessage是一个异步生成器负责解析 SSE 流按\n\n切分事件块、提取data:前缀的 JSON 负载并将result字段逐个yield出去。由于 SSE 事件可能被 TCP 分片截断实现里维护了一个buffer变量处理粘包见 client.tsx。客户端根据 Agent Card 的capabilities.streaming决定走哪条路径支持流式时先用占位气泡展示 Thinking... 状态再随事件流不断刷新文本与状态徽章不支持时回退到message/send。流式事件中kind为messageagent 回复、status-update状态变更status.message可能携带最终回复、task完整任务对象三种类型都会被消费这也完整对应了服务器端ExecutionEventBus发布的事件种类。配置解读wrangler.jsonc 的四个关键点示例的 Worker 配置集中在 wrangler.jsonc理解它才能顺利部署到生产环境配置项值作用mainsrc/server.tsWorker 入口即上面导出的fetch与MyA2A类compatibility_date/compatibility_flags2026-06-11/[nodejs_compat]兼容性日期与 Node.js 兼容层a2a-js/sdk等依赖可能用到 Node APIai.bindingAIremote: true声明 Workers AI 绑定对应env.AI见 env.d.tsdurable_objects.bindings类名与绑定名均为MyA2A注册 Durable Object 命名空间migrationsnew_sqlite_classes: [MyA2A]tagv1声明 MyA2A 使用SQLite存储这是ctx.storage.sql可用的前提assetsSPA 模式 run_worker_first: [/.well-known/*, /a2a]静态资源走单页应用回退同时保证 A2A 相关路径优先由 WorkerDurable Object处理assets.run_worker_first尤其关键它保证/.well-known/*与/a2a的请求先进入 Worker 路由而不会命中前端 SPA 的回退页面。vite.config.ts中的cloudflare()插件见 vite.config.ts正是依赖这份配置在本地模拟上述运行时环境。与其他示例的衔接该示例与仓库中另一个 AI Chat 示例 形成对照后者使用cloudflare/ai-chat构建同类 AI Agent而 A2A 示例强调的是协议互操作性——遵循 A2A 标准的任意客户端不仅是本示例自带的 UI都能发现并调用该 Agent。当你需要把自己的 Agent 接入更大的 Agent 生态时本文的DefaultRequestHandler AgentExecutor DO TaskStore模式就是一条经过验证的实现路径。小结回顾整个示例值得沉淀的三个工程要点是第一协议逻辑交给 SDK业务方只实现AgentExecutor与TaskStore两个接口即可获得完整的 A2A 服务器能力第二任务生命周期通过事件总线显式表达submitted → working → completed的状态流转天然适配 SSE 实时推送第三Durable Object SQLite 作为默认持久层让任务状态具备跨请求的可恢复性同时new_sqlite_classes迁移声明让整个过程零额外基础设施。【免费下载链接】agentsBuild and deploy AI Agents on Cloudflare项目地址: https://gitcode.com/GitHub_Trending/agents1/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表