SpringBoot快速接入OpenAI大模型的方法(JDK8)
使用AI4J快速接入OpenAI大模型
本博文給大家介紹一下如何使用AI4J快速接入OpenAI大模型,并且如何實(shí)現(xiàn)流式與非流式的輸出,以及對(duì)函數(shù)調(diào)用的使用。
介紹
由于SpringAI需要使用JDK17和Spring Boot3,但是目前很多應(yīng)用依舊使用的JDK8版本,所以使用可以支持JDK8的AI4J來接入OpenAI大模型。
AI4J是一款JavaSDK用于快速接入AI大模型應(yīng)用,整合多平臺(tái)大模型,如OpenAi、智譜Zhipu(ChatGLM)、深度求索DeepSeek、月之暗面Moonshot(Kimi)、騰訊混元Hunyuan、零一萬物(01)等等,提供統(tǒng)一的輸入輸出(對(duì)齊OpenAi)消除差異化,優(yōu)化函數(shù)調(diào)用(Tool Call),優(yōu)化RAG調(diào)用、支持向量數(shù)據(jù)庫(kù)(Pinecone),并且支持JDK1.8,為用戶提供快速整合AI的能力。
AI4J-GitHub
快速使用
目前較多的應(yīng)用場(chǎng)景為Spring應(yīng)用,而AI4J接入SpringBoot應(yīng)用也是非常簡(jiǎn)單的,本篇博文先帶著大家為SpringBoot應(yīng)用集成OpenAI服務(wù),后續(xù)會(huì)介紹如何再非Spring項(xiàng)目中搭建。
創(chuàng)建SpringBoot項(xiàng)目


這里以JDK1.8為例創(chuàng)建SpringBoot2項(xiàng)目,當(dāng)然你也可以創(chuàng)建JDK17、SpringBoot3。
引入AI4J依賴
<!-- Spring應(yīng)用 -->
<dependency>
<groupId>io.github.lnyo-cly</groupId>
<artifactId>ai4j-spring-boot-stater</artifactId>
<version>0.5.2</version>
</dependency>如果你使用阿里源無法引入,可能是阿里云鏡像還沒有同步。
配置application.yml
給大家兩種配置方法
第一種:使用官網(wǎng)的url,自己有代理

第二種:使用中轉(zhuǎn)代理地址(或第三方中轉(zhuǎn)平臺(tái))
如:https://api.openai-proxy.com

上面任意配置一種即可。
搭建聊天服務(wù)Controller
下面是一個(gè)小的demo演示:
@RestController
public class OpenAiController {
// 注入Ai服務(wù)
@Autowired
private AiService aiService;
@GetMapping("/chat")
public String getChatMessage(@RequestParam String question) throws Exception {
// 獲取OpenAi的聊天服務(wù)
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
// 創(chuàng)建請(qǐng)求參數(shù)
ChatCompletion chatCompletion = ChatCompletion.builder()
.model("gpt-4o-mini")
.message(ChatMessage.withUser(question))
.build();
System.out.println(chatCompletion);
// 發(fā)送chat請(qǐng)求
ChatCompletionResponse chatCompletionResponse = chatService.chatCompletion(chatCompletion);
// 獲取聊天內(nèi)容和token消耗
String content = chatCompletionResponse.getChoices().get(0).getMessage().getContent();
long totalTokens = chatCompletionResponse.getUsage().getTotalTokens();
System.out.println("總token消耗: " + totalTokens);
return content;
}
}

實(shí)現(xiàn)stream流式輸出(打字機(jī)效果)
編寫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的聊天服務(wù)
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
// 創(chuàng)建請(qǐng)求參數(shù)
ChatCompletion chatCompletion = ChatCompletion.builder()
.model("gpt-4o-mini")
.message(ChatMessage.withUser(question))
.build();
PrintWriter writer = response.getWriter();
// 發(fā)送chat請(qǐng)求
SseListener 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());
}
注意:上面只是一個(gè)簡(jiǎn)單的示例,你也可以使用其它方法,比如:
@GetMapping("/chatStream")
public ResponseBodyEmitter getChatMessageStream(@RequestParam String question) {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
// 獲取OpenAi的聊天服務(wù)
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
// 創(chuàng)建請(qǐng)求參數(shù)
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()); // 打印當(dāng)前發(fā)送的內(nèi)容
} catch (IOException e) {
emitter.completeWithError(e);
}
}
};
// 發(fā)送流式數(shù)據(jù)
chatService.chatCompletionStream(chatCompletion, sseListener);
// 完成后關(guān)閉連接
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}實(shí)現(xiàn)函數(shù)調(diào)用
首先我們需要編寫一個(gè)函數(shù),以天氣預(yù)報(bào)為例子:
@FunctionCall(name = "queryWeather", description = "查詢目標(biāo)地點(diǎn)的天氣預(yù)報(bào)")
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.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()) {
// 解析響應(yīng)體
return response.body() != null ? response.body().string() : "";
} else {
return "獲取天氣失敗 當(dāng)前天氣未知";
}
} catch (Exception e) {
// 處理異常
e.printStackTrace();
return "獲取天氣失敗 當(dāng)前天氣未知";
}
}
@Data
@FunctionRequest
public static class Request{
@FunctionParameter(description = "需要查詢天氣的目標(biāo)位置, 可以是城市中文名、城市拼音/英文名、省市名稱組合、IP 地址、經(jīng)緯度")
private String location;
@FunctionParameter(description = "需要查詢未來天氣的天數(shù), 最多15日")
private int days = 15;
@FunctionParameter(description = "預(yù)報(bào)的天氣類型,daily表示預(yù)報(bào)多天天氣、hourly表示預(yù)測(cè)當(dāng)天24天氣、now為當(dāng)前天氣實(shí)況")
private Type type;
}
public enum Type{
daily,
hourly,
now
}
}其中有三個(gè)核心注解:
@FunctionCall:標(biāo)識(shí)這個(gè)類為一個(gè)函數(shù)@FunctionRequest:標(biāo)識(shí)為該類為函數(shù)的請(qǐng)求類@FunctionParameter:標(biāo)識(shí)為函數(shù)的具體參數(shù)
接下來稍微修改下剛剛編寫的Stream實(shí)現(xiàn)函數(shù):
@GetMapping("/chatStream")
public void getChatMessageStream(@RequestParam String question, HttpServletResponse response) throws Exception {
// ......
// 創(chuàng)建請(qǐng)求參數(shù)
ChatCompletion chatCompletion = ChatCompletion.builder()
.model("gpt-4o-mini")
.message(ChatMessage.withUser(question))
.functions("queryWeather") // 這里傳入剛剛我們定義的函數(shù)名稱即可
.build();
// ......
}
如果想要知道函數(shù)調(diào)用的參數(shù),只需要在剛剛的代碼中,添加下面這一行即可:
sseListener.setShowToolArgs(true);

更換其它平臺(tái)
細(xì)心的你可能已經(jīng)發(fā)現(xiàn),我們?cè)趧?chuàng)建chatService的時(shí)候傳入了PlatformType.OPENAI,如果我們想要更換其它平臺(tái),只需要更換PlatformType即可。如果你不懂,那下篇博文再詳細(xì)的說說
IChatService chatService = aiService.getChatService(PlatformType.OPENAI);
其它功能
篇幅有限,其它功能使用,下篇再講
到此這篇關(guān)于SpringBoot快速接入OpenAI大模型(JDK8)的文章就介紹到這了,更多相關(guān)SpringBoot接入OpenAI大模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
自己動(dòng)手編寫一個(gè)Mybatis插件之Mybatis脫敏插件
這篇文章主要介紹了自己動(dòng)手編寫一個(gè)Mybatis插件之Mybatis脫敏插件,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
SpringBoot3整合MinIO實(shí)現(xiàn)分布式文件存儲(chǔ)系統(tǒng)
MinIO是一個(gè)高性能的分布式對(duì)象存儲(chǔ)系統(tǒng),兼容Amazon S3協(xié)議,廣泛用于存儲(chǔ)大量非結(jié)構(gòu)化數(shù)據(jù),SpringBoot3提供了與MinIO的良好集成,可以很方便地將MinIO用于分布式文件存儲(chǔ),在這篇文章中,我們將介紹如何在SpringBoot3中集成MinIO,搭建一個(gè)分布式文件存儲(chǔ)系統(tǒng)2025-07-07
springboot定時(shí)任務(wù)SchedulingConfigurer異步多線程實(shí)現(xiàn)方式
這篇文章主要介紹了springboot定時(shí)任務(wù)SchedulingConfigurer異步多線程實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
解決java.util.NoSuchElementException異常正確方法
java.util.NoSuchElementException是Java中的一種異常,表示在迭代器或枚舉中找不到元素,這篇文章主要給大家介紹了關(guān)于解決java.util.NoSuchElementException異常的相關(guān)資料,需要的朋友可以參考下2023-11-11
Java 線程池_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
系統(tǒng)啟動(dòng)一個(gè)新線程的成本是比較高的,因?yàn)樗婕暗脚c操作系統(tǒng)的交互。在這種情況下,使用線程池可以很好的提供性能,尤其是當(dāng)程序中需要?jiǎng)?chuàng)建大量生存期很短暫的線程時(shí),更應(yīng)該考慮使用線程池2017-05-05
解決Spring boot整合mybatis,xml資源文件放置及路徑配置問題
這篇文章主要介紹了解決Spring boot整合mybatis,xml資源文件放置及路徑配置問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Java 根據(jù)網(wǎng)絡(luò)URL獲取該網(wǎng)頁(yè)上面所有的img標(biāo)簽并下載圖片
這篇文章主要介紹了Java 根據(jù)網(wǎng)絡(luò)URL獲取該網(wǎng)頁(yè)上面所有的img標(biāo)簽并下載圖片,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11
SpringBoot整合EasyExcel實(shí)現(xiàn)導(dǎo)入導(dǎo)出數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了如何使用Vue、SpringBoot和EasyExcel實(shí)現(xiàn)導(dǎo)入導(dǎo)出數(shù)據(jù)功能,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-05-05

