SpringBoot快速接入OpenAI大模型(JDK8)
使用AI4J快速接入OpenAI大模型
本博文给大家介绍一下如何使用AI4J快速接入OpenAI大模型,并且如何实现流式与非流式的输出,以及对函数调用的使用。
介绍
由于SpringAI需要使用JDK17和Spring Boot3,但是目前很多应用依旧使用的JDK8版本,所以使用可以支持JDK8的AI4J来接入OpenAI大模型。
AI4J是一款JavaSDK用于快速接入AI大模型应用,整合多平台大模型,如OpenAi、智谱Zhipu(ChatGLM)、深度求索DeepSeek、月之暗面Moonshot(Kimi)、腾讯混元Hunyuan、零一万物(01)等等,提供统一的输入输出(对齐OpenAi)消除差异化,优化函数调用(Tool Call),优化RAG调用、支持向量数据库(Pinecone),并且支持JDK1.8,为用户提供快速整合AI的能力。
AI4J-GitHub
快速使用
目前较多的应用场景为Spring应用,而AI4J接入SpringBoot应用也是非常简单的,本篇博文先带着大家为SpringBoot应用集成OpenAI服务,后续会介绍如何再非Spring项目中搭建。
创建SpringBoot项目


这里以JDK1.8为例创建SpringBoot2项目,当然你也可以创建JDK17、SpringBoot3。
引入AI4J依赖
<!-- Spring应用 -->
<dependency><groupId>io.github.lnyo-cly</groupId><artifactId>ai4j-spring-boot-stater</artifactId><version>0.5.2</version>
</dependency>
如果你使用阿里源无法引入,可能是阿里云镜像还没有同步。
配置application.yml
给大家两种配置方法
第一种:使用官网的url,自己有代理

第二种:使用中转代理地址(或第三方中转平台)
如:https://api.openai-proxy.com

上面任意配置一种即可。
搭建聊天服务Controller
下面是一个小的demo演示:
@RestController
public class OpenAiController {// 注入Ai服务@Autowiredprivate AiService aiService;@GetMapping("/chat")public String getChatMessage(@RequestParam String question) throws Exception {// 获取OpenAi的聊天服务IChatService chatService = aiService.getChatService(PlatformType.OPENAI);// 创建请求参数ChatCompletion chatCompletion = ChatCompletion.builder().model("gpt-4o-mini").message(ChatMessage.withUser(question)).build();System.out.println(chatCompletion);// 发送chat请求ChatCompletionResponse chatCompletionResponse = chatService.chatCompletion(chatCompletion);// 获取聊天内容和token消耗String content = chatCompletionResponse.getChoices().get(0).getMessage().getContent();long totalTokens = chatCompletionResponse.getUsage().getTotalTokens();System.out.println("总token消耗: " + totalTokens);return content;}
}


实现stream流式输出(打字机效果)
编写stream.html:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Stream Example</title>
</head>
<body>
<input id="question" type="text" placeholder="输入需要提问的问题"/><button id="startButton">开始</button><div id="output"></div><script>const input = document.getElementById("question");const outputDiv = document.getElementById('output');const startButton = document.getElementById('startButton');async function getResponse(){const question = input.value;const resp = await fetch("/chatStream" + "?question=" + question,{method: 'GET'})const reader = resp.body.getReader();const textDecoder = new TextDecoder();while (1){const { done , value } = await reader.read()if(done) break;const str = textDecoder.decode(value);outputDiv.innerText += str;console.log(str)}}startButton.addEventListener("click", getResponse)
</script>
</body>
</html>
向controller中添加stream接口:
@GetMapping("/chatStream")public void getChatMessageStream(@RequestParam String question, HttpServletResponse response) throws Exception {// 中文乱码问题response.setCharacterEncoding("UTF-8");// 获取OpenAi的聊天服务IChatService chatService = aiService.getChatService(PlatformType.OPENAI);// 创建请求参数ChatCompletion chatCompletion = ChatCompletion.builder().model("gpt-4o-mini").message(ChatMessage.withUser(question)).build();PrintWriter writer = response.getWriter();// 发送chat请求SseListener sseListener = new SseListener() {@Overrideprotected void send() {writer.write(this.getCurrStr());writer.flush();System.out.println(this.getCurrStr());}};chatService.chatCompletionStream(chatCompletion, sseListener);writer.close();System.out.println(sseListener.getOutput());}

注意:上面只是一个简单的示例,你也可以使用其它方法,比如:
@GetMapping("/chatStream")public ResponseBodyEmitter getChatMessageStream(@RequestParam String question) {ResponseBodyEmitter emitter = new ResponseBodyEmitter();// 获取OpenAi的聊天服务IChatService chatService = aiService.getChatService(PlatformType.OPENAI);// 创建请求参数ChatCompletion chatCompletion = ChatCompletion.builder().model("gpt-4o-mini").message(ChatMessage.withUser(question)).build();Executors.newSingleThreadExecutor().submit(() -> {try {SseListener sseListener = new SseListener() {@Overrideprotected void send() {try {emitter.send(this.getCurrStr());System.out.println(this.getCurrStr()); // 打印当前发送的内容} catch (IOException e) {emitter.completeWithError(e);}}};// 发送流式数据chatService.chatCompletionStream(chatCompletion, sseListener);// 完成后关闭连接emitter.complete();} catch (Exception e) {emitter.completeWithError(e);}});return emitter;}
实现函数调用
首先我们需要编写一个函数,以天气预报为例子:
@FunctionCall(name = "queryWeather", description = "查询目标地点的天气预报")
public class QueryWeatherFunction implements Function<QueryWeatherFunction.Request, String> {@Overridepublic String apply(Request request) {final String key = "abcdefg";// https://api.seniverse.com/v3/weather/hourly.json?key=your_api_key&location=beijing&start=0&hours=24// https://api.seniverse.com/v3/weather/daily.json?key=your_api_key&location=beijing&start=0&days=5String url = String.format("https://api.seniverse.com/v3/weather/%s.json?key=%s&location=%s&days=%d",request.type.name(),key,request.location,request.days);OkHttpClient client = new OkHttpClient();okhttp3.Request http = new okhttp3.Request.Builder().url(url).get().build();try (Response response = client.newCall(http).execute()) {if (response.isSuccessful()) {// 解析响应体return response.body() != null ? response.body().string() : "";} else {return "获取天气失败 当前天气未知";}} catch (Exception e) {// 处理异常e.printStackTrace();return "获取天气失败 当前天气未知";}}@Data@FunctionRequestpublic static class Request{@FunctionParameter(description = "需要查询天气的目标位置, 可以是城市中文名、城市拼音/英文名、省市名称组合、IP 地址、经纬度")private String location;@FunctionParameter(description = "需要查询未来天气的天数, 最多15日")private int days = 15;@FunctionParameter(description = "预报的天气类型,daily表示预报多天天气、hourly表示预测当天24天气、now为当前天气实况")private Type type;}public enum Type{daily,hourly,now}
}
其中有三个核心注解:
@FunctionCall:标识这个类为一个函数@FunctionRequest:标识为该类为函数的请求类@FunctionParameter:标识为函数的具体参数
接下来稍微修改下刚刚编写的Stream实现函数:
@GetMapping("/chatStream")public void getChatMessageStream(@RequestParam String question, HttpServletResponse response) throws Exception {// ......// 创建请求参数ChatCompletion chatCompletion = ChatCompletion.builder().model("gpt-4o-mini").message(ChatMessage.withUser(question)).functions("queryWeather") // 这里传入刚刚我们定义的函数名称即可.build();// ......}

如果想要知道函数调用的参数,只需要在刚刚的代码中,添加下面这一行即可:
sseListener.setShowToolArgs(true);

更换其它平台
细心的你可能已经发现,我们在创建chatService的时候传入了PlatformType.OPENAI,如果我们想要更换其它平台,只需要更换PlatformType即可。如果你不懂,那下篇博文再详细的说说
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
其它功能
篇幅有限,其它功能使用,下篇再讲
相关文章:
SpringBoot快速接入OpenAI大模型(JDK8)
使用AI4J快速接入OpenAI大模型 本博文给大家介绍一下如何使用AI4J快速接入OpenAI大模型,并且如何实现流式与非流式的输出,以及对函数调用的使用。 介绍 由于SpringAI需要使用JDK17和Spring Boot3,但是目前很多应用依旧使用的JDK8版本&…...
UniApp 中制作一个横向滚动工具栏
前言 最近在用 UniApp 开发项目时,需要一个横向滑动的工具栏。常见的工具栏一般都是竖着的,但横向滑动的工具栏不仅能展示更多内容,还能让界面看起来更加丰富。不过很多朋友可能会发现,如何让内容“横着”展示又不变形、能流畅滚…...
react中如何获取真实的dom
在 React 中,获取真实的 DOM 元素通常通过 ref 来实现。ref 是一个特殊的属性,用于引用组件或 DOM 元素的实例。你可以通过 ref 获取到组件的真实 DOM 元素或组件实例。 1. 函数组件中的 useRef 在函数组件中,获取 DOM 元素的引用需要使用 …...
5G与物联网的协同发展:打造智能城市的未来
引言 随着科技的不断进步,智能城市的概念已经不再是科幻小说中的幻想,它正在逐步走进我们的生活。而这背后的两大驱动力无疑是 5G和 物联网(IoT)。5G网络以其高速率、低延迟、大容量的优势,与物联网的强大连接能力相结…...
【Qt】实现定期清理程序日志
在现有Qt程序中实现可配置日志保存天数的代码示例,分为界面修改、配置存储和核心逻辑三部分: // 1. 在配置文件(如settings.h)中添加保存天数的配置项 class Settings { public:int logRetentionDays() const {return m_settings…...
git bisect 使用二分法查找引入错误的提交
git bisect 使用二分法查找引入错误的提交 Git bisect 命令官方文档 git bisect 这个命令使用二分搜索算法来查找项目历史中哪个提交引入了一个错误 使用该命令时,首先告诉它一个已知包含错误的 “坏” 提交 以及一个已知在错误出现之前的 “好” 提交 然后 git b…...
一种面向车载时间敏感网络的联合路由与时隙调度负载均衡算法
论文标题 中文标题:一种面向车载时间敏感网络的联合路由与时隙调度负载均衡算法 英文标题:A Joint Routing and Time-Slot Scheduling Load Balancing Algorithm for In-Vehicle TSN 作者信息 Bo Xu, Xinrui Chang, Dongyang Xu, Shuo Wang, Uzair As…...
【弹性计算】容器、裸金属
容器、裸金属 1.容器和云原生1.1 容器服务1.2 弹性容器实例1.3 函数计算 2.裸金属2.1 弹性裸金属服务器2.2 超级计算集群 1.容器和云原生 容器技术 起源于虚拟化技术,Docker 和虚拟机和谐共存,用户也找到了适合两者的应用场景,二者对比如下图…...
Golang关于结构体组合赋值的问题
现在有一个结构体,其中一个属性组合了另外一个结构体,如下所示: type User struct {Id int64Name stringAge int64UserInfo }type UserInfo struct {Phone stringAddress string }如果要给 User 结构体的 Phone 和 Address 赋值的话&am…...
DeepSeek vs ChatGPT:AI对决中的赢家是……人类吗?
DeepSeek vs ChatGPT:AI对决中的赢家是……人类吗? 文章目录 DeepSeek vs ChatGPT:AI对决中的赢家是……人类吗?一、引言1. 背景2. 问题 二、DeepSeek vs ChatGPT:谁更胜一筹?2.1 语言生成能力评测对比场景…...
新建github操作
1.在github.com的主页根据提示新建一个depository。 2.配置用户名和邮箱 git config --global user.name "name" git config --global user.email "email" 3.生成ssh秘钥 ssh-keygen -t rsa 找到public key 对应的文件路径 cat /root/.ssh/id_rsa 复制显…...
Spring Boot 携手 DeepSeek:开启智能交互新时代
前言 在当今数字化浪潮汹涌澎湃的时代,人工智能技术正以前所未有的速度改变着我们的生活和工作方式。大语言模型作为人工智能领域的一颗璀璨明星,凭借其强大的自然语言处理能力,为各个行业带来了新的发展机遇。DeepSeek 作为一款性能卓越的大语言模型,以其高效、准确的文本…...
基于SSM+uniapp的数学辅导小程序+LW示例参考
1.项目介绍 系统角色:管理员、普通用户功能模块:用户管理、学习中心、知识分类管理、学习周报管理、口算练习管理、试题管理、考试管理、错题本等技术选型:SSM,Vue(后端管理web),uniapp等测试环…...
HTML的入门
一、HTML HTML(HyperText Markup Language,超文本标记语言)是一种用来告知浏览器如何组织页面的标记语言。 超文本:就是超越了文本;HTML不仅仅可以用来显示文本(字符串、数字之类),还可以显示视频、音频等…...
Windows 安装 GDAL 并配置 Rust-GDAL 开发环境-1
Rust-GDAL 是 Rust 语言的 GDAL(Geospatial Data Abstraction Library) 绑定库,用于处理地理数据。由于 GDAL 依赖较多,在 Windows 上的安装相对复杂,本文档将介绍如何安装 GDAL 并配置 Rust-GDAL 的开发环境。 1. 检…...
IntelliJ IDEA 接入 AI 编程助手(Copilot、DeepSeek、GPT-4o Mini)
IntelliJ IDEA 接入 AI 编程助手(Copilot、DeepSeek、GPT-4o Mini) 📊 引言 近年来,AI 编程助手已成为开发者的高效工具,它们可以加速代码编写、优化代码结构,并提供智能提示。本文介绍如何在 IntelliJ I…...
【金三银四】分享数据库笔试题及答案~~
你是否在面试中遇到过关于数据库的笔试题?如何高效地准备这些题目,提升自己的竞争力?本文将为你整理一些经典的数据库笔试题及其答案,助你备战面试。 金三银四马上来了,测试年限较短难免会碰到笔试题,最近…...
3.1 AI Agent产品管理革命:从愿景定义到用户价值交付的全链路方法论
AI Agent产品管理革命:从愿景定义到用户价值交付的全链路方法论 引言:AI时代产品经理的范式跃迁 Gartner预测,到2026年75%的AI项目失败将归因于产品管理缺失。本文揭示AI Agent产品经理的六大核心能力模型,通过GitHub Sentinel等案例,展示如何将大模型技术转化为可持续商…...
MySQL常见错误码及解决方法(1130、1461、2003、1040、2000、1049、1062、1129、2002、1690等)
目录 【问题1】、FATAL: error 1130: Unknown error 1130 【问题2】、FATAL: error: 1461 【问题3】、ERROR 2003 (HY000): Cant connect to MySQL server on "" (113) 【问题4】、FATAL: error 2003: Cant connect to MySQL server on 172.19.111.151 (111) 【问…...
Rhel Centos环境开关机自动脚本
Rhel Centos环境开关机自动脚本 1. 业务需求2. 解决方法2.1 rc.local2.2 rc.d2.3 systemd2.4 systemd附着的方法2.5 tuned 3. 测试 1. 业务需求 一台较老的服务器上面业务比较简单,提供一个简单的网站,但已经没有业务的运维人员. 想达到的效果: 由于是非标准的apache或者nginx…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
