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

一、前言

    在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

<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.complete(); // Complete the SSE connection}}}} catch (Exception e) {emitter.complete();log.error("流式返回结果异常",e);}});return emitter;
}

流式输出返回的数据结构:

    调用结果:

 

4.2、调用Ollama API

Spring封装的很好,基本和调用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.complete(); // Complete the SSE connection}}}} catch (Exception e) {emitter.complete();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.commons.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 {@Autowiredprivate 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.complete(); // Complete the SSE connection}}}} catch (Exception e) {emitter.complete();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.commons.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 {@Autowiredprivate 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.complete(); // Complete the SSE connection}}}} catch (Exception e) {emitter.complete();log.error("流式返回结果异常",e);}});return emitter;}
}

5.6、核心配置

spring:ai:openai:api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxollama:base-url: http://localhost:11434chat: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);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/517449.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习Java的第一天

一、Java简介 Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。由 James Gosling和同事们共同研发&#xff0c;并在 1995 年正式推出。 后来 Sun 公司被 Oracle &#xff08;甲骨文&#xff09;公司收购&#xff0c;Jav…

嵌入式开发的常用软件、学习资源网站推荐

1、软件推荐 1.1、文本编辑软件 ——Notepad 1、适合编写和查看文本文件&#xff0c;也可以安装插件来查看二进制文件、对比文件 2、参考博客&#xff1a;《Notepad实用小技巧》&#xff1b; 1.2、PDF文件阅读软件——福昕PDF阅读器 福昕PDF阅读器&#xff0c;在官网就可以下载…

xinput1_3.dll丢失都有什么办法可以有效的解决、xinput1_3.dll导致游戏不能启动怎么办?

使用电脑的过程中是不是会遇到关于某个dll文件丢失的提示&#xff0c;今天想和大家聊的是xinput1_3.dll文件&#xff0c;如果电脑提示xinput1_3.dll丢失有什么办法可以有效的解决&#xff0c;解决办法都有哪些&#xff0c;如果xinput1_3.dll丢失会对电脑有什么影响。&#xff0…

LeetCode-第137题-只出现一次的数||

1.题目描述 给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 2.样例描述 3.思路描述 先把数组排序&am…

01_Maven

文章目录 Maven安装MavenMaven的工作流程配置MavenMaven的使用module和project的关系如何用Maven导包 如何用Maven进行项目构建指令介绍clean指令compile指令package指令install指令 Maven的依赖管理如何导包scope作用域依赖传递依赖冲突 使用Maven开发项目Junit如何使用Junit …

深圳市萨科微半导体有限公司一直研究新材料新工艺,不断推出新产品,驱动公司不断发展

深圳市萨科微半导体有限公司一直研究新材料新工艺&#xff0c;不断推出新产品&#xff0c;驱动公司不断发展。最近萨科微推出SL40T120FL系列IGBT单管&#xff0c;和CMOS运算放大器SLA333等产品&#xff0c;为新能源汽车、太阳能光伏、交流电机、变频器、开关电源和工业伺服器行…

更快更强,Claude 3全面超越GPT4,能归纳15万单词

ChatGPT4和Gemini Ultra被Claude 3 AI模型超越了&#xff1f; 3月4日周一&#xff0c;人工智能公司Anthropic推出了Claude 3系列AI模型和新型聊天机器人&#xff0c;其中包括Opus、Sonnet和Haiku三种模型&#xff0c;该公司声称&#xff0c;这是迄今为止它们开发的最快速、最强…

Spark(2)-基础tranform算子(一)

一、算子列表 编号名称1map算子2flatMap算子3filter算子4mapPartitions算子5mapPartitionsWithIndex算子6keys算子7values算子8mapValues算子9flatMaplValues算子10union算子11reducedByKey算子12combineByKey算子13groupByKey算子14foldByKey算子15aggregateByKey算子16Shuff…

【DPDK】基于dpdk实现用户态UDP网络协议栈

文章目录 一.背景及导言二.协议栈架构设计1. 数据包接收和发送引擎2. 协议解析3. 数据包处理逻辑 三.网络函数编写1.socket2.bind3.recvfrom4.sendto5.close 四.总结 一.背景及导言 在当今数字化的世界中&#xff0c;网络通信的高性能和低延迟对于许多应用至关重要。而用户态网…

react native封装ScrollView,实现(滑到底部)和(滑到顶部+手指继续向下滑)时拉取新数据

里面的tw是在react native中使用tailwind的第三方库 只求读者把样式看个大概&#xff0c;主要还是功能的实现 ScrollView的官方文档如下 https://reactnative.cn/docs/scrollview import tw from twrnc import { View, Text, ScrollView, RefreshControl } from react-native …

安卓部分手机使用webview加载链接后白屏(Android低版本会出现的问题)

前言 大爷&#xff1a;小伙我这手机怎么打开你们呢这个是白屏什么都不显示。 大娘&#xff1a;小伙我这也是打开你们呢这功能&#xff0c;就是一个白屏什么也没有&#xff0c;你们呢的应用不会有病毒吧。 小伙&#xff1a;我的手机也正常&#xff1b; 同事&#xff1a;我的也正…

linux安装ngnix

一、将nginx-1.20.1.tar.gz上传至linux服务器目录下 二、将nginx安装包解压到/usr/local目录下 tar -zxvf /home/local/nginx-1.20.1.tar.gz -C /usr/local/三、预先安装依赖 yum -y install pcre-devel yum -y install openssl openssl-devel yum -y install gcc gcc-c auto…