文章目录
🎯 基础理论
什么是 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:8848
username: nacos
password: nacos
namespace: 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: true
description: "用户姓名"
code-review:
content: |
请对以下代码进行审查:
```{language}
{code}
```
请从以下方面进行分析:
1. 代码质量
2. 性能优化建议
3. 安全性考虑
4. 最佳实践建议
description: "代码审查模板"
variables:
- name: "language"
type: "string"
required: true
description: "编程语言"
- name: "code"
type: "string"
required: true
description: "待审查的代码"
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:8848
username: nacos
password: nacos
namespace: public
client:
sse:
connections:
weather-service:
service-name: weather-mcp-server
version: 1.0.0
calculator-service:
service-name: calculator-mcp-server
version: 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:8848
username: nacos
password: nacos
namespace: public
registry:
service-register: true
service-name: weather-mcp-server
service-version: 1.0.0
service-group: DEFAULT_GROUP
server:
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 {
@Override
public String getName() {
return "get_weather";
}
@Override
public String getDescription() {
return "获取指定城市的天气信息";
}
@Override
public McpSchema.ToolInputSchema getInputSchema() {
return McpSchema.ToolInputSchema.builder()
.type("object")
.properties(Map.of(
"city", Map.of(
"type", "string",
"description", "城市名称"
)
))
.required(List.of("city"))
.build();
}
@Override
public 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) {
// 这里可以调用真实的天气 API
return 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");
}
@Override
public String getName() {
return "calculate";
}
@Override
public String getDescription() {
return "执行数学计算";
}
@Override
public 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();
}
@Override
public 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:8848
username: nacos
password: nacos
namespace: public
dynamic:
service-namespace: public
service-group: DEFAULT_GROUP
service-names:
- weather-service
- calculator-service
server:
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: dev
ai:
nacos:
prompt:
template:
enabled: true
alibaba:
nacos:
server-addr: dev-nacos:8848
namespace: dev
---
# 生产环境
spring:
profiles: prod
ai:
alibaba:
nacos:
server-addr: prod-nacos:8848
namespace: 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: 20
max-idle: 10
min-idle: 5
max-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 {
@EventListener
public 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: DEBUG
com.alibaba.nacos: DEBUG
org.springframework.ai.mcp: DEBUG
2. 使用 Actuator 监控
management:
endpoints:
web:
exposure:
include: health,info,metrics,nacos
endpoint:
health:
show-details: always