如果你在用Spring AI构建Agent应用,现在有了一个社区项目Spring AI A2A,可以让你的Agent轻松接入A2A生态。这篇文章是Spring AI官方Agentic Patterns系列的第五篇,我们来看看具体怎么用。
当你的AI应用里有多个Agent需要协作时,麻烦就来了——天气查询Agent、酒店推荐Agent、行程规划Agent,每个都用不同的框架实现,彼此之间怎么通信?自己写一套RPC?维护成本太高。用消息队列?又太重了。
Google在2025年4月发布的A2A(Agent2Agent)协议就是为了解决这个问题。这是一个开放标准,让不同平台、不同框架的AI Agent能够相互发现、通信和协作。Salesforce、ServiceNow、MongoDB等超过50家技术公司参与了这个协议的制定。
如果你在用Spring AI构建Agent应用,现在有了一个社区项目Spring AI A2A,可以让你的Agent轻松接入A2A生态。这篇文章是Spring AI官方Agentic Patterns系列的第五篇,我们来看看具体怎么用。
先搞清楚A2A协议在干什么
A2A协议的核心思路很简单:给每个Agent一张"名片",让其他Agent能找到它、知道它能干什么、然后按标准格式发消息。
这张名片叫做AgentCard,是一个JSON文档,放在固定路径 /.well-known/agent-card.json 下。其他Agent访问这个地址就能知道:这个Agent叫什么名字、能提供什么技能、支持什么输入输出格式。
协议定义了两种角色:
•A2A Server- 暴露端点,处理请求,提供服务的Agent
•A2A Client- 发现远程Agent、发送消息、发起协作的Agent
通信流程是:发现 → 发起 → 完成。底层用的是HTTP、SSE和JSON-RPC这些成熟的标准,不用学什么新协议。
A2A和MCP(Model Context Protocol)是互补的关系。MCP解决的是LLM与工具、数据的连接问题,A2A解决的是Agent与Agent之间的协作问题,两者在不同层面工作。
Spring AI A2A做了什么
A2A有一个官方的Java SDK,但要把它和Spring AI整合起来还需要写不少胶水代码。Spring AI A2A这个社区项目就是帮你省掉这些麻烦的。
目前它主要做服务端集成,具体包括:
•Spring Boot自动配置- 自动暴露A2A端点
•Spring AI集成- 直接对接ChatClient和Tools
•JSON-RPC传输- 通过REST Controller提供Agent Card和消息处理端点
•AgentExecutor实现- 用DefaultAgentExecutor桥接A2A SDK和Spring AI
加上依赖后,框架会自动暴露这些端点:
• POST / - 处理sendMessage请求
• GET /.well-known/agent-card.json - 暴露Agent Card
• GET /card - Agent Card的备用端点
环境准备
开始之前,确认你的环境:
• Java 17及以上
• Spring Boot 4.0.1
• Spring AI 2.0.0-M2
• 一个LLM提供商(OpenAI、Anthropic等)
添加Maven依赖:
<dependency> <groupId>org.springaicommunity</groupId> <artifactId>spring-ai-a2a-server-autoconfigure</artifactId> <version>0.2.0</version> </dependency>这个starter会自动引入A2A Java SDK(v0.3.3.Final)作为传递依赖。
如果你的应用需要调用远程A2A Agent,还要显式添加SDK客户端:
<dependency> <groupId>io.github.a2asdk</groupId> <artifactId>a2a-java-sdk-client</artifactId> <version>0.3.3.Final</version> </dependency>实战一:把你的Agent变成A2A Server
假设你有一个天气查询Agent,带着一些工具方法,现在要把它暴露成A2A服务。
首先在application.properties里配置:
# 服务配置 server.servlet.context-path=/weather # LLM配置(以Anthropic Claude为例) spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY} spring.ai.anthropic.chat.options.model=claude-sonnet-4-5-20250929然后写配置类,定义AgentCard:
@Configuration public class WeatherAgentConfiguration { @Bean public AgentCard agentCard( @Value("${server.port:8080}") int port, @Value("${server.servlet.context-path:/}") String contextPath) { return new AgentCard.Builder() .name("Weather Agent") .description("Provides weather information for cities") .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("Search weather") .description("Get temperature for any city") .tags(List.of("weather")) .examples(List.of("What's the weather in London?")) .build())) .protocolVersion("0.3.0") .build(); } }再定义AgentExecutor,桥接Spring AI的ChatClient:
@Bean public AgentExecutor agentExecutor( ChatClient.Builder chatClientBuilder, WeatherTools weatherTools) { ChatClient chatClient = chatClientBuilder.clone() .defaultSystem("You are a weather assistant. " + "Use the temperature tool to answer questions.") .defaultTools(weatherTools) .build(); return new DefaultAgentExecutor(chatClient, (chat, requestContext) -> { String userMessage = DefaultAgentExecutor .extractTextFromMessage(requestContext.getMessage()); return chat.prompt().user(userMessage).call().content(); }); }就这么多代码。启动应用后,你的天气Agent就是一个A2A Server了。其他Agent可以通过 /.well-known/agent-card.json 发现它,然后向根端点发送天气查询请求。
实战二:构建多Agent编排系统
更有意思的场景是让一个主控Agent调度多个专业Agent。比如做一个旅行规划助手,背后有Airbnb住宿Agent和天气查询Agent配合工作。
先在配置里指定远程Agent的地址:
remote.agents.urls=http://localhost:10001/airbnb/,http://localhost:10002/weather/然后实现远程Agent连接管理,关键是把sendMessage方法标记为@Tool:
@Service public class RemoteAgentConnections { private final Map<String, AgentCard> agentCards = new HashMap<>(); public RemoteAgentConnections( @Value("${remote.agents.urls}") List<String> agentUrls) { // 启动时发现远程Agent 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 = "Sends a task to a remote agent.") public String sendMessage( @ToolParam(description = "The agent name") String agentName, @ToolParam(description = "The task to send") String task) { AgentCard agentCard = this.agentCards.get(agentName); Message message = new Message.Builder() .role(Message.Role.USER) .parts(List.of(new TextPart(task, null))) .build(); 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); } }主控Agent的配置,把RemoteAgentConnections注册为Tool:
@Configuration public class HostAgentConfiguration { @Bean public ChatClient routingChatClient( ChatClient.Builder chatClientBuilder, RemoteAgentConnections remoteAgentConnections) { String systemPrompt = """ You coordinate tasks across specialized agents. Available agents: %s Use the sendMessage tool to delegate tasks. """.formatted( remoteAgentConnections.getAgentDescriptions()); return chatClientBuilder .defaultSystem(systemPrompt) .defaultTools(remoteAgentConnections) .build(); } }这里的关键是:RemoteAgentConnections被注册为Spring AI的Tool。当用户问"帮我规划一次伦敦之旅"时,LLM会自动决定调用哪些远程Agent——先查天气、再找住宿,最后汇总结果。这就是LLM驱动的路由,模型根据用户意图自主决定调用哪些专业Agent。
未来可能的增强
Spring AI A2A目前主要做服务端集成,社区正在探索更多可能:
•安全- 支持A2A认证和授权机制
•Agent发现- Spring Boot自动配置发现和路由A2A Agent
•客户端自动配置- 提供更友好的Spring风格抽象
•多传输支持- SSE实时流式响应,不只是JSON-RPC
•可观测性- 集成Spring Boot Actuator监控A2A交互
小结
A2A协议给多Agent系统提供了一个标准化的通信方式。有了它,你不用再为不同Agent之间的通信格式发愁,也不用担心被某个厂商锁定。Spring AI A2A这个社区项目则让Java开发者能够用熟悉的Spring Boot风格来接入这个生态。
随着更多Agent、工具和平台采用A2A标准,跨系统的Agent协作会变得越来越容易。如果你正在用Spring AI构建Agent应用,现在就可以尝试把它暴露成A2A Server了。