ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Gemini CLI 跑 A2A 任务编排:Key 用 TaoToken

Gemini CLI 跑 A2A 任务编排:Key 用 TaoToken 1. 四个 Agent 准备开跑先想清楚 API 配额从哪来把 Gemini CLI 部署成 A2A Server再用 a2a-js/sdk 把前端、后端、数据库、测试四个专长 Agent 串成一条流水线这个思路在 A2A 协议解析里看很顺真跑起来最先卡住你的不是协议而是「这批会话到底烧谁的额度」。A2A 工作流和普通对话不一样每个 Agent 都是一段持续数分钟的长会话中间还有工具调用、状态回传、失败重试模型 API 的消耗是叠加的。手里攒着好几个官方 Key 的时候有的快用完有的还没拆封切来切去反而把责任田搞乱了。我这次把整条 A2A 工作流的模型 API 统一收口到 TaoToken先打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建一把 API Key再把 A2A Server 进程里的模型端点指到 https://taotoken.net/api同一把 Key 就能支撑四个 Agent 的并发会话与工具调用调用记录也集中在一处可对账。1.1 长会话 多工具协作烧额度的方式和普通对话不一样A2A 的任务编排里一个 Agent 的一次任务可能包含好几轮 LLM 生成每轮生成之间还要穿插 MCP 工具调用。以原文第 4 章的全栈应用案例为例databaseAgent 先设计 schemabackendAgent 基于 schema 构建 REST APIfrontendAgent 再连 API 写 React 页面testAgent 最后补端到端测试。任何一个 Agent 卡在工具调用上重试都会额外消耗模型 token。更麻烦的是这类长任务不会在一次对话里结束你随时可能因为一个字段没对齐把某个 Agent 的会话重新拉起之前的调用次数又叠加一次。官方 Key 分散在不同账号下想在事后判断「这次工作流到底花了多少」非常困难。1.2 TaoToken 统一收口一把 Key 管住所有 Agent 的模型调用TaoToken 的定位是统一 API 通道不是另起一套协议。A2A 负责 Agent 与 Agent 之间的通信MCP 负责 Agent 与工具之间的通信TaoToken 只解决其中「模型 API Key 从哪来、去哪个端点调」这一层。每个 Agent 的会话最终都要走到模型推理把推理端点统一指向 TaoToken 之后四个 Agent 共用 YOUR_API_KEYAPI 调用记录也会统一出现在 TaoToken 控制台。这样你在排查「哪个 Agent 烧了最多额度」时不需要再翻四个平台的账单。2. 先把 A2A 的三个核心概念落成代码文件原文第 4 章把 A2A 拆成 AgentCard、Task 状态机、EventBus 三块动手配置之前我建议先把这三个概念落成三个小文件后面部署 A2A Server 才不会对着源码发懵。A2A 的代码结构并不复杂难的是理解「状态流转」和「事件广播」这两件事它们直接决定了你之后看到任务卡住时怎么定位问题。2.1 AgentCard每个 Agent 的身份和能力声明AgentCard 相当于每个 Agent 贴在大门上的一份简历告诉别人「我叫什么、能做什么、支持哪些能力」。原文给的 AgentCard 里name、url、protocolVersion、capabilities、skills 是必填字段。capabilities 里最值得关注的是streaming和stateTransitionHistory前者决定客户端能不能通过 SSE 实时收到中间状态后者决定能不能翻看任务从 submitted 到 completed 的完整变迁记录。长任务编排场景下这两个能力最好都打开否则任务跑一半你只能干等最终结果。const agentCard { name: Gemini SDLC Agent, description: Full-stack development agent with streaming support, url: http://localhost:41242/, protocolVersion: 0.3.0, capabilities: { streaming: true, pushNotifications: false, stateTransitionHistory: true }, skills: [ { id: code_generation, name: Code Generation, description: Generate code from natural language, tags: [code, development] } ] };2.2 Task 状态机与 EventBus长任务不再裸等A2A 定义了六种 Task 状态submitted、working、input-required、completed、failed、canceled。状态流转的核心路径是submitted - working - input-required - working - completed其中input-required是一个很关键的中间态当 Agent 需要用户确认工具调用、或者需要补充额外输入时任务会停在input-required而不是直接失败。这个设计让长任务有了「暂停 - 恢复」的能力而不像普通 HTTP 请求那样只能等最终响应。EventBus 则是整条流水线的消息中枢。Agent 的状态变化、工具调用的开始与结束、LLM 生成的文本片段都会以事件的形式经过 EventBus 推给客户端。原文里 EventBus 同时维护本地监听器和 SSE 客户端列表本地监听器供同进程的其它组件消费SSE 供远程客户端实时刷新页面。写排障脚本时只需要订阅state-change和tool-call-update两类事件就能把任务卡住的环节定位到具体是模型生成慢、还是某个工具调用一直 pending。eventBus.publish({ kind: state-change, taskId, oldState: working, newState: input-required, timestamp: Date.now() });3. 把 Gemini CLI 部署成 A2A Server模型端点指向 TaoToken原文第 6.2 节给出了一个很简洁的 A2A Server 启动方式用a2a-js/sdk/server/express里的A2AExpressApp挂到 Express 的/api路由上监听 41242 端口。真实环境下这一步之前要先解决模型 API 配置否则 Gemini CLI 拉起的 A2A Server 不知道去哪个端点、用哪把 Key 调模型。3.1 从官网拿 Key再设置三个环境变量先打开 TaoToken 注册并创建 API Key复制后填到下面的YOUR_API_KEY。A2A Server 进程里需要一个 Gemini 兼容的模型客户端关键是让这个客户端读出你配置的三个变量Key、Base URL、模型 ID。Base URL 填 https://taotoken.net/api注意末尾不要带/v1。export GEMINI_API_KEYYOUR_API_KEY export GEMINI_BASE_URLhttps://taotoken.net/api export GEMINI_MODEL以TaoToken模型广场列表为准这三个环境变量不是只对单个请求生效A2A Server 启动后四个 Agent 共用同一个进程环境所以它们在后续所有长会话里都会被自动继承。之前用官方 Key 时每个 Key 的配额单独计算多 Agent 并发会话经常出现某个 Key 触发限流统一指向 TaoToken 之后模型 ID 也可以按模型广场当前列表直接切换不用再改代码里的硬编码。3.2 启动 A2A Express 服务环境变量就位后按原文的思路启动服务。requestHandler是处理 A2A 请求的核心回调它内部会通过 Gemini CLI 的模型客户端发送消息流并把工具调用事件抛给 EventBus。这里保留原文的 Express 挂载方式端口仍用 41242。import express from express; import { A2AExpressApp } from a2a-js/sdk/server/express; const app express(); const a2aApp new A2AExpressApp(requestHandler); a2aApp.setupRoutes(app, /api); app.listen(41242, () { console.log(Gemini A2A Server running on http://localhost:41242); });启动后其它 Agent 通过http://localhost:41242/api就能找到这个 Server。注意agentUrl要带上/api路径这是 A2A Express 路由的固定前缀漏掉它会直接连不上。3.3 MCP 工具层保持原样A2A 和 MCP 不是替代关系A2A 负责 Agent 之间的协作MCP 依然是 Agent 调用外部工具的标准层。原文第 4.2 节展示了 A2A Server 内部如何初始化多个 MCP Client并把工具的 qualified name 注册到任务里。这部分配置不需要因为引入 TaoToken 而改动~/.gemini/settings.json里的 MCP Server 配置原样保留即可。TaoToken 只管模型 API 这一层工具调用仍然走本地的 MCP Server这样职责清晰排查问题时也容易分边。4. 用 a2a-js/sdk 编排四个 Agent 的全栈应用工作流A2A Server 跑起来只是第一步真正体现价值的是用a2a-js/sdk把多个 Agent 编排成一条带依赖关系的流水线。原文第 4.3 节的全栈电商应用案例是很好的参照数据库、后端、前端、测试四个角色分工明确每个 Agent 负责自己擅长的部分依赖关系由编排器统一管理。4.1 定义专业 Agent 团队先用createAgent创建四个 Agent每个 Agent 通过agentUrl指向各自的 A2A Server。如果四个 Agent 跑在同一台机器上端口需要区分开如果分散在不同机器agentUrl换成对应机器的地址即可。skills数组用来声明这个 Agent 擅长什么编排器在做任务分配时会把任务描述和技能列表做匹配。import { createAgent, AgentOrchestrator } from a2a-js/sdk; const agents { frontendAgent: await createAgent({ name: Frontend Specialist, agentUrl: http://localhost:8001/api, skills: [react, typescript, css] }), backendAgent: await createAgent({ name: Backend Specialist, agentUrl: http://localhost:8002/api, skills: [nodejs, express, api-design] }), databaseAgent: await createAgent({ name: Database Specialist, agentUrl: http://localhost:8003/api, skills: [postgresql, schema-design, migrations] }), testAgent: await createAgent({ name: QA Specialist, agentUrl: http://localhost:8004/api, skills: [jest, e2e-testing] }) }; const orchestrator new AgentOrchestrator(agents);4.2 定义带依赖关系的工作流工作流的定义核心是steps数组里每个步骤的dependencies字段。这里的设计思路是数据库 schema 设计是所有任务的地基后端 API 依赖 schema前端依赖 API测试依赖前端和后端都完成。原文用{{ steps.design-schema.result.schema }}这样的模板语法把上一步的输出传给下一步实际运行时编排器会解析模板并注入真实结果。const workflow orchestrator.defineWorkflow({ name: Build E-Commerce App, steps: [ { id: design-schema, agent: databaseAgent, task: 设计电商应用的数据库 schema包括用户、产品、订单表, dependencies: [] }, { id: create-migrations, agent: databaseAgent, task: 根据 schema 生成数据库迁移文件, dependencies: [design-schema] }, { id: build-api, agent: backendAgent, task: 基于数据库 schema 构建 REST API包括 CRUD 和认证, dependencies: [design-schema], inputs: { schema: {{ steps.design-schema.result.schema }} } }, { id: build-frontend, agent: frontendAgent, task: 构建 React 前端连接到后端 API, dependencies: [build-api], inputs: { apiSpec: {{ steps.build-api.result.openapi }} } }, { id: write-tests, agent: testAgent, task: 编写端到端测试, dependencies: [build-frontend, build-api] } ] });注意这里的 databaseAgent 只负责「生成 schema 和迁移文件」不会直接连接生产数据库执行 SQL。迁移文件生成后由你在本地数据库或 SQL*Plus 里执行再把结果贴回对话。这样做既符合 A2A 的定位也避免 Agent 越权操作真实数据。4.3 监听事件并等待完成执行工作流时execution.on可以在每个步骤的不同阶段挂上回调。这比等到所有任务跑完再看结果要实用得多A2A 的 EventBus 会实时推送状态你可以在前端页面上显示“当前正在执行哪个 Agent 的哪个步骤”也可以在某个步骤失败时立即止损而不是等整条流水线跑完才发现中间断了。const execution await orchestrator.execute(workflow); execution.on(step-started, ({ stepId, agent }) { console.log(${agent} 开始工作: ${stepId}); }); execution.on(step-completed, ({ stepId, result, duration }) { console.log(${stepId} 完成耗时 ${duration}ms); }); execution.on(error, ({ stepId, error }) { console.error(${stepId} 失败: ${error.message}); }); const finalResult await execution.complete(); console.log(全部完成总耗时 ${finalResult.totalDuration}ms);长会话场景下如果某个步骤超过 30 秒还没有反馈优先去 A2A Server 的日志里看 EventBus 是否还在推working状态以及模型 API 的调用是否超时重试。你在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 控制台可以对照这一步大概消耗了多少 token再决定是换更大的模型还是把任务拆细。5. 跑完去控制台对一次调用记录再处理两类报错A2A 工作流跑通一次后别急着庆祝先在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的用量页确认这次编排的调用记录都在再去排查刚才可能遇到的报错。统一 API 通道最大的好处就在这一步以前四个官方 Key 的消耗数据分散在四个地方现在所有 Agent 的模型调用在同一个控制台里按时间倒序排列你可以对应到 workflow 里每个 step 的执行时间一眼看出哪个 Agent 是调用大户。5.1 去 TaoToken 控制台核对调用配置保存后先在 TaoToken 模型对话 里用同一把 Key 发一条测试消息确认模型 ID 和 Base URL 没填错。若要长期跑 A2A 流水线可以打开 Coding Plan 看套餐是否够用新 Key 在 控制台 API Keys 创建每个 Agent 可以分配不同的 Key方便后期做最小权限管理。5.2 常见报错task 一直 working、模型 404我在本地跑这套 A2A 工作流时遇到两类报错都和配置直接相关。第一类是 task 状态长期停在working控制台也没有新的 model 调用记录。这种情况通常是 EventBus 正常推送了开始事件但工具调用环节shouldConfirmTool返回了需要用户确认而没有人响应input-required状态。解决办法是在 orchestration 层加上自动确认策略对于只读操作和文件读取类工具设为自动批准写操作才要求人工确认。第二类是模型 API 返回 404。这种大多是 Base URL 末尾多了/v1A2A Server 内部的模型客户端拼 URL 时用了完整路径你再补一个/v1就拼重了。把环境变量里的GEMINI_BASE_URL改回 https://taotoken.net/api然后重启 A2A Server。还有一种是模型 ID 写死成文档里的旧 ID但模型广场当前列表里已经没有这个 ID 了重新去模型广场确认当前可用 ID 再填。跑通之后这套 A2A 编排就很顺手了。后续如果要加新 Agent只需要在createAgent里加一段配置再在工作流的 steps 里声明依赖关系模型 API 不需要再额外申请 Key。调用记录继续在 TaoToken 控制台统一核对额度不够时直接在 Coding Plan 里调整不用再逐个平台去充值。
返回列表