基于A2A协议将智能体注册到Nacos3.x
1.配置和简介
Nacos3.x比Nacos2.x多了可以注册智能体的功能。
配置密钥,32位即可
启动分为集群模式和单机模式,单机模式下,默认存储在derby下。
2.智能体注册中心:
AgentScope也是自带注册中心的,叫AgentScopeA2aServer。
现在我们是把当前项目的注册中心改成nacos。
1.通过SpringBoot,以Bean的形式注册到注册中心
2.手动写入注册中心,好处能够自定义智能体卡片对象。通过Builder方法传入。
本项目采用Nacos为注册中心。
那么springBoot怎么知道我的注册中心是Nacos?
通过yml文件配置即可:
agentscope: a2a: server: enabled: true card: name: TripPlanner Agent description: 行程规划agent nacos: server-addr: localhost:8848 username: nacos password: nacos创建一个生成智能体的工具类:
@Slf4j @Service public class AgentUtils { //从配置中读取敏感资源,不能使用static @Resource private Properties properties; public ReActAgent.Builder getReActAgentBuilder(String name, String description) { return ReActAgent.builder() .name(name) .description(description) .model(DashScopeChatModel.builder() //请求语言大模型的apikey .apiKey(properties.getAlibabaDashscopeKey()) //所使用的语言大模型 .modelName(properties.getModelName()) .stream(true) .build()); } public static Flux<Event> streamResponse(AgentBase agent, String prompt) { return agent.stream(Msg.builder().role(MsgRole.USER) .content(List.of(TextBlock.builder().text(prompt).build())).build()); } }主管智能体在nacos上获得了智能体卡片并知道了这个智能体的功能,然后就会把任务分发下去。
在routeMakingAgent目录下的agent包下创建这个类:
!注意主管智能体是不用注册到nacos的
@Component @Slf4j public class RouteMakingAgent { @Resource private AgentUtils agentUtils; @Resource private BaiduMapMCP baiduMapMCP; @Bean public ReActAgent getRouteMakingAgent() { //创建百度地图MCP客户端 baiduMapMCP.getBaiduMapMCP(); //初始化百度地图MCP客户端 McpClientWrapper mcpClient = baiduMapMCP.initBaiduMapMCP(); ToolUtils toolUtils = new ToolUtils(); //将百度地图MCP注册到工具包 Toolkit toolkit = toolUtils.getToolkit(mcpClient); //打印挂载的工具 Set<String> toolNames = toolkit.getToolNames(); log.info("============="); toolNames.stream().forEach( value -> log.info("挂载的工具名称:" + value) ); log.info("============="); //注入到nacos return agentUtils.getReActAgentBuilder("RouteMakingAgent", "擅长路线制定规划") //工具包 .toolkit(toolkit) .build(); } }@Component public class TripPlannerAgent { @Resource private AgentUtils agentUtils; @Resource private SuggestSightAgent suggestSightAgent; @Bean public ReActAgent getTripPlannerAgent() throws Exception { /* ********************** * * 1. * AgentScope框架自带了注册中心: AgentScopeA2aServer * * 2. * AgentScope框架将智能体卡片注册到注册中心,有2种方案: * a. 通过SpringBoot, 以Bean的形式自动注入 * b. 手动写入注册中心, 主要针对于AgentScopeA2aServer * * * *********************/ Toolkit toolkit = new Toolkit(); //子智能体 toolkit.registration().subAgent( suggestSightAgent::getSuggestSightAgent ).apply(); //构建skill ,将工具包和skill结合 ReActAgent.Builder builder = agentUtils.getReActAgentBuilder( "TripPlannerAgent", "擅长处理景点行程规划" ) //挂载工具包 .toolkit(toolkit); return builder.build(); } }写一个工具类让主管智能体去nacos发现是否有这样的智能体,读取智能体卡片,
@Slf4j public class RemoteAgentTool { @Tool(description = "擅长制定最优驾车路线的Agent") public void callRouteMakingAgent( @ToolParam(name = "prompt", description = "驾车的起点和终点") String prompt ) throws NacosException { log.info("============"); log.info("工具方法:路线制定智能体...正在调用中"); log.info("============"); A2aAgent agent = A2aAgent.builder() .name("RouteMakingAgent") //必须和注册中心的智能体名字一样 .agentCardResolver( //创建 Nacos 的 AgentCardResolver new NacosAgentCardResolver(NacosUtil.getNacosClient())) .build(); prompt = "调用百度地图MCP, 制定最优驾车路线:" + prompt; PromptUtils promptUtils = new PromptUtils(); Msg userMsg = promptUtils.getPrompt(prompt); log.info("============"); log.info("获取到的远程Agent描述:" + agent.getDescription()); log.info("============"); AgentUtils.streamResponse(agent, "调用百度地图MCP"); } @Tool(description = "从Nacos注册中心获取行程规划Agent") public void callTripPlannerAgent() throws NacosException { A2aAgent agent = A2aAgent.builder() .name("TripPlannerAgent") .agentCardResolver( //创建 Nacos 的 AgentCardResolver new NacosAgentCardResolver(NacosUtil.getNacosClient())) .build(); //远程Agent运行 agent.call().block(); } }创建一个百度地图MCP客户端
@Slf4j @Component public class BaiduMapMCP { @Resource private Properties properties; //MCP 客户端 private volatile McpClientWrapper baiduMapMCP = null; //MCP 客户端初始化 private volatile boolean mcpInitialized = false; public void getBaiduMapMCP() { //创建MCP客户端 baiduMapMCP = McpClientBuilder.create("BaiduMap-mcp") //和MCP Server以SSE方式进行通信 .sseTransport(properties.getBaiduMapAddr()) //请求超时 .timeout(Duration.ofSeconds(120)) //异步请求 .buildAsync() .block(); } /** * * description: 初始化百度地图MCP客户端 * @param : * @return io.agentscope.core.tool.mcp.McpClientWrapper */ public McpClientWrapper initBaiduMapMCP() { //通过Optional判断百度MCP客户端是否为null Optional<McpClientWrapper> mcpClientWrapper = Optional.ofNullable(baiduMapMCP); if(mcpClientWrapper.isPresent()) { if(!mcpInitialized) { //线程锁 synchronized (this) { if (!mcpInitialized) { try { //MCP客户端初始化, 通过阻塞线程让客户端和服务端成功建立联系。 baiduMapMCP.initialize().block(); //获取MCP服务端工具列表 if(baiduMapMCP.isInitialized()) { log.info("============="); log.info("百度地图MCP 客户端初始化成功!"); log.info("============="); baiduMapMCP.listTools().block().forEach(tool -> { log.info("=================="); log.info("百度地图MCP工具列表:" + tool.name()); log.info("=================="); }); mcpInitialized=true; } } catch (Exception e) { log.error("百度地图MCP客户端初始化失败: {}", e.getMessage(), e); baiduMapMCP = null; } } } } } return baiduMapMCP; } }在魔塔社区配置百度地图的客户端,这里使用百度地图,SSE协议就用SSE,
通过工具包挂载到智能体上面,在RouteMakingAgent的代码里面有详解,
具体的工具包类:
那么百度地图的MCP的客户端走第二个getToolkit方法,这是重写的方法。
public class ToolUtils { private final Toolkit toolkit; public ToolUtils() { toolkit = new Toolkit(); } public Toolkit getToolkit(Object tool) { toolkit.registerTool(tool); return toolkit; } public Toolkit getToolkit(McpClientWrapper mcp) { toolkit.registerMcpClient(mcp); return toolkit; } }主管智能体会根据智能体的description的描述来分配任务,所以description有两种配置方式,
1.yml文件配置(优先级最高)
agentscope: a2a: server: enabled: true card: name: TripPlanner Agent description: 行程规划agent nacos: server-addr: localhost:8848 username: nacos password: nacos@Component public class TripPlannerAgent { @Resource private AgentUtils agentUtils; @Resource private SuggestSightAgent suggestSightAgent; @Bean public ReActAgent getTripPlannerAgent() throws Exception { Toolkit toolkit = new Toolkit(); //子智能体 toolkit.registration().subAgent( suggestSightAgent::getSuggestSightAgent ).apply(); //构建skill ,将工具包和skill结合 return agentUtils.getReActAgentBuilder( "TripPlannerAgent", "擅长处理景点行程规划" //这里就是我对这个处理景点智能体的描述 ) //挂载工具包 .toolkit(toolkit) .build(); } }打开nacos:可以发现还是以yml文件为主
解决方法:注释description即可,但同时要先删除nacos已经注册的智能体卡片。
