最近在学习SpringAI相关的技术,之前也接触过一些,但并不是系统的了解和学习,今天分享一些个人学习的心得,也是个人整理出来的SpringAI的入门教程吧。话不多说,开始分享!

一、介绍

首先依旧是简单介绍一下:

SpringAI就是在Spring生态中集成人工智能能力,提供标准化的接口,支持开发者通过配置切换不同 AI 服务提供商。

二、准备

因为会演示SpringAI的优势,所以需要准备多个AI服务,分别感受。也可以不做,至少需要有一个。

1.DeepSeek模型

首先去官网 https://www.deepseek.com/ ,进入API开放平台,并进行登录。

点击API keys 进行命名创建,key要保存好后续会使用。刚开始注册会给体验金额的,如果早就注册但没有使用过可能是过期了,我就是,充了10块钱,自己用能用很久的。

2.Ollama模型

直接去ollama官网,Ollama,下载ollama。下载慢就去找教程就行很多的。

下载后试着安装几个ollama模型,首先要确认好自己电脑的显卡和内存配置。可以让AI给你智能推荐。我下了这几个模型,我的电脑没有独显就选一些小模型。

三、SpringAI使用

1.依赖引入(Spring Boot Starter)

    <?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>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.4.5</version>
            <relativePath/>
        </parent>
    
        <groupId>com.Luoyi</groupId>
        <artifactId>AITest</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>21</maven.compiler.source>
            <maven.compiler.target>21</maven.compiler.target>
            <spring-ai.version>1.0.0</spring-ai.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <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>
            </dependency>
            <!-- DeepSeek -->
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-starter-model-deepseek</artifactId>
            </dependency>
             <!--Ollama -->
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-starter-model-ollama</artifactId>
            </dependency>
            <!--会话记忆-->
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId>
            </dependency>
        </dependencies>
        <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>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    2.配置文件

    • api-key 配置你自己的key
    • model 可以更换deepseek的模型(deepseek-reasoner模型是深度思考模型)
    • temperature 是模型温度,模型温度越低模型输出越规矩、稳定,温度越高输出越多变、富有惊喜,通常是0.5~0.8
    • maxTokens 可以理解为字数上限,这个值越低消耗的token就越少,不过太低回答会被截断
    • stop 就是输出截断,可以设置输出一行截断,输出敏感词截断等等
    • base-url ollama的默认访问地址就是配置中的地址无需修改
    spring:
      ai:
        #deepseek模型配置
        deepseek:
          api-key: deepseek-key
          chat:
            options:
              model: deepseek-chat #deepseek模型
              temperature: 0.5 #模型温度
              max-tokens: 1000 #字数上限
              stop:
                - "党"  #敏感词
        #ollama模型配置
        ollama:
          chat:
            model: gemma3:4b #ollama模型
          base-url: http://localhost:11434

    3.调用模型

    DeepSeek模型

    (1) 直接调用

    创建一个测试类进行演示

    @SpringBootTest
    public class DeepseekTest {
    
        @Autowired
        private DeepSeekChatModel chatModel;
    
        @Test
        public void testChat(){
            String call = chatModel.call("你是谁?");
            System.out.println( call );
        }
    }

    运行结果:

    (2) 流式输出

    我们平常使用AI时的输出都是几个字几个字输出而不是一下子全出来的

        @Test
        public void testChat2() {
            Flux<String> stream = chatModel.stream("你是谁?");
            // 阻塞输出
            stream.toIterable().forEach(System.out::print);
        }
    (3) 思考推理

    使用AI时会有深度思考或推理的功能如下:

    通过代码进行演示:
     

        @Test
        public void deepSeekReasonerExample() {
            Prompt prompt = new Prompt("讲一个睡前故事。");
            ChatResponse res = chatModel.call(prompt);
    
            DeepSeekAssistantMessage assistantMessage =  (DeepSeekAssistantMessage)res.getResult().getOutput();
            //思考
            String reasoningContent = assistantMessage.getReasoningContent();
            //内容
            String content = assistantMessage.getText();
    
            System.out.println("思考:" + reasoningContent);
            System.out.println("===============================================");
            System.out.println("回答:" + content);
        }

    如果没有切换思考模型就会没有思考只有输出:

    在配置文件中切换模型:

    spring:
      ai:
        #deepseek模型配置
        deepseek:
          chat:
            options:
              model: deepseek-reasoner #思考模型

    也可进行流式输出:

        @Test
        public void deepSeekReasonerStreamExample() {
            Prompt prompt = new Prompt("讲个睡前故事。");
            Flux<ChatResponse> stream = chatModel.stream(prompt);
    
            stream.toIterable().forEach(res -> {
                DeepSeekAssistantMessage assistantMessage =  (DeepSeekAssistantMessage)res.getResult().getOutput();
                String reasoningContent = assistantMessage.getReasoningContent();
                System.out.print(reasoningContent);
            });
            System.out.println("===============================================");
            stream.toIterable().forEach(res -> {
                DeepSeekAssistantMessage assistantMessage =  (DeepSeekAssistantMessage)res.getResult().getOutput();
                String content = assistantMessage.getText();
                System.out.print(content);
            });
    
        }

    Ollama模型

    (1) 直接调用 流式输出

    Ollama的响应响应速度取决你的配置,如果你的电脑配置不好使用的还是参数大的模型响应自然就慢,使用小模型响应就较快。

    @SpringBootTest
    public class OllamaTest {
    
        @Test
        public void Ollamatest(@Autowired OllamaChatModel chatModel){
            String call = chatModel.call("你是谁?");
            System.out.println( call );
        }
    
        @Test
        public void testStream() {
            Flux<String> stream = chatModel.stream("你是谁?");
            // 阻塞输出
            stream.toIterable().forEach(System.out::println);
        }
    }
    (2) 多模态

    这里我们选用能进行图片识别的进行测试,在ollama的模型中找到可以识别图片的模型或有视觉能力,就是 vision ,我这选用gemma3:4b 模型(大的带不动),这个模型对于手写的识别很一般,当然也是因为参数小换个大的就会好很多。

    代码和示例图片如下:

    @Test
        public void testMultimodality() {
            // 加载类路径下的图片资源
            var imageResource = new ClassPathResource("img.png");
            // 创建Media对象,指定图片的MIME类型为PNG
            Media media = new Media(MimeTypeUtils.IMAGE_PNG, imageResource);
            // 调用OllamaChatModel的多模态接口,传入图片和文本提示
            ChatResponse response = chatModel.call(
                    new Prompt(
                            UserMessage.builder()
                                    .media(media)
                                    .text("识别图片")
                                    .build()
                    )
            );
            // 输出结果
            System.out.println(response.getResult().getOutput().getText());
        }

    运行结果:

    使用ChatClient

    使用ChatClient的优点:
    1. 统一 API:简化不同模型的调用方式。  
    2. 多模型支持:动态切换 DeepSeek、Ollama 等模型。  
    3. 流式响应:支持实时数据流(如 `Flux`)。  
    4. Spring 集成:依赖注入和测试友好。  
    5. 代码简洁:链式调用,减少样板代码。

    (1) ChatClient不能自动选择模型

    当有多个模型时,直接使用chatclient会报错,因为没有默认设置模型。

    @SpringBootTest
    public class ChatClientTest {
    
        /**
         * @Description: 多模型无法自动选择
         * @param builder
         * @return void
         */
        @Test
        public void testChatClient(ChatClient.Builder builder) {
            ChatClient chatClient = builder.build();
            String content = chatClient.prompt()
                    .user("你是谁?")
                    .call()
                    .content();
    
            System.out.println( content );
        }
    }
    (2) ChatClient调用不同模型
    @SpringBootTest
    public class ChatClientTest {
    
        @Autowired
        private DeepSeekChatModel deepSeekChatModel;
        @Autowired
        private OllamaChatModel ollamaChatModel;
        
        /**
         * @Description: 指定模型deepseek
         * @param
         * @return void
         */
        @Test
        public void testChatOptions() {
    
            ChatClient chatClient = ChatClient.builder(deepSeekChatModel).build();
            String content = chatClient.prompt()
                    .user("你是谁")
                    .call()
                    .content();
            System.out.println(content);
        }
        /**
         * @Description: 模型ollama
         * @param
         * @return void
         */
        @Test
        public void testChatOptions1() {
    
            ChatClient chatClient = ChatClient.builder(ollamaChatModel).build();
            String content = chatClient.prompt()
                    .user("你是谁")
                    .call()
                    .content();
            System.out.println(content);
        }
        /**
         * @Description: 阻塞输出
         * @param
         * @return void
         */
        @Test
        public void testChatStream(){
            ChatClient chatClient = ChatClient.builder(deepSeekChatModel).build();
            Flux<String> content = chatClient.prompt()
                    .user("你能告诉我2025年1月ai界的大事吗")
                    .stream()
                    .content();
            //阻塞输出
            content.toIterable().forEach(System.out::print);
    
        }
    
    
    }

    四、AIDemo

    通过上面的了解我使用ChatClient做一个小Demo,主要实现切换不同的模型,后续会对这个Demo进行升级。

    1.配置ChatClient

    在application中增加日志配置

    logging:
      level:
        org.springframework.ai.chat.client.advisor: debug # AI对话的日志级别

    创建AIConfig配置类,其中.defaultAdvisors(new SimpleLoggerAdvisor()) 是增加了一个日志输出。

    package com.Luoyi.config;
    
    import org.springframework.ai.chat.client.ChatClient;
    import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
    import org.springframework.ai.deepseek.DeepSeekChatModel;
    import org.springframework.ai.deepseek.DeepSeekChatOptions;
    import org.springframework.ai.deepseek.api.DeepSeekApi;
    import org.springframework.ai.model.ollama.autoconfigure.OllamaChatProperties;
    import org.springframework.ai.ollama.OllamaChatModel;
    import org.springframework.ai.ollama.api.OllamaApi;
    import org.springframework.ai.ollama.api.OllamaOptions;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @author Luoyi
     * @description: 模型配置
     */
    @Configuration
    public class AIConfig {
    
        @Autowired
        private DeepSeekChatModel deepSeekChatModel;
        @Autowired 
        private OllamaApi ollamaApi;
        @Autowired 
        private OllamaChatProperties options;
        /**
         * @Description: deepseek模型
         * @param
         * @return org.springframework.ai.chat.client.ChatClient
         */
        @Bean
        public ChatClient deepseek(){
            return ChatClient.builder(deepSeekChatModel)
                    .defaultAdvisors(new SimpleLoggerAdvisor())//记录日志
                    .build();
        }
        /**
         * @Description: 本地ollama模型
         * @param 
         * @return org.springframework.ai.chat.client.ChatClient
         */
        @Bean
        public ChatClient ollama() {
            OllamaChatModel ollamaChatModel = OllamaChatModel.builder()
                    .ollamaApi(ollamaApi)
                    .defaultOptions(OllamaOptions.builder().model(options.getModel()).build())
                    .build();
    
            return ChatClient.builder(ollamaChatModel)
                    .defaultAdvisors(new SimpleLoggerAdvisor())//记录日志
                    .build();
        }
    
    }
    

    再编写一个控制类根据传入不同的参数使用不同的模型

    @Controller
    public class MultiModelsController {
    
        //注册ChatClient的bean
        @Autowired
        private Map<String, ChatClient> chatClientMap;
        /**
         * @Description: 模型对话流式输出
         * @param message 消息
         * @param model 指定模型
         * @return reactor.core.publisher.Flux<java.lang.String>
         */
        @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")
        Flux<String> generation(@RequestParam String message,
                          @RequestParam String model) {
            ChatClient chatClient = chatClientMap.get(model);
            Flux<String> content = chatClient.prompt()//创建聊天请求对象
                    .user(message)//设置用户输入信息
                    .stream()//开启流式响应并获取内容
                    .content();
    
            return content;
        }
    }

    运行结果:

    五、后续会继续更新增加对话记忆(内存、redis和数据库存储)、会话隔离、使用工具和AIDemo升级等等

    Logo

    有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

    更多推荐