|
1 | 1 | --- |
2 | 2 | title: 分布式智能体(A2A Agent) |
3 | | -description: 了解如何在Spring AI Alibaba中实现Multi-agent协作,包括工具调用和交接模式 |
4 | | -keywords: [Multi-agent, Multi-Agent, 工具调用, Tool Calling, Handoffs, Agent协作, 子Agent] |
| 3 | +description: 了解如何在Spring AI Alibaba中使用A2A协议实现分布式Agent通信,包括Agent注册、发现和远程调用 |
| 4 | +keywords: [A2A, Agent-to-Agent, 分布式Agent, 远程Agent, Nacos, Agent注册, Agent发现] |
5 | 5 | --- |
6 | 6 |
|
7 | | -## 分布式 Agent |
8 | | -### A2A 协议简介 |
| 7 | +## A2A 协议简介 |
| 8 | + |
9 | 9 | 随着智能体应用的广泛落地,智能体应用间的分布式部署与远程通信成为要解决的关键问题,Google 推出的 [Agent2Agent(A2A)协议](https://a2a-protocol.org/latest/)即面向这一落地场景:A2A 解决智能体与其他使用不同框架、部署在不同机器、不同公司的智能体进行有效通信和协作的问题。 |
10 | 10 |
|
11 | | - |
| 11 | +A2A 协议定义了智能体之间通信的标准方式,使得不同框架、不同部署环境的智能体能够无缝协作。 |
| 12 | + |
| 13 | +## A2A 架构 |
| 14 | + |
| 15 | +Spring AI Alibaba 的 A2A 实现包含三个核心组件: |
| 16 | + |
| 17 | +1. **A2A Server**:将本地 ReactAgent 暴露为 A2A 服务 |
| 18 | +2. **A2A Registry**:Agent 注册中心(支持 Nacos) |
| 19 | +3. **A2A Discovery**:Agent 发现机制(支持 Nacos) |
| 20 | + |
| 21 | +### 注册与发现流程 |
| 22 | + |
| 23 | +``` |
| 24 | +┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐ |
| 25 | +│ Agent Provider │ │ Nacos │ │ Agent Consumer │ |
| 26 | +│ (本地Agent) │────────▶│ Registry │◀────────│ (远程调用) │ |
| 27 | +└─────────────────┘ └──────────────┘ └─────────────────┘ |
| 28 | + │ │ │ |
| 29 | + │ 1. 注册 AgentCard │ │ |
| 30 | + │───────────────────────────▶│ │ |
| 31 | + │ │ │ |
| 32 | + │ │ 2. 查询 AgentCard │ |
| 33 | + │ │◀──────────────────────────│ |
| 34 | + │ │ │ |
| 35 | + │ 3. 远程调用 │ │ |
| 36 | + │◀───────────────────────────│ │ |
| 37 | + │ │ │ |
| 38 | +``` |
| 39 | + |
| 40 | +## 发布 A2A 智能体 |
| 41 | + |
| 42 | +要将一个智能体发布为 A2A 服务,需要: |
| 43 | + |
| 44 | +1. 创建 ReactAgent Bean |
| 45 | +2. 配置 A2A Server |
| 46 | +3. (可选)配置 Nacos Registry 进行自动注册 |
| 47 | + |
| 48 | +### 定义本地 Agent |
| 49 | + |
| 50 | +<Code |
| 51 | + language="java" |
| 52 | + title="定义本地 ReactAgent 示例" sourceUrl="https://github.com/alibaba/spring-ai-alibaba/tree/main/examples/documentation/src/main/java/com/alibaba/cloud/ai/examples/documentation/framework/advanced/A2AExample.java" |
| 53 | +> |
| 54 | +{`import com.alibaba.cloud.ai.graph.agent.ReactAgent; |
| 55 | +import org.springframework.ai.chat.model.ChatModel; |
| 56 | +import org.springframework.beans.factory.annotation.Qualifier; |
| 57 | +import org.springframework.context.annotation.Bean; |
| 58 | +import org.springframework.context.annotation.Configuration; |
| 59 | + |
| 60 | +@Configuration |
| 61 | +public class A2AAgentConfig { |
| 62 | + |
| 63 | + @Bean(name = "dataAnalysisAgent") |
| 64 | + public ReactAgent dataAnalysisAgent(@Qualifier("dashscopeChatModel") ChatModel chatModel) { |
| 65 | + return ReactAgent.builder() |
| 66 | + .name("data_analysis_agent") |
| 67 | + .model(chatModel) |
| 68 | + .description("专门用于数据分析和统计计算的本地智能体") |
| 69 | + .instruction("你是一个专业的数据分析专家,擅长处理各类数据统计和分析任务。" + |
| 70 | + "你能够理解用户的数据分析需求,提供准确的统计计算结果和专业的分析建议。") |
| 71 | + .outputKey("messages") |
| 72 | + .build(); |
| 73 | + } |
| 74 | +}`} |
| 75 | +</Code> |
12 | 76 |
|
13 | | -### Spring AI Alibaba 中如何调用 A2A 远程智能体 |
14 | | -A2aRemoteAgent 用来声明一个远程通信智能体,通过 AgentCard 指定远程智能体信息,包括连接的 url 地址、capabilities 等。 |
| 77 | +### 配置 A2A Server |
15 | 78 |
|
16 | | - |
| 79 | +在 `application.yml` 中配置 A2A Server: |
17 | 80 |
|
18 | | -以上示例中分别实现了两个远程智能体,然后使用 SequentialAgent 将两个智能体组成串行流程,就像使用同进程内的智能体一样。可在此查看以上代码片段[完整示例](https://github.com/alibaba/spring-ai-alibaba/blob/main/spring-ai-alibaba-graph-core/src/test/java/com/alibaba/cloud/ai/graph/agent/RemoteAgentTest.java)。 |
| 81 | +<Code |
| 82 | + language="yaml" |
| 83 | + title="A2A Server 配置示例" |
| 84 | +> |
| 85 | +{`spring: |
| 86 | + ai: |
| 87 | + alibaba: |
| 88 | + a2a: |
| 89 | + server: |
| 90 | + version: 1.0.0 |
| 91 | + card: |
| 92 | + name: data_analysis_agent |
| 93 | + description: 专门用于数据分析和统计计算的本地智能体 |
| 94 | + provider: |
| 95 | + name: Spring AI Alibaba Documentation |
| 96 | + organization: Spring AI Alibaba`} |
| 97 | +</Code> |
19 | 98 |
|
20 | | - |
| 99 | +启动应用后,A2A Server 会自动: |
| 100 | +- 根据 ReactAgent Bean 生成 AgentCard |
| 101 | +- 暴露 REST API 端点: |
| 102 | + - `/.well-known/agent.json` - AgentCard 元数据 |
| 103 | + - `/a2a/message` - Agent 调用端点 |
21 | 104 |
|
22 | | -### Spring AI Alibaba 中如何发布 A2A 智能体 |
23 | | -如果要将一个智能体发布为 A2A 服务,需要增加 Spring AI Alibaba Runtime 组件依赖, Spring AI Alibaba Runtime 负责将智能体发布出去。具体请参见后续 Spring AI Alibaba Runtime 文章解读。 |
| 105 | +## 调用 A2A 远程智能体 |
| 106 | + |
| 107 | +### 使用 AgentCardProvider 发现 Agent |
| 108 | + |
| 109 | +Spring AI Alibaba 支持通过 `AgentCardProvider` 从注册中心(如 Nacos)发现远程 Agent。 |
| 110 | + |
| 111 | +<Code |
| 112 | + language="java" |
| 113 | + title="使用 AgentCardProvider 发现并调用远程 Agent" sourceUrl="https://github.com/alibaba/spring-ai-alibaba/tree/main/examples/documentation/src/main/java/com/alibaba/cloud/ai/examples/documentation/framework/advanced/A2AExample.java" |
| 114 | +> |
| 115 | +{`import com.alibaba.cloud.ai.graph.agent.a2a.A2aRemoteAgent; |
| 116 | +import com.alibaba.cloud.ai.graph.agent.a2a.AgentCardProvider; |
| 117 | +import com.alibaba.cloud.ai.graph.OverAllState; |
| 118 | +import org.springframework.beans.factory.annotation.Autowired; |
| 119 | +import org.springframework.stereotype.Component; |
| 120 | + |
| 121 | +import java.util.Optional; |
| 122 | + |
| 123 | +@Component |
| 124 | +public class A2AExample { |
| 125 | + |
| 126 | + private final AgentCardProvider agentCardProvider; |
| 127 | + |
| 128 | + @Autowired |
| 129 | + public A2AExample(AgentCardProvider agentCardProvider) { |
| 130 | + this.agentCardProvider = agentCardProvider; |
| 131 | + } |
| 132 | + |
| 133 | + public void callRemoteAgent() { |
| 134 | + // 通过 AgentCardProvider 从注册中心发现 Agent |
| 135 | + A2aRemoteAgent remote = A2aRemoteAgent.builder() |
| 136 | + .name("data_analysis_agent") |
| 137 | + .agentCardProvider(agentCardProvider) // 从 Nacos 自动获取 AgentCard |
| 138 | + .description("数据分析远程代理") |
| 139 | + .build(); |
| 140 | + |
| 141 | + // 远程调用 |
| 142 | + Optional<OverAllState> result = remote.invoke("请根据季度数据给出同比与环比分析概要。"); |
| 143 | + |
| 144 | + result.ifPresent(state -> { |
| 145 | + System.out.println("调用成功: " + state.value("output")); |
| 146 | + }); |
| 147 | + } |
| 148 | +}`} |
| 149 | +</Code> |
| 150 | + |
| 151 | +## 基于 Nacos 的 A2A Registry |
24 | 152 |
|
25 | | -### 基于 Nacos A2A Registry 的远程智能体自动发现 |
26 | 153 | Nacos3 最新版本提供了 A2A AgentCard 模型的存储与推送支持,因此可以作为 A2A Registry 实现。Spring AI Alibaba 通过与 Nacos A2A Registry 集成,可以实现: |
27 | 154 |
|
28 | | -1. A2A Server AgentCard 自动注册到 Nacos A2A Registry |
29 | | -2. A2a Client 自动订阅发现可用 AgentCard,实现 AgentCard 调用的负载均衡 |
| 155 | +1. **A2A Server AgentCard 自动注册到 Nacos A2A Registry** |
| 156 | +2. **A2a Client 自动订阅发现可用 AgentCard,实现 AgentCard 调用的负载均衡** |
| 157 | + |
| 158 | +### 配置 Nacos Registry 和 Discovery |
| 159 | + |
| 160 | +<Code |
| 161 | + language="yaml" |
| 162 | + title="Nacos A2A 配置示例" |
| 163 | +> |
| 164 | +{`spring: |
| 165 | + ai: |
| 166 | + alibaba: |
| 167 | + a2a: |
| 168 | + nacos: |
| 169 | + server-addr: 127.0.0.1:8848 |
| 170 | + username: nacos |
| 171 | + password: nacos |
| 172 | + discovery: |
| 173 | + enabled: true # 启用服务发现(查询其他 Agent) |
| 174 | + registry: |
| 175 | + enabled: true # 启用服务注册(注册本地 Agent) |
| 176 | + server: |
| 177 | + version: 1.0.0 |
| 178 | + card: |
| 179 | + name: data_analysis_agent |
| 180 | + description: 专门用于数据分析和统计计算的本地智能体 |
| 181 | + provider: |
| 182 | + name: Spring AI Alibaba Documentation |
| 183 | + organization: Spring AI Alibaba`} |
| 184 | +</Code> |
| 185 | + |
| 186 | +**重要配置说明**: |
| 187 | +- `registry.enabled: true` - 必须启用才能将 Agent 注册到 Nacos(服务提供者) |
| 188 | +- `discovery.enabled: true` - 启用后才能通过 AgentCardProvider 发现其他 Agent(服务消费者) |
| 189 | +- `server.card.name` - 必须与 ReactAgent Bean 的 `name` 一致 |
| 190 | + |
| 191 | +### 完整示例 |
| 192 | + |
| 193 | +<Code |
| 194 | + language="java" |
| 195 | + title="A2A 一体化示例:注册 -> 发现 -> 调用" |
| 196 | + sourceUrl="https://github.com/alibaba/spring-ai-alibaba/tree/main/examples/documentation/src/main/java/com/alibaba/cloud/ai/examples/documentation/framework/advanced/A2AExample.java" |
| 197 | +> |
| 198 | +{`import com.alibaba.cloud.ai.graph.agent.ReactAgent; |
| 199 | +import com.alibaba.cloud.ai.graph.agent.a2a.A2aRemoteAgent; |
| 200 | +import com.alibaba.cloud.ai.graph.agent.a2a.AgentCardProvider; |
| 201 | +import com.alibaba.cloud.ai.graph.OverAllState; |
| 202 | +import org.springframework.ai.chat.model.ChatModel; |
| 203 | +import org.springframework.beans.factory.annotation.Autowired; |
| 204 | +import org.springframework.beans.factory.annotation.Qualifier; |
| 205 | +import org.springframework.stereotype.Component; |
| 206 | + |
| 207 | +import java.util.Optional; |
| 208 | + |
| 209 | +@Component |
| 210 | +public class A2AExample { |
| 211 | + |
| 212 | + private final ChatModel chatModel; |
| 213 | + private final AgentCardProvider agentCardProvider; |
| 214 | + private final ReactAgent localDataAnalysisAgent; |
| 215 | + |
| 216 | + @Autowired |
| 217 | + public A2AExample(@Qualifier("dashscopeChatModel") ChatModel chatModel, |
| 218 | + AgentCardProvider agentCardProvider, |
| 219 | + @Qualifier("dataAnalysisAgent") ReactAgent localDataAnalysisAgent) { |
| 220 | + this.chatModel = chatModel; |
| 221 | + this.agentCardProvider = agentCardProvider; |
| 222 | + this.localDataAnalysisAgent = localDataAnalysisAgent; |
| 223 | + } |
| 224 | + |
| 225 | + public void runDemo() { |
| 226 | + // 1. 本地直连:验证本地注册的 ReactAgent 可用 |
| 227 | + Optional<OverAllState> localResult = localDataAnalysisAgent.invoke( |
| 228 | + "请对上月销售数据进行趋势分析,并给出关键结论。" |
| 229 | + ); |
| 230 | + localResult.ifPresent(state -> { |
| 231 | + System.out.println("本地调用成功"); |
| 232 | + }); |
| 233 | + |
| 234 | + // 2. 发现:通过 AgentCardProvider 从注册中心获取该 Agent 的 AgentCard |
| 235 | + A2aRemoteAgent remote = A2aRemoteAgent.builder() |
| 236 | + .name("data_analysis_agent") |
| 237 | + .agentCardProvider(agentCardProvider) // 从 Nacos 自动获取 AgentCard |
| 238 | + .description("数据分析远程代理") |
| 239 | + .build(); |
| 240 | + |
| 241 | + // 3. 远程调用:通过 A2aRemoteAgent 调用 |
| 242 | + Optional<OverAllState> remoteResult = remote.invoke( |
| 243 | + "请根据季度数据给出同比与环比分析概要。" |
| 244 | + ); |
| 245 | + remoteResult.ifPresent(state -> { |
| 246 | + System.out.println("远程调用成功"); |
| 247 | + }); |
| 248 | + } |
| 249 | +}`} |
| 250 | +</Code> |
| 251 | + |
| 252 | +## 验证和测试 |
| 253 | + |
| 254 | +### 验证本地 AgentCard |
| 255 | + |
| 256 | +```bash |
| 257 | +curl http://localhost:8080/.well-known/agent.json |
| 258 | +``` |
| 259 | + |
| 260 | +### 验证 Nacos 注册 |
| 261 | + |
| 262 | +1. 打开 Nacos 控制台:http://localhost:8848/nacos |
| 263 | +2. 登录(nacos/nacos) |
| 264 | +3. 查看 A2A 服务注册维度,应该能看到注册的 Agent |
| 265 | + |
| 266 | +### 注册与发现的区别 |
| 267 | + |
| 268 | +| 功能 | 配置项 | 作用 | 角色 | |
| 269 | +|------|--------|------|------| |
| 270 | +| **Registry(注册)** | `registry.enabled: true` | 将本地 Agent 注册到 Nacos | 服务提供者 | |
| 271 | +| **Discovery(发现)** | `discovery.enabled: true` | 从 Nacos 查询其他 Agent | 服务消费者 | |
| 272 | + |
| 273 | +两者可独立配置,也可同时启用。当同时启用时: |
| 274 | +- 作为**提供者**:注册本地 Agent 到 Nacos |
| 275 | +- 作为**消费者**:可发现并调用其他已注册的 Agent(包括自己) |
| 276 | + |
| 277 | +## 注意事项 |
| 278 | + |
| 279 | +1. **依赖要求**: |
| 280 | + - 需要添加 `spring-ai-alibaba-starter-a2a-nacos` 依赖 |
| 281 | + - 确保 Nacos 服务正常运行 |
| 282 | + |
| 283 | +2. **AgentCard 元数据**: |
| 284 | + - `server.card.name` 必须与 ReactAgent Bean 的 `name` 一致 |
| 285 | + - `server.card.provider` 可选,用于标识 Agent 提供者信息 |
| 286 | + |
| 287 | +3. **多 Agent 注册**: |
| 288 | + - 默认情况下,只有一个 Agent Bean 会被注册 |
| 289 | + - 如需注册多个 Agent,需运行多个应用实例,每个实例配置不同的 Agent |
| 290 | + |
| 291 | +## 故障排查 |
| 292 | + |
| 293 | +### Agent 没有注册到 Nacos |
| 294 | +- 检查 `registry.enabled: true` 是否配置 |
| 295 | +- 查看应用日志,确认 Nacos Registry AutoConfiguration 是否生效 |
| 296 | +- 验证 Nacos 连接配置(server-addr、username、password) |
| 297 | + |
| 298 | +### AgentCardProvider 无法发现 Agent |
| 299 | +- 检查 `discovery.enabled: true` 是否配置 |
| 300 | +- 确认 Agent 已成功注册到 Nacos |
| 301 | +- 验证 agent name 是否匹配 |
30 | 302 |
|
31 | | - |
| 303 | +### 远程调用失败 |
| 304 | +- 确认目标 Agent 的 REST API 端点可访问 |
| 305 | +- 检查网络连接和防火墙配置 |
| 306 | +- 查看 A2A 消息传输日志 |
0 commit comments