开源模子应用落地-工具利用篇-Spring AI(七)

打印 上一主题 下一主题

主题 844|帖子 844|积分 2532

一、前言

在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+

下载地点:https://www.oracle.com/java/technologies/downloads/#jdk17-windows

类文件具有错误的版本 61.0, 应为 52.0
3.2、创建Maven项目

SpringBoot版本为3.2.3
  1. <parent>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-parent</artifactId>
  4.     <version>3.2.3</version>
  5.     <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
复制代码
3.3、导入Maven依赖包

  1. <dependency>
  2.         <groupId>org.projectlombok</groupId>
  3.         <artifactId>lombok</artifactId>
  4.         <optional>true</optional>
  5. </dependency>
  6. <dependency>
  7.         <groupId>ch.qos.logback</groupId>
  8.         <artifactId>logback-core</artifactId>
  9. </dependency>
  10. <dependency>
  11.         <groupId>ch.qos.logback</groupId>
  12.         <artifactId>logback-classic</artifactId>
  13. </dependency>
  14. <dependency>
  15.         <groupId>cn.hutool</groupId>
  16.         <artifactId>hutool-core</artifactId>
  17.         <version>5.8.24</version>
  18. </dependency>
  19. <dependency>
  20.         <groupId>org.springframework.ai</groupId>
  21.         <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
  22.         <version>0.8.0</version>
  23. </dependency>
  24. <dependency>
  25.         <groupId>org.springframework.ai</groupId>
  26.         <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
  27.         <version>0.8.0</version>
  28. </dependency>
复制代码
3.4、 科学上网的软件

3.5、 安装Ollama及部署Qwen模子

拜见:开源模子应用落地-工具利用篇-Ollama(六)-CSDN博客

四、技能实现

4.1、调用Open AI

4.1.1、非流式调用

  1. @RequestMapping("/chat")
  2. public String chat(){
  3.         String systemPrompt = "{prompt}";
  4.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  5.         String userPrompt = "广州有什么特产?";
  6.         Message userMessage = new UserMessage(userPrompt);
  7.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  8.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  9.         List<Generation> response = openAiChatClient.call(prompt).getResults();
  10.         String result = "";
  11.         for (Generation generation : response){
  12.                 String content = generation.getOutput().getContent();
  13.                 result += content;
  14.         }
  15.         return result;
  16. }
复制代码
调用结果:

4.1.2、流式调用

  1. @RequestMapping("/stream")
  2. public SseEmitter stream(HttpServletResponse response){
  3.         response.setContentType("text/event-stream");
  4.         response.setCharacterEncoding("UTF-8");
  5.         SseEmitter emitter = new SseEmitter();
  6.         String systemPrompt = "{prompt}";
  7.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  8.         String userPrompt = "广州有什么特产?";
  9.         Message userMessage = new UserMessage(userPrompt);
  10.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  11.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  12.         openAiChatClient.stream(prompt).subscribe(x -> {
  13.                 try {
  14.                         log.info("response: {}",x);
  15.                         List<Generation> generations = x.getResults();
  16.                         if(CollUtil.isNotEmpty(generations)){
  17.                                 for(Generation generation:generations){
  18.                                    AssistantMessage assistantMessage =  generation.getOutput();
  19.                                         String content = assistantMessage.getContent();
  20.                                         if(StringUtils.isNotEmpty(content)){
  21.                                                 emitter.send(content);
  22.                                         }else{
  23.                                                 if(StringUtils.equals(content,"null"))
  24.                                                 emitter.complete(); // Complete the SSE connection
  25.                                         }
  26.                                 }
  27.                         }
  28.                 } catch (Exception e) {
  29.                         emitter.complete();
  30.                         log.error("流式返回结果异常",e);
  31.                 }
  32.         });
  33.         return emitter;
  34. }
复制代码
流式输出返回的数据结构:

调用结果:


4.2、调用Ollama API

Spring封装的很好,根本和调用OpenAI的代码一致
4.2.1、非流式调用

  1. @RequestMapping("/chat")
  2. public String chat(){
  3.         String systemPrompt = "{prompt}";
  4.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  5.         String userPrompt = "广州有什么特产?";
  6.         Message userMessage = new UserMessage(userPrompt);
  7.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  8.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  9.         List<Generation> response = ollamaChatClient.call(prompt).getResults();
  10.         String result = "";
  11.         for (Generation generation : response){
  12.                 String content = generation.getOutput().getContent();
  13.                 result += content;
  14.         }
  15.         return result;
  16. }
复制代码
调用结果:
Ollam的server.log输出


4.2.2、流式调用

  1. @RequestMapping("/stream")
  2. public SseEmitter stream(HttpServletResponse response){
  3.         response.setContentType("text/event-stream");
  4.         response.setCharacterEncoding("UTF-8");
  5.         SseEmitter emitter = new SseEmitter();
  6.         String systemPrompt = "{prompt}";
  7.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  8.         String userPrompt = "广州有什么特产?";
  9.         Message userMessage = new UserMessage(userPrompt);
  10.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  11.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  12.         ollamaChatClient.stream(prompt).subscribe(x -> {
  13.                 try {
  14.                         log.info("response: {}",x);
  15.                         List<Generation> generations = x.getResults();
  16.                         if(CollUtil.isNotEmpty(generations)){
  17.                                 for(Generation generation:generations){
  18.                                         AssistantMessage assistantMessage =  generation.getOutput();
  19.                                         String content = assistantMessage.getContent();
  20.                                         if(StringUtils.isNotEmpty(content)){
  21.                                                 emitter.send(content);
  22.                                         }else{
  23.                                                 if(StringUtils.equals(content,"null"))
  24.                                                         emitter.complete(); // Complete the SSE connection
  25.                                         }
  26.                                 }
  27.                         }
  28.                 } catch (Exception e) {
  29.                         emitter.complete();
  30.                         log.error("流式返回结果异常",e);
  31.                 }
  32.         });
  33.         return emitter;
  34. }
复制代码
调用结果:



五、附带说明

5.1、OpenAiChatClient默认利用gpt-3.5-turbo模子


5.2、流式输出如何关闭连接

不能判断是否为’'(即空字符串),以下代码将提前关闭连接

流式输出会返回’'的环境

应该在返回内容为字符串null的时候关闭


5.3、设置文件中指定的Ollama的模子参数,要和运行的模子一致



5.4、OpenAI调用完整代码

  1. import cn.hutool.core.collection.CollUtil;
  2. import cn.hutool.core.map.MapUtil;
  3. import jakarta.servlet.http.HttpServletResponse;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.apache.commons.lang3.StringUtils;
  6. import org.springframework.ai.chat.Generation;
  7. import org.springframework.ai.chat.messages.AssistantMessage;
  8. import org.springframework.ai.chat.messages.Message;
  9. import org.springframework.ai.chat.messages.UserMessage;
  10. import org.springframework.ai.chat.prompt.Prompt;
  11. import org.springframework.ai.chat.prompt.SystemPromptTemplate;
  12. import org.springframework.ai.openai.OpenAiChatClient;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.bind.annotation.RestController;
  16. import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  17. import java.util.List;
  18. @Slf4j
  19. @RestController
  20. @RequestMapping("/api")
  21. public class OpenaiTestController {
  22.     @Autowired
  23.     private OpenAiChatClient openAiChatClient;
  24. //    http://localhost:7777/api/chat
  25.     @RequestMapping("/chat")
  26.     public String chat(){
  27.         String systemPrompt = "{prompt}";
  28.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  29.         String userPrompt = "广州有什么特产?";
  30.         Message userMessage = new UserMessage(userPrompt);
  31.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  32.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  33.         List<Generation> response = openAiChatClient.call(prompt).getResults();
  34.         String result = "";
  35.         for (Generation generation : response){
  36.             String content = generation.getOutput().getContent();
  37.             result += content;
  38.         }
  39.         return result;
  40.     }
  41.     @RequestMapping("/stream")
  42.     public SseEmitter stream(HttpServletResponse response){
  43.         response.setContentType("text/event-stream");
  44.         response.setCharacterEncoding("UTF-8");
  45.         SseEmitter emitter = new SseEmitter();
  46.         String systemPrompt = "{prompt}";
  47.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  48.         String userPrompt = "广州有什么特产?";
  49.         Message userMessage = new UserMessage(userPrompt);
  50.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  51.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  52.         openAiChatClient.stream(prompt).subscribe(x -> {
  53.             try {
  54.                 log.info("response: {}",x);
  55.                 List<Generation> generations = x.getResults();
  56.                 if(CollUtil.isNotEmpty(generations)){
  57.                     for(Generation generation:generations){
  58.                        AssistantMessage assistantMessage =  generation.getOutput();
  59.                         String content = assistantMessage.getContent();
  60.                         if(StringUtils.isNotEmpty(content)){
  61.                             emitter.send(content);
  62.                         }else{
  63.                             if(StringUtils.equals(content,"null"))
  64.                             emitter.complete(); // Complete the SSE connection
  65.                         }
  66.                     }
  67.                 }
  68.             } catch (Exception e) {
  69.                 emitter.complete();
  70.                 log.error("流式返回结果异常",e);
  71.             }
  72.         });
  73.         return emitter;
  74.     }
  75. }
复制代码
5.5、Ollama调用完整代码

  1. import cn.hutool.core.collection.CollUtil;
  2. import cn.hutool.core.map.MapUtil;
  3. import jakarta.servlet.http.HttpServletResponse;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.apache.commons.lang3.StringUtils;
  6. import org.springframework.ai.chat.Generation;
  7. import org.springframework.ai.chat.messages.AssistantMessage;
  8. import org.springframework.ai.chat.messages.Message;
  9. import org.springframework.ai.chat.messages.UserMessage;
  10. import org.springframework.ai.chat.prompt.Prompt;
  11. import org.springframework.ai.chat.prompt.SystemPromptTemplate;
  12. import org.springframework.ai.ollama.OllamaChatClient;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.bind.annotation.RestController;
  16. import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  17. import java.util.List;
  18. @Slf4j
  19. @RestController
  20. @RequestMapping("/api")
  21. public class OllamaTestController {
  22.     @Autowired
  23.     private OllamaChatClient ollamaChatClient;
  24.     @RequestMapping("/chat")
  25.     public String chat(){
  26.         String systemPrompt = "{prompt}";
  27.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  28.         String userPrompt = "广州有什么特产?";
  29.         Message userMessage = new UserMessage(userPrompt);
  30.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  31.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  32.         List<Generation> response = ollamaChatClient.call(prompt).getResults();
  33.         String result = "";
  34.         for (Generation generation : response){
  35.             String content = generation.getOutput().getContent();
  36.             result += content;
  37.         }
  38.         return result;
  39.     }
  40.     @RequestMapping("/stream")
  41.     public SseEmitter stream(HttpServletResponse response){
  42.         response.setContentType("text/event-stream");
  43.         response.setCharacterEncoding("UTF-8");
  44.         SseEmitter emitter = new SseEmitter();
  45.         String systemPrompt = "{prompt}";
  46.         SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
  47.         String userPrompt = "广州有什么特产?";
  48.         Message userMessage = new UserMessage(userPrompt);
  49.         Message systemMessage = systemPromptTemplate.createMessage(MapUtil.of("prompt", "you are a helpful AI assistant"));
  50.         Prompt prompt = new Prompt(List.of(userMessage, systemMessage));
  51.         ollamaChatClient.stream(prompt).subscribe(x -> {
  52.             try {
  53.                 log.info("response: {}",x);
  54.                 List<Generation> generations = x.getResults();
  55.                 if(CollUtil.isNotEmpty(generations)){
  56.                     for(Generation generation:generations){
  57.                         AssistantMessage assistantMessage =  generation.getOutput();
  58.                         String content = assistantMessage.getContent();
  59.                         if(StringUtils.isNotEmpty(content)){
  60.                             emitter.send(content);
  61.                         }else{
  62.                             if(StringUtils.equals(content,"null"))
  63.                                 emitter.complete(); // Complete the SSE connection
  64.                         }
  65.                     }
  66.                 }
  67.             } catch (Exception e) {
  68.                 emitter.complete();
  69.                 log.error("流式返回结果异常",e);
  70.             }
  71.         });
  72.         return emitter;
  73.     }
  74. }
复制代码
5.6、核心设置

  1. spring:
  2.   ai:
  3.     openai:
  4.       api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  5.     ollama:
  6.       base-url: http://localhost:11434
  7.       chat:
  8.         model: qwen:1.8b-chat
复制代码
5.7、启动类

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. @SpringBootApplication
  4. public class AiApplication {
  5.     public static void main(String[] args) {
  6.         System.setProperty("http.proxyHost","127.0.0.1");
  7.         System.setProperty("http.proxyPort","7078"); // 修改为你代理软件的端口
  8.         System.setProperty("https.proxyHost","127.0.0.1");
  9.         System.setProperty("https.proxyPort","7078"); // 同理
  10.         SpringApplication.run(AiApplication.class, args);
  11.     }
  12. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

乌市泽哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表