A2A 服务
智能体之间用 A2A 协议对话:两条入口共用一个执行器和任务存储,路由配置决定请求交给本地智能体、远端智能体还是回给请求方。
依据 agent-runtime develop@0a47a523(2026-11-12)核实
A2A 是什么
A2A(Agent-to-Agent)是一种智能体之间互相调用的开放协议:每个智能体用一张 Agent Card 描述自己能干什么,别人按标准的 JSON-RPC 发消息,对话以 Task 为单位推进,Task 有提交、处理中、需要输入、完成、失败等状态。
agent-runtime 的 applications/a2a_service 就是一个 A2A 服务的实现。
三个端点
| 端点 | 用途 |
|---|---|
GET /a2a/.well-known/agent-card.json | 标准 Agent Card |
POST /a2a/ | 标准 A2A JSON-RPC 入口 |
POST /v1/{project_id}/agents/{agent_id}/conversations/{conv_id} | 定制入口,兼容某个已有平台的请求格式,支持 SSE 流式返回 |
两条路径共用同一个执行器和同一个 Redis 任务存储,所以不管从哪个入口进来,Task 状态都是一致的。
定制入口怎么接上多轮对话:首轮在 Redis 里按会话 ID 查不到任务,就新建一个 task_id 写进去;续轮从 Redis 取回 task_id,再从任务存储读出 Task。执行器看 Task 当前状态是不是 INPUT_REQUIRED,判断这是不是续轮。
执行器只做一件事
Executor.execute 的原则写在注释里:只做"构建事件 → 分发",不判断路由目标。
- 如果是被别的智能体调用的,从请求里取出上游的
traceparent接上链路 - 解析出用户问题、原始请求头和请求体
- 拿到这个会话的心跳管理器(长任务期间保持连接)
- 包成一个标准化事件,交给
RouteDispatcher
路由由配置决定
RouteDispatcher 读一份路由配置,把事件交给三类处理器之一:
| 处理器 | 负责 |
|---|---|
requester | 面向请求方:哪些状态算"挂起等用户" |
local_agent | 本进程里的智能体:哪些事件类型算"委托出去" |
remote_agent | 远端智能体:远端返回的状态怎么映射成内部帧类型,哪些算终止 |
默认配置的关键内容:
max_cascade_depth: 10 # 委托链最多 10 层
default_profile:
requester:
suspended_states: [INPUT_REQUIRED, AUTH_REQUIRED]
local_agent:
delegate_types: [delegate, sub_agent_dispatch, multi_delegate]
remote_agent:
terminal_frame_types: [CONTROL_COMPLETED, CONTROL_FAILED]
源码route_config.yamlagent-runtime/applications/a2a_service/orchestrator/config/route_config.yaml@0a47a523
处理器类名也写在配置里、运行时加载,所以换一个远端协议或加一种处理方式,不用改执行器。max_cascade_depth 防止智能体之间无限互相委托。
渠道适配
不同的前端渠道请求格式各不一样。Channel 抽象定义三件事:解析请求、构建 A2A 消息、把事件格式化成渠道要的样子。新接一个渠道就是再写一个 Channel。
小结
- A2A 服务对外同时提供标准入口和定制入口,共用执行器和任务存储。
- 执行器只构建事件、分发;路由规则、挂起状态、终止状态都在配置里。
- 委托链有深度上限,跨智能体的链路追踪靠 traceparent 串联。
- 任务状态机的细节,在 agent-solution 的"A2A Task 状态机"一关里动手体验。
源码出处
- agent-runtime/applications/a2a_service/app.py进程入口与三个端点
- agent-runtime/applications/a2a_service/api/dispatch.py定制入口:首轮建任务、续轮取任务
- agent-runtime/applications/a2a_service/orchestrator/executor.py:94
class Executor编排执行器 - agent-runtime/applications/a2a_service/orchestrator/route/route_dispatcher.py:19
class RouteDispatcher按配置路由事件 - agent-runtime/applications/a2a_service/orchestrator/config/route_config.yaml默认路由配置
- agent-runtime/applications/a2a_service/channels/base.py:22
class Channel渠道适配:把各家请求格式转成 A2A 消息
链接指向固定提交,仓库后续更新不影响这里的行号。
过关测验
1. A2A 服务的标准入口和定制入口,Task 状态是否一致?
2. 按默认路由配置,远端智能体回了 INPUT_REQUIRED,请求方会怎样?
3. 主智能体调用子智能体时,链路追踪怎么串起来?