SpringAI1.0.0 入门案例
SpringAI 入门案例
本项目基于SpringBoot使用SpringAI调用DeepSeek实现AI问答
版本说明
技术栈 | 版本 |
---|---|
SpringBoot | 3.5.0 |
SpringAI | 1.0.0 |
JDK | 17 |
Maven | 3.8.4 |
创建Maven工程
创建工程
file->new->project->选择左侧maven,创建Maven工程->指定SDK为17->next->输入项目名->finish
环境检查
Maven版本
Maven版本不兼容会导致项目构建失败,项目编译前需确保maven版本兼容
file-> Setting -> build -> build tools -> maven -> user settings -> 选择maven3.8.4版本的settings.xml所在路径
JDK版本
file -> Project Structure -> project ->确定SDK版本为17
引入依赖
依赖列表
- spring-boot-starter-web web工程依赖
- lombok 简化代码依赖
- junit 单元测试依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><version>3.5.0</version><artifactId>spring-boot-starter-parent</artifactId></parent><groupId>org.example</groupId><artifactId>demo25</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.0.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
</project>
SpringBoot工程前置准备
项目入口
创建项目启动类
package com.pj.ai;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author pj* @date 2025/5/30 8:24**/
@SpringBootApplication
public class Demo25Application {public static void main(String[] args) {SpringApplication.run(Demo25Application.class, args);}
}
配置文件
在resources目录下创建application.yml
创建logback.xml配置日志记录
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds"><!-- 定义日志文件的存储路径 --><property name="LOG_PATH" value="./logs" /><!-- 定义日志文件的名称格式 --><property name="LOG_FILE" value="app" /><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- 日志输出格式 --><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n</pattern><!-- 字符编码 --><charset>UTF-8</charset></encoder></appender><!-- 滚动日志文件 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 日志文件路径 --><file>${LOG_PATH}/${LOG_FILE}.log</file><!-- 滚动策略:按日期和文件大小 --><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 文件名格式 --><fileNamePattern>${LOG_PATH}/archived/${LOG_FILE}-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern><!-- 单个文件最大大小 --><maxFileSize>100MB</maxFileSize><!-- 保留最多 30 天或 10 个备份文件 --><maxHistory>30</maxHistory><totalSizeCap>1GB</totalSizeCap></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern><charset>UTF-8</charset></encoder></appender><!-- 日志级别设置 --><!-- 对特定包设置 DEBUG 级别 --><logger name="com.pj" level="DEBUG" /><!-- Spring 框架日志级别 --><logger name="org.springframework" level="INFO" /><!-- 捕获 Spring MVC 请求日志 --><logger name="org.springframework.web.servlet.DispatcherServlet" level="DEBUG" /><!-- 捕获 Spring MVC 请求日志 --><logger name="org.springframework.web.client.RestTemplate" level="DEBUG" /><!-- Spring Security 日志配置 --><logger name="org.springframework.security" level="DEBUG" additivity="false"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></logger><!-- 根日志级别 --><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /></root></configuration>
整合SpringAI
引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-client-chat -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-client-chat</artifactId><version>1.0.0</version>
</dependency>
添加配置application.yml
server:port: 7087
spring:ai:deepseek:api-key: sk-abf60234a...........chat:options:model: deepseek-chattemperature: 0.7
如果你没有api-key请登录deepseek官网注册账号,申请api-key,购买接口的调用次数,如果用于学习的话,买个10块钱就可以用很久了
Spring托管大模型对象
package com.pj.ls.chat;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ChatClientConfig {@Beanpublic ChatClient openAiChatClient(DeepSeekChatModel chatModel) {return ChatClient.create(chatModel);}}
创建controller首次调用deepseek
package com.pj.ls.chat.controller;import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;import java.util.Map;@RestController
@AllArgsConstructor
public class ChatController {public static final Logger logger = LoggerFactory.getLogger(ChatController.class);private final ChatClient client;@GetMapping("/ai")public Flux<String> ai(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {return Flux.concat(client.prompt(message).stream().content(),Flux.just("[DONE]") // 添加结束标记);}}
前端调用deepseek接口
// 创建 SSE 连接eventSource = new EventSource(`${import.meta.env.VITE_API_BASE_URL + import.meta.env.VITE_API}/ai?message=${encodeURIComponent(userMessage)}`);eventSource.onmessage = (event) => {try {if (event.data === '[DONE]') {eventSource.close();isLoading.value = false;inputMessage.value = '';// 确保滚动到底部nextTick(() => {scrollToBottom();});return}result += event.data || ' ';aiMessage.content = parseMarkdown(result);messages.value = [...messages.value];} catch (e) {console.error('解析错误:', e);}};eventSource.onerror = () => {eventSource.close();isLoading.value = false;if (!aiMessage.content) {aiMessage.content = '连接中断,请重试';messages.value = [...messages.value];}};