开源模型应用落地-工具使用篇-SpringAI(七)
- 人工智能
- 2025-09-18 19:18:01

一、前言
在AI大模型百花齐放的时代,很多人都对新兴技术充满了热情,都想尝试一下。但是,实际上要入门AI技术的门槛非常高。除了需要高端设备,还需要面临复杂的部署和安装过程,这让很多人望而却步。不过,随着开源技术的不断进步,使得入门AI变得越来越容易。通过使用**Ollama**,您可以快速体验大语言模型的乐趣,不再需要担心繁琐的设置和安装过程。另外,通过集成Spring AI,让更多Java爱好者能便捷的将AI能力集成到项目中,接下来,跟随我的脚步,一起来体验一把。
二、术语 2.1、Spring AI
是 Spring 生态系统的一个新项目,它简化了 Java 中 AI 应用程序的创建。它提供以下功能:
支持所有主要模型提供商,例如 OpenAI、Microsoft、Amazon、Google 和 Huggingface。支持的模型类型包括“聊天”和“文本到图像”,还有更多模型类型正在开发中。跨 AI 提供商的可移植 API,用于聊天和嵌入模型。支持同步和流 API 选项。支持下拉访问模型特定功能。AI 模型输出到 POJO 的映射。 2.2、Ollama是一个强大的框架,用于在 Docker 容器中部署 LLM(大型语言模型)。它的主要功能是在 Docker 容器内部署和管理 LLM 的促进者,使该过程变得简单。它可以帮助用户快速在本地运行大模型,通过简单的安装指令,用户可以执行一条命令就在本地运行开源大型语言模型。
Ollama 支持 GPU/CPU 混合模式运行,允许用户根据自己的硬件条件(如 GPU、显存、CPU 和内存)选择不同量化版本的大模型。它提供了一种方式,使得即使在没有高性能 GPU 的设备上,也能够运行大型模型。
三、前置条件 3.1、JDK 17+
下载地址: .oracle /java/technologies/downloads/#jdk17-windows
类文件具有错误的版本 61.0, 应为 52.0
3.2、创建Maven项目SpringBoot版本为3.2.3
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> 3.3、导入Maven依赖包 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core</artifactId> <version>5.8.24</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>0.8.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> <version>0.8.0</version> </dependency> 3.4、 科学上网的软件 3.5、 安装Ollama及部署Qwen模型参见:开源模型应用落地-工具使用篇-Ollama(六)-CSDN博客
四、技术实现 4.1、调用Open AI 4.1.1、非流式调用 @RequestMapping("/chat") public String chat(){ String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); List<Generation> response = openAiChatClient.call(prompt).getResults(); String result = ""; for (Generation generation : response){ String content = generation.getOutput().getContent(); result += content; } return result; }
调用结果:
4.1.2、流式调用 @RequestMapping("/stream") public SseEmitter stream(HttpServletResponse response){ response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); SseEmitter emitter = new SseEmitter(); String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); openAiChatClient.stream(prompt).subscribe(x -> { try { log.info("response: {}",x); List<Generation> generations = x.getResults(); if(CollUtil.isNotEmpty(generations)){ for(Generation generation:generations){ AssistantMessage assistantMessage = generation.getOutput(); String content = assistantMessage.getContent(); if(StringUtils.isNotEmpty(content)){ emitter.send(content); }else{ if(StringUtils.equals(content,"null")) emitter plete(); // Complete the SSE connection } } } } catch (Exception e) { emitter plete(); log.error("流式返回结果异常",e); } }); return emitter; }流式输出返回的数据结构:
调用结果:
4.2、调用Ollama APISpring封装的很好,基本和调用OpenAI的代码一致
4.2.1、非流式调用 @RequestMapping("/chat") public String chat(){ String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); List<Generation> response = ollamaChatClient.call(prompt).getResults(); String result = ""; for (Generation generation : response){ String content = generation.getOutput().getContent(); result += content; } return result; }调用结果:
Ollam的server.log输出
4.2.2、流式调用 @RequestMapping("/stream") public SseEmitter stream(HttpServletResponse response){ response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); SseEmitter emitter = new SseEmitter(); String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); ollamaChatClient.stream(prompt).subscribe(x -> { try { log.info("response: {}",x); List<Generation> generations = x.getResults(); if(CollUtil.isNotEmpty(generations)){ for(Generation generation:generations){ AssistantMessage assistantMessage = generation.getOutput(); String content = assistantMessage.getContent(); if(StringUtils.isNotEmpty(content)){ emitter.send(content); }else{ if(StringUtils.equals(content,"null")) emitter plete(); // Complete the SSE connection } } } } catch (Exception e) { emitter plete(); log.error("流式返回结果异常",e); } }); return emitter; }调用结果:
五、附带说明 5.1、OpenAiChatClient默认使用gpt-3.5-turbo模型 5.2、流式输出如何关闭连接
不能判断是否为’'(即空字符串),以下代码将提前关闭连接
流式输出会返回’'的情况
应该在返回内容为字符串null的时候关闭
5.3、配置文件中指定的Ollama的模型参数,要和运行的模型一致 5.4、OpenAI调用完整代码 import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache mons.lang3.StringUtils; import org.springframework.ai.chat.Generation; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.SystemPromptTemplate; import org.springframework.ai.openai.OpenAiChatClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.List; @Slf4j @RestController @RequestMapping("/api") public class OpenaiTestController { @Autowired private OpenAiChatClient openAiChatClient; // http://localhost:7777/api/chat @RequestMapping("/chat") public String chat(){ String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); List<Generation> response = openAiChatClient.call(prompt).getResults(); String result = ""; for (Generation generation : response){ String content = generation.getOutput().getContent(); result += content; } return result; } @RequestMapping("/stream") public SseEmitter stream(HttpServletResponse response){ response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); SseEmitter emitter = new SseEmitter(); String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); openAiChatClient.stream(prompt).subscribe(x -> { try { log.info("response: {}",x); List<Generation> generations = x.getResults(); if(CollUtil.isNotEmpty(generations)){ for(Generation generation:generations){ AssistantMessage assistantMessage = generation.getOutput(); String content = assistantMessage.getContent(); if(StringUtils.isNotEmpty(content)){ emitter.send(content); }else{ if(StringUtils.equals(content,"null")) emitter plete(); // Complete the SSE connection } } } } catch (Exception e) { emitter plete(); log.error("流式返回结果异常",e); } }); return emitter; } } 5.5、Ollama调用完整代码 import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache mons.lang3.StringUtils; import org.springframework.ai.chat.Generation; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.SystemPromptTemplate; import org.springframework.ai.ollama.OllamaChatClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.List; @Slf4j @RestController @RequestMapping("/api") public class OllamaTestController { @Autowired private OllamaChatClient ollamaChatClient; @RequestMapping("/chat") public String chat(){ String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); List<Generation> response = ollamaChatClient.call(prompt).getResults(); String result = ""; for (Generation generation : response){ String content = generation.getOutput().getContent(); result += content; } return result; } @RequestMapping("/stream") public SseEmitter stream(HttpServletResponse response){ response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); SseEmitter emitter = new SseEmitter(); String systemPrompt = "{prompt}"; SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt); String userPrompt = "广州有什么特产?"; Message userMessage = new UserMessage(userPrompt); Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant")); Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); ollamaChatClient.stream(prompt).subscribe(x -> { try { log.info("response: {}",x); List<Generation> generations = x.getResults(); if(CollUtil.isNotEmpty(generations)){ for(Generation generation:generations){ AssistantMessage assistantMessage = generation.getOutput(); String content = assistantMessage.getContent(); if(StringUtils.isNotEmpty(content)){ emitter.send(content); }else{ if(StringUtils.equals(content,"null")) emitter plete(); // Complete the SSE connection } } } } catch (Exception e) { emitter plete(); log.error("流式返回结果异常",e); } }); return emitter; } } 5.6、核心配置 spring: ai: openai: api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ollama: base-url: http://localhost:11434 chat: model: qwen:1.8b-chat 5.7、启动类 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AiApplication { public static void main(String[] args) { System.setProperty("http.proxyHost","127.0.0.1"); System.setProperty("http.proxyPort","7078"); // 修改为你代理软件的端口 System.setProperty("https.proxyHost","127.0.0.1"); System.setProperty("https.proxyPort","7078"); // 同理 SpringApplication.run(AiApplication.class, args); } }开源模型应用落地-工具使用篇-SpringAI(七)由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“开源模型应用落地-工具使用篇-SpringAI(七)”