基于 Spring AI 构建智能餐厅推荐系统:多模型集成的实践指南
本文将教您如何使用 Spring AI 项目构建基于不同聊天模型的应用程序。Spring AI 聊天模型是一个简单易用的接口,允许我们与这些模型进行交互。我们的 Spring Boot 示例应用程序将在 OpenAI、Mistral AI 和 Ollama 提供的三种流行聊天模型之间切换,并展示如何使用 Spring AI 框架实现多轮对话、结构化输出等核心功能。
源代码
如果您想亲自尝试,可以随时查看我的源代码。为此,您必须克隆我的示例 GitHub 仓库。然后,您只需按照我的说明进行操作即可。
项目目标
使用 Spring AI 构建一个智能餐厅推荐系统,实现以下核心功能:
- ✅ 智能推荐:根据用户偏好推荐合适的餐厅
- ✅ 多轮对话:支持上下文对话,提供连贯的用户体验
- ✅ 结构化输出:返回标准化的 JSON 数据格式
- ✅ 多模型支持:支持多个 AI 模型提供商的无缝切换
- ✅ 中文支持:完美支持中文参数和响应
- ✅ 生产就绪:包含完整的配置管理和错误处理
环境搭建
技术栈
- Java 21:使用最新的 LTS 版本
- Spring Boot 3.5.9:提供企业级应用框架
- Spring AI 1.1.2:AI 集成框架
- Maven:依赖管理和构建工具
- Lombok:简化 Java 代码
依赖配置
Spring AI 项目仍在积极开发中,当前使用里程碑版本 1.1.2。
<repositories> <repository> <id>central</id> <name>Central</name> <url>https://repo1.maven.org/maven2/</url> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository></repositories>然后,我们应该包含指定版本的 Spring AI 项目的 Maven BOM。
<properties> <java.version>17</java.version> <spring-ai.version>1.1.2</spring-ai.version></properties>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>由于我们的示例应用暴露了一些 REST 端点,我们应该包含 Spring Boot Web Starter。我们可以包含 Spring Boot Test Starter 来创建一些 JUnit 测试。Spring AI 模块包含在 Maven profiles 部分中。每个聊天模型提供商都有三个不同的配置文件。默认情况下,我们的应用使用 OpenAI,因此它激活了 open-ai 配置文件,该文件包含 spring-ai-starter-model-openai 库。我们应该激活 mistral-ai 配置文件来切换到 Mistral AI。第三个选项是 ollama-ai 配置文件,包含 spring-ai-starter-model-ollama 依赖。这将使在不同聊天模型 AI 提供商之间切换变得轻而易举——我们只需要在 Maven 运行命令中设置配置文件参数。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency></dependencies>
<profiles> <profile> <id>open-ai</id> <activation> <activeByDefault>true</activeByDefault> </activation> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> </dependencies> </profile> <profile> <id>mistral-ai</id> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-mistral-ai</artifactId> </dependency> </dependencies> </profile> <profile> <id>ollama-ai</id> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-ollama</artifactId> </dependency> </dependencies> </profile></profiles>项目配置
环境配置
在开始开发之前,我们需要配置 AI 模型提供商的 API 密钥。
配置 OpenAI
我们必须在 OpenAI 平台门户上拥有一个账户。登录后,访问 API 密钥 页面来生成 API 令牌。
export OPENAI_API_KEY=<YOUR_TOKEN_VALUE>配置 Mistral AI
在 Mistral AI 平台门户上创建账户,访问 API 密钥 页面生成令牌。
export MISTRAL_API_KEY=<YOUR_TOKEN_VALUE>运行和配置 Ollama
Ollama 允许在本地运行大型语言模型。从 下载页面 下载并安装 Ollama,然后运行模型:
ollama run llama3.2配置兼容 OpenAI 的模型
- Groq AI
- 模型: Llama 3.1 70B Versatile
- 特点: 极快的推理速度,高性能
- API: https://api.groq.com/openai/v1
- 获取 API Key: https://console.groq.com/keys
- Docker Model Runner (DMR)
- 模型: Llama 3.2
- 特点: 本地运行,Docker 容器化部署
- API: http://localhost:11434/v1
- 安装: https://docs.docker.com/ai/model-runner/
- OpenRouter AI
- 模型: Llama 3.1 8B Instruct (Free)
- 特点: 多种开源模型选择,成本较低
- API: https://openrouter.ai/api/v1
- 获取 API Key: https://openrouter.ai/keys
- DeepSeek AI
- 模型: DeepSeek Chat
- 特点: 强大的中文理解能力
- API: https://api.deepseek.com/v1
- 获取 API Key: https://platform.deepseek.com/api_keys
- Qwen AI
- 模型: Qwen Plus
- 特点: 阿里巴巴开发的中文大模型
- API: https://dashscope.aliyuncs.com/compatible-mode/v1
- 获取 API Key: https://dashscope.console.aliyun.com/apiKey
Spring Boot 配置
1. 通用配置 (application.yml)
spring.ai.openai.api-key: ${OPENAI_API_KEY}spring.ai.openai.chat.options.model: gpt-5spring.ai.openai.chat.options.temperature: 1
spring.ai.mistralai.api-key: ${MISTRAL_API_KEY}spring.ai.ollama.chat.options.model: llama3.22. OpenAI 兼容模型配置
Groq AI 配置 (application-groq.yml)
spring.ai.openai.api-key: ${GROQ_API_KEY}spring.ai.openai.base-url: https://api.groq.comspring.ai.openai.chat.options.model: llama-3.1-70b-versatileDeepSeek AI 配置 (application-deepseek.yml)
spring.ai.openai.api-key: ${DEEPSEEK_API_KEY}spring.ai.openai.base-url: https://api.deepseek.comspring.ai.openai.chat.options.model: deepseek-chatOpenRouter AI 配置 (application-openrouter.yml)
spring.ai.openai.api-key: ${OPENROUTER_API_KEY}spring.ai.openai.base-url: https://openrouter.aispring.ai.openai.chat.completions-path: /api/v1/chat/completionsspring.ai.openai.chat.options.model: qwen/qwen3-coder:freeQwen AI 配置 (application-qwen.yml)
spring.ai.openai.api-key: ${QWEN_API_KEY}spring.ai.openai.base-url: https://dashscope.aliyuncs.com/compatible-mode/v1spring.ai.openai.chat.options.model: qwen-plusDocker Model Runner 配置 (application-dmr.yml)
spring.ai.openai.base-url: http://localhost:12434/engines/spring.ai.openai.api-key: dummy-keyspring.ai.openai.chat.options.model: llama3.23. 环境变量设置
# 选择其中一个模型设置对应的环境变量export OPENAI_API_KEY=your-openai-api-keyexport MISTRAL_API_KEY=your-mistral-api-keyexport GROQ_API_KEY=your-groq-api-keyexport DEEPSEEK_API_KEY=your-deepseek-api-keyexport OPENROUTER_API_KEY=your-openrouter-api-keyexport QWEN_API_KEY=your-qwen-api-key核心功能实现
1. 数据模型设计
首先定义我们的核心数据模型,使用 Lombok 简化代码:
@Data@NoArgsConstructor@AllArgsConstructorpublic class Restaurant { private Long id; private String name; private String cuisine; private String location; private Double rating; private String description; private String priceRange; private String[] features;}
@Data@NoArgsConstructor@AllArgsConstructorpublic class Dish { private Long id; private String name; private String description; private String cuisine; private Double price; private String category; private List<String> ingredients; private String dietaryInfo; private Integer calories; private String preparationTime; private String difficulty;}2. REST API 设计
设计 RESTful API 接口,支持中文参数和 JSON 数据交换:
@PostMapping("/dishes/generate")public ResponseEntity<List<Dish>> generateDishes(@RequestBody Map<String, Object> request) { String cuisine = (String) request.get("cuisine"); Integer countObj = (Integer) request.get("count"); int count = countObj != null ? countObj : 5;
// 限制菜品数量在合理范围内 int validCount = Math.max(1, Math.min(count, 10));
PromptTemplate template = new PromptTemplate(""" 为{cuisine}菜系生成{count}道特色菜品,包含以下信息: - 菜品名称 - 详细描述 - 主要食材 - 价格范围 - 菜品分类(开胃菜/主菜/甜点等) - 饮食信息(素食/无麸质/低卡等) - 卡路里 - 制作时间 - 难度等级
请返回JSON格式的菜品数据,不要包含解释性文字。 """);
Prompt prompt = template.create(Map.of( "cuisine", cuisine, "count", validCount ));
List<Dish> dishes = chatClient.prompt(prompt) .call() .entity(new ParameterizedTypeReference<List<Dish>>() { });
return ResponseEntity.ok(dishes);}@RestController 类注入自动配置的 ChatClient.Builder 来创建 ChatClient 实例。RestaurantRecommendationController 实现了从 POST /api/restaurants/recommend 端点返回餐厅列表的方法。主要目标是生成一个包含 5 个对象的列表,这些对象具有在 Restaurant 类中定义的字段。
@RequiredArgsConstructor@RestController@RequestMapping("/api/restaurants")public class RestaurantRecommendationController {
private final ChatClient chatClient;
@PostMapping("/recommend") public ResponseEntity<List<Restaurant>> recommendRestaurants(@RequestBody RecommendationRequest request) { PromptTemplate template = new PromptTemplate(""" 根据以下用户偏好推荐5家合适的餐厅: 位置: {location} 菜系: {cuisine} 价格范围: {priceRange} 饮食限制: {dietaryRestrictions} 场合: {occasion} 人数: {groupSize} 用餐时间: {timeOfDay} 其他偏好: {preferences}
请返回餐厅列表,包含餐厅名称、菜系、位置、评分、描述、价格范围和特色。 不要包含任何解释性文字,只返回JSON格式的餐厅数据。 """);
Prompt prompt = template.create(Map.of( "location", request.getLocation() != null ? request.getLocation() : "北京市", "cuisine", request.getCuisine() != null ? request.getCuisine() : "不限", "priceRange", request.getPriceRange() != null ? request.getPriceRange() : "不限", "dietaryRestrictions", request.getDietaryRestrictions() != null ? String.join(", ", request.getDietaryRestrictions()) : "无", "occasion", request.getOccasion() != null ? request.getOccasion() : "日常用餐", "groupSize", request.getGroupSize() != null ? request.getGroupSize().toString() : "1-2人", "timeOfDay", request.getTimeOfDay() != null ? request.getTimeOfDay() : "午餐", "preferences", request.getPreferences() != null ? String.join(", ", request.getPreferences()) : "无" ));
List<Restaurant> restaurants = chatClient.prompt(prompt) .call() .entity(new ParameterizedTypeReference<List<Restaurant>>() {});
return ResponseEntity.ok(restaurants); }}结果并不令人惊讶——系统会返回符合用户偏好的餐厅列表。然而,第二次调用同一个端点时,列表会略有不同。根据我们的提示,聊天客户端应该”返回当前餐厅列表”。所以,我期望得到与之前相同的列表。在这种情况下,问题是聊天客户端不记得之前的对话。
运行应用
# 使用 OpenAI GPT-4o(推荐)mvn spring-boot:run
# 使用 OpenAI(默认配置)mvn spring-boot:run
# 使用 Mistral AImvn spring-boot:run -Pmistral-ai
# 使用 Ollamamvn spring-boot:run -Pollama-ai
# 使用 Groq AImvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=groq"
# 使用 DeepSeek AImvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=deepseek"
# 使用 Qwen AImvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=qwen"
# 使用 OpenRouter AImvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=openrouter"
# 使用 DMR AImvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=dmr"测试 API
# 推荐餐厅curl -X POST http://localhost:8080/api/restaurants/recommend \ -H "Content-Type: application/json" \ -d '{ "location": "北京市", "cuisine": "中餐", "priceRange": "中等价位", "dietaryRestrictions": ["素食"], "occasion": "商务聚餐", "groupSize": 4, "timeOfDay": "晚餐" }'
# 生成菜品curl -X POST "http://localhost:8080/api/restaurants/dishes/generate" \ -H "Content-Type: application/json" \ -d '{"cuisine": "中餐", "count": 3}'
# 获取建议curl -X POST "http://localhost:8080/api/restaurants/advice" \ -H "Content-Type: application/json" \ -d '{"query": "适合情侣约会的餐厅"}'
# 多语言聊天curl -X POST "http://localhost:8080/api/restaurants/chat" \ -H "Content-Type: application/json" \ -d '{"message": "推荐一家好吃的川菜馆", "language": "zh"}'核心技术特性
1. 多轮对话支持
多轮对话是智能应用的核心特性,Spring AI 提供了开箱即用的解决方案:
@Configurationpublic class ChatConfig {
/** * 配置聊天记忆 */ @Bean public ChatMemory chatMemory() { return MessageWindowChatMemory.builder() .chatMemoryRepository(new InMemoryChatMemoryRepository()) .build(); }
/** * 配置 ChatClient * 包含记忆功能和日志记录 */ @Bean public ChatClient chatClient(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory) { return chatClientBuilder .defaultSystem("你是一个专业的餐厅推荐助手。请用中文回答,提供准确、有用的餐厅和菜品推荐。") .defaultAdvisors( MessageChatMemoryAdvisor.builder(chatMemory).build(), new SimpleLoggerAdvisor()) .build(); }}@SpringBootApplicationpublic class RestaurantApplication {
public static void main(String[] args) { SpringApplication.run(RestaurantApplication.class, args); }}现在,让我们进行最终测试。应用重启后,我们可以调用生成餐厅列表的端点。然后,我们将调用 GET /api/restaurants/{id}/details 端点来仅显示具有指定 ID 的单个餐厅。最后,我们可以重复调用 POST /api/restaurants/recommend 端点来验证它是否返回相同的列表。
多轮对话测试
让我们测试多轮对话功能:
# 第一轮对话:询问川菜馆推荐curl -X POST http://localhost:8080/api/restaurants/chat \ -H "Content-Type: application/json" \ -d '{"message": "我想在北京找一家川菜馆", "language": "zh"}'
# 第二轮对话:询问价格(AI 能记住之前的推荐)curl -X POST http://localhost:8080/api/restaurants/chat \ -H "Content-Type: application/json" \ -d '{"message": "刚才推荐的餐厅中,哪家最便宜?", "language": "zh"}'测试结果:AI 能够记住之前的对话内容,提供连贯的回复,准确回答关于之前推荐餐厅的问题。
多轮对话实现原理
- 自动记忆管理:
MessageChatMemoryAdvisor自动管理对话历史 - 内存存储:使用
MessageWindowChatMemory+InMemoryChatMemoryRepository - 透明集成:通过
ChatClient的defaultAdvisors配置 - 上下文保持:每次对话都会包含完整的对话历史
2. 结构化输出支持
Spring AI 提供了多种结构化输出方式,满足不同的开发需求:
1. 直接 .entity() 方法(最简单)
@PostMapping("/restaurant/direct-entity")public ResponseEntity<Restaurant> getRestaurantDirectEntity(@RequestBody Map<String, Object> request) { String cuisine = (String) request.get("cuisine");
PromptTemplate template = new PromptTemplate(""" 推荐1家{cuisine}餐厅,返回JSON格式的餐厅信息。 包含:name, cuisine, location, rating, description, priceRange, features """);
Prompt prompt = template.create(Map.of("cuisine", cuisine));
// 直接使用 .entity() 方法 Restaurant restaurant = chatClient.prompt(prompt) .call() .entity(Restaurant.class);
return ResponseEntity.ok(restaurant);}2. ParameterizedTypeReference(当前项目使用)
@PostMapping("/restaurants/type-ref")public ResponseEntity<List<Restaurant>> getRestaurantsWithTypeRef(@RequestBody Map<String, Object> request) { String cuisine = (String) request.get("cuisine");
PromptTemplate template = new PromptTemplate(""" 推荐3家{cuisine}餐厅,返回JSON格式的餐厅列表。 每个餐厅包含:name, cuisine, location, rating, description, priceRange, features """);
Prompt prompt = template.create(Map.of("cuisine", cuisine));
// 使用 ParameterizedTypeReference List<Restaurant> restaurants = chatClient.prompt(prompt) .call() .entity(new ParameterizedTypeReference<List<Restaurant>>() {});
return ResponseEntity.ok(restaurants);}3. BeanOutputConverter
@PostMapping("/restaurant/bean-converter")public ResponseEntity<Restaurant> getRestaurantWithBeanConverter(@RequestBody Map<String, Object> request) { String cuisine = (String) request.get("cuisine");
PromptTemplate template = new PromptTemplate(""" 推荐1家{cuisine}餐厅,返回JSON格式的餐厅信息。 包含:name, cuisine, location, rating, description, priceRange, features """);
Prompt prompt = template.create(Map.of("cuisine", cuisine));
// 使用 BeanOutputConverter BeanOutputConverter<Restaurant> converter = new BeanOutputConverter<>(Restaurant.class);
String response = chatClient.prompt(prompt) .call() .content();
Restaurant restaurant = converter.convert(response);
return ResponseEntity.ok(restaurant);}4. MapOutputConverter
@PostMapping("/restaurant/map-converter")public ResponseEntity<Map<String, Object>> getRestaurantWithMapConverter(@RequestBody Map<String, Object> request) { String cuisine = (String) request.get("cuisine");
PromptTemplate template = new PromptTemplate(""" 推荐1家{cuisine}餐厅,返回JSON格式的餐厅信息。 包含:name, cuisine, location, rating, description, priceRange, features """);
Prompt prompt = template.create(Map.of("cuisine", cuisine));
// 使用 MapOutputConverter MapOutputConverter converter = new MapOutputConverter();
String response = chatClient.prompt(prompt) .call() .content();
@SuppressWarnings("unchecked") Map<String, Object> restaurant = (Map<String, Object>) converter.convert(response);
return ResponseEntity.ok(restaurant);}5. ListOutputConverter
@PostMapping("/restaurants/list-converter")public ResponseEntity<List<Map<String, String>>> getRestaurantsWithListConverter(@RequestBody Map<String, Object> request) { String cuisine = (String) request.get("cuisine");
PromptTemplate template = new PromptTemplate(""" 推荐3家{cuisine}餐厅,返回JSON格式的餐厅列表。 每个餐厅包含:name, cuisine, location, rating, description, priceRange, features """);
Prompt prompt = template.create(Map.of("cuisine", cuisine));
// 使用 ListOutputConverter ListOutputConverter converter = new ListOutputConverter();
String response = chatClient.prompt(prompt) .call() .content();
@SuppressWarnings("unchecked") List<String> restaurantStrings = (List<String>) converter.convert(response);
// 将字符串列表转换为 Map 列表(这里简化处理) List<Map<String, String>> restaurants = restaurantStrings.stream() .map(str -> Map.of("name", str, "cuisine", cuisine)) .toList();
return ResponseEntity.ok(restaurants);}结构化输出方式对比
| 输出方式 | 代码简洁度 | 类型安全 | 灵活性 | 推荐场景 |
|---|---|---|---|---|
.entity() | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 简单对象 |
ParameterizedTypeReference | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 复杂泛型 |
BeanOutputConverter | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 自定义转换 |
MapOutputConverter | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | 动态结构 |
ListOutputConverter | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | 简单列表 |
结构化输出测试
# 测试直接 .entity() 方法curl -X POST http://localhost:8080/api/structured/restaurant/direct-entity \ -H "Content-Type: application/json" \ -d '{"cuisine": "川菜"}'
# 测试 ParameterizedTypeReferencecurl -X POST http://localhost:8080/api/structured/restaurants/type-ref \ -H "Content-Type: application/json" \ -d '{"cuisine": "川菜"}'
# 测试 BeanOutputConvertercurl -X POST http://localhost:8080/api/structured/restaurant/bean-converter \ -H "Content-Type: application/json" \ -d '{"cuisine": "川菜"}'测试结果:所有结构化输出方式都能正确工作,返回符合预期格式的数据。
功能扩展
基于对当前项目的分析,以下是本项目未涉及但 Spring AI 框架支持的强大功能:
🚀 核心功能扩展
1. 流式响应 (Streaming)
// 当前项目:同步调用List<Restaurant> restaurants = chatClient.prompt() .user("推荐餐厅") .call() .entity(new ParameterizedTypeReference<List<Restaurant>>() {});
// 未实现:流式响应Flux<String> stream = chatClient.prompt() .user("推荐餐厅") .stream() .content();2. 函数调用 (Function Calling)
// 未实现:工具调用@Beanpublic Function<WeatherRequest, WeatherResponse> weatherFunction() { return request -> { // 调用天气 API return weatherService.getWeather(request.getLocation()); };}
// 在 ChatClient 中使用chatClient.prompt() .user("北京今天天气如何?") .functions("weatherFunction") .call();3. 向量数据库集成 (RAG)
// 未实现:检索增强生成@Beanpublic VectorStore vectorStore() { return new PineconeVectorStore(pineconeApiKey, "restaurant-index");}
// RAG 查询chatClient.prompt() .user("推荐适合商务聚餐的餐厅") .advisors(RetrievalAugmentationAdvisor.builder(vectorStore).build()) .call();🎨 多模态支持
4. 图像识别和处理
// 未实现:图像输入@PostMapping("/analyze-image")public ResponseEntity<String> analyzeImage(@RequestParam MultipartFile image) { return chatClient.prompt() .user("分析这张餐厅图片") .media(image) .call() .content();}5. 语音转文字和文字转语音
// 未实现:语音处理@PostMapping("/voice-chat")public ResponseEntity<byte[]> voiceChat(@RequestParam MultipartFile audio) { // 语音转文字 String text = speechToTextService.transcribe(audio);
// AI 处理 String response = chatClient.prompt() .user(text) .call() .content();
// 文字转语音 return textToSpeechService.synthesize(response);}⚡ 性能优化功能
6. 异步处理
// 未实现:异步调用@Asyncpublic CompletableFuture<List<Restaurant>> recommendRestaurantsAsync(RecommendationRequest request) { return chatClient.prompt() .user("推荐餐厅") .call() .entity(new ParameterizedTypeReference<List<Restaurant>>() {}) .toFuture();}7. 缓存机制
// 未实现:响应缓存@Cacheable("restaurant-recommendations")public List<Restaurant> getCachedRecommendations(RecommendationRequest request) { return chatClient.prompt() .user("推荐餐厅") .call() .entity(new ParameterizedTypeReference<List<Restaurant>>() {});}8. 批量处理
// 未实现:批量处理public List<List<Restaurant>> batchRecommend(List<RecommendationRequest> requests) { return chatClient.batch() .prompt("推荐餐厅") .call() .entity(new ParameterizedTypeReference<List<Restaurant>>() {});}🔧 高级管理功能
9. 模型路由和负载均衡
// 未实现:智能路由@Beanpublic ModelRouter modelRouter() { return ModelRouter.builder() .addRoute("restaurant", "gpt-4o") .addRoute("dish", "claude-3") .addRoute("chat", "llama-3") .build();}10. 提示词模板管理
// 未实现:复杂模板@Beanpublic PromptTemplate restaurantTemplate() { return new PromptTemplate(""" 你是一个专业的餐厅推荐助手。 用户偏好:{preferences} 位置:{location} 预算:{budget}
{% if occasion == "商务聚餐" %} 请推荐环境优雅、服务专业的餐厅。 {% elif occasion == "朋友聚会" %} 请推荐氛围轻松、菜品丰富的餐厅。 {% endif %} """);}🏠 企业级功能
11. 多租户支持
// 未实现:多租户隔离@Beanpublic TenantAwareChatClient tenantAwareChatClient() { return TenantAwareChatClient.builder() .tenantResolver(tenantResolver) .modelProvider(tenantModelProvider) .build();}12. 安全性和内容过滤
// 未实现:内容安全@Beanpublic ContentFilterAdvisor contentFilterAdvisor() { return ContentFilterAdvisor.builder() .contentFilter(contentFilter) .build();}13. 监控和指标
// 未实现:性能监控@Beanpublic MetricsAdvisor metricsAdvisor() { return MetricsAdvisor.builder() .meterRegistry(meterRegistry) .build();}💰 成本优化功能
14. 成本控制
// 未实现:成本控制@Beanpublic CostOptimizationAdvisor costOptimizationAdvisor() { return CostOptimizationAdvisor.builder() .maxCostPerRequest(0.01) .fallbackModel("gpt-3.5-turbo") .build();}15. 模型热更新
// 未实现:动态切换@PostMapping("/switch-model")public ResponseEntity<String> switchModel(@RequestParam String modelName) { modelManager.switchModel(modelName); return ResponseEntity.ok("模型已切换");}总结
Spring AI 作为 Spring 生态系统的新成员,为 Java 开发者提供了构建智能化应用的强大工具。随着 AI 技术的不断发展,我们可以期待:
- 更多模型支持:集成更多 AI 模型提供商
- 功能增强:更丰富的 AI 功能特性
- 开发工具:更完善的开发工具和调试支持
- 企业级功能:更强大的企业级特性和监控支持
参考资源
本文基于 Spring AI 1.1.2 版本编写,随着框架的不断发展,部分 API 可能会有变化。建议参考官方文档获取最新信息。