什么是 A2A?从协议原理到 AgentScope Java 最小实践
摘要:A2A 让不同团队、不同框架构建的智能体通过统一协议协作。本文介绍 Agent Card、Message、Task 等核心对象,解释服务发现、任务跟踪与流式通信,并结合 AgentScope Java 样例演示服务端、客户端和 SSE 调用。
一个智能体擅长理解用户需求,另一个智能体掌握订单系统,第三个智能体负责生成报告。它们可能由不同团队开发,用不同框架运行。如何让第一个智能体发现另外两个、交付任务、等待结果,并在任务需要补充信息时继续对话?A2A 解决的就是这类协作问题。
本文先解释 A2A 的定义、使用场景和通信流程,再以 agentscope-a2a 项目的真实代码展示服务端、客户端和流式调用。文中的协议概念参考 A2A 官方核心概念;样例项目使用 AgentScope Java 2.0.0。
一、A2A 是什么?
A2A(Agent2Agent)是智能体之间通信与协作的开放协议。 它约定一个智能体如何公开自己的能力,另一个智能体如何发送消息、跟踪任务、接收结果。协议不规定智能体内部必须使用什么模型、提示词、工具或编排框架,因此服务端可以保留自己的实现细节。A2A 官方介绍
可以把它理解成智能体之间的"服务接口契约":
text
用户 → 主智能体(A2A 客户端) → 专业智能体(A2A 服务端)
↳ 返回消息、任务状态或交付物
它与普通 HTTP API 的区别在于,接口围绕智能体能力、会话消息和长任务生命周期设计,而不是只围绕固定的业务动作。与 MCP 的关注点也不同:MCP 常用于智能体连接工具和数据源;A2A 主要用于一个智能体调用另一个独立运行的智能体。二者可以同时存在,例如远端智能体通过 A2A 接单,再通过 MCP 查询数据库。

二、什么时候用 A2A?
| 场景 | A2A 带来的能力 |
|---|---|
| 跨团队专业智能体协作 | 主智能体根据能力说明找到订单、财务、法务等专业智能体,无须了解其内部实现。 |
| 长时间任务 | 提交任务后通过轮询、流式事件或回调跟踪进度。 |
| 人工补充信息 | 服务端将任务置为需要输入的状态,客户端补充资料后继续同一任务。 |
| 跨语言、跨框架集成 | 双方只需支持共同的 A2A 协议版本和传输绑定。 |
例如,"分析本周退款异常并写报告"可以拆给两个智能体:数据分析智能体负责统计退款数据,报告智能体负责解释指标并产出文档。若只是调用一个确定的 queryRefunds() 函数,普通 API 或工具调用通常更简单;当远端有自己的规划、工具、状态和交付过程时,A2A 更有价值。
三、协议里有哪些对象?
| 对象 | 作用 |
|---|---|
| Agent Card | 智能体的"名片",说明名称、能力、服务地址、支持的传输方式和认证要求。 |
| Message | 双方的一轮通信,包含发送方与内容。 |
| Part | Message 或 Artifact 的内容单元,可承载文本、文件或结构化数据。 |
| Task | 有 ID 和状态的工作单元,用于跟踪需要持续处理的请求。 |
| Artifact | 任务产出的文档、图片、结构化数据等交付物。 |

这些对象及其关系见 A2A 官方核心概念。Message 不一定创建 Task:简单请求可以直接返回一条消息;需要跟踪进度的工作会返回 Task。Task 的状态可能从工作中进入完成、失败、取消,或进入需要更多输入的状态。不要把一次 HTTP 请求等同于整个任务生命周期。
四、底层协议与工作原理
A2A 先解决发现 ,再解决通信 。服务端可以在 /.well-known/agent-card.json 暴露 Agent Card;客户端读取能力、端点、传输协议和认证信息,判断能否调用。Agent Card 也可以通过私有注册中心发现,不要求所有服务都公开在互联网。官方发现机制
在传输层,A2A 定义了 JSON-RPC、gRPC、HTTP+JSON 等标准绑定。JSON-RPC 方式通过 HTTP 发送请求;实时更新可用 SSE,长时间离线任务也可使用推送通知。具体可用能力以 Agent Card 中的声明和双方支持的协议版本为准。A2A 1.0.1 规范、异步与流式通信
一个容易踩的坑是混用协议版本 。截至本文编写时,A2A 官方文档已有 1.0 系列;但样例使用的 AgentScope Java 2.0.0 A2A 扩展依赖 a2a-java-sdk 0.3.3.Final,其 Agent Card 声明 protocolVersion: "0.3.0"。因此下面的样例演示的是 AgentScope 2.0.0 与同版本客户端之间的调用,不能据此断言它能直接与只接受 A2A 1.0 的服务互通。部署时应读取实际 Agent Card,再核对协议版本与传输绑定。
五、用 agentscope-a2a 项目跑通一次调用
下面直接使用 study-docs/agentscope-a2a 的实现。它将 ReActAgent 暴露为 A2A 服务端,在同一项目中提供命令行客户端和 HTTP 流式测试接口。项目使用 JDK 17+、Spring Boot 4.0.3、AgentScope Java 2.0.0,监听 127.0.0.1:8082。代码分别位于 config/AgentConfiguration.java、client/A2aClient.java 和 controller/A2aTestController.java。

1. 依赖与配置
项目的 pom.xml 使用 agentscope-a2a-spring-boot-starter 暴露服务,使用 agentscope-extensions-model-openai 接入 OpenAI 兼容模型,并引入 WebFlux 支持 SSE。关键依赖如下:
xml
<properties>
<java.version>17</java.version>
<agentscope.version>2.0.0</agentscope.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-a2a-spring-boot-starter</artifactId>
<version>${agentscope.version}</version>
</dependency>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-model-openai</artifactId>
<version>${agentscope.version}</version>
</dependency>
</dependencies>
实际项目还使用 AspectJ 记录 A2A 请求和 SSE 事件,并通过 Maven Exec 插件运行命令行客户端。以下配置只保留讲解所需字段,密钥必须由环境变量提供:
yaml
server:
address: ${A2A_HOST:127.0.0.1}
port: 8082
agentscope:
a2a:
server:
enabled: true
card:
name: A2A Assistant
description: AgentScope Java A2A 问答样例
version: 1.0.0
demo:
a2a:
server-url: ${A2A_SERVER_URL:http://127.0.0.1:8082}
model:
base-url: ${MODEL_BASE_URL}
api-key: ${MODEL_API_KEY}
name: ${MODEL_NAME}
这段配置为保护凭证,省略了样例文件中的模型默认值;运行前需要设置 MODEL_BASE_URL、MODEL_API_KEY 和 MODEL_NAME。card.version 是智能体服务自身的版本 ,不是 A2A 协议版本;协议版本应从实际返回的 Agent Card 的 protocolVersion 字段读取。
2. 服务端:把 ReActAgent 暴露为 A2A 服务
项目的 AgentConfiguration 创建模型和 Agent Builder。下面是其中的核心代码:
java
@Bean
Model chatModel(
@Value("${demo.model.base-url}") String baseUrl,
@Value("${demo.model.api-key}") String apiKey,
@Value("${demo.model.name}") String modelName) {
if (apiKey.isBlank()) {
throw new IllegalStateException("请先设置 MODEL_API_KEY");
}
return OpenAIChatModel.builder()
.baseUrl(baseUrl)
.apiKey(apiKey)
.modelName(modelName)
.endpointPath("/chat/completions")
.stream(true)
.build();
}
@Bean
ReActAgent.Builder agentBuilder(Model chatModel) {
return ReActAgent.builder()
.name("a2a-assistant")
.description("通过 A2A 协议提供中文问答")
.sysPrompt("你是一个简洁、准确的中文助手。")
.model(chatModel);
}
A2A Starter 接收这个 Builder,提供 Agent Card 和 JSON-RPC 端点。先启动服务,再查看名片:
bash
export MODEL_BASE_URL=https://your-openai-compatible-endpoint/v1
export MODEL_API_KEY=your-api-key
export MODEL_NAME=your-model-name
mvn spring-boot:run
curl http://127.0.0.1:8082/.well-known/agent-card.json
名片中的服务地址、传输绑定和协议版本决定了客户端如何连接。这里的模型调用需要真实可用的密钥;仅查看 Agent Card 通常不需要发起模型请求。
3. 客户端:读取 Agent Card 并发送问题
项目的 A2aClient.ask() 通过 WellKnownAgentCardResolver 获取名片,再用 A2aAgent 调用远端服务:
java
public String ask(String question) {
A2aAgent agent = A2aAgent.builder()
.name("remote-assistant")
.agentCardResolver(WellKnownAgentCardResolver.builder()
.baseUrl(serverUrl)
.relativeCardPath("/.well-known/agent-card.json")
.authHeaders(Map.of())
.build())
.build();
Msg reply = agent.call(new UserMessage(question)).block();
if (reply == null) {
throw new IllegalStateException("A2A 服务未返回消息");
}
return reply.getTextContent();
}
项目提供的命令行入口 A2aClientMain 调用的就是这个方法。服务端启动后,在另一个终端运行:
bash
mvn -q exec:java \
-Dexec.mainClass=com.jianjang.agentscope.a2a.client.A2aClientMain \
-Dexec.args="用一句话介绍 A2A 协议"
调用路径是 A2aClientMain → A2aClient → Agent Card → A2A JSON-RPC → ReActAgent → 模型。A2aAgent 帮客户端完成 A2A 消息转换;调用方只处理 AgentScope 的 Msg。
4. 流式接口:观察协议事件
同一项目还提供 /api/a2a/test。它接收问题,调用 A2aClient.stream(),将远端的 message/stream SSE 事件转发给浏览器或 curl。客户端组装的请求主体如下:
java
Map<String, Object> message = Map.of(
"kind", "message",
"role", "user",
"messageId", UUID.randomUUID().toString(),
"parts", List.of(Map.of("kind", "text", "text", question)));
Map<String, Object> request = Map.of(
"jsonrpc", "2.0",
"id", UUID.randomUUID().toString(),
"method", "message/stream",
"params", Map.of("message", message));
这段是本项目依赖的 A2A 0.3 风格 JSON-RPC 消息,不能直接当作 A2A 1.0 的通用模板。运行测试接口:
bash
curl -N -X POST http://127.0.0.1:8082/api/a2a/test \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-d '{"message":"用一句话介绍 A2A 协议"}'
返回的多条 data: 事件可以展示任务状态与内容。若要直接观察 A2A 端点,可向服务根路径 / 发送同样的 message/stream JSON-RPC 请求;测试接口只是方便调用和转发。
六、从样例走向真实协作
这个项目演示了三件事:Agent Card 让客户端发现远端能力;A2aAgent 把远端服务包装成可调用的 Agent;message/stream 把执行过程作为事件持续送回。项目中的 A2aProtocolLoggingAspect 还能记录请求与 SSE 事件,方便理解协议流转。
接入业务系统时,还需补齐认证、访问控制、超时、任务状态存储和失败恢复。尤其要注意模型密钥与日志:请求正文和 SSE 事件可能包含用户输入或业务数据,不能不加筛选地写入生产日志。若要把本样例的 Starter 接入另一个 Spring Boot 项目,应先核对 Spring Boot 与 AgentScope 的依赖版本,再进行启动和协议互通验证。
结语
A2A 的核心价值是让独立智能体通过统一的能力描述、消息结构与任务生命周期协作。理解它时,抓住四步即可:发现 Agent Card → 发送 Message → 跟踪 Task → 接收 Message 或 Artifact。真正接入时,还要检查协议版本、传输方式、认证与任务状态管理;这些条件决定两个智能体能否可靠互通。