獨立開發(fā):高效集成大模型,看這篇就夠了
個人能力:會限制大模型發(fā)揮?
一、簡介
七月初全職獨立開發(fā),忙忙碌碌中已經(jīng)過了四周,最近兩個星期在做產(chǎn)品集成大模型的功能,所以在節(jié)奏上偏重開發(fā)這條線。
開發(fā)前感覺復(fù)雜,完成后感覺更復(fù)雜。
之前對于多款大模型的集成,更多是從技術(shù)角度調(diào)研文檔,再加上重要的前端編程,自己也是半吊子水平,對時間把握上心里沒底,所以準(zhǔn)備用兩周的時間,先把基礎(chǔ)能力封裝搭建好,方便后續(xù)的迭代擴展。
整體流程:【1】熟悉幾款模型的接入文檔,【2】集成文本模式的對話功能,【3】封裝提示詞動態(tài)管理。
為什么接入完成后感覺更復(fù)雜?
在接入并適配業(yè)務(wù)的過程中,不斷的調(diào)整和優(yōu)化提示詞,見識到大模型各種場景下的文本能力,也讓自己反思AI方向的能力不足,更是缺乏比較系統(tǒng)的知識和經(jīng)驗。
個人能力會限制大模型發(fā)揮,我成了AI的那什么豬隊友。
為什么只接入文本能力?
在大模型的使用中,感覺最核心的是文本能力,即信息輸入的理解和輸出的效果,把有限的時間先放在這一塊,爭取在不斷的提問和回復(fù)中,找到更加準(zhǔn)確高效的對話方式。
遵循熟能生巧的思路,積累一定的文本能力之后,在此基礎(chǔ)上挖掘應(yīng)用場景。
雖然產(chǎn)品只集成了4款模型,但是開發(fā)卻至少用了7款A(yù)I工具,涉及產(chǎn)品和前后端的全部環(huán)節(jié),大模型在其他行業(yè)使用,效果如何不清楚。
在研發(fā)領(lǐng)域,絕對已成氣候。
下面將從:集成原理、提示詞、數(shù)據(jù)庫、后端接口、前端對接,這5個維度總結(jié)整個開發(fā)流程。
二、集成原理
看了不少開源倉庫的教程,以及各個模型的官方文檔,這里更多是為了開闊思路,最終還是決定采用穩(wěn)妥的方式,前端調(diào)用后端API,后端處理大模型對接和數(shù)據(jù)存儲。

交互層面看,主要分為3段過程:【1】前后端,【2】后端和大模型,【3】后端和數(shù)據(jù)庫。即產(chǎn)品本身的對話交互,對話調(diào)用第三方模型,對話消息的存儲管理。
流程層面看,主要分為5段過程:【1】接收用戶消息,【2】會話記錄管理,【3】對話流程管理,【4】大模型調(diào)用,【5】前端輸出回復(fù)。
三、提示詞管理
在開始具體的代碼編程之前,必須先了解提示詞的基本用法,即不同身份角色所發(fā)出的消息類型。
public enum MessageType {
/**
* A {@link Message} of type {@literal user}, having the user role and originating
* from an end-user or developer.
* @see UserMessage
*/
USER("user"),
/**
* A {@link Message} of type {@literal assistant} passed in subsequent input
* {@link Message Messages} as the {@link Message} generated in response to the user.
* @see AssistantMessage
*/
ASSISTANT("assistant"),
/**
* A {@link Message} of type {@literal system} passed as input {@link Message
* Messages} containing high-level instructions for the conversation, such as behave
* like a certain character or provide answers in a specific format.
* @see SystemMessage
*/
SYSTEM("system"),
}
- 用戶類型的消息,具有用戶角色,來自最終用戶或開發(fā)人員,也就是產(chǎn)品中輸入的文本。
- 系統(tǒng)類型的消息,是相對高級的指令,要求模型扮演的角色或身份以及約束行為,比在用戶消息中設(shè)定的效果好。
- 助手類型的消息,模型響應(yīng)用戶生成的消息,也可以在對話的上下文中傳遞,可以聚焦會話的主題。
產(chǎn)品集成大模型的對話能力,最常用的就是三種消息類型,具體的場景可以具體的組合設(shè)計,AI的本質(zhì)在追求智能,所以可以做一些跳脫的嘗試挖掘模型能力。
四、數(shù)據(jù)庫設(shè)計
目前開發(fā)的進度,數(shù)據(jù)庫的設(shè)計只有4張關(guān)鍵的表,管理模型和提示詞,以及對話數(shù)據(jù)的存儲。

- 大模型配置表:統(tǒng)一封裝API調(diào)用,可以動態(tài)添加和禁用集成的模型和版本,前面的內(nèi)容已經(jīng)寫過。
- 提示詞配置表:給大模型和使用場景,動態(tài)配置系統(tǒng)提示詞,用戶消息末尾加限制,參考的是LastSQL方式。
- 會話和消息表:這種就是常見設(shè)計,會話就是保存每輪對話用戶的第一條消息,列表存放不同角色的輸出。
對話模塊表結(jié)構(gòu)設(shè)計,問過幾款主流的模型,給出的結(jié)構(gòu)都很類似,只圍繞產(chǎn)品需求做了小部分調(diào)整;模型和提示詞表結(jié)構(gòu),是抽取模型組件的API參數(shù)。
五、接口設(shè)計
1、大模型API基礎(chǔ)
使用的核心組件是spring-ai-openai的依賴包,主流的模型基本都適配了,該組件定義的模型API接口規(guī)范,這樣有利于模型統(tǒng)一管理和切換。
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>${spring-ai-openai.version}</version>
</dependency>
</dependencies>
- 消息(Message):用來封裝一條具體的消息,結(jié)構(gòu)涉及具體的角色和相應(yīng)的內(nèi)容。
- 提示詞(Prompt):不同角色的文本指令或者問題,用來引導(dǎo)大模型的響應(yīng)內(nèi)容。
- 客戶端(ChatClient):聊天客戶端,與大模型交互的工具,封裝了模型配置和調(diào)用的各種方法。
在具體的使用場景中,通常在提示詞中設(shè)定系統(tǒng)和用戶消息,用來引導(dǎo)模型的回復(fù),通過客戶端工具把指令發(fā)給具體的模型。
2、阻塞響應(yīng)
在上篇內(nèi)容SpringBoot3集成大模型中,使用的就是「阻塞」模式,請求發(fā)出后等大模型響應(yīng)完成,再把結(jié)果回傳給用戶,這種在長文本中體驗很差,比較適用內(nèi)容簡短的對話。
@GetMapping(value = "/client")
public String chatClient() {
String message = "講個笑話,最好能把我聽哭的那一種。";
return chatClient.prompt(new Prompt(message)).call().content();
}
3、Flux流式響應(yīng)
后端最初設(shè)計的是Flux接口,但是最終沒有采用,用的是WebSocket會話方式,具體原因前端對接模塊會細(xì)說。
大模型不會一次輸出完整結(jié)果,而是逐步返回中間內(nèi)容,需要完整的拼接起來才是全部內(nèi)容,這樣可以減少用戶等待時間,也降低超時的風(fēng)險。
@PostMapping(value = "/flux-chat",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChatTextVO> fluxChat (@RequestBody UserTextDTO dto){
// 1、參數(shù)校驗,模型ID和消息
if (ObjectUtil.hasNull(dto.getMsgText(),dto.getModelId())){
throw new BizExe(RepCode.PARAM_ERROR);
}
// 2、模型校驗獲取
ModelConfig model = modelConfigService.checkGetModel(dto.getModelId());
ChatClient myClient = ModelFactory.getModel(model.getModelVersion());
// 3、構(gòu)建會話進程
chatService.buildUserChat(dto, model, MessageType.USER.getValue());
// 4、模型對話與本地業(yè)務(wù)
return myClient.prompt(new Prompt(dto.getMsgText())).stream().chatResponse()
.map(chunk -> {
// 消息響應(yīng)片段
Generation generation = chunk.getResult();
AssistantMessage msg = generation.getOutput();
// 對話響應(yīng)
ChatTextVO chatTextVO = new ChatTextVO();
chatTextVO.setBlockId(msg.getMetadata().get(ChatParamEnum.MSG_BLOCK_ID.getParam()).toString());
chatTextVO.setMessageType(msg.getMessageType().toString());
chatTextVO.setTextContent(msg.getContent());
return chatTextVO;
})
.doOnComplete(() -> {
log.info("流式響應(yīng)結(jié)束,處理業(yè)務(wù)===>>>");
})
.doOnCancel(() -> {
log.info("流式響應(yīng)取消,處理業(yè)務(wù)===>>>");
})
.doOnError(error -> {
log.info("請求失敗: {}",error.getMessage());
});
}
這里值得注意的問題,如果流式響應(yīng)完整那最好,但用戶可能主動結(jié)束等待,或者會發(fā)生錯誤,為了保證流程的完整,需要執(zhí)行相應(yīng)的中斷方法完善業(yè)務(wù)邏輯。
4、WebSocket會話
此前寫過SpringBoot3的系列教程,其中包括如何集成WebSocket組件,源碼和案例都已歸檔在Git倉庫,所以這一塊就不展開詳聊了,重點來看如何集成模型對話。
private static final ConcurrentHashMap<String,Disposable> chatFlow = new ConcurrentHashMap<>();
public void socketChat(Session session, ChatTextDTO dto) throws Exception {
// 1、參數(shù)校驗
if (ObjectUtil.hasNull(dto.getMsgText(),dto.getModelId())){
throw new BizExe(RepCode.PARAM_ERROR);
}
// 2、模型校驗獲取
ModelConfig model = modelConfigService.checkGetModel(dto.getModelId());
ChatClient myClient = ModelFactory.getModel(model.getModelVersion());
// 3、構(gòu)建會話進程
this.buildUserChat(dto, model, MessageType.USER.getValue());
// 4、調(diào)用模型服務(wù)獲取響應(yīng)流
Disposable disposable = myClient.prompt(new Prompt(dto.getMsgText()))
.stream()
.chatResponse()
.doOnCancel(() -> {
log.info("會話結(jié)束,處理取消業(yè)務(wù)");
})
.subscribe(
chunk -> {
// 消息響應(yīng)片段
Generation generation = chunk.getResult();
AssistantMessage msg = generation.getOutput();
// 響應(yīng)消息主體
ChatTextVO chatTextVO = new ChatTextVO();
chatTextVO.setBlockId(msg.getMetadata().get(ChatParamEnum.MSG_BLOCK_ID.getParam()).toString());
chatTextVO.setMessageType(msg.getMessageType().toString());
chatTextVO.setTextContent(msg.getContent());
// 會話中響應(yīng)數(shù)據(jù)
this.sendMessage(session, chatTextVO);
},
error -> {
log.error("流式處理出錯", error);
},
() -> {
log.info("流式響應(yīng)結(jié)束,開始處理業(yè)務(wù)===>>>");
}
);
// 方便Session中斷時取消模型回復(fù)
chatFlow.put(session.getId(),disposable);
}
private void sendMessage(Session session, Object message) {
try {
session.getBasicRemote().sendText(objMapper.writeValueAsString(message));
} catch (Exception e) {
log.error("發(fā)送WebSocket消息出錯", e);
}
}
基于WebSocket會話模式,其調(diào)用的依舊是流式接口,只不過增加了Session和ChatClient整體協(xié)調(diào)的復(fù)雜度,這種模式前端調(diào)用更加絲滑。
六、前端對接
1、接口對接思路
前端跟大模型對話的場景上,需要實現(xiàn)響應(yīng)內(nèi)容的分段輸出。一是會提高接口的效率,二是減少用戶不必要的等待時間,可以看到實時的內(nèi)容。
前端是基于vue3和uni-app搭建的框架,所以用到了uni-app提供的request函數(shù),調(diào)用這個流式接口。經(jīng)過各種測試,該函數(shù)支持H5和小程序端,在app端不支持分段響應(yīng)。永遠(yuǎn)都是把所有的響應(yīng)一起返回。
于是找了其他辦法,比如:1、封裝XMLHttpRequest來實現(xiàn)SSE;2、使用分頁和輪詢模擬流;3、使用RenderJS,RenderJS是uni-app提供的一種運行在視圖層的腳本技術(shù),它可以直接操作視圖層的DOM和BOM,特別適合處理高性能渲染需求。
第一種方式,在IOS運行沒生效,第二種方式,覺得效率不高,第三種方式,小程序端不生效。
最后,左思右想,也參考了很多資料。還是采用websocket。
2、WebSocket對接和設(shè)計
WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議,它實現(xiàn)了瀏覽器與服務(wù)器之間的實時雙向數(shù)據(jù)交換。
uni-app官方文檔上就有專門支持WebSocket的函數(shù),不管是H5端,小程序端,APP端都支持。所以果斷采用了這個方案。
不過還是用后端的套路,避免過多的連接和斷開連接,這樣比較耗費資源,所以將用戶的連接采用單例的方式進行管理。
展示一下完整的全局WebSocket管理器集成方案:
interface WebSocketConfig {
url: string
headers?: Record<string, string>
protocols?: string | string[]
}
interface WebSocketCallbacks {
onOpen?: (event: any) => void
onMessage?: (event: any) => void
onError?: (event: any) => void
onClose?: (event: any) => void
}
class WebSocketManager {
private static instance: WebSocketManager
private socketTask: any = null
private config: WebSocketConfig | null = null
private callbacks: WebSocketCallbacks = {}
private isConnecting = false
private reconnectTimer: any = null
private reconnectAttempts = 0
private maxReconnectAttempts = 5
private reconnectInterval = 3000
private constructor() {}
// 獲取單例實例
static getInstance(): WebSocketManager {
if (!WebSocketManager.instance) {
WebSocketManager.instance = new WebSocketManager()
}
return WebSocketManager.instance
}
// 檢查是否已連接
isConnected(): boolean {
return this.socketTask && this.socketTask.readyState === 1
}
// 連接WebSocket
async connect(config: WebSocketConfig, callbacks: WebSocketCallbacks = {}): Promise<boolean> {
// 如果已經(jīng)連接且配置相同,直接返回
if (this.isConnected() && this.isSameConfig(config)) {
console.log('WebSocket已連接,復(fù)用現(xiàn)有連接')
this.updateCallbacks(callbacks)
return true
}
// 如果正在連接中,等待連接完成
if (this.isConnecting) {
console.log('WebSocket正在連接中,等待連接完成')
return this.waitForConnection()
}
// 關(guān)閉現(xiàn)有連接
if (this.socketTask) {
this.disconnect()
}
this.config = config
this.callbacks = callbacks
this.isConnecting = true
return new Promise((resolve) => {
console.log('開始連接WebSocket:', config.url)
this.socketTask = uni.connectSocket({
url: config.url,
header: config.headers || {},
protocols: config.protocols,
success: () => {
console.log('WebSocket連接請求發(fā)送成功')
},
fail: (error) => {
console.error('WebSocket連接請求失敗:', error)
this.isConnecting = false
this.callbacks.onError?.(error)
resolve(false)
}
})
// 連接打開
this.socketTask.onOpen((event: any) => {
console.log('WebSocket連接已打開')
this.isConnecting = false
this.reconnectAttempts = 0
this.clearReconnectTimer()
this.callbacks.onOpen?.(event)
resolve(true)
})
// 接收消息
this.socketTask.onMessage((event: any) => {
this.callbacks.onMessage?.(event)
})
// 連接錯誤
this.socketTask.onError((event: any) => {
console.error('WebSocket連接錯誤:', event)
this.isConnecting = false
this.callbacks.onError?.(event)
this.scheduleReconnect()
resolve(false)
})
// 連接關(guān)閉
this.socketTask.onClose((event: any) => {
console.log('WebSocket連接已關(guān)閉:', event)
this.isConnecting = false
this.callbacks.onClose?.(event)
// 如果不是主動關(guān)閉,嘗試重連
if (event.code !== 1000) {
this.scheduleReconnect()
}
if (!this.isConnected()) {
resolve(false)
}
})
})
}
// 發(fā)送消息
send(data: string | ArrayBuffer): boolean {
if (!this.isConnected()) {
console.error('WebSocket未連接,無法發(fā)送消息')
return false
}
this.socketTask.send({
data: data,
success: () => {
console.log('WebSocket消息發(fā)送成功')
},
fail: (error: any) => {
console.error('WebSocket消息發(fā)送失敗:', error)
}
})
return true
}
// 斷開連接
disconnect(): void {
this.clearReconnectTimer()
if (this.socketTask) {
this.socketTask.close({
code: 1000,
reason: '主動斷開連接'
})
this.socketTask = null
}
this.isConnecting = false
this.config = null
this.callbacks = {}
this.reconnectAttempts = 0
console.log('WebSocket連接已斷開')
}
// 更新回調(diào)函數(shù)
updateCallbacks(callbacks: WebSocketCallbacks): void {
this.callbacks = { ...this.callbacks, ...callbacks }
}
// 獲取連接狀態(tài)
getStatus(): string {
if (this.isConnected()) return 'connected'
if (this.isConnecting) return 'connecting'
return 'disconnected'
}
}
// 導(dǎo)出單例實例
export const websocketManager = WebSocketManager.getInstance()
// 導(dǎo)出類型
export type { WebSocketConfig, WebSocketCallbacks }
使用方式
簡單使用
// 基本連接
const connected = await websocketManager.connect({
url: 'ws://example.com/socket',
headers: {
'Authorization': 'Bearer token'
}
}, {
onMessage: (event) => {
console.log('收到消息:', event.data)
}
})
檢查連接狀態(tài)
// 檢查是否已連接
if (websocketManager.isConnected()) {
// 直接使用現(xiàn)有連接
websocketManager.send('hello')
} else {
// 需要先連接
await websocketManager.connect(config, callbacks)
}
發(fā)送消息
// 發(fā)送消息
const success = websocketManager.send(JSON.stringify(data))
if (!success) {
console.error('發(fā)送失敗,連接未建立')
}
架構(gòu)優(yōu)勢
性能優(yōu)化
- 避免重復(fù)連接: 頁面切換時復(fù)用連接
- 減少資源消耗: 單例模式減少內(nèi)存占用
- 智能重連: 自動處理網(wǎng)絡(luò)異常
代碼簡化
- 統(tǒng)一管理: 所有WebSocket邏輯集中管理
- 易于維護: 業(yè)務(wù)代碼只需關(guān)注配置和回調(diào)
- 類型安全: 完整的TypeScript類型支持
擴展性強
- 多頁面支持: 可在任意頁面使用
- 配置靈活: 支持不同的URL和headers
- 回調(diào)自定義: 每個頁面可定義自己的消息處理邏輯
3、websocket的設(shè)計優(yōu)化
基于上面的封裝,其實還有一點要考慮,WebSocket連接的斷開時機,分了三個維度去考慮這個事情:
連接的斷開時機
1. 應(yīng)用進入后臺時斷開
- 時機: onHide 應(yīng)用生命周期
- 原因: 節(jié)省資源,避免后臺保持連接
- 優(yōu)勢: 系統(tǒng)資源優(yōu)化,電池續(xù)航
2. 用戶登出時斷開
- 時機: 用戶主動登出
- 原因: 安全考慮,避免無效連接
- 優(yōu)勢: 數(shù)據(jù)安全,連接清理
3. 長時間無活動時斷開
- 時機: 設(shè)置定時器檢測活動
- 原因: 避免僵尸連接
- 優(yōu)勢: 資源優(yōu)化
所以對上面的WebSocketManager做了調(diào)整。
class WebSocketManager {
private static instance: WebSocketManager
private socketTask: any = null
private config: WebSocketConfig | null = null
private pageCallbacks: Map<string, WebSocketCallbacks> = new Map()
private currentPageId: string = ''
private connecting = false
private reconnectTimer: any = null
private reconnectAttempts = 0
private maxReconnectAttempts = 5
private reconnectInterval = 3000
// 連接管理相關(guān)
private lastActivityTime: number = Date.now()
private activityTimer: any = null
private inactivityTimeout = 30 * 60 * 1000 // 30分鐘無活動自動斷開
private isAppInBackground = false
// 發(fā)送消息
send(data: string | ArrayBuffer): boolean {
if (!this.isConnected()) {
console.error('WebSocket未連接,無法發(fā)送消息')
return false
}
// 記錄用戶活動
this.recordActivity()
this.socketTask.send({
data: data,
success: () => {
console.log('WebSocket消息發(fā)送成功')
},
fail: (error: any) => {
console.error('WebSocket消息發(fā)送失敗:', error)
}
})
return true
}
// 記錄用戶活動
recordActivity(): void {
this.lastActivityTime = Date.now()
this.resetActivityTimer()
}
// 重置活動計時器
private resetActivityTimer(): void {
if (this.activityTimer) {
clearTimeout(this.activityTimer)
}
this.activityTimer = setTimeout(() => {
console.log('WebSocket長時間無活動,自動斷開連接')
this.disconnect()
}, this.inactivityTimeout)
}
// 應(yīng)用進入后臺
onAppHide(): void {
console.log('應(yīng)用進入后臺,斷開WebSocket連接')
this.isAppInBackground = true
this.disconnect()
}
// 應(yīng)用回到前臺
onAppShow(): void {
console.log('應(yīng)用回到前臺')
this.isAppInBackground = false
}
// 用戶登出時斷開連接
onUserLogout(): void {
console.log('用戶登出,斷開WebSocket連接')
this.disconnect()
}
// 斷開連接
disconnect(): void {
this.clearReconnectTimer()
this.clearActivityTimer()
if (this.socketTask) {
this.socketTask.close({
code: 1000,
reason: '主動斷開連接'
})
this.socketTask = null
}
this.connecting = false
this.config = null
this.pageCallbacks.clear()
this.currentPageId = ''
this.reconnectAttempts = 0
console.log('WebSocket連接已斷開')
}
// 清理活動計時器
private clearActivityTimer(): void {
if (this.activityTimer) {
clearTimeout(this.activityTimer)
this.activityTimer = null
}
}
}
增加生命周期管理類
/**
* 應(yīng)用生命周期管理
* 處理WebSocket連接的智能斷開和重連
*/
import { websocketManager } from './websocket'
class AppLifecycleManager {
private static instance: AppLifecycleManager
private isInitialized = false
// 初始化應(yīng)用生命周期監(jiān)聽
init(): void {
if (this.isInitialized) {
console.log('應(yīng)用生命周期管理已初始化')
return
}
console.log('初始化應(yīng)用生命周期管理')
// 監(jiān)聽?wèi)?yīng)用隱藏(進入后臺)
uni.onAppHide(() => {
console.log('應(yīng)用進入后臺')
websocketManager.onAppHide()
})
// 監(jiān)聽?wèi)?yīng)用顯示(回到前臺)
uni.onAppShow(() => {
console.log('應(yīng)用回到前臺')
websocketManager.onAppShow()
})
// 監(jiān)聽網(wǎng)絡(luò)狀態(tài)變化
uni.onNetworkStatusChange((res) => {
console.log('網(wǎng)絡(luò)狀態(tài)變化:', res)
if (!res.isConnected) {
console.log('網(wǎng)絡(luò)斷開,斷開WebSocket連接')
websocketManager.disconnect()
}
// 網(wǎng)絡(luò)恢復(fù)時不自動重連,等待用戶操作
})
this.isInitialized = true
}
// 用戶登出時調(diào)用
onUserLogout(): void {
console.log('用戶登出,清理WebSocket連接')
websocketManager.onUserLogout()
}
}
// 導(dǎo)出單例實例
export const appLifecycleManager = AppLifecycleManager.getInstance()
最后,是斷開連接的用法。
import { defineStore } from 'pinia';
import { appLifecycleManager } from '@/utils/app-lifecycle';
export const useUserStore = defineStore('user', {
actions: {
// 退出登錄
logout() {
this.userInfo = null;
this.token = '';
this.isLoggedIn = false;
// 清除本地存儲
uni.removeStorageSync('token');
uni.removeStorageSync('userInfo');
// 斷開WebSocket連接
appLifecycleManager.onUserLogout();
}
}
});
上面貼了部分核心代碼,不過都是以自己后端的角度去考慮的。
最后,呼應(yīng)上面,再列舉不斷開連接的情況。
不斷開的情況
1. 頁面切換時
- 保持連接: 在home和square頁面間切換
- 原因: 提供流暢的用戶體驗
- 優(yōu)勢: 快速響應(yīng),無需重新連接
2. 應(yīng)用回到前臺時
- 不自動重連: 等待用戶主動操作
- 原因: 按需連接,節(jié)省資源
- 優(yōu)勢: 用戶控制連接時機
3. 網(wǎng)絡(luò)恢復(fù)時
- 不自動重連: 等待用戶發(fā)送消息時重連
- 原因: 避免不必要的連接
- 優(yōu)勢: 按需連接
4、WebSocket最后總結(jié)
這套封裝,使WebSocket連接完全抽離為全局管理,首次進入頁面會檢查連接狀態(tài),有連接就復(fù)用,沒有就初始化,外部只需要定義URL和請求頭即可。
并且,連接也具有完整的智能管理策略,能夠在合適的時機自動斷開連接,既保證了用戶體驗,又優(yōu)化了資源使用。
七、寫在最后
對于大模型的集成,本質(zhì)就是第三方API的調(diào)用,剛開始做的時候也有點犯難,不過花時間和心思研究文檔之后,其實原理并不算復(fù)雜。
所謂套殼大模型的產(chǎn)品,體驗上的差距更多在于:開發(fā)者對模型能力的理解和運用。有句話現(xiàn)在越來越認(rèn)可,人工智能時代:模型本身即產(chǎn)品。
文檔倉庫:
https://gitee.com/cicadasmile/butte-java-note
源碼倉庫:
https://gitee.com/cicadasmile/butte-mound

在接入并適配業(yè)務(wù)的過程中,不斷的調(diào)整和優(yōu)化提示詞,見識到大模型各種場景下的文本能力,也讓自己反思AI方向的能力不足。
浙公網(wǎng)安備 33010602011771號