引言
随着人工智能技术的快速发展,Spring AI 提供了一个强大的框架,让开发者能够轻松集成 AI 模型到 Spring Boot 应用中。本文将深入探讨如何通过 Spring AI 集成 DeepSeek 和 ZhiPu AI 模型,实现基础对话、流式输出、带记忆的会话以及 Function Call 的基础功能。无论你是初学者还是有经验的开发者,这篇博客都将为你提供清晰的实现路径和实用代码示例。
1. 项目初始化
Spring AI 是基于 Spring Boot 的 AI 集成框架,官方支持版本为 Spring Boot 3.2.x 和 3.3.x。更多详情可参考 Spring AI 官方文档。
创建项目
使用 Spring Initializr 或你喜欢的 IDE 创建一个 Spring Boot 项目,确保选择兼容的版本。
2. 依赖配置
为了集成 AI 模型,我们需要引入相应的依赖。这里以 OpenAI 和 ZhiPu AI 模型为例,使用 BOM(Bill of Materials)统一管理版本。
OpenAI 模型依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
ZhiPu AI 模型依赖(用于 Function Call)
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
BOM 版本管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
添加 Maven 仓库
由于部分依赖不在 Maven 中央仓库中,需要添加以下仓库:
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases><enabled>false</enabled></releases>
</repository>
<repository>
<id>central-portal-snapshots</id>
<name>Central Portal Snapshots</name>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
3. 配置文件设置
Spring AI 通过配置文件指定模型的请求地址、API Key 和参数。以下是两个模型的配置示例。
DeepSeek 模型配置
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.api-key=${DS_AI_KEY}
spring.ai.openai.chat.options.model=deepseek-reasoner
spring.ai.openai.chat.options.temperature=0.7
temperature
:控制生成内容的创造性,值越小越严谨,默认设为 0.7。
ZhiPu AI 模型配置
spring.ai.zhipuai.api-key=${ZP_AI_KEY}
spring.ai.zhipuai.chat.options.model=GLM-4-Plus
spring.ai.zhipuai.chat.options.temperature=0.7
- ZhiPu AI 默认请求地址无需配置。
4. 实现基础 AI 接口
以下是使用 DeepSeek 模型实现基础对话和流式输出的代码。
@RestController
@RequestMapping("/ai")
public class ChatController {
@Autowired
private OpenAiChatModel chatModel;
// 普通对话
@GetMapping("/generate")
public Map<String, String> generate(@RequestParam(defaultValue = "讲一个笑话") String message) {
return Map.of("generation", chatModel.call(message));
}
// 流式输出(解决乱码问题)
@GetMapping(value = "/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatResponse> generateStream(@RequestParam(defaultValue = "讲一个笑话") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
Flux<ChatResponse> stream = chatModel.stream(prompt);
stream.subscribe(System.out::println);
return stream;
}
}
5. 实现带记忆的会话
为了支持上下文记忆和会话隔离,我们使用 InMemoryChatMemory
和 PromptChatMemoryAdvisor
。
@CrossOrigin
@RestController
@RequestMapping("/ai")
public class ChatController {
@Autowired
private OpenAiChatModel chatModel;
private final InMemoryChatMemory memory = new InMemoryChatMemory();
@GetMapping("/generateStreamWithMemory")
public Flux<ChatResponse> generateStreamWithMemory(
@RequestParam(defaultValue = "讲一个笑话") String prompt,
@RequestParam("chatId") String chatId) {
ChatClient client = ChatClient.builder(chatModel)
.defaultAdvisors(new PromptChatMemoryAdvisor(memory))
.build();
return client.prompt()
.user(prompt)
.advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
.stream()
.chatResponse();
}
}
chatId
:用于隔离不同会话。CHAT_MEMORY_RETRIEVE_SIZE_KEY
:设置记忆检索的最大消息数。
6. 实现 Function Call(基于 ZhiPu AI)
DeepSeek 不支持 Function Call,因此我们切换到 ZhiPu AI 模型。Function Call 允许模型调用外部工具获取实时信息或执行操作。
配置依赖和属性
已在第 2、3 节完成。
基础对话与流式输出
@RestController
@RequestMapping("/zp")
public class ZpChatController {
@Autowired
private ZhiPuAiChatModel chatModel;
@GetMapping("/generate")
public Map<String, String> generate(@RequestParam(defaultValue = "讲一个笑话") String prompt) {
return Map.of("generation", chatModel.call(prompt));
}
@GetMapping(value = "/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatResponse> generateStream(@RequestParam(defaultValue = "讲一个笑话") String message) {
Prompt prompt = new Prompt(new UserMessage(message));
return chatModel.stream(prompt);
}
}
定义工具类
以下工具类用于获取当前时间和设置闹钟:
public class DateTimeTools {
@Tool(description = "获取用户时区中的当前日期和时间")
public String getCurrentDateTime() {
return LocalDateTime.now().atZone(LocaleContextHolder.getTimeZone().toZoneId()).toString();
}
@Tool(description = "在指定时间后设置闹钟")
public void setAlarm(
@ToolParam(description = "当前时间,格式为 yyyy-MM-dd HH:mm:ss") String time,
@ToolParam(description = "间隔时间(秒)") Long intervalSecond) {
System.out.println("设置闹钟时间: " + time);
System.out.println("间隔秒数: " + intervalSecond);
}
}
测试 Function Call
@Test
void testFunctionCall() {
String response = ChatClient.create(zhiPuAiChatModel)
.prompt("在10分钟后设置一个闹钟")
.tools(new DateTimeTools())
.call()
.content();
System.out.println(response);
}
输出示例:
设置闹钟时间: 2025-03-26 21:19:26
间隔秒数: 600
闹钟设置成功,将在10分钟后响起。
7. 总结与扩展
通过以上步骤,我们实现了从基础对话到带记忆会话,再到 Function Call 的完整功能。Spring AI 的灵活性使其成为 AI 集成的理想选择。想了解更多?请查阅以下资源:
希望这篇博客能为你的 Spring AI 之旅提供启发!有什么问题或建议,欢迎留言讨论。