Spring AI Alibaba Nacos 集成实践
文章目录
- 🎯 基础理论
- 什么是 Spring AI Alibaba Nacos 集成?
- 核心组件架构
- 🛠️ 环境搭建
- 1. 前置条件
- 2. 启动 Nacos 服务器
- 使用 Docker 启动 Nacos
- 验证 Nacos 启动
- 3. 项目依赖配置
- 📝 Nacos Prompt 模板管理
- 1. 基础配置
- 2. 在 Nacos 中配置 Prompt 模板
- 步骤 1:登录 Nacos 控制台
- 步骤 2:创建配置
- 3. Java 代码实现
- 创建 Prompt 服务类
- 创建控制器
- 4. 测试 Prompt 模板
- 启动应用
- 测试接口
- 🔌 Nacos MCP 客户端
- 1. MCP 客户端配置
- 2. 创建 MCP 客户端服务
- 3. 创建 MCP 控制器
- 🖥️ Nacos MCP 服务端
- 1. 创建 MCP 服务端项目
- 添加依赖
- 配置文件
- 2. 实现 MCP 工具
- 天气查询工具
- 计算器工具
- 3. 启动类
- 🌐 Nacos MCP 网关
- 1. 网关配置
- 2. 在 Nacos 中配置服务模板
- 🚀 实战项目
- 项目:智能客服系统
- 1. 项目结构
- 2. 主应用实现
- 3. 在 Nacos 中配置客服模板
- 📋 最佳实践
- 1. 配置管理最佳实践
- 环境隔离
- 配置版本管理
- 2. 性能优化
- 缓存策略
- 连接池配置
- 3. 监控和日志
- 自定义监控指标
- 🔧 故障排除
- 常见问题及解决方案
- 1. Nacos 连接失败
- 2. Prompt 模板加载失败
- 3. MCP 服务发现问题
- 调试技巧
- 1. 启用详细日志
- 2. 使用 Actuator 监控
- 📚 参考资料
🎯 基础理论
什么是 Spring AI Alibaba Nacos 集成?
Spring AI Alibaba 与 Nacos 的集成提供了以下核心功能:
- Prompt 模板管理:通过 Nacos 配置中心动态管理 AI 提示词模板
- MCP 服务发现:基于 Nacos 的 MCP (Model Context Protocol) 服务注册与发现
- 动态配置:实时更新 AI 相关配置,无需重启应用
- 负载均衡:支持 MCP 服务的负载均衡和故障转移
核心组件架构
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ AI 应用 │ │ Nacos 服务 │ │ MCP 服务 │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │Prompt模板 │◄┼────┼►│配置中心 │ │ │ │工具服务 │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │MCP客户端 │◄┼────┼►│服务注册中心 │◄┼────┼►│服务注册 │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
🛠️ 环境搭建
1. 前置条件
- Java 17+
- Maven 3.6+
- Nacos Server 2.x 或 3.x
- Spring Boot 3.x
2. 启动 Nacos 服务器
使用 Docker 启动 Nacos
# 启动 Nacos 容器
docker run -d \--name nacos-server \-p 8848:8848 \-p 9848:9848 \-e MODE=standalone \nacos/nacos-server:v2.3.0
验证 Nacos 启动
访问 Nacos 控制台:http://localhost:8848/nacos
- 用户名:nacos
- 密码:nacos
3. 项目依赖配置
创建基础的 Spring Boot 项目,添加以下依赖:
<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring AI Alibaba Core --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId><version>1.0.0-M8.1-SNAPSHOT</version></dependency><!-- Nacos Prompt 模板支持 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-nacos-prompt</artifactId><version>1.0.0-M8.1-SNAPSHOT</version></dependency><!-- Nacos MCP 客户端支持 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-nacos-mcp-client</artifactId><version>1.0.0-M8.1-SNAPSHOT</version></dependency>
</dependencies>
📝 Nacos Prompt 模板管理
1. 基础配置
在 application.yml
中配置 Nacos 连接信息:
spring:ai:nacos:prompt:template:enabled: true # 启用 Nacos Prompt 模板alibaba:nacos:server-addr: localhost:8848username: nacospassword: nacosnamespace: public
2. 在 Nacos 中配置 Prompt 模板
步骤 1:登录 Nacos 控制台
访问 http://localhost:8848/nacos,使用 nacos/nacos 登录。
步骤 2:创建配置
在「配置管理」→「配置列表」中,点击「+」创建新配置:
- Data ID:
ai-prompt-templates
- Group:
DEFAULT_GROUP
- 配置格式:
YAML
- 配置内容:
templates:greeting:content: "你好,{name}!欢迎使用 Spring AI Alibaba。"description: "问候语模板"variables:- name: "name"type: "string"required: truedescription: "用户姓名"code-review:content: |请对以下代码进行审查:```{language}{code}```请从以下方面进行分析:1. 代码质量2. 性能优化建议3. 安全性考虑4. 最佳实践建议description: "代码审查模板"variables:- name: "language"type: "string"required: truedescription: "编程语言"- name: "code"type: "string"required: truedescription: "待审查的代码"
3. Java 代码实现
创建 Prompt 服务类
package com.example.demo.service;import com.alibaba.cloud.ai.prompt.ConfigurablePromptTemplateFactory;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.stereotype.Service;import java.util.Map;@Service
public class PromptService {private final ConfigurablePromptTemplateFactory promptTemplateFactory;public PromptService(ConfigurablePromptTemplateFactory promptTemplateFactory) {this.promptTemplateFactory = promptTemplateFactory;}/*** 获取问候语*/public String getGreeting(String name) {PromptTemplate template = promptTemplateFactory.create("greeting");return template.render(Map.of("name", name));}/*** 获取代码审查提示词*/public String getCodeReviewPrompt(String language, String code) {PromptTemplate template = promptTemplateFactory.create("code-review");return template.render(Map.of("language", language,"code", code));}
}
创建控制器
package com.example.demo.controller;import com.example.demo.service.PromptService;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/prompt")
public class PromptController {private final PromptService promptService;public PromptController(PromptService promptService) {this.promptService = promptService;}@GetMapping("/greeting")public String greeting(@RequestParam String name) {return promptService.getGreeting(name);}@PostMapping("/code-review")public String codeReview(@RequestBody CodeReviewRequest request) {return promptService.getCodeReviewPrompt(request.language(), request.code());}public record CodeReviewRequest(String language, String code) {}
}
4. 测试 Prompt 模板
启动应用
mvn spring-boot:run
测试接口
# 测试问候语
curl "http://localhost:8080/api/prompt/greeting?name=张三"# 测试代码审查
curl -X POST "http://localhost:8080/api/prompt/code-review" \-H "Content-Type: application/json" \-d '{"language": "java","code": "public class Hello { public static void main(String[] args) { System.out.println(\"Hello World\"); } }"}'
🔌 Nacos MCP 客户端
1. MCP 客户端配置
在 application.yml
中添加 MCP 客户端配置:
spring:ai:alibaba:mcp:nacos:server-addr: localhost:8848username: nacospassword: nacosnamespace: publicclient:sse:connections:weather-service:service-name: weather-mcp-serverversion: 1.0.0calculator-service:service-name: calculator-mcp-serverversion: 1.0.0
2. 创建 MCP 客户端服务
package com.example.demo.service;import com.alibaba.cloud.ai.mcp.nacos.client.transport.LoadbalancedMcpSyncClient;
import org.springframework.ai.mcp.client.McpSyncClient;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;@Service
public class McpClientService {private final LoadbalancedMcpSyncClient mcpClient;public McpClientService(LoadbalancedMcpSyncClient mcpClient) {this.mcpClient = mcpClient;}/*** 获取可用的工具列表*/public List<McpSchema.Tool> getAvailableTools() {return mcpClient.listTools().tools();}/*** 调用天气查询工具*/public String getWeather(String city) {var request = McpSchema.CallToolRequest.builder().name("get_weather").arguments(Map.of("city", city)).build();var response = mcpClient.callTool(request);return response.content().get(0).text();}/*** 调用计算器工具*/public String calculate(String expression) {var request = McpSchema.CallToolRequest.builder().name("calculate").arguments(Map.of("expression", expression)).build();var response = mcpClient.callTool(request);return response.content().get(0).text();}
}
3. 创建 MCP 控制器
package com.example.demo.controller;import com.example.demo.service.McpClientService;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/api/mcp")
public class McpController {private final McpClientService mcpClientService;public McpController(McpClientService mcpClientService) {this.mcpClientService = mcpClientService;}@GetMapping("/tools")public List<McpSchema.Tool> getTools() {return mcpClientService.getAvailableTools();}@GetMapping("/weather")public String getWeather(@RequestParam String city) {return mcpClientService.getWeather(city);}@GetMapping("/calculate")public String calculate(@RequestParam String expression) {return mcpClientService.calculate(expression);}
}
🖥️ Nacos MCP 服务端
1. 创建 MCP 服务端项目
添加依赖
<dependencies><!-- MCP 服务端支持 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-nacos-mcp-server</artifactId><version>1.0.0-M8.1-SNAPSHOT</version></dependency><!-- WebFlux 支持 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId><version>1.0.0-M8</version></dependency>
</dependencies>
配置文件
spring:ai:alibaba:mcp:nacos:server-addr: localhost:8848username: nacospassword: nacosnamespace: publicregistry:service-register: trueservice-name: weather-mcp-serverservice-version: 1.0.0service-group: DEFAULT_GROUPserver:port: 8081
2. 实现 MCP 工具
天气查询工具
package com.example.weather.tools;import org.springframework.ai.mcp.server.McpAsyncFunction;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;@Component
public class WeatherTool implements McpAsyncFunction {@Overridepublic String getName() {return "get_weather";}@Overridepublic String getDescription() {return "获取指定城市的天气信息";}@Overridepublic McpSchema.ToolInputSchema getInputSchema() {return McpSchema.ToolInputSchema.builder().type("object").properties(Map.of("city", Map.of("type", "string","description", "城市名称"))).required(List.of("city")).build();}@Overridepublic CompletableFuture<List<McpSchema.TextContent>> apply(Map<String, Object> arguments) {String city = (String) arguments.get("city");// 模拟天气查询String weatherInfo = getWeatherInfo(city);var content = McpSchema.TextContent.builder().type("text").text(weatherInfo).build();return CompletableFuture.completedFuture(List.of(content));}private String getWeatherInfo(String city) {// 这里可以调用真实的天气 APIreturn String.format("{
" +" \"city\": \"%s\",
" +" \"temperature\": \"22°C\",
" +" \"weather\": \"晴天\",
" +" \"humidity\": \"65%%\",
" +" \"wind\": \"东南风 3级\"
" +"}", city);}
}
计算器工具
package com.example.weather.tools;import org.springframework.ai.mcp.server.McpAsyncFunction;
import org.springframework.ai.mcp.spec.McpSchema;
import org.springframework.stereotype.Component;import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;@Component
public class CalculatorTool implements McpAsyncFunction {private final ScriptEngine scriptEngine;public CalculatorTool() {this.scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript");}@Overridepublic String getName() {return "calculate";}@Overridepublic String getDescription() {return "执行数学计算";}@Overridepublic McpSchema.ToolInputSchema getInputSchema() {return McpSchema.ToolInputSchema.builder().type("object").properties(Map.of("expression", Map.of("type", "string","description", "数学表达式,如:2+3*4"))).required(List.of("expression")).build();}@Overridepublic CompletableFuture<List<McpSchema.TextContent>> apply(Map<String, Object> arguments) {String expression = (String) arguments.get("expression");try {Object result = scriptEngine.eval(expression);var content = McpSchema.TextContent.builder().type("text").text("计算结果:" + expression + " = " + result).build();return CompletableFuture.completedFuture(List.of(content));} catch (Exception e) {var content = McpSchema.TextContent.builder().type("text").text("计算错误:" + e.getMessage()).build();return CompletableFuture.completedFuture(List.of(content));}}
}
3. 启动类
package com.example.weather;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class WeatherMcpServerApplication {public static void main(String[] args) {SpringApplication.run(WeatherMcpServerApplication.class, args);}
}
🌐 Nacos MCP 网关
MCP 网关提供了动态代理功能,可以将 Nacos 中注册的服务转换为 MCP 协议服务。
1. 网关配置
spring:ai:alibaba:mcp:nacos:server-addr: localhost:8848username: nacospassword: nacosnamespace: publicdynamic:service-namespace: publicservice-group: DEFAULT_GROUPservice-names:- weather-service- calculator-serviceserver:port: 8082
2. 在 Nacos 中配置服务模板
在 Nacos 控制台中创建配置:
- Data ID:
weather-service-mcp-template
- Group:
DEFAULT_GROUP
- 配置内容:
{"tools": [{"name": "get_weather","description": "获取天气信息","inputSchema": {"type": "object","properties": {"city": {"type": "string","description": "城市名称"}},"required": ["city"]},"requestTemplate": {"url": "/api/weather?city={{.args.city}}","method": "GET"},"responseTemplate": {"body": "天气信息:{{.response.body}}"}}]
}
🚀 实战项目
项目:智能客服系统
我们将创建一个完整的智能客服系统,集成所有 Nacos 功能。
1. 项目结构
intelligent-customer-service/
├── customer-service-app/ # 主应用
├── weather-mcp-server/ # 天气服务
├── knowledge-mcp-server/ # 知识库服务
├── mcp-gateway/ # MCP 网关
└── docker-compose.yml # 容器编排
2. 主应用实现
package com.example.customerservice.service;import com.alibaba.cloud.ai.prompt.ConfigurablePromptTemplateFactory;
import com.example.customerservice.mcp.McpClientService;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;import java.util.Map;@Service
public class CustomerServiceBot {private final ChatClient chatClient;private final ConfigurablePromptTemplateFactory promptFactory;private final McpClientService mcpClientService;public CustomerServiceBot(ChatClient chatClient, ConfigurablePromptTemplateFactory promptFactory,McpClientService mcpClientService) {this.chatClient = chatClient;this.promptFactory = promptFactory;this.mcpClientService = mcpClientService;}public String handleCustomerQuery(String query, String customerName) {// 1. 使用 Nacos 中的 prompt 模板var promptTemplate = promptFactory.create("customer-service");// 2. 根据查询类型调用相应的 MCP 服务String contextInfo = "";if (query.contains("天气")) {contextInfo = mcpClientService.getWeather(extractCity(query));} else if (query.contains("计算")) {contextInfo = mcpClientService.calculate(extractExpression(query));}// 3. 构建完整的提示词String fullPrompt = promptTemplate.render(Map.of("customerName", customerName,"query", query,"contextInfo", contextInfo));// 4. 调用 AI 模型生成回复return chatClient.call(new Prompt(fullPrompt)).getResult().getOutput().getContent();}private String extractCity(String query) {// 简单的城市提取逻辑return "北京"; // 实际应用中需要更复杂的 NLP 处理}private String extractExpression(String query) {// 简单的表达式提取逻辑return "2+3"; // 实际应用中需要更复杂的解析}
}
3. 在 Nacos 中配置客服模板
templates:customer-service:content: |你是一个专业的客服助手,正在为客户 {customerName} 提供服务。客户问题:{query}相关信息:{contextInfo}请根据以上信息,用友好、专业的语气回复客户。如果需要更多信息,请礼貌地询问。回复要求:1. 语气友好、专业2. 回答准确、有用3. 如果无法解答,请引导客户联系人工客服description: "客服回复模板"variables:- name: "customerName"type: "string"required: true- name: "query"type: "string"required: true- name: "contextInfo"type: "string"required: false
📋 最佳实践
1. 配置管理最佳实践
环境隔离
# 开发环境
spring:profiles:active: devai:nacos:prompt:template:enabled: truealibaba:nacos:server-addr: dev-nacos:8848namespace: dev---
# 生产环境
spring:profiles: prodai:alibaba:nacos:server-addr: prod-nacos:8848namespace: prod
配置版本管理
@Component
public class PromptVersionManager {private final ConfigurablePromptTemplateFactory promptFactory;public PromptVersionManager(ConfigurablePromptTemplateFactory promptFactory) {this.promptFactory = promptFactory;}public String getPromptWithFallback(String templateName, String version) {try {// 尝试获取指定版本的模板return promptFactory.create(templateName + "_v" + version).getTemplate();} catch (Exception e) {// 回退到默认版本return promptFactory.create(templateName).getTemplate();}}
}
2. 性能优化
缓存策略
@Service
public class CachedPromptService {private final ConfigurablePromptTemplateFactory promptFactory;private final Cache<String, PromptTemplate> templateCache;public CachedPromptService(ConfigurablePromptTemplateFactory promptFactory) {this.promptFactory = promptFactory;this.templateCache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(Duration.ofMinutes(10)).build();}public PromptTemplate getTemplate(String name) {return templateCache.get(name, key -> promptFactory.create(key));}
}
连接池配置
spring:ai:alibaba:nacos:# 连接池配置pool:max-active: 20max-idle: 10min-idle: 5max-wait: 5000
3. 监控和日志
自定义监控指标
@Component
public class NacosMetrics {private final MeterRegistry meterRegistry;private final Counter promptLoadCounter;private final Timer mcpCallTimer;public NacosMetrics(MeterRegistry meterRegistry) {this.meterRegistry = meterRegistry;this.promptLoadCounter = Counter.builder("nacos.prompt.load").description("Prompt template load count").register(meterRegistry);this.mcpCallTimer = Timer.builder("nacos.mcp.call").description("MCP service call duration").register(meterRegistry);}public void recordPromptLoad(String templateName) {promptLoadCounter.increment(Tags.of("template", templateName));}public void recordMcpCall(String serviceName, Duration duration) {mcpCallTimer.record(duration, Tags.of("service", serviceName));}
}
🔧 故障排除
常见问题及解决方案
1. Nacos 连接失败
问题:应用启动时无法连接到 Nacos 服务器
解决方案:
# 检查 Nacos 服务状态
curl http://localhost:8848/nacos/v1/ns/operator/metrics# 检查网络连通性
telnet localhost 8848# 查看应用日志
tail -f logs/spring.log | grep nacos
2. Prompt 模板加载失败
问题:提示词模板无法从 Nacos 加载
解决方案:
@Component
public class PromptHealthChecker {@EventListenerpublic void onApplicationReady(ApplicationReadyEvent event) {try {// 验证关键模板是否可用promptFactory.create("customer-service");log.info("Prompt templates loaded successfully");} catch (Exception e) {log.error("Failed to load prompt templates", e);// 可以选择使用本地备份模板}}
}
3. MCP 服务发现问题
问题:MCP 客户端无法发现服务
解决方案:
@Component
public class McpServiceHealthChecker {@Scheduled(fixedRate = 30000) // 每30秒检查一次public void checkMcpServices() {try {List<McpSchema.Tool> tools = mcpClientService.getAvailableTools();log.info("Available MCP tools: {}", tools.size());} catch (Exception e) {log.warn("MCP service check failed", e);}}
}
调试技巧
1. 启用详细日志
logging:level:com.alibaba.cloud.ai: DEBUGcom.alibaba.nacos: DEBUGorg.springframework.ai.mcp: DEBUG
2. 使用 Actuator 监控
management:endpoints:web:exposure:include: health,info,metrics,nacosendpoint:health:show-details: always
📚 参考资料
- Spring AI Alibaba 官方文档
- Nacos 官方文档
- MCP 协议规范
- Spring AI 文档