基于 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 令牌。

Terminal window
export OPENAI_API_KEY=<YOUR_TOKEN_VALUE>

配置 Mistral AI

Mistral AI 平台门户上创建账户,访问 API 密钥 页面生成令牌。

Terminal window
export MISTRAL_API_KEY=<YOUR_TOKEN_VALUE>

运行和配置 Ollama

Ollama 允许在本地运行大型语言模型。从 下载页面 下载并安装 Ollama,然后运行模型:

Terminal window
ollama run llama3.2

配置兼容 OpenAI 的模型

  1. Groq AI
  1. Docker Model Runner (DMR)
  1. OpenRouter AI
  1. DeepSeek AI
  1. Qwen AI

Spring Boot 配置

1. 通用配置 (application.yml)

spring.ai.openai.api-key: ${OPENAI_API_KEY}
spring.ai.openai.chat.options.model: gpt-5
spring.ai.openai.chat.options.temperature: 1
spring.ai.mistralai.api-key: ${MISTRAL_API_KEY}
spring.ai.ollama.chat.options.model: llama3.2

2. OpenAI 兼容模型配置

Groq AI 配置 (application-groq.yml)

spring.ai.openai.api-key: ${GROQ_API_KEY}
spring.ai.openai.base-url: https://api.groq.com
spring.ai.openai.chat.options.model: llama-3.1-70b-versatile

DeepSeek AI 配置 (application-deepseek.yml)

spring.ai.openai.api-key: ${DEEPSEEK_API_KEY}
spring.ai.openai.base-url: https://api.deepseek.com
spring.ai.openai.chat.options.model: deepseek-chat

OpenRouter AI 配置 (application-openrouter.yml)

spring.ai.openai.api-key: ${OPENROUTER_API_KEY}
spring.ai.openai.base-url: https://openrouter.ai
spring.ai.openai.chat.completions-path: /api/v1/chat/completions
spring.ai.openai.chat.options.model: qwen/qwen3-coder:free

Qwen AI 配置 (application-qwen.yml)

spring.ai.openai.api-key: ${QWEN_API_KEY}
spring.ai.openai.base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
spring.ai.openai.chat.options.model: qwen-plus

Docker Model Runner 配置 (application-dmr.yml)

spring.ai.openai.base-url: http://localhost:12434/engines/
spring.ai.openai.api-key: dummy-key
spring.ai.openai.chat.options.model: llama3.2

3. 环境变量设置

Terminal window
# 选择其中一个模型设置对应的环境变量
export OPENAI_API_KEY=your-openai-api-key
export MISTRAL_API_KEY=your-mistral-api-key
export GROQ_API_KEY=your-groq-api-key
export DEEPSEEK_API_KEY=your-deepseek-api-key
export OPENROUTER_API_KEY=your-openrouter-api-key
export QWEN_API_KEY=your-qwen-api-key

核心功能实现

1. 数据模型设计

首先定义我们的核心数据模型,使用 Lombok 简化代码:

@Data
@NoArgsConstructor
@AllArgsConstructor
public 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
@AllArgsConstructor
public 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);
}
}

结果并不令人惊讶——系统会返回符合用户偏好的餐厅列表。然而,第二次调用同一个端点时,列表会略有不同。根据我们的提示,聊天客户端应该”返回当前餐厅列表”。所以,我期望得到与之前相同的列表。在这种情况下,问题是聊天客户端不记得之前的对话。

运行应用

Terminal window
# 使用 OpenAI GPT-4o(推荐)
mvn spring-boot:run
# 使用 OpenAI(默认配置)
mvn spring-boot:run
# 使用 Mistral AI
mvn spring-boot:run -Pmistral-ai
# 使用 Ollama
mvn spring-boot:run -Pollama-ai
# 使用 Groq AI
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=groq"
# 使用 DeepSeek AI
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=deepseek"
# 使用 Qwen AI
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=qwen"
# 使用 OpenRouter AI
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=openrouter"
# 使用 DMR AI
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=dmr"

测试 API

Terminal window
# 推荐餐厅
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 提供了开箱即用的解决方案:

@Configuration
public 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();
}
}
@SpringBootApplication
public class RestaurantApplication {
public static void main(String[] args) {
SpringApplication.run(RestaurantApplication.class, args);
}
}

现在,让我们进行最终测试。应用重启后,我们可以调用生成餐厅列表的端点。然后,我们将调用 GET /api/restaurants/{id}/details 端点来仅显示具有指定 ID 的单个餐厅。最后,我们可以重复调用 POST /api/restaurants/recommend 端点来验证它是否返回相同的列表。

多轮对话测试

让我们测试多轮对话功能:

Terminal window
# 第一轮对话:询问川菜馆推荐
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 能够记住之前的对话内容,提供连贯的回复,准确回答关于之前推荐餐厅的问题。

多轮对话实现原理

  1. 自动记忆管理MessageChatMemoryAdvisor 自动管理对话历史
  2. 内存存储:使用 MessageWindowChatMemory + InMemoryChatMemoryRepository
  3. 透明集成:通过 ChatClientdefaultAdvisors 配置
  4. 上下文保持:每次对话都会包含完整的对话历史

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⭐⭐⭐⭐⭐⭐⭐⭐⭐简单列表

结构化输出测试

Terminal window
# 测试直接 .entity() 方法
curl -X POST http://localhost:8080/api/structured/restaurant/direct-entity \
-H "Content-Type: application/json" \
-d '{"cuisine": "川菜"}'
# 测试 ParameterizedTypeReference
curl -X POST http://localhost:8080/api/structured/restaurants/type-ref \
-H "Content-Type: application/json" \
-d '{"cuisine": "川菜"}'
# 测试 BeanOutputConverter
curl -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)

// 未实现:工具调用
@Bean
public Function<WeatherRequest, WeatherResponse> weatherFunction() {
return request -> {
// 调用天气 API
return weatherService.getWeather(request.getLocation());
};
}
// 在 ChatClient 中使用
chatClient.prompt()
.user("北京今天天气如何?")
.functions("weatherFunction")
.call();

3. 向量数据库集成 (RAG)

// 未实现:检索增强生成
@Bean
public 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. 异步处理

// 未实现:异步调用
@Async
public 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. 模型路由和负载均衡

// 未实现:智能路由
@Bean
public ModelRouter modelRouter() {
return ModelRouter.builder()
.addRoute("restaurant", "gpt-4o")
.addRoute("dish", "claude-3")
.addRoute("chat", "llama-3")
.build();
}

10. 提示词模板管理

// 未实现:复杂模板
@Bean
public PromptTemplate restaurantTemplate() {
return new PromptTemplate("""
你是一个专业的餐厅推荐助手。
用户偏好:{preferences}
位置:{location}
预算:{budget}
{% if occasion == "商务聚餐" %}
请推荐环境优雅、服务专业的餐厅。
{% elif occasion == "朋友聚会" %}
请推荐氛围轻松、菜品丰富的餐厅。
{% endif %}
""");
}

🏠 企业级功能

11. 多租户支持

// 未实现:多租户隔离
@Bean
public TenantAwareChatClient tenantAwareChatClient() {
return TenantAwareChatClient.builder()
.tenantResolver(tenantResolver)
.modelProvider(tenantModelProvider)
.build();
}

12. 安全性和内容过滤

// 未实现:内容安全
@Bean
public ContentFilterAdvisor contentFilterAdvisor() {
return ContentFilterAdvisor.builder()
.contentFilter(contentFilter)
.build();
}

13. 监控和指标

// 未实现:性能监控
@Bean
public MetricsAdvisor metricsAdvisor() {
return MetricsAdvisor.builder()
.meterRegistry(meterRegistry)
.build();
}

💰 成本优化功能

14. 成本控制

// 未实现:成本控制
@Bean
public 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 可能会有变化。建议参考官方文档获取最新信息。

订阅文章

订阅更新,不错过后续文章

直接通过 RSS 和 Telegram 订阅本站更新。

分享文章

如果这篇有帮助,可以顺手转发

直接分享给同事、朋友,或者发到你的社交平台。