SpringBoot快速接入OpenAI大模型的方法(JDK8)

2025-02-28 17:50

本文主要是介绍SpringBoot快速接入OpenAI大模型的方法(JDK8),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《SpringBoot快速接入OpenAI大模型的方法(JDK8)》本文介绍了如何使用AI4J快速接入OpenAI大模型,并展示了如何实现流式与非流式的输出,以及对函数调用的使用,AI4J支持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项目

SpringBoot快速接入OpenAI大模型的方法(JDK8)

SpringBoot快速接入OpenAI大模型的方法(JDK8)

这里以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,自己有代理

SpringBoot快速接入OpenAI大模型的方法(JDK8)

第二种:使用中转代理地址(或第三方中转平台)

如:https://api.openai-proxy.com

SpringBoot快速接入OpenAI大模型的方法(JDK8)

上面任意配置一种即可。

搭建聊天服务Controller

下面是一个小的demo演示:

@RestController
public class OpenAiController {
    // 注入Ai服务
    @Autowired
    private 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;
    }
}

SpringBoot快速接入OpenAI大模型的方法(JDK8)

SpringBoot快速接入OpenAI大模型的方法(JDK8)

实现stream流式输出(打字机效果)

编写stream.html

<!DOCTYPE html>
<html>
<head>
   http://www.chinasem.cn <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请求
        SseListeneChina编程r sseListener = new SseListener() {
            @Override
            protected void send() {
                writer.write(this.getCurrStr());
                writer.flush();
                System.out.println(this.getCurrStr());
            }
        };
        chatService.chatCompletionStream(chatCompletion, sseListener);
        writer.close();
        System.out.println(sseListener.getOutput());
    }

SpringBoot快速接入OpenAI大模型的方法(JDK8)

注意:上面只是一个简单的示例,你也可以使用其它方法,比如:

    @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() {
                    @Override
                    protected 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> {
    @Override
    public 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=5
        String url = String.format("https://api.seniverse.com/v3/weather/%s.json?key=%s&location=%s&days=%d",
                request.type.name(),
                key,
                request.locahttp://www.chinasem.cntion,
                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
    @FunctionRequest
    public 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(ChaChina编程tMessage.withUser(question))
                .functions("queryWeather") // 这里传入刚刚我们定义的函数名称即可
                .build();
        // ......
    }

SpringBoot快速接入OpenAI大模型的方法(JDK8)

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

sseListener.setShowToolArgs(true);

SpringBoot快速接入OpenAI大模型的方法(JDK8)

更换其它平台

细心的你可能已经发现,我们在创建chatService的时候传入了PlatformType.OPENAI,如果我们想要更换其它平台,只需要更换PlatformType即可。如果你不懂,那下篇博文再详细的说说

IChatService chatService = aiService.getChatService(PlatformType.OPENAI);

其它功能

篇幅有限,其它功能使用,下篇再讲

到此这篇关于SpringBoot快速接入OpenAI大模型(JDK8)的文章就介绍到这了,更多相关SpringBoot接入OpenAI大模型内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于SpringBoot快速接入OpenAI大模型的方法(JDK8)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153586

相关文章

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操