Agent2Agent协议·A2A v1.0

让代理独立部署 一起工作。

A2A 为 AI 智能体提供了一种标准方式,可以向另一个代理介绍自己、接受作业或任务、报告进度、请求更多信息并返回有用的结果,即使另一个代理在不同的 AI 服务中运行、使用不同的编程语言或代理框架或部署在另一个云中也是如此。两个代理都不需要了解对方是如何构建的。他们使用A2A标准进行通信和协同工作。

11 v1 操作代理卡JSON-RPC + RESTSSE 流媒体多回合任务认证推送RemoteA2aAgent

ADK-Rust A2A 参考架构

A2A远程代理的架构

The network contract stays separate from the agent's model, tools, memory, and internal orchestration.

01

呼叫系统

代理或应用程序要求另一个代理完成工作。

协调代理

决定哪位远程专家应接收任务。

A2A 客户端

发现卡、选择流式传输并发送协议消息。

HTTPS

02

A2A 服务边界

每个兼容的客户端都可以理解的公共合同。

代理卡

名称、技能、端点、协议版本、安全性和声明的功能。

请求支票

版本、内容类型、ID、消息部分、元数据、身份和限制。

请求处理程序

通过一个共享实现调度 JSON-RPC 或 REST 操作。

键入呼叫

03

ADK-Rust运行时

该框架执行任务并生成类型化的进度。

Runner

创建调用上下文并流代理事件。

代理系统

LLM、工作流、图形、自定义或多代理逻辑。

工具

Rust 工具和 MCP

状态

会话和内存

代理工作时记录任务状态和事件

04

任务生命周期

经过验证的状态机使长时间运行的工作变得可检查。

任务商店

状态、上下文、历史记录、工件、元数据和推送配置。

状态机

仅接受有效的转换;终端任务保持终端状态。

05

进度交付

呼叫者选择接收找零的方式。

直接回应

返回完整的任务及其工件。

SSE 流

首先是任务,然后是状态和工件更新。

06

收到请求后工作

长任务可以稍后报告,而无需保持一个连接打开。

订阅

客户端监听现有任务的更新。

推送网络钩子

通过重试和 SSRF 检查进行身份验证的交付。

ADK-Rust 将 A2A 电汇合同、任务生命周期、代理执行和交付通道保留为单独的部分,以便每个部分都可以独立保护、测试和替换。

从想法开始

如何与外部托管的 AI 智能体合作?

在一个 ADK-Rust 进程内,代理可以共享 Rust 类型、会话、工具和直接函数调用。一旦代理属于另一个服务或另一个组织,这些私人实施细节就不再是安全的合同。

A2A 定义了该边界处的共享语言。调用者发现远程代理提供的内容、发送结构化消息、通过已知状态跟踪任务并接收工件,而无需知道端点后面运行的模型、框架或工具。

ADK-Rust 在 adk-server 中实现 A2A v1,并将该协议直接连接到 Runner。您在本地测试的同一个代理可以成为网络服务,而 RemoteA2aAgent 让另一个 ADK-Rust 系统通过正常的代理接口使用它。

代理卡

代理的服务配置文件

一份小型公共文档告诉呼叫者代理的名称、端点、技能、协议版本、安全要求以及是否支持流媒体或通知。

留言

一名特工对另一名特工所说的话

消息携带角色、唯一 ID 以及一个或多个部分(例如文本或结构化数据)。唯一的 ID 使安全重试成为可能。

任务

两个系统都可以遵循的作业

任务为远程工作提供 ID、对话上下文、状态、消息历史记录、元数据以及沿途产生的任何工件。

神器

工作的有用输出

工件是附加到任务的命名结果:报告、决策、计划、生成的文件或其他系统可以使用的其他结构化输出。

关注一份工作

该协议既承载了请求,也承载了作品的生命周期。

调用者可以等待一个响应、打开实时事件流、订阅现有任务或注册 Webhook 以供以后更新。任务标识和上下文使每种交付模式都附加到同一份工作。

任务状态机

远程工作有你可以遵循的生活。

A2A 的作用不仅仅是返回文本。它赋予工作身份、对话上下文、当前状态、历史和工件。 ADK-Rust 在保存之前验证每个转换。

SUBMITTED

服务器接受了任务。

WORKING

代理正在执行它。

INPUT REQUIRED

代理需要更多信息。

AUTH REQUIRED

调用者必须提供授权。

COMPLETED

工作和工件已准备就绪。

FAILED

执行因错误而结束。

CANCELED

允许的取消结束了任务。

REJECTED

服务器拒绝了任务。

多回转工作: 当任务达到 INPUT_REQUIRED,呼叫者发送另一条具有相同内容的消息 contextId。 ADK-Rust 找到任务,返回给 WORKING,附加消息,并继续相同的工作。

现实世界的逻辑流程

Case Study: Resolve a customer's damaged order across two distinct agent services.

A customer tells the company's support agent that an order arrived damaged. The support agent remains responsible for the conversation: it understands the request, keeps the customer informed, collects any missing evidence, and presents the final decision. It does not have direct access to warehouse stock, delivery records, or replacement policy.

该操作信息属于单独部署的履行代理。通过 A2A,支持代理可以发现履行代理的职责,将调查作为任务发送给其,跟踪其进度,回答更多信息请求,并接收最终的替换决定。每个服务都有自己的代码、数据、工具、模型提供者和安全控制;它们仅共享 A2A 合约定义的消息、任务状态和工件。

01

发现专家

支持协调员读取履行代理的卡并确认其处理订单调查并流式传输进度。

02

发送一份明确的工作

它发送订单号、客户的请求、唯一的 messageId 和新的对话上下文。

03

服务内的路由

远程 ADK-Rust 代理检查订单工具、库存、交付历史记录和公司政策,而不会将这些内部信息暴露给调用者。

04

询问缺少什么

如果需要损坏证明,任务将变为 INPUT_REQUIRED,而不是猜测或默默失败。

05

继续执行相同的任务

协调员使用相同的 contextId 提供批准的证据;历史和任务身份保持不变。

06

返回可审核的结果

该任务完成时会包含状态历史记录以及包含替换决策和后续步骤的工件。

Sequence diagram

The task pauses and resumes without losing its identity.

Read from top to bottom. The A2A service owns the network contract and task record. The fulfilment agent owns its reasoning and private tools.

Support coordinator

Calling agent

A2A service

Protocol boundary

Fulfilment agent

ADK-Rust Runner

Business systems

Orders · inventory · policy

通过 A2A 调用
发送至 Runner
使用经批准的工具

GET /.well-known/agent-card.json

Discover skills and streaming

Agent Card

Fulfilment capability published

SendStreamingMessage

ORD-1042 · messageId msg-order-1042

Runner invocation

Create task and execute agent

order.lookup + policy.check

Use private business tools

Evidence required

Damage photo is missing

INPUT_REQUIRED

Persist state and context

SSE status update

Ask support for evidence

SendMessage · same contextId

Approved photo reference

Resume task

INPUT_REQUIRED → WORKING

inventory.reserve

Reserve replacement stock

Artifact + COMPLETED

Replacement decision

Final SSE events

Auditable result returned

The support coordinator never receives database credentials or fulfilment code. It receives only the Agent Card, protocol events, task state, and final artifact.

代码和电报响应

查看双方发送和接收的内容。

这些示例使用与 ADK-Rust 实现相同的 v1 操作名称、消息字段、任务状态和 SSE 响应形状。 ID 和订单详细信息是固定的,因此整个对话很容易理解。

fulfilment.rs履行服务 · 锈
let fulfilment = LlmAgentBuilder::new("fulfilment")
      .description("Investigates orders and delivery")
      .model(model)
      .instruction(
          "Use the approved order, inventory, and policy tools.            Ask for evidence when the replacement policy requires it."
      )
      .build()?;

  A2aServer::builder()
      .agent(Arc::new(fulfilment))
      .agent_card_name("Fulfilment Agent")
      .streaming(true)
      .build()?
      .serve()
      .await?;
support.rs支持协调员·Rust
let fulfilment = RemoteA2aAgent::builder("fulfilment")
      .description("Investigates orders and delivery")
      .agent_url("https://agents.example.com/fulfilment")
      .streaming(true)
      .build()?;

  let support = LlmAgentBuilder::new("support")
      .model(model)
      .instruction("Own the customer conversation.")
      .sub_agent(Arc::new(fulfilment))
      .build()?;
SendStreamingMessage.json1 · 发送作业
{
    "jsonrpc": "2.0",
    "id": "replace-1",
    "method": "SendStreamingMessage",
    "params": {
      "message": {
        "messageId": "msg-order-1042",
        "role": "ROLE_USER",
        "parts": [{
          "text": "Investigate damaged order ORD-1042 and prepare a replacement decision."
        }]
      }
    }
  }
text/event-stream2·流任务进度
data: {
    "jsonrpc":"2.0", "id":"replace-1",
    "result":{"task":{
      "id":"task-order-1042",
      "contextId":"ctx-order-1042",
      "status":{"state":"TASK_STATE_SUBMITTED"}
    }}
  }

  data: {
    "jsonrpc":"2.0", "id":"replace-1",
    "result":{"statusUpdate":{
      "taskId":"task-order-1042",
      "contextId":"ctx-order-1042",
      "status":{"state":"TASK_STATE_WORKING"}
    }}
  }
input-required.event.json3·索取缺失的证据
{
    "statusUpdate": {
      "taskId": "task-order-1042",
      "contextId": "ctx-order-1042",
      "status": {
        "state": "TASK_STATE_INPUT_REQUIRED",
        "message": {
          "role": "ROLE_AGENT",
          "parts": [{
            "text": "Please provide a photo showing the damaged item."
          }]
        }
      }
    }
  }
SendMessage.follow-up.json4·继续执行相同的任务
{
    "jsonrpc": "2.0",
    "id": "replace-2",
    "method": "SendMessage",
    "params": {
      "message": {
        "messageId": "msg-order-1042-photo",
        "contextId": "ctx-order-1042",
        "role": "ROLE_USER",
        "parts": [{
          "text": "Evidence received and approved: damage-photo-8841.jpg"
        }]
      }
    }
  }
final-events.json5·接收神器并完成
{
    "artifactUpdate": {
      "taskId": "task-order-1042",
      "contextId": "ctx-order-1042",
      "artifact": {
        "artifactId": "replacement-decision-1042",
        "name": "Replacement decision",
        "parts": [{
          "text": "Approved. Reserve SKU-RED-42 and dispatch with priority shipping."
        }]
      }
    }
  }

  {
    "statusUpdate": {
      "taskId": "task-order-1042",
      "contextId": "ctx-order-1042",
      "status": { "state": "TASK_STATE_COMPLETED" }
    }
  }

A2A v1 API

客户端在远程代理上开始、跟踪和完成工作所需的一切。

ADK-Rust实现了A2A v1中的全部11个操作。对于短作业,调用SendMessage并等待任务结果。当工作可能需要更长的时间时,请首先使用 SendStreamingMessage 接收任务,然后通过 SSE 接收实时状态和工件事件。

返回的任务 ID 可让您的客户端重新连接,而无需再次提交作业。它可以获取最新状态、列出相关任务、订阅进一步更新或请求取消。如果客户端无法保持连接打开,它可以注册一个经过身份验证的 Webhook,并让远程代理传递稍后的更改。

01

开始工作

发送消息并接收完整的任务或实时流。

SendMessageSendStreamingMessage
02

检查与控制

读取当前工作、列出匹配的任务或在状态允许时取消任务。

GetTaskListTasksCancelTask
03

关注进度

打开 SSE 订阅以获取已存在任务的更新。

SubscribeToTask
04

接收稍后更新

创建、读取、列出和删除任务的经过身份验证的 Webhook 目标。

CreatePushConfigGetPushConfigListPushConfigsDeletePushConfig
05

发现更多

请求代理已发布的服务配置文件的扩展版本。

GetExtendedAgentCard

两个绑定的一个处理程序

JSON-RPC 和 REST 将调度路由到同一 RequestHandler,因此任务行为不会在传输之间漂移。

Runner 支持的执行

传入的 A2A 消息成为 ADK-Rust 内容。 Runner 执行选定的代理并将其事件转换为任务状态和工件。

安全重试

重复的 messageId 返回现有任务,而不是运行相同的工作两次。生产部署应在重新启动后保留此映射。

从上下文开始的流式传输

第一个 SSE 事件是完整的任务。后续事件携带状态和工件更新,因此客户端始终知道流属于什么。

远程座席感觉就像本地人一样

RemoteA2aAgent 实现 ADK-Rust 代理特征。协调器可以在其代理层次结构中包含网络服务并接收正常的框架事件。

边界保护

版本协商、消息验证、承载身份验证、速率限制、审计拦截器、Webhook 身份验证和 SSRF 检查可以保护服务。

选择正确的边界

本地子代理与远程 A2A 代理

A2A 引入了网络、公共合约、身份验证、故障处理和远程任务状态。当这些成本创造真正的独立性时,它们就很有价值。当每个代理都已经生活在同一个进程中时,它们是不必要的。

当地分代理

远程A2A代理

最适合
一个应用程序拥有的代理
代理独立部署或拥有
通讯
进程内代理调用和键入事件
HTTP、JSON-RPC 或 REST 和 SSE
共享状态
可以使用相同的会话和服务
仅共享声明的消息、任务和工件
失效边界
一个运行时和部署
网络、超时、重试和远程服务故障
互操作性
ADK-Rust 组件
任何 A2A 兼容的语言或框架

从Rust代理到网络服务

暴露一个代理,然后将其作为代理使用。

便利服务器创建一个 Axum 应用程序,其中包含代理卡、会话、A2A 路由和启用的流。远程适配器发现该服务并将其任务更新转换回 ADK-Rust 事件。

serve.rs曝光特工
use adk_server::a2a::convenience::A2aServer;

  let app = A2aServer::quick_start(agent);
  let listener = tokio::net::TcpListener::bind(
      "0.0.0.0:8080"
  ).await?;

  axum::serve(listener, app).await?;
coordinator.rs从另一个代理处调用
use adk_server::a2a::RemoteA2aAgent;

  let fulfilment = RemoteA2aAgent::builder("fulfilment")
      .description("Investigates orders and delivery")
      .agent_url("https://agents.example.com/fulfilment")
      .build()?;

  let coordinator = LlmAgentBuilder::new("support")
      .model(model)
      .sub_agent(Arc::new(fulfilment))
      .build()?;
对于完全配置的 v1 服务: 使用记录的 RequestHandler::with_runner 显式选择任务存储、推送发送者、代理卡、Runner 服务、JSON-RPC 路由、REST 路由器和版本协商中间件的路径。

生产前

部署 A2A 代理

ADK-Rust 提供 v1 类型、处理程序、生命周期、客户端、验证、交付原语以及与 Runner 的集成。生产准备情况仍然取决于为您的服务选择的存储、身份、网络、可观察性和操作策略。

01

发布诚信卡

仅公布部署真正支持的技能、绑定、流式传输、推送交付和安全方案。

02

选择耐用状态

包含的 InMemoryTaskStore 和内存中幂等性映射对于开发很有用。长时间运行的生产工作需要能够在流程重新启动后继续存在的存储。

03

确保两个方向

验证入站呼叫并保护出站推送传送。 HTTP 推送发送器支持承载凭证、通知令牌、重试和私有地址拒绝。

04

设计取消和超时

远程工作可能会比请求持续时间更长。定义客户端超时、取消策略、重试行为以及任一服务不可用时会发生什么情况。

连接代理系统

通过标准 A2A 接口公开您的代理。

从一张诚实的代理卡和一项有用的任务开始。随着工作变得更长、服务变得更加重要,添加流式传输、多轮输入、任务持久性、订阅、身份验证推送和边界控制。