<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      獨立開發(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ù)存儲。

      1

      交互層面看,主要分為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ù)的存儲。

      2

      • 大模型配置表:統(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
      
      posted @ 2025-07-25 08:49  七號樓  閱讀(913)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲精品不卡av在线播放| 蒙自县| 国产av无码专区亚洲草草| 午夜国产理论大片高清| 亚洲欧洲无码av电影在线观看| 少妇熟女天堂网av| 高清无码爆乳潮喷在线观看| 无码精品人妻一区二区三区中| 色欲天天婬色婬香综合网| 欧美自拍另类欧美综合图片区| 河西区| 国产久爱免费精品视频| 久久国产精品-国产精品| 亚洲成人av高清在线| 青草99在线免费观看| 国产亚洲999精品AA片在线爽 | 亚洲精品熟女一区二区| 亚洲欧美精品一中文字幕| 激情自拍校园春色中文| 国产一区二区不卡在线视频| 高清国产精品人妻一区二区| 久久国内精品一区二区三区| 色猫咪av在线网址| 办公室强奷漂亮少妇视频| 免费观看日本污污ww网站69| 4hu44四虎www在线影院麻豆 | 无人去码一码二码三码区| bt天堂新版中文在线| 精品中文人妻在线不卡| 久久精品国产99国产精品严洲 | 孕妇特级毛片ww无码内射| 欧美xxxx做受欧美| 亚洲色一区二区三区四区| 人妻体内射精一区二区三区 | 亚洲综合国产激情另类一区| 国产办公室秘书无码精品99| 成人免费A级毛片无码片2022 | 国产午夜福利av在线麻豆| 精品日韩人妻中文字幕| 久久天天躁狠狠躁夜夜婷| 日韩有码中文字幕av|