Agent2Agent(A2A)协议 是一种用于实现 AI 智能体无缝通信的开放标准。它让不同平台的智能体能够彼此发现能力、交换消息、协同工作流,而不受其底层实现方式的限制。
Spring AI A2A 通过 Spring Boot 自动配置,将 A2A Java SDK 与 Spring AI 深度集成。它能把 A2A 协议与 Spring AI 的 ChatClient 和工具体系无缝连接,让你可以将自己的智能体暴露为 A2A 服务端。
本文是 Spring AI 智能体模式 系列的一部分。前面几篇分别介绍了如何增强单个智能体的能力(智能体技能、询问用户工具、待办写入工具、子智能体编排),而本文将通过实际示例,展示 A2A 协议如何让智能体跨越系统边界实现协作。
Agent2Agent(A2A)协议
A2A 协议 是面向 AI 智能体通信的开放标准,提供厂商中立的底层能力,使智能体能够发现彼此功能、交换消息、协调工作流。它基于 HTTP、SSE 和 JSON-RPC 标准构建。
智能体发现 是 A2A 通信的基础。智能体通过 AgentCard 发现彼此的能力——这是一份标准化的 JSON 文档,暴露在 /.well-known/agent-card.json 路径下,描述智能体的身份、能力与技能。整个过程遵循三步模式:发现 → 初始化 → 完成。
协议定义两种角色:
- A2A 服务端:对外提供发现与消息处理端点
- A2A 客户端:通过发现远程智能体并发送消息发起通信
A2A Java SDK 提供 Java 语言实现,包含处理请求与管理任务的服务端组件,以及调用远程智能体的客户端组件。它支持多种传输方式(HTTP、SSE、JSON-RPC),并处理底层协议细节。
Spring AI A2A 集成
A2A Java SDK 只提供协议实现,而与 Spring AI 集成需要额外的衔接层,Spring AI A2A 项目正是为此而生。
spring-ai-a2a 目前专注于服务端集成,让你可以将 Spring AI 智能体暴露为符合 A2A 标准的服务端。

它涵盖:
- Spring Boot 自动配置:自动配置 A2A 端点
- Spring AI 集成:直接对接 Spring AI 的
ChatClient与工具 - 基于 REST 控制器的 JSON-RPC 传输:当前实现基于 JSON-RPC 完成智能体通信,控制器提供智能体卡片与消息处理端点
- AgentExecutor 实现:
DefaultAgentExecutor作为 A2A SDK 与 Spring AI 之间的桥梁
框架会自动暴露以下 A2A 端点(相对于应用上下文路径):
|
1 2 3 |
POST / 处理 JSON-RPC sendMessage 请求 GET /.well-known/agent-card.json 标准 A2A 位置的智能体卡片 GET /card 备用智能体卡片端点 |
工作原理

执行流程:
- 智能体发现:通信开始前,客户端从
/.well-known/agent-card.json获取服务端的 AgentCard,以发现能力、技能与协议细节 - 请求接收:
MessageController在根端点接收 A2A JSON-RPC 的sendMessage请求 - 执行:路由到你的
AgentExecutorBean(Spring AI A2A 提供默认实现DefaultAgentExecutor) - 处理器调用:
ChatClientExecutorHandlerLambda 被调用,传入 Spring AI ChatClient 与请求上下文 - Spring AI ChatClient 响应:将 Spring AI
ChatClient的响应包装为 A2A JSON-RPC 消息
快速开始
我们将使用 Spring AI A2A 构建可互操作的智能体系统。从环境准备开始,然后实现两个示例:单智能体服务端、多智能体编排。
环境要求
- Java 17 及以上
- Spring Boot 4.0.1
- Spring AI 2.0.0-M2
- 一个大模型服务(OpenAI、Anthropic 等)
依赖
将 Spring AI 智能体暴露为 A2A 服务端,添加依赖如下:
|
1 2 3 4 5 |
<dependency> <groupId>org.springaicommunity</groupId> <artifactId>spring-ai-a2a-server-autoconfigure</artifactId> <version>0.2.0</version> </dependency> |
如果应用需要调用远程 A2A 智能体,显式添加 A2A SDK 客户端:
|
1 2 3 4 5 |
<dependency> <groupId>io.github.a2asdk</groupId> <artifactId>a2a-java-sdk-client</artifactId> <version>0.3.3.Final</version> </dependency> |
配置
在 application.properties 中配置:
|
1 2 3 4 5 6 7 8 9 |
# 服务配置 server.servlet.context-path=/weather # 大模型配置(以 Anthropic Claude 为例) spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY} spring.ai.anthropic.chat.options.model=claude-sonnet-4-5-20250929 # 多智能体编排(示例2),配置远程智能体 URL: # remote.agents.urls=http://localhost:10001/foo/,http://localhost:10002/bar/ |
示例 1:智能体服务端
将带工具的 Spring AI 应用暴露为 A2A 服务端:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
@Configuration public class WeatherAgentConfiguration { @Bean public AgentCard agentCard( @Value("${server.port:8080}") int port, @Value("${server.servlet.context-path:/}") String contextPath) { // 此 AgentCard 会自动暴露在 /.well-known/agent-card.json // 其他智能体通过该端点发现此智能体的能力 return new AgentCard.Builder() .name("Weather Agent") .description("提供城市天气信息") .url("http://localhost:" + port + contextPath + "/") .version("1.0.0") .capabilities(new AgentCapabilities.Builder().streaming(false).build()) .defaultInputModes(List.of("text")) .defaultOutputModes(List.of("text")) .skills(List.of(new AgentSkill.Builder() .id("weather_search") .name("搜索天气") .description("获取任意城市气温") .tags(List.of("weather")) .examples(List.of("伦敦天气如何?")) .build())) .protocolVersion("0.3.0") .build(); } @Bean public AgentExecutor agentExecutor( ChatClient.Builder chatClientBuilder, WeatherTools weatherTools) { ChatClient chatClient = chatClientBuilder.clone() .defaultSystem("你是天气助手。使用气温工具回答问题。") .defaultTools(weatherTools) // 注册 Spring AI 工具 .build(); return new DefaultAgentExecutor(chatClient, (chat, requestContext) -> { String userMessage = DefaultAgentExecutor.extractTextFromMessage(requestContext.getMessage()); return chat.prompt().user(userMessage).call().content(); }); } } @Service class WeatherTools { // 工具实现... } |
你的 Spring AI 智能体现在已是符合 A2A 标准的服务端。其他智能体可通过标准的 /.well-known/agent-card.json 端点发现其能力,并通过 POST 请求发送天气查询。自动配置会处理好 AgentCard 与消息端点的暴露。
示例 2:智能体客户端
一个实用的智能体客户端示例:主调度智能体,编排专业子智能体完成旅行规划(民宿住宿与天气信息)。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
@Service public class RemoteAgentConnections { private final Map<String, AgentCard> agentCards = new HashMap<>(); public RemoteAgentConnections(@Value("${remote.agents.urls}") List<String> agentUrls) { // 启动时发现远程智能体(见上文智能体发现章节) for (String url : agentUrls) { String path = new URI(url).getPath(); AgentCard card = A2A.getAgentCard(url, path + ".well-known/agent-card.json", null); this.agentCards.put(card.name(), card); } } @Tool(description = "向远程智能体发送任务。用于将工作委派给专业智能体。") public String sendMessage( @ToolParam(description = "智能体名称") String agentName, @ToolParam(description = "要发送的任务描述") String task) { AgentCard agentCard = this.agentCards.get(agentName); // 创建 A2A 消息 Message message = new Message.Builder() .role(Message.Role.USER) .parts(List.of(new TextPart(task, null))) .build(); // 使用 A2A Java SDK 客户端 CompletableFuture<String> responseFuture = new CompletableFuture<>(); Client client = Client.builder(agentCard) .clientConfig(new ClientConfig.Builder() .setAcceptedOutputModes(List.of("text")) .build()) .withTransport(JSONRPCTransport.class, new JSONRPCTransportConfig()) .addConsumers(List.of(consumer -> { if (consumer instanceof TextPart textPart) { responseFuture.complete(textPart.getText()); } })) .build(); client.sendMessage(message); return responseFuture.get(60, TimeUnit.SECONDS); } public String getAgentDescriptions() { return agentCards.values().stream() .map(card -> card.name() + ": " + card.description()) .collect(Collectors.joining("\n")); } } @Configuration public class HostAgentConfiguration { @Bean public ChatClient routingChatClient( ChatClient.Builder chatClientBuilder, RemoteAgentConnections remoteAgentConnections) { String systemPrompt = """ 你负责在专业智能体之间协调任务。 可用智能体: %s 使用 sendMessage 工具将任务委派给合适的智能体。 """.formatted(remoteAgentConnections.getAgentDescriptions()); return chatClientBuilder .defaultSystem(systemPrompt) .defaultTools(remoteAgentConnections) // 注册为 Spring AI 工具 .build(); } } |
执行逻辑
- 主智能体(客户端)在启动时通过标准
.well-known/agent-card.json端点发现远程智能体 RemoteAgentConnections被注册为 Spring AI 的@Tool,并注入ChatClient- 当用户提问“规划去伦敦的旅行”时,大模型通过
sendMessage工具决定调用哪些智能体 - 工具使用 A2A Java SDK Client 与远程智能体通信
- 结果汇总后返回给用户
这种模式实现了大模型驱动的路由:模型根据用户查询决定调用哪些专业智能体。
未来规划
当前版本专注于服务端集成,Spring AI 社区正在探索增强 Spring AI 应用的 A2A 客户端体验。
未来可能的增强:
- 安全:支持 A2A 认证与授权
- 智能体发现:Spring Boot 自动配置,用于发现与路由到 A2A 智能体
- 客户端自动配置:基于 Spring 友好抽象的自动配置 A2A 客户端连接
- 多传输支持:SSE 实时流式响应,扩展当前仅 JSON-RPC 的实现
- 增强可观测性:与 Spring Boot Actuator 集成,监控 A2A 交互
这些增强将为作为 A2A 客户端的 Spring AI 应用提供更多支持,为客户端与服务端提供一致的集成模式。
总结
A2A 协议是迈向可互操作 AI 智能体生态的重要一步。通过标准化智能体通信方式,它消除了构建复杂多智能体系统的障碍。
Spring AI A2A 社区项目提供了参与该生态所需的集成能力。通过 Spring Boot 自动配置,你可以将 Spring AI 智能体暴露为 A2A 服务端,与其他 A2A 标准智能体集成,并构建基于 Spring Boot 约定的编排模式。