news 2026/9/14 7:48:58

OmniRoute A2A Server 接入指南:用 Agent-to-Agent 协议把 OmniRoute 变成智能路由 Agent

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OmniRoute A2A Server 接入指南:用 Agent-to-Agent 协议把 OmniRoute 变成智能路由 Agent

OmniRoute A2A Server 接入指南:用 Agent-to-Agent 协议把 OmniRoute 变成智能路由 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

本文依据 docs/frameworks/A2A-SERVER.md 编写,结合仓库源码与测试佐证。OmniRoute 以 Agent-to-Agent Protocol(A2A)v0.3 暴露自身能力,让任何支持 A2A 的 Agent(Claude Code、Codex、Hermes 等)通过 JSON-RPC 2.0 把任务委托给它:由它根据配额、成本、延迟与可靠性智能路由到 352 个提供者、1200+ 模型之一,并返回带路由解释、成本信封与韧性追踪的结构化结果。读完本文,你将掌握 OmniRoute A2A 的完整接入姿势——从发现 Agent Card、鉴权、四个 JSON-RPC 方法到六个内置 Skill,再到自定义 Skill、TTL 调优与 Python/TypeScript 客户端集成。

A2A 表面总览:一个入口,两种协议面

OmniRoute 的 A2A 服务有两张"面孔",均用于让外部 Agent 与网关互操作:

  • JSON-RPC 2.0POST /a2a):规范入口,处理message/sendmessage/streamtasks/gettasks/cancel四个方法,实现在 src/app/a2a/route.ts。
  • REST 辅助面/api/a2a/*):面向仪表盘与工具链,提供状态查询、任务列表、取消等能力。

任务的完整生命周期由A2ATaskManager管理(src/lib/a2a/taskManager.ts,默认 TTL 5 分钟),Skill 的调度则通过A2A_SKILL_HANDLERS注册表完成(src/lib/a2a/taskExecution.ts)。在深入协议细节前,先看协议版本兼容性:路由层内置了A2A 1.0 ↔ v0.3 兼容层(src/app/a2a/route.ts),将 1.0 的方法名SendMessageSendStreamingMessage分别映射到message/sendmessage/stream,并把 v0.3 的顶层artifacts/metadata重塑为 1.0 客户端期望的task.status.message.parts[].text。这意味着 a2a-sdk 1.x、Hermes 等 1.0 客户端无需改动即可直连本端点,v0.3 客户端也完全不受影响。

Agent Discovery:获取 Agent Card

任何 A2A 客户端的第一步都是"发现"对端能力。OmniRoute 在标准路径提供 Agent Card:

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

返回的 JSON 描述 OmniRoute 的能力、Skill 清单与认证要求(字段包括namedescriptionurlversioncapabilitiesskillsauthentication)。该端点在 src/app/.well-known/agent.json/route.ts 实现:

  • version字段直接取自process.env.npm_package_version(route.ts:17),每次发版随package.json自动同步;
  • Agent Card 动态拼装,除 6 个内置 Skill 外,还通过getFleetSkills()注入 OmniConductor 编排集群的 fleet skills(Conductor PRD RF2,集群未配置/离线时为空数组,卡片依然有效);
  • 响应带Cache-Control: public, max-age=3600,客户端可放心缓存 1 小时。

从源码结构可以推断,authentication.schemes["api-key"]apiKeyHeaderAuthorization,与下文的 Bearer 鉴权方式完全一致。

认证与启用开关

认证

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

Authorization: Bearer YOUR_OMNIROUTE_API_KEY

鉴权逻辑集中在 src/lib/a2a/authenticate.ts,JSON-RPC 路由与 REST 任务路由共享同一实现,避免两处漂移。其判定顺序为:

  1. 若启用了REQUIRE_API_KEY特性开关,则校验传入 Key 是否有效;无 Key 时回退到仪表盘会话认证(与/api/v1/*的会话回退保持一致);
  2. 否则若配置了OMNIROUTE_API_KEY环境变量,则用timingSafeEqual做常量时间比较;
  3. 两者皆无——即服务器未配置任何 Key 时,鉴权直接放行(本地优先的 keyless 默认姿态)。

也就是说,未配置 API Key 时认证会被绕过。此外,每个任务都会记录调用者身份owner(API Key 的 SHA-256 哈希前 32 位,会话登录者为"dashboard",keyless 为undefined),用于任务可见性与取消操作的归属隔离(GHSA-jcm5-6wpp-wjj8 修复),见 resolveA2AOwner。

启用开关

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

  • GET /api/a2a/status返回status: "disabled"online: false
  • POST /a2a的 JSON-RPC 调用返回 HTTP 503 与错误码-32000(错误信息提示从 Endpoints 页面启用)。

路由层通过rejectIfA2ADisabled(src/app/a2a/route.ts)读取settings.a2aEnabled判断,因此这是一个可持久化、可随时切换的运行期开关。

JSON-RPC 2.0 方法

所有方法统一走POST /a2a,正文为 JSON-RPC 2.0 格式。下面逐一给出可直接运行的 curl 示例与响应形态。

message/send— 同步执行

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

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" } } } }

从实现看,message/send的流程为:解析skill(缺省smart-routing)→ 归一化messages(支持messages[]{message: {content}}及遗留的{message: {parts: [...]}}三种形态,见toMessageArray)→ 查A2A_SKILL_HANDLERS→ 创建任务(submitted)→ 置working→ 执行 Skill → 置completed。若 Skill 为smart-routing,还会调用logRoutingDecision把路由决策写入日志(src/app/a2a/route.ts)。

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注释行保活连接(createHeartbeat);
  • Skill 结果以chunk事件逐段下发(非流式 Skill 走模拟分块),完成时以metadata事件收尾;
  • 支持AbortSignal取消:客户端断开或取消时下发failed事件并关闭流;
  • 响应头为SSE_HEADERStext/event-streamno-cacheX-Accel-Buffering: no),确保代理服务器不缓冲。

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"}}'

参数既支持taskId也兼容id。查询时会先检查过期:若任务处于submitted/working且已过 TTL,则自动置为failed("Task expired")再返回。

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"}}'

取消遵循归属校验:只能取消自己owner的任务,且"任务不存在"与"无权操作"返回同一错误信息,防止 IDOR 探测(taskManager.ts:268-L278)。

可用 Skill:6 个内置处理器

所有 Skill 注册在 src/lib/a2a/taskExecution.ts 的A2A_SKILL_HANDLERS中,每个模块位于 src/lib/a2a/skills/,均采用懒加载(await import(...)),首次调用才载入模块:

SkillID说明Tags示例
Smart Routingsmart-routing用组合引擎 + 评分把提示路由到最优提供者/组合routing, 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返回完整 Agent Skills 目录(45 项:23 API + 21 CLI + 1 配置),附带 SKILL.md 原始 URLcatalog, discovery, skills"List all OmniRoute capabilities"

smart-routing为例(src/lib/a2a/skills/smartRouting.ts):它接收model(默认"auto")、combobudget等元数据,调用网关自身的POST /v1/chat/completions(30 秒超时),随后把真实延迟、实际成本、路由解释、韧性追踪与预算策略裁决(withinBudget判定)组装进metadata返回。这解释了示例响应中routing_explanation等字段的来源——它们不是凭空生成的文案,而是本次请求的真实度量。

list-capabilitiesSkill 细节

对外部 Agent 而言,list-capabilities是在发请求前了解 OmniRoute 能做什么的入口。它返回结构化 markdown 表格制品:

| 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。更完整的 Skill 说明可参考 docs/frameworks/AGENT-SKILLS.md。

提示:Agent Card 的提供者数据与运行时注册表保持同步——文档明确要求 Agent Card 与实时 352 提供者目录对齐,提供者数量与免费/免认证元数据均来自运行时注册表,而非硬编码。

REST 辅助 API

JSON-RPC 的/a2a是规范入口,以下 REST 端点向仪表盘与外部工具提供辅助访问:

端点方法说明认证
/api/a2a/statusGET服务器状态、已注册 Skill公开
/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 委派

其中POST /api/a2a/tasks是 OmniRoute 与 OmniConductor 编排集群协作的关键通道:外部 A2A Agent 把编码任务委托给 Conductor 集群执行。请求体形如:

{ "skill": "conductor" | "conductor-cli-<profile>", "messages": [{role, content}], "metadata": { "conductor": { "repo": { "url": ..., "base_ref"? }, "mode"?, "cli"?, "model"? } } }

规则要点:

  • 只有 Agent Card 上公布过的 Conductor 集群 Skill 才可委派;
  • metadata.conductor.repo.url为必填(集群在 git 仓库上工作);
  • 路由会翻译为 hub 的POST /v1/tasks,使用服务端CONDUCTOR_ORCHESTRATOR_TOKEN(回退CONDUCTOR_HUB_TOKEN),返回201 { conductor_task_id, state: "submitted" }
  • 任务状态通过 SSE→A2A 镜像回流,可通过GET /api/a2a/tasks?skill=conductor查询。

任务生命周期与 TTL

状态机

submitted → working → completed → failed → cancelled
  • 默认 5 分钟过期(可配置,见下);
  • 终态:completedfailedcancelled
  • 事件日志记录每一次状态迁移。

从源码看,状态机有明确的合法迁移表(taskManager.ts:121-L127):submitted → working/failed/cancelledworking → completed/failed/cancelled,终态不可再迁移,非法迁移直接抛错。每次迁移都会:追加events日志、通过事件总线发布agent.task.updated(供编排画布消费,监听器异常不会打断写路径)、并尽力持久化到 SQLite 历史表(persist全程 best-effort,失败仅记日志)。

任务 TTL 定制

A2ATaskManager构造器接受ttlMinutes参数,默认 5 分钟(taskManager.ts:139)。如需调整,fork 单例实例化并传入新值,例如new A2ATaskManager(15)得到 15 分钟 TTL。后台每60 秒清扫一次过期任务:

  • 非终态任务到期 → 置为failed("TTL expired");
  • 终态任务超过 2 倍 TTL → 从内存移除;
  • 历史表清理受OMNIROUTE_A2A_HISTORY_RETENTION_DAYS环境变量控制(默认保留 30 天,每天至多 purge 一次,见 historyRetentionDays)。

此外,流式任务通过beginStream/endStream维护活跃流计数,可在GET /api/a2a/status中体现;listTasks支持state/skill筛选与offset/limit分页(默认 limit 50)。

错误码

代码含义
-32700解析错误(无效 JSON)
-32600无效请求 / 未授权
-32601方法或 Skill 不存在
-32602参数无效
-32603内部错误
-32000A2A 端点已禁用

对应的 HTTP 状态映射见 src/app/a2a/route.ts:-32600→ 400,-32601→ 404,-32603→ 500,其余(含-32700-32000与非法方法)→ 200,其中-32000场景为 HTTP 503(route.ts:147-L161)。实际调用时建议同时检查 HTTP 状态码与 JSON-RPCerror字段。

新增一个 Skill 的完整流程

A2A 的 Skill 扩展遵循"文件 → 注册 → 暴露 → 测试 → 文档"五步:

  1. 创建 Skill 文件src/lib/a2a/skills/<your-skill>.ts,导出异步函数(task: A2ATask) => Promise<{ artifacts, metadata }>,参照smartRouting.ts的既有形状。

  2. 注册处理器:在 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); }, };
  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,覆盖 happy path 与错误路径。仓库的 a2a 单元测试同时覆盖了任务管理器、认证、流式输出与各 Skill 模块。

  5. 文档同步:在本文件Available Skills表中登记新 Skill。

说明:本文为技术指南,仅介绍如何阅读、运行与配置仓库;仓库为只读,文中不涉及修改仓库内容的操作建议。

集成示例

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);

扩展阅读与源码索引

  • 规范文档:docs/frameworks/A2A-SERVER.md(本指南原始依据)
  • Agent Skills 目录:docs/frameworks/AGENT-SKILLS.md
  • JSON-RPC 路由:src/app/a2a/route.ts
  • Agent Card 端点:src/app/.well-known/agent.json/route.ts
  • 任务管理器:src/lib/a2a/taskManager.ts
  • Skill 调度与执行:src/lib/a2a/taskExecution.ts
  • 认证与归属解析:src/lib/a2a/authenticate.ts
  • SSE 流式封装:src/lib/a2a/streaming.ts
  • Skill 实现目录:src/lib/a2a/skills/

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 7:48:50

SVM与SVR在降水量预测中的实战:从回归原理到调参优化

简介&#xff1a;一套基于支持向量机算法的降水量预测模型代码&#xff0c;适合气象、水文等领域研究者&#xff0c;以及希望掌握支持向量机回归流程的机器学习初学者。完整工程覆盖数据读取、缺失处理、核函数选择、惩罚系数与核参数调优、模型评估与预测输出等环节&#xff0…

作者头像 李华
网站建设 2026/9/14 7:48:32

双旋翼无人机飞控实战:双ESP32分工与PID调参

简介&#xff1a;鲲鹏是一套基于Arduino IDE开发的双旋翼无人机完整开源方案&#xff0c;飞控采用两颗ESP32芯片&#xff0c;兼顾Wi-Fi/蓝牙通信与多核算力&#xff0c;适合无人机爱好者、嵌入式开发者及机器人方向学生。资源覆盖硬件设计、嵌入式源码到装配模型全链路&#xf…

作者头像 李华
网站建设 2026/9/14 7:47:59

博士论文答辩:理论创新点的高效表达方法论

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 7:46:58

资源下载工具 res-downloader:边刷视频号边把资源链接收进本地列表

资源下载工具 res-downloader&#xff1a;边刷视频号边把资源链接收进本地列表 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader …

作者头像 李华
网站建设 2026/9/14 7:45:35

用Python手写BP神经网络实现鸢尾花分类:从原理到调参

简介&#xff1a;面向Python初学者的人工智能实践项目&#xff0c;使用BP神经网络对经典鸢尾花数据集进行分类&#xff0c;配套完整源码、数据集和文档说明&#xff0c;可满足期末大作业、课程设计等场景。除BP神经网络两个版本&#xff08;V1/V2&#xff09;外&#xff0c;还提…

作者头像 李华
网站建设 2026/9/14 7:44:55

使用 NiceGUI 与 ZeroMQ PUSH/PULL 构建实时数据流可视化看板

使用 NiceGUI 与 ZeroMQ PUSH/PULL 构建实时数据流可视化看板 【免费下载链接】nicegui Create web-based user interfaces with Python. The nice way. 项目地址: https://gitcode.com/GitHub_Trending/ni/nicegui 本指南基于 examples/zeromq 示例&#xff0c;讲解如何…

作者头像 李华