OmniRoute A2A Server 实战指南:把 OmniRoute 打造成可被任意 Agent 调用的智能路由 Agent
2026/9/24 18:51:04 网站建设 项目流程

OmniRoute A2A Server 实战指南:把 OmniRoute 打造成可被任意 Agent 调用的智能路由 Agent

【免费下载链接】OmniRouteNever stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoute

OmniRoute 内置了符合 Agent-to-Agent Protocol(A2A)v0.3 规范的 A2A Server,它把 OmniRoute 暴露为一个"智能路由 Agent":外部 Agent 通过标准的 JSON-RPC 2.0 协议调用smart-routingquota-management等技能,即可复用 OmniRoute 的模型路由、成本核算、配额管理与弹性回退能力。读完本文,你将掌握 A2A 端点的发现、鉴权、四大核心 RPC 方法、六大内置技能、任务生命周期与错误码,并能在 Python/TypeScript 中完成真实调用,还能按规范扩展自己的 A2A 技能。

本文以 docs/i18n/fr/docs/frameworks/A2A-SERVER.md(法文版)与 docs/frameworks/A2A-SERVER.md(英文原版)为主体,结合仓库源码(src/lib/a2a/src/app/a2a/)进行原理级佐证。

一、A2A Server 概览:双面接口

OmniRoute 的 A2A 面由两个互补的入口构成:

  • JSON-RPC 2.0 规范入口POST /a2a(规范入口,实现在src/app/a2a/route.ts),承载message/sendmessage/streamtasks/gettasks/cancel四个方法;
  • REST 辅助入口/api/a2a/*,为仪表盘和外部工具提供状态查询、任务列表、取消等辅助能力。

所有任务的追踪由A2ATaskManager负责(src/lib/a2a/taskManager.ts,默认 5 分钟 TTL),技能的调度则通过A2A_SKILL_HANDLERS注册表完成(src/lib/a2a/taskExecution.ts)。

二、Agent Discovery:发现 Agent Card

与其他 A2A Agent 一样,外部调用方首先通过 well-known 端点发现 OmniRoute 的能力声明:

curl http://localhost:20128/.well-known/agent.json

该端点返回描述 OmniRoute 能力、技能清单与鉴权要求的Agent Card。Agent Card 中的version字段取自process.env.npm_package_version,因此每次发布都会自动与package.json保持同步,无需手工维护版本号。

Agent Card 应始终与运行时 352+ 提供方目录保持一致,提供方数量与 free/no-auth 元数据均来自运行时注册表。

三、启用 A2A:默认关闭,需显式开启

A2A 由Endpoints → A2A开关控制,默认处于关闭状态。关闭时:

  • GET /api/a2a/status返回status: "disabled"online: false
  • POST /a2a的 JSON-RPC 调用返回 HTTP 503,并携带 JSON-RPC 错误码-32000(A2A endpoint is disabled)。

四、Authentication:Bearer API Key

所有/a2a请求都需要通过Authorization头携带 API Key:

Authorization: Bearer YOUR_OMNIROUTE_API_KEY

如果服务器上未配置任何 API Key,则鉴权被跳过(keyless 本地优先模式)。鉴权逻辑集中实现在 src/lib/a2a/authenticate.ts:

  1. REQUIRE_API_KEY特性开启,则校验请求携带的 key 是否为合法 OmniRoute key(isValidApiKey);
  2. 否则若配置了OMNIROUTE_API_KEY环境变量,则用timingSafeEqual做常量时间比较;
  3. 否则(既无要求也无配置)放行所有请求。

同时,resolveA2AOwner会对调用方的 API Key 做 SHA-256 哈希并截取前 32 位作为任务的 owner 标识(GHSA-jcm5-6wpp-wjj8),用于任务可见性隔离:带 owner 的任务只对同一 owner 可见,keyless 下产生的无主任务对所有调用方可见。tasks/gettasks/cancellistTasks均执行该 owner 作用域检查。

五、JSON-RPC 2.0 方法

所有方法统一走POST http://localhost:20128/a2a,请求体遵循 JSON-RPC 2.0 规范(jsonrpcidmethodparams)。

5.1message/send— 同步执行

向指定技能发送消息并等待完整响应:

curl -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Write a hello world in Python"}], "metadata": {"model": "auto", "combo": "fast-coding"} } }'

响应示例:

{ "jsonrpc": "2.0", "id": "1", "result": { "task": { "id": "uuid", "state": "completed" }, "artifacts": [{ "type": "text", "content": "..." }], "metadata": { "routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)", "cost_envelope": { "estimated": 0.005, "actual": 0.003, "currency": "USD" }, "resilience_trace": [ { "event": "primary_selected", "provider": "anthropic", "timestamp": "..." } ], "policy_verdict": { "allowed": true, "reason": "within budget and quota limits" } } } }

metadatasmart-routing技能的精华所在:routing_explanation解释选中了哪个模型与提供方,cost_envelope给出预估/实际成本,resilience_trace记录弹性回退事件,policy_verdict给出预算与配额策略裁决。

5.2message/stream— SSE 流式返回

message/send相同,但通过 Server-Sent Events 实时推送:

curl -N -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "message/stream", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Explain quantum computing"}] } }'

SSE 事件流:

data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"..."}}} : heartbeat 2026-03-03T17:00:00Z data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}

流式过程中会周期性发送: heartbeat ...注释行保活;A2ATaskManager内部通过beginStream()/endStream()跟踪活跃流数量(activeStreams),统计信息可通过getStats()获取。

5.3tasks/get— 查询任务状态

curl -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}'

底层由 src/lib/a2a/taskManager.ts 的getTask实现:读取时若发现任务已超过expiresAt且仍处于非终态,会先将其标记为failed("Task expired"),再按 owner 可见性过滤返回。

5.4tasks/cancel— 取消任务

curl -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}'

cancelTask在变更状态之前执行 owner 检查,且对"任务不存在"与"任务存在但不属于你"返回相同的 not-found 错误,防止 IDOR 探测。

六、Available Skills:六大内置技能

OmniRoute 通过 src/lib/a2a/taskExecution.ts 中的A2A_SKILL_HANDLERS注册了 6 个 A2A 技能,每个技能模块位于src/lib/a2a/skills/目录下:

技能ID描述标签示例调用
Smart Routingsmart-routing使用 OmniRoute 的 combo 引擎 + 评分将提示词路由到最优提供方/comborouting, providers"Route this prompt via the best model"
Quota Managementquota-management报告各提供方配额状态,帮助调用方决定何时限流/切换quota, providers"Check quota for anthropic"
Provider Discoveryprovider-discovery列出已安装提供方及其能力、免费档标志、OAuth 状态providers, discovery"What providers are available?"
Cost Analysiscost-analysis基于目录与近期用量估算请求/对话成本cost, usage"Estimate cost for this conversation"
Health Reporthealth-report聚合各提供方的熔断器、冷却、锁定状态health, resilience"Show health status of all providers"
List Capabilitieslist-capabilities返回完整 45 项 Agent 技能目录(23 API + 21 CLI + 1 配置)的 markdown 表格,附带原始 SKILL.md URLcatalog, discovery, skills"List all OmniRoute capabilities"

smart-routing为例,其实现位于 src/lib/a2a/skills/smartRouting.ts:它从任务输入中读取metadata.model(默认"auto")、metadata.combometadata.budget,随后调用 OmniRoute 自身的/v1/chat/completions完成路由(请求超时 30 秒),最后组装routing_explanationcost_enveloperesilience_trace(包含可选的fallback_needed事件)与policy_verdict(当实际成本超出budget时裁决allowed: false)。

list-capabilities技能对外部 Agent 尤其有用:它返回结构化的 markdown 表格 artifact,每行包含 ID、名称、类别、区域、端点和rawUrl列,Agent 拿到rawUrl后即可立即抓取完整 SKILL.md 注入上下文;metadata.totalSkills字段镜像目录大小(当前为 45)。实现见src/lib/a2a/skills/listCapabilities.ts,可配合 docs/frameworks/AGENT-SKILLS.md 阅读。

七、Task 生命周期与 TTL

任务遵循如下状态机:

submitted → working → completed → failed → cancelled
  • 任务默认在 5 分钟后过期ttlMinutes,可在A2ATaskManager构造时传入其他值,如new A2ATaskManager(15)表示 15 分钟 TTL);
  • 终态为completedfailedcancelled
  • 事件日志记录每一次状态迁移。

源码层面(src/lib/a2a/taskManager.ts)有更多细节值得关注:

  • 合法迁移表VALID_TRANSITIONS明确定义了每个状态允许的后续状态(如submitted只能转working/failed/cancelled),非法迁移直接抛错;
  • 后台清理:构造函数启动一个每 60 秒执行一次的cleanupExpired定时器,将过期且未处于终态的任务标记为failed(消息 "TTL expired"),并清理超过 2×TTL 的终态任务;
  • 历史持久化:任务通过upsertA2ATaskappendA2ATaskEvent写入 SQLite 历史表(尽力而为,失败仅告警不影响内存主路径),并通过purgeA2AHistory按保留天数清理历史,保留天数由环境变量OMNIROUTE_A2A_HISTORY_RETENTION_DAYS控制(默认 30 天);
  • 可观测性:每次状态迁移会通过事件总线发布agent.task.updated事件(监听器异常不会破坏任务写入路径);任务执行时还会以最后一条用户消息为查询词做记忆检索(OMNIROUTE_A2A_MEMORY_HITS=0可关闭),命中结果仅作为可观测数据写入metadata.memoryHits,不会注入技能提示词。

八、Error Codes:错误码表

代码含义
-32700解析错误(非法 JSON)
-32600无效请求 / 未授权
-32601方法或技能未找到
-32602无效参数
-32603内部错误
-32000A2A 端点未启用

九、REST 辅助 API

/a2a是规范的 JSON-RPC 入口,以下 REST 端点为仪表盘与外部工具提供辅助访问(详见 docs/frameworks/A2A-SERVER.md):

端点方法描述鉴权
/api/a2a/statusGET服务器状态、已注册技能公开
/api/a2a/tasksGET带过滤条件列出任务management
/api/a2a/tasks/[id]GET按 ID 获取任务management
/api/a2a/tasks/[id]/cancelPOST取消运行中的任务management
/.well-known/agent.jsonGETAgent Card(A2A 发现,公开,缓存 3600s)公开
/api/a2a/tasksPOST向 OmniConductor 编队入站委派(Conductor PRD RF5)Bearer 与OMNIROUTE_API_KEY+a2aEnabled

入站 Conductor 委派:外部 A2A Agent 可通过POST /api/a2a/tasks将编码工作委派给 OmniConductor 编队。请求体为{ skill: "conductor" | "conductor-cli-<profile>", messages: [{role, content}], metadata: { conductor: { repo: { url, base_ref? }, mode?, cli?, model? } } }—— 只有 Agent Card 上公布的 Conductor 编队技能可被委派,且metadata.conductor.repo.url必填(编队工作在 git 仓库上)。该路由使用服务端CONDUCTOR_ORCHESTRATOR_TOKEN(回退CONDUCTOR_HUB_TOKEN)转发到 hub 的POST /v1/tasks,返回201 { conductor_task_id, state: "submitted" };任务状态通过 SSE→A2A 镜像回流,可通过GET /api/a2a/tasks?skill=conductor查看。

十、集成示例

Python(requests)

import requests resp = requests.post("http://localhost:20128/a2a", json={ "jsonrpc": "2.0", "id": "1", "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Hello"}] } }, headers={"Authorization": "Bearer YOUR_KEY"}) result = resp.json()["result"] print(result["artifacts"][0]["content"]) print(result["metadata"]["routing_explanation"])

TypeScript(fetch)

const resp = await fetch("http://localhost:20128/a2a", { method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer YOUR_KEY", }, body: JSON.stringify({ jsonrpc: "2.0", id: "1", method: "message/send", params: { skill: "smart-routing", messages: [{ role: "user", content: "Hello" }], }, }), }); const { result } = await resp.json(); console.log(result.metadata.routing_explanation);

两个示例都读取了result.artifacts[0].content(技能输出文本)与result.metadata.routing_explanation(路由解释),前者拿到答案,后者拿到"为什么选了这条路由"的可审计证据。

十一、扩展指南:添加一个新 Skill

若需为 A2A Server 增加自定义技能,可按以下五步操作(前提是 fork 或本地运行此仓库,仓库本身是只读的):

  1. 创建技能文件src/lib/a2a/skills/<your-skill>.ts,导出一个异步函数(task: A2ATask) => Promise<{ artifacts, metadata }>,参考现有技能(如smartRouting.ts)的形状;

  2. 注册 handler:在src/lib/a2a/taskExecution.tsA2A_SKILL_HANDLERS中追加条目:

    export const A2A_SKILL_HANDLERS = { // ...existing skills "your-skill": async (task) => { const skillModule = await import("./skills/yourSkill"); return skillModule.executeYourSkill(task); }, };
  3. 暴露到 Agent Card:在src/app/.well-known/agent.json/route.tsskills数组中追加声明:

    { "id": "your-skill", "name": "Your Skill", "description": "Brief, intent-focused description", "tags": ["routing", "quota"], "examples": ["Sample natural-language invocation"] }
  4. 编写测试:在tests/unit/下新增a2a-<your-skill>.test.ts,覆盖正常路径与错误路径;

  5. 更新文档:在本文对应的Available Skills表格中登记新技能。

十二、源码脉络速览

  • 任务状态机与 TTL:src/lib/a2a/taskManager.ts ——A2ATaskManager类、VALID_TRANSITIONS、60 秒清理定时器、SQLite 历史持久化;
  • 技能调度:src/lib/a2a/taskExecution.ts ——A2A_SKILL_HANDLERS注册表、executeA2ATaskWithState(统一完成/失败收尾与记忆命中采集);
  • 技能实现:src/lib/a2a/skills/ ——smartRouting.tsquotaManagement.tsproviderDiscovery.tscostAnalysis.tshealthReport.tslistCapabilities.ts
  • 鉴权与 owner 隔离:src/lib/a2a/authenticate.ts ——authenticateA2ARequestresolveA2AOwner
  • 入口路由src/app/a2a/route.ts(JSON-RPC 规范入口)、src/app/api/a2a/*(REST 辅助端点);
  • 官方文档:docs/frameworks/A2A-SERVER.md(英文原版,含 Enablement、REST 表、扩展指南等更完整的说明)。

至此,你已拥有从"发现 → 鉴权 → 调用 → 追踪 → 扩展"的完整 A2A 接入链路:用message/send获得带路由解释与成本核算的同步结果,用message/stream获得实时流式输出,用tasks/get/tasks/cancel管理异步任务,再用六大内置技能覆盖路由、配额、发现、成本、健康与能力目录等场景——让任意遵循 A2A 协议的 Agent 都能把 OmniRoute 当成一个可信的"智能路由大脑"来使用。

【免费下载链接】OmniRouteNever stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors项目地址: https://gitcode.com/GitHub_Trending/om/OmniRoute

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询