OmniRoute A2A 服务器接入指南:用 Agent-to-Agent 协议将 AI 网关暴露为智能路由 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 内置 A2A(Agent-to-Agent Protocol v0.3)服务器,将整个 AI 路由网关封装成一个可供其他 Agent 直接调用的"智能路由 Agent"。本文基于 docs/frameworks/A2A-SERVER.md(含其 韩语译本)并结合仓库源码,完整讲解 A2A 端点的发现、认证、JSON-RPC 方法、内置技能、任务生命周期、错误码与多语言调用示例。读完本文,你将能够用curl、Python 或 TypeScript 让任意 Agent 通过 OmniRoute 完成智能路由、配额查询、成本分析等任务。
Agent 发现:读取 Agent Card
任何符合 A2A 协议的客户端,第一步都是通过/.well-known/agent.json发现对端 Agent 的能力。OmniRoute 在默认端口20128上提供该端点:
curl http://localhost:20128/.well-known/agent.json返回的 Agent Card 描述 OmniRoute 的能力、技能(Skills)和认证要求。该端点由 src/app/.well-known/agent.json/route.ts 动态生成,其中:
version字段直接取自process.env.npm_package_version,每次发版自动与package.json保持同步;url指向/a2a(即 JSON-RPC 规范入口);capabilities.streaming为true,pushNotifications为false,表示当前实现支持流式响应、不支持主动推送;skills数组声明的每个技能都与A2A_SKILL_HANDLERS(见下文"可用技能")一一对应。
此外,A2A 端点还通过OPTIONS请求返回 CORS 头(Access-Control-Allow-Methods: POST, OPTIONS),方便浏览器端 Agent 跨域调用,实现位于 src/app/a2a/route.ts。
认证与开关
Bearer API Key
所有/a2a请求都需要在Authorization头中携带 API Key:
Authorization: Bearer YOUR_OMNIROUTE_API_KEY认证逻辑集中在 src/lib/a2a/authenticate.ts 的authenticateA2ARequest中,采用与/v1一致的分层策略:
- 若开启了强制 API Key(
REQUIRE_API_KEY),则必须提供合法 OmniRoute Key; - 否则若设置了
OMNIROUTE_API_KEY环境变量,则按该 Key 校验(使用timingSafeEqual恒定时间比较); - 若服务端既未要求也未配置 Key,则跳过认证——这是与
/v1相同的"本地优先(local-first)"默认姿态。
同时,resolveA2AOwner会对调用方 API Key 做 SHA-256 哈希(截取前 32 位)作为任务归属标识,用于将任务读写限定到同一调用方(安全加固 GHSA-jcm5-6wpp-wjj8):无 Key 调用创建的任务对所有调用方可见,带 Key 创建的任务仅同 Key 可见。
启用开关
A2A 由Endpoints(端点)→ A2A开关控制,默认关闭。关闭状态下:
GET /api/a2a/status返回status: "disabled"、online: false(实现见 src/app/api/a2a/status/route.ts);- 向
POST /a2a发起 JSON-RPC 调用会收到 HTTP 503 与 JSON-RPC 错误码-32000("A2A endpoint is disabled"),该判断依据设置项settings.a2aEnabled,见 src/app/a2a/route.ts 中的rejectIfA2ADisabled。
JSON-RPC 2.0 方法
A2A 规范入口是POST /a2a,统一使用 JSON-RPC 2.0 信封(jsonrpc: "2.0"+id+method+params)。路由层还内置了 A2A 1.0 兼容层:1.0 客户端使用的方法名SendMessage、SendStreamingMessage会被自动映射到message/send、message/stream,响应也会被重塑为 1.0 的task.status.message.parts[].text结构,因此 a2a-sdk 1.x 等新老客户端可以无改动调用。
message/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"} } }'其中params支持三种消息形态:messages数组、单个message.content字符串,以及兼容旧版的message.parts数组(toMessageArray会统一归一化)。metadata可按技能透传额外参数(如model、combo、budget)。
响应:
{ "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" } } } }从源码看(src/lib/a2a/skills/smartRouting.ts),smart-routing技能会把请求转发给网关自身的/v1/chat/completions(内部通过resolveOmniRouteBaseUrl()解析回环地址,携带OMNIROUTE_API_KEY,30 秒超时),随后组装出四段可观测元数据:
routing_explanation:实际选中的模型、提供者、延迟与成本;cost_envelope:估算成本与真实成本(USD);resilience_trace:主提供者选择及是否触发过备选回退;policy_verdict:预算/配额策略裁决结果(metadata.budget用于设置预算上限)。
执行成功后,若技能为smart-routing,路由层还会把结果写入logRoutingDecision(路由决策日志),供控制台回放与统计。
message/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":{...}}}流式实现见 src/lib/a2a/streaming.ts:
- 每 15 秒发送一次
: heartbeat注释行保活(Nginx 等反代可配合X-Accel-Buffering: no头关闭缓冲); - 技能结果被拆成若干
chunk事件(当前为对完整 artifacts 的模拟流式输出),最后发送携带metadata的completed事件; - 支持通过
req.signal的AbortSignal中断连接,中断时发送failed事件; - 流开始/结束时调用
beginStream/endStream更新任务管理器的活跃流计数。
tasks/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"}}'返回result.task(含状态、事件日志、artifacts)。若任务已过期且仍处于非终态,会先被标记为failed("Task expired"),见 src/lib/a2a/taskManager.ts 的getTask。
tasks/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"}}'取消前会先做归属校验(不是自己的任务按"不存在"处理,避免 IDOR 探测),随后将任务置为cancelled("Cancelled by client")。
可用技能
OmniRoute 目前向 A2A 客户端暴露 6 个技能,全部注册在 src/lib/a2a/taskExecution.ts 的A2A_SKILL_HANDLERS中,每个技能模块位于 src/lib/a2a/skills/:
| 技能 | ID | 说明 |
|---|---|---|
| Smart Routing | smart-routing | 通过 OmniRoute 的组合引擎与评分,将提示词路由到最优提供者/组合,返回路由解释、成本与韧性追踪 |
| Quota Management | quota-management | 报告各提供者的配额状态,帮助调用方决定何时限流或切换提供者 |
| Provider Discovery | provider-discovery | 列出已安装提供者及其能力、免费层标记、OAuth 状态 |
| Cost Analysis | cost-analysis | 基于目录与近期用量估算单次请求/会话成本 |
| Health Report | health-report | 聚合各提供者的熔断器、冷却、锁定状态 |
| List Capabilities | list-capabilities | 返回完整的 Agent Skills 目录(当前 45 项:23 API + 21 CLI + 1 配置),输出 Markdown 表格并附带原始 SKILL.md 链接 |
其中smart-routing与quota-management是文档重点演示的两个技能,前者负责"把提示词路由给最优模型"(支持基于优先级、加权、轮询、成本优化等策略的组合路由),后者支持用自然语言查询各提供者配额、建议免费组合与配额排名。
Agent Card 应始终与运行时提供者目录保持一致:提供者数量、免费/免认证元数据均来自运行时注册表(registry),而非硬编码。
list-capabilities技能详解
list-capabilities对需要先探测 OmniRoute 能力再发请求的外部 Agent 尤其有用。它返回结构化的 Markdown 表格 artifact:
| ID | Name | Category | Area | Endpoints/Commands | Raw URL | | --- | --- | --- | --- | --- | --- | | omni-auth | Auth & Sessions | api | auth | POST /api/auth/login, ... | https://raw.githubusercontent.com/... | ...每行包含rawUrl列,Agent 可立即抓取完整的 SKILL.md;metadata.totalSkills字段镜像目录大小(当前 45)。实现位于 src/lib/a2a/skills/listCapabilities.ts,与 AGENT-SKILLS.md 保持同步。
REST 辅助接口
POST /a2a是 A2A 的规范入口,除此之外还有一组供仪表盘与外部工具使用的 REST 辅助端点:
| 端点 | 方法 | 说明 | 认证 |
|---|---|---|---|
/api/a2a/status | GET | 服务器状态、已注册技能 | 公开 |
/api/a2a/tasks | GET | 带过滤条件的任务列表 | management |
/api/a2a/tasks/[id] | GET | 按 ID 查询任务 | management |
/api/a2a/tasks/[id]/cancel | POST | 取消运行中的任务 | management |
/.well-known/agent.json | GET | Agent Card(A2A 发现,公开缓存 3600s) | 公开 |
/api/a2a/tasks | POST | 入站委托给 OmniConductor 集群(Conductor PRD RF5) | BearerOMNIROUTE_API_KEY+a2aEnabled |
其中POST /api/a2a/tasks用于外部 A2A Agent 把编码类工作委托给 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必填;路由层会使用服务端CONDUCTOR_ORCHESTRATOR_TOKEN(备选CONDUCTOR_HUB_TOKEN)转发到 Hub 的POST /v1/tasks,返回201 { conductor_task_id, state: "submitted" }。
任务生命周期与 TTL
A2ATaskManager(src/lib/a2a/taskManager.ts)负责任务的完整生命周期管理:
submitted → working → completed → failed → cancelled- 任务默认 5 分钟过期(TTL 可配置,见下);
- 终态为
completed、failed、cancelled; - 每次状态迁移都会追加到事件日志(
events数组),并同步持久化到 SQLite 历史表(upsertA2ATask/appendA2ATaskEvent,失败时静默降级,内存 Map 仍是活任务的唯一事实来源); - 状态迁移受
VALID_TRANSITIONS约束,非法迁移直接抛错; - 后台定时器每 60 秒清扫过期任务:非终态过期任务置为
failed("TTL expired"),终态任务在超过 2 倍 TTL 后从内存移除; - 历史表保留天数由环境变量
OMNIROUTE_A2A_HISTORY_RETENTION_DAYS控制,默认 30 天,清扫节流为每 24 小时至多一次; - 并发流由
activeStreams计数跟踪,可通过getStats()观测。
自定义 TTL
默认 TTL 为 5 分钟,在A2ATaskManager构造函数处配置。如需调整,可自行 fork 实例化逻辑并传入不同值,例如new A2ATaskManager(15)得到 15 分钟 TTL。框架默认通过全局单例getTaskManager()提供 5 分钟实例,cleanupInterval已unref(),不会阻塞进程退出。
错误码
A2A 端点遵循 JSON-RPC 2.0 标准错误码约定:
| 代码 | 含义 |
|---|---|
| -32700 | 解析错误(JSON 无效) |
| -32600 | 无效请求 / 未授权 |
| -32601 | 方法或技能不存在 |
| -32602 | 参数无效 |
| -32603 | 内部错误(技能执行失败) |
| -32000 | A2A 端点已禁用 |
HTTP 状态码与错误码的映射:-32600→ 400,-32601→ 404,-32603→ 500,其余返回 200(错误信息在 JSON-RPCerror字段中)。
集成示例
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);扩展:如何新增一个技能
A2A 技能的扩展遵循固定流程(与A2A_SKILL_HANDLERS的模式一致):
创建技能文件:在
src/lib/a2a/skills/下新建<your-skill>.ts,导出一个async (task: A2ATask) => Promise<{ artifacts, metadata }>函数,参考现有smartRouting.ts的形状;注册处理器:在
src/lib/a2a/taskExecution.ts的A2A_SKILL_HANDLERS中追加条目:export const A2A_SKILL_HANDLERS = { // ...existing skills "your-skill": async (task) => { const skillModule = await import("./skills/yourSkill"); return skillModule.executeYourSkill(task); }, };暴露到 Agent Card:在
src/app/.well-known/agent.json/route.ts的skills数组追加声明(含id、name、description、tags、examples);编写测试:在
tests/unit/下新增a2a-<your-skill>.test.ts,覆盖成功路径与错误路径;更新文档:将新技能补入本文档的可用技能表。
小结
OmniRoute 的 A2A 服务器以 JSON-RPC 2.0 为规范入口、Agent Card 为发现机制,让任何 A2A 客户端都能通过 Bearer Key 调用smart-routing、quota-management、provider-discovery、cost-analysis、health-report、list-capabilities六个技能,从而获得智能路由、配额洞察与健康巡检能力。任务由A2ATaskManager统一管理生命周期(5 分钟 TTL、终态事件日志、SQLite 历史持久化),配合 REST 辅助端点与 A2A 1.0 兼容层,可平滑嵌入现有 Agent 生态。相关实现可继续深入阅读 src/app/a2a/route.ts、src/lib/a2a/taskManager.ts、src/lib/a2a/taskExecution.ts 与 AGENT-SKILLS.md。
【免费下载链接】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),仅供参考