建立帶數(shù)據(jù)庫(kù)的網(wǎng)站關(guān)鍵詞排名網(wǎng)絡(luò)推廣
當(dāng)Spring Boot遇見(jiàn)豆包大模型:一場(chǎng)流式響應(yīng)的"魔法吟唱"儀式
一、前言:關(guān)于流式響應(yīng)的奇妙比喻
想象一下你正在火鍋店點(diǎn)單,如果服務(wù)員必須等所有菜品都備齊才一次性端上來(lái),你可能會(huì)餓得把菜單都啃了。而流式響應(yīng)就像貼心的服務(wù)員,毛肚剛切好就立刻端上桌,肥牛卷還在空中飛著就送到你面前——這就是我們今天要施展的"異步上菜大法"!
注:完整代碼見(jiàn)底部
二、Spring Boot魔法陣搭建
2.1 召喚SSE精靈
@PostMapping(value = "/ask", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter ask() {SseEmitter emitter = new SseEmitter(60_000L); // 設(shè)置60秒超時(shí)結(jié)界//...后續(xù)魔法吟唱
}
這段咒語(yǔ)相當(dāng)于在Spring Boot的魔法陣中召喚了一個(gè)SSE(Server-Sent Events)精靈,它將負(fù)責(zé)持續(xù)不斷地把豆包大模型的智慧結(jié)晶傳送給前端。
2.2 構(gòu)建跨次元傳送門(mén)
@CrossOrigin(origins = "*") // 允許所有位面的訪(fǎng)問(wèn)
這行代碼就像在霍格沃茨的墻上開(kāi)了個(gè)任意門(mén),讓前端、移動(dòng)端、甚至隔壁王大爺?shù)闹悄芄照榷寄苓B接我們的服務(wù)。
三、豆包大模型召喚儀式
3.1 拼裝召喚咒語(yǔ)
ArkService arkService = ArkService.builder().apiKey("你的魔法密鑰") // 請(qǐng)自行替換成阿拉霍洞開(kāi)咒.build();
這里我們正在拼裝哈利·波特級(jí)別的魔法道具,apiKey
就是你的魔杖認(rèn)證,記得千萬(wàn)不要像把WiFi密碼寫(xiě)成紙條貼在電梯里一樣暴露它!
3.2 構(gòu)建魔法對(duì)話(huà)卷軸
List<ChatMessage> chatMessages = new ArrayList<>();
chatMessages.add(ChatMessage.builder().role(ChatMessageRole.USER) // 麻瓜用戶(hù)身份.content("求Java策略模式代碼") // 你的靈魂拷問(wèn).build());
這相當(dāng)于在羊皮紙上書(shū)寫(xiě)你的問(wèn)題,就像給貓頭鷹系上求助信。注意提問(wèn)要像調(diào)制福靈劑一樣精準(zhǔn),才能得到理想的回答。
四、流式響應(yīng)的煉金術(shù)
4.1 啟動(dòng)魔法反應(yīng)堆
new Thread(() -> {// 這里開(kāi)始煉制長(zhǎng)生不老藥...哦不,處理響應(yīng)
}).start();
我們開(kāi)啟了多線(xiàn)程煉丹爐(誤),確保主線(xiàn)程不會(huì)像被石化的赫敏一樣僵住。
4.2 實(shí)時(shí)傳輸咒語(yǔ)
arkService.streamChatCompletion(...).forEach(j -> {emitter.send(SseEmitter.event().data(JSON.toJSONString(aiChatDTO))); // 把知識(shí)碎片裝進(jìn)漂流瓶
});
這就像用魔法把一本厚書(shū)拆成一頁(yè)頁(yè)的羊皮紙,通過(guò)飛路網(wǎng)持續(xù)傳送。前端可以像收快遞一樣實(shí)時(shí)展示每個(gè)字的到來(lái)。
五、魔法的收尾工作
5.1 關(guān)閉魔法陣
finally {arkService.shutdownExecutor(); // 收拾魔法實(shí)驗(yàn)室
}
就像優(yōu)秀的巫師總會(huì)清理遺忘咒的施法痕跡,這里確保我們的魔法資源不會(huì)像韋斯萊家的飛車(chē)一樣失控亂跑。
5.2 異常處理小精靈
emitter.completeWithError(ex); // 把鍋甩給異常對(duì)象
當(dāng)魔藥課發(fā)生爆炸時(shí),我們要優(yōu)雅地把錯(cuò)誤信息封裝成記憶球,而不是讓整個(gè)霍格沃茨城堡崩潰。
六、實(shí)戰(zhàn)效果展示
當(dāng)你在控制臺(tái)看到這樣的輸出:
"定義策略接口->創(chuàng)建具體策略類(lèi)->配置上下文..."
說(shuō)明你的魔法已經(jīng)生效!前端會(huì)像收到鄧布利多軍的秘密信號(hào)一樣,逐字顯示出策略模式的代碼實(shí)現(xiàn)。
postman效果圖
七、寫(xiě)給麻瓜程序員的注意事項(xiàng)
- 密鑰保護(hù):把你的apiKey當(dāng)成隱形衣,千萬(wàn)別學(xué)洛哈特教授到處?kù)乓?/li>
- 超時(shí)設(shè)置:60秒足夠熬制一鍋標(biāo)準(zhǔn)的緩和劑,但復(fù)雜問(wèn)題可能需要更久
- 流量控制:別讓你的魔法管道像韋斯萊笑話(huà)商店的煙花一樣噴涌過(guò)度
八、結(jié)語(yǔ):你已學(xué)會(huì)的魔法
現(xiàn)在你已經(jīng)掌握了:
- 搭建SSE雙向鏡通信
- 流式響應(yīng)煉金術(shù)
- 大模型召喚儀式
- 異常處理的黑魔法防御術(shù)
快去創(chuàng)建你自己的"魔法AI助手"吧!記住:好的代碼應(yīng)該像福靈劑一樣令人愉悅,而不是像嘔吐味的比比多味豆讓人措手不及。愿代碼之神永遠(yuǎn)眷顧你的IDE!
附
package com.ideal.jason.controller;import com.alibaba.fastjson.JSON;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.volcengine.ark.runtime.service.ArkService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
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.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** @author: jason* @Date: 14 2月 2025*/
@CrossOrigin(origins = "*")
@Slf4j
@RestController
@RequestMapping("/api/ai")
public class AIController {@PostMapping(value = "/ask", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter ask() {SseEmitter emitter = new SseEmitter(60_000L); // 超時(shí)時(shí)間 60 秒String apiKey = "ccde85e1-6ae4-1234-abe1-423164b9f965";//替換成自己的 API KeyString content = "java策略模式代碼樣例提供";//替換成自己的 API KeyString model = "doubao-1.5-pro-32k-250115";//替換成自己的 模型id// 創(chuàng)建ArkService實(shí)例ArkService arkService = ArkService.builder().apiKey(apiKey).build();// 模擬流式數(shù)據(jù)new Thread(() -> {try {// 初始化消息列表List<ChatMessage> chatMessages = new ArrayList<>();// 創(chuàng)建用戶(hù)消息ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER) // 設(shè)置消息角色為用戶(hù).content(content) // //替換成自己的 提問(wèn)內(nèi)容.build();// 將用戶(hù)消息添加到消息列表chatMessages.add(userMessage);// 創(chuàng)建聊天完成請(qǐng)求ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder().model(model)// 需要替換為Model ID.messages(chatMessages) // 設(shè)置消息列表.stream(true)//以流式返回.build();// 發(fā)送聊天完成請(qǐng)求并打印響應(yīng)// 獲取響應(yīng)并打印每個(gè)選擇的消息內(nèi)容StringBuilder sb = new StringBuilder();arkService.streamChatCompletion(chatCompletionRequest).blockingIterable().forEach(j -> j.getChoices().forEach(choice -> {//System.out.print(choice.getMessage().getContent());AIChatDTO aiChatDTO =AIChatDTO.builder().content(choice.getMessage().getContent().toString()).build();try {emitter.send(SseEmitter.event()//.id(choice.getMessage().getToolCallId()).data(JSON.toJSONString(aiChatDTO)));sb.append(aiChatDTO.getContent());} catch (IOException e) {log.error("ask IOException");}}));System.out.println(sb);emitter.complete();} catch (Exception ex) {emitter.completeWithError(ex);} finally {// 關(guān)閉服務(wù)執(zhí)行器arkService.shutdownExecutor();}}).start();return emitter;}
}
maven依賴(lài)
<!-- 豆包 --><dependency><groupId>com.volcengine</groupId><artifactId>volcengine-java-sdk-ark-runtime</artifactId><version>LATEST</version></dependency>