找回密码
 立即注册
首页 业界区 业界 独立开发:高效集成大模型,看这篇就够了 ...

独立开发:高效集成大模型,看这篇就够了

求几少 2025-7-25 08:04:36
目录

  • 一、简介
  • 二、集成原理
  • 三、提示词管理
  • 四、数据库设计
  • 五、接口设计

    • 1、大模型API基础
    • 2、阻塞响应
    • 3、Flux流式响应
    • 4、WebSocket会话

  • 六、前端对接

    • 1、接口对接思路
    • 2、WebSocket对接和设计

      • 使用方式

        • 简单使用
        • 检查连接状态
        • 发送消息

      • 架构优势

        • 性能优化
        • 代码简化
        • 扩展性强


    • 3、websocket的设计优化

      • 连接的断开时机

        • 1. 应用进入后台时断开
        • 2. 用户登出时断开
        • 3. 长时间无活动时断开

      • 不断开的情况

        • 1. 页面切换时
        • 2. 应用回到前台时
        • 3. 网络恢复时


    • 4、WebSocket最后总结

  • 七、写在最后

个人能力:会限制大模型发挥?
一、简介

七月初全职独立开发,忙忙碌碌中已经过了四周,最近两个星期在做产品集成大模型的功能,所以在节奏上偏重开发这条线。
开发前感觉复杂,完成后感觉更复杂。
之前对于多款大模型的集成,更多是从技术角度调研文档,再加上重要的前端编程,自己也是半吊子水平,对时间把握上心里没底,所以准备用两周的时间,先把基础能力封装搭建好,方便后续的迭代扩展。
整体流程:【1】熟悉几款模型的接入文档,【2】集成文本模式的对话功能,【3】封装提示词动态管理。
为什么接入完成后感觉更复杂?
在接入并适配业务的过程中,不断的调整和优化提示词,见识到大模型各种场景下的文本能力,也让自己反思AI方向的能力不足,更是缺乏比较系统的知识和经验。
个人能力会限制大模型发挥,我成了AI的那什么猪队友。
为什么只接入文本能力?
在大模型的使用中,感觉最核心的是文本能力,即信息输入的理解和输出的效果,把有限的时间先放在这一块,争取在不断的提问和回复中,找到更加准确高效的对话方式。
遵循熟能生巧的思路,积累一定的文本能力之后,在此基础上挖掘应用场景。
虽然产品只集成了4款模型,但是开发却至少用了7款AI工具,涉及产品和前后端的全部环节,大模型在其他行业使用,效果如何不清楚。
在研发领域,绝对已成气候。
下面将从:集成原理、提示词、数据库、后端接口、前端对接,这5个维度总结整个开发流程。
二、集成原理

看了不少开源仓库的教程,以及各个模型的官方文档,这里更多是为了开阔思路,最终还是决定采用稳妥的方式,前端调用后端API,后端处理大模型对接和数据存储。
1.png

交互层面看,主要分为3段过程:【1】前后端,【2】后端和大模型,【3】后端和数据库。即产品本身的对话交互,对话调用第三方模型,对话消息的存储管理。
流程层面看,主要分为5段过程:【1】接收用户消息,【2】会话记录管理,【3】对话流程管理,【4】大模型调用,【5】前端输出回复。
三、提示词管理

在开始具体的代码编程之前,必须先了解提示词的基本用法,即不同身份角色所发出的消息类型。
  1. public enum MessageType {
  2.         /**
  3.          * A {@link Message} of type {@literal user}, having the user role and originating
  4.          * from an end-user or developer.
  5.          * @see UserMessage
  6.          */
  7.         USER("user"),
  8.         /**
  9.          * A {@link Message} of type {@literal assistant} passed in subsequent input
  10.          * {@link Message Messages} as the {@link Message} generated in response to the user.
  11.          * @see AssistantMessage
  12.          */
  13.         ASSISTANT("assistant"),
  14.         /**
  15.          * A {@link Message} of type {@literal system} passed as input {@link Message
  16.          * Messages} containing high-level instructions for the conversation, such as behave
  17.          * like a certain character or provide answers in a specific format.
  18.          * @see SystemMessage
  19.          */
  20.         SYSTEM("system"),
  21. }
复制代码

  • 用户类型的消息,具有用户角色,来自最终用户或开发人员,也就是产品中输入的文本。
  • 系统类型的消息,是相对高级的指令,要求模型扮演的角色或身份以及约束行为,比在用户消息中设定的效果好。
  • 助手类型的消息,模型响应用户生成的消息,也可以在对话的上下文中传递,可以聚焦会话的主题。
产品集成大模型的对话能力,最常用的就是三种消息类型,具体的场景可以具体的组合设计,AI的本质在追求智能,所以可以做一些跳脱的尝试挖掘模型能力。
四、数据库设计

目前开发的进度,数据库的设计只有4张关键的表,管理模型和提示词,以及对话数据的存储。
2.png


  • 大模型配置表:统一封装API调用,可以动态添加和禁用集成的模型和版本,前面的内容已经写过。
  • 提示词配置表:给大模型和使用场景,动态配置系统提示词,用户消息末尾加限制,参考的是LastSQL方式。
  • 会话和消息表:这种就是常见设计,会话就是保存每轮对话用户的第一条消息,列表存放不同角色的输出。
对话模块表结构设计,问过几款主流的模型,给出的结构都很类似,只围绕产品需求做了小部分调整;模型和提示词表结构,是抽取模型组件的API参数。
五、接口设计

1、大模型API基础

使用的核心组件是spring-ai-openai的依赖包,主流的模型基本都适配了,该组件定义的模型API接口规范,这样有利于模型统一管理和切换。
  1. <dependencies>
  2.   <dependency>
  3.     <groupId>org.springframework.ai</groupId>
  4.     spring-ai-openai-spring-boot-starter</artifactId>
  5.     <version>${spring-ai-openai.version}</version>
  6.   </dependency>
  7. </dependencies>
复制代码

  • 消息(Message):用来封装一条具体的消息,结构涉及具体的角色和相应的内容。
  • 提示词(Prompt):不同角色的文本指令或者问题,用来引导大模型的响应内容。
  • 客户端(ChatClient):聊天客户端,与大模型交互的工具,封装了模型配置和调用的各种方法。
在具体的使用场景中,通常在提示词中设定系统和用户消息,用来引导模型的回复,通过客户端工具把指令发给具体的模型。
2、阻塞响应

在上篇内容SpringBoot3集成大模型中,使用的就是「阻塞」模式,请求发出后等大模型响应完成,再把结果回传给用户,这种在长文本中体验很差,比较适用内容简短的对话。
  1. @GetMapping(value = "/client")
  2. public String chatClient() {
  3.     String message = "讲个笑话,最好能把我听哭的那一种。";
  4.     return  chatClient.prompt(new Prompt(message)).call().content();
  5. }
复制代码
3、Flux流式响应

后端最初设计的是Flux接口,但是最终没有采用,用的是WebSocket会话方式,具体原因前端对接模块会细说。
大模型不会一次输出完整结果,而是逐步返回中间内容,需要完整的拼接起来才是全部内容,这样可以减少用户等待时间,也降低超时的风险。
  1. @PostMapping(value = "/flux-chat",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  2. public Flux<ChatTextVO> fluxChat (@RequestBody UserTextDTO dto){
  3.     // 1、参数校验,模型ID和消息
  4.     if (ObjectUtil.hasNull(dto.getMsgText(),dto.getModelId())){
  5.         throw new BizExe(RepCode.PARAM_ERROR);
  6.     }
  7.     // 2、模型校验获取
  8.     ModelConfig model = modelConfigService.checkGetModel(dto.getModelId());
  9.     ChatClient myClient = ModelFactory.getModel(model.getModelVersion());
  10.     // 3、构建会话进程
  11.     chatService.buildUserChat(dto, model, MessageType.USER.getValue());
  12.     // 4、模型对话与本地业务
  13.     return myClient.prompt(new Prompt(dto.getMsgText())).stream().chatResponse()
  14.             .map(chunk -> {
  15.                 // 消息响应片段
  16.                 Generation generation = chunk.getResult();
  17.                 AssistantMessage msg = generation.getOutput();
  18.                 // 对话响应
  19.                 ChatTextVO chatTextVO = new ChatTextVO();
  20.                 chatTextVO.setBlockId(msg.getMetadata().get(ChatParamEnum.MSG_BLOCK_ID.getParam()).toString());
  21.                 chatTextVO.setMessageType(msg.getMessageType().toString());
  22.                 chatTextVO.setTextContent(msg.getContent());
  23.                 return chatTextVO;
  24.             })
  25.             .doOnComplete(() -> {
  26.                 log.info("流式响应结束,处理业务===>>>");
  27.             })
  28.             .doOnCancel(() -> {
  29.                 log.info("流式响应取消,处理业务===>>>");
  30.             })
  31.             .doOnError(error -> {
  32.                 log.info("请求失败: {}",error.getMessage());
  33.             });
  34. }
复制代码
这里值得注意的问题,如果流式响应完整那最好,但用户可能主动结束等待,或者会发生错误,为了保证流程的完整,需要执行相应的中断方法完善业务逻辑。
4、WebSocket会话

此前写过SpringBoot3的系列教程,其中包括如何集成WebSocket组件,源码和案例都已归档在Git仓库,所以这一块就不展开详聊了,重点来看如何集成模型对话。
  1. private static final ConcurrentHashMap<String,Disposable> chatFlow = new ConcurrentHashMap<>();
  2. public void socketChat(Session session, ChatTextDTO dto) throws Exception {
  3.     // 1、参数校验
  4.     if (ObjectUtil.hasNull(dto.getMsgText(),dto.getModelId())){
  5.         throw new BizExe(RepCode.PARAM_ERROR);
  6.     }
  7.     // 2、模型校验获取
  8.     ModelConfig model = modelConfigService.checkGetModel(dto.getModelId());
  9.     ChatClient myClient = ModelFactory.getModel(model.getModelVersion());
  10.     // 3、构建会话进程
  11.     this.buildUserChat(dto, model, MessageType.USER.getValue());
  12.     // 4、调用模型服务获取响应流
  13.     Disposable disposable = myClient.prompt(new Prompt(dto.getMsgText()))
  14.             .stream()
  15.             .chatResponse()
  16.             .doOnCancel(() -> {
  17.                 log.info("会话结束,处理取消业务");
  18.             })
  19.             .subscribe(
  20.                     chunk -> {
  21.                         // 消息响应片段
  22.                         Generation generation = chunk.getResult();
  23.                         AssistantMessage msg = generation.getOutput();
  24.                         // 响应消息主体
  25.                         ChatTextVO chatTextVO = new ChatTextVO();
  26.                         chatTextVO.setBlockId(msg.getMetadata().get(ChatParamEnum.MSG_BLOCK_ID.getParam()).toString());
  27.                         chatTextVO.setMessageType(msg.getMessageType().toString());
  28.                         chatTextVO.setTextContent(msg.getContent());
  29.                         // 会话中响应数据
  30.                         this.sendMessage(session, chatTextVO);
  31.                     },
  32.                     error -> {
  33.                         log.error("流式处理出错", error);
  34.                     },
  35.                     () -> {
  36.                         log.info("流式响应结束,开始处理业务===>>>");
  37.                     }
  38.             );
  39.     // 方便Session中断时取消模型回复
  40.     chatFlow.put(session.getId(),disposable);
  41. }
  42. private void sendMessage(Session session, Object message) {
  43.     try {
  44.         session.getBasicRemote().sendText(objMapper.writeValueAsString(message));
  45.     } catch (Exception e) {
  46.         log.error("发送WebSocket消息出错", e);
  47.     }
  48. }
复制代码
基于WebSocket会话模式,其调用的依旧是流式接口,只不过增加了Session和ChatClient整体协调的复杂度,这种模式前端调用更加丝滑。
六、前端对接

1、接口对接思路

前端跟大模型对话的场景上,需要实现响应内容的分段输出。一是会提高接口的效率,二是减少用户不必要的等待时间,可以看到实时的内容。
前端是基于vue3和uni-app搭建的框架,所以用到了uni-app提供的request函数,调用这个流式接口。经过各种测试,该函数支持H5和小程序端,在app端不支持分段响应。永远都是把所有的响应一起返回。
于是找了其他办法,比如:1、封装XMLHttpRequest来实现SSE;2、使用分页和轮询模拟流;3、使用RenderJS,RenderJS是uni-app提供的一种运行在视图层的脚本技术,它可以直接操作视图层的DOM和BOM,特别适合处理高性能渲染需求。
第一种方式,在IOS运行没生效,第二种方式,觉得效率不高,第三种方式,小程序端不生效。
最后,左思右想,也参考了很多资料。还是采用websocket。
2、WebSocket对接和设计

WebSocket是一种在单个TCP连接上进行全双工通信的协议,它实现了浏览器与服务器之间的实时双向数据交换。
uni-app官方文档上就有专门支持WebSocket的函数,不管是H5端,小程序端,APP端都支持。所以果断采用了这个方案。
不过还是用后端的套路,避免过多的连接和断开连接,这样比较耗费资源,所以将用户的连接采用单例的方式进行管理。
展示一下完整的全局WebSocket管理器集成方案:
  1. interface WebSocketConfig {
  2.   url: string
  3.   headers?: Record<string, string>
  4.   protocols?: string | string[]
  5. }
  6. interface WebSocketCallbacks {
  7.   onOpen?: (event: any) => void
  8.   onMessage?: (event: any) => void
  9.   onError?: (event: any) => void
  10.   onClose?: (event: any) => void
  11. }
  12. class WebSocketManager {
  13.   private static instance: WebSocketManager
  14.   private socketTask: any = null
  15.   private config: WebSocketConfig | null = null
  16.   private callbacks: WebSocketCallbacks = {}
  17.   private isConnecting = false
  18.   private reconnectTimer: any = null
  19.   private reconnectAttempts = 0
  20.   private maxReconnectAttempts = 5
  21.   private reconnectInterval = 3000
  22.   private constructor() {}
  23.   // 获取单例实例
  24.   static getInstance(): WebSocketManager {
  25.     if (!WebSocketManager.instance) {
  26.       WebSocketManager.instance = new WebSocketManager()
  27.     }
  28.     return WebSocketManager.instance
  29.   }
  30.   // 检查是否已连接
  31.   isConnected(): boolean {
  32.     return this.socketTask && this.socketTask.readyState === 1
  33.   }
  34.   // 连接WebSocket
  35.   async connect(config: WebSocketConfig, callbacks: WebSocketCallbacks = {}): Promise<boolean> {
  36.     // 如果已经连接且配置相同,直接返回
  37.     if (this.isConnected() && this.isSameConfig(config)) {
  38.       console.log('WebSocket已连接,复用现有连接')
  39.       this.updateCallbacks(callbacks)
  40.       return true
  41.     }
  42.     // 如果正在连接中,等待连接完成
  43.     if (this.isConnecting) {
  44.       console.log('WebSocket正在连接中,等待连接完成')
  45.       return this.waitForConnection()
  46.     }
  47.     // 关闭现有连接
  48.     if (this.socketTask) {
  49.       this.disconnect()
  50.     }
  51.     this.config = config
  52.     this.callbacks = callbacks
  53.     this.isConnecting = true
  54.     return new Promise((resolve) => {
  55.       console.log('开始连接WebSocket:', config.url)
  56.       this.socketTask = uni.connectSocket({
  57.         url: config.url,
  58.         header: config.headers || {},
  59.         protocols: config.protocols,
  60.         success: () => {
  61.           console.log('WebSocket连接请求发送成功')
  62.         },
  63.         fail: (error) => {
  64.           console.error('WebSocket连接请求失败:', error)
  65.           this.isConnecting = false
  66.           this.callbacks.onError?.(error)
  67.           resolve(false)
  68.         }
  69.       })
  70.       // 连接打开
  71.       this.socketTask.onOpen((event: any) => {
  72.         console.log('WebSocket连接已打开')
  73.         this.isConnecting = false
  74.         this.reconnectAttempts = 0
  75.         this.clearReconnectTimer()
  76.         this.callbacks.onOpen?.(event)
  77.         resolve(true)
  78.       })
  79.       // 接收消息
  80.       this.socketTask.onMessage((event: any) => {
  81.         this.callbacks.onMessage?.(event)
  82.       })
  83.       // 连接错误
  84.       this.socketTask.onError((event: any) => {
  85.         console.error('WebSocket连接错误:', event)
  86.         this.isConnecting = false
  87.         this.callbacks.onError?.(event)
  88.         this.scheduleReconnect()
  89.         resolve(false)
  90.       })
  91.       // 连接关闭
  92.       this.socketTask.onClose((event: any) => {
  93.         console.log('WebSocket连接已关闭:', event)
  94.         this.isConnecting = false
  95.         this.callbacks.onClose?.(event)
  96.         
  97.         // 如果不是主动关闭,尝试重连
  98.         if (event.code !== 1000) {
  99.           this.scheduleReconnect()
  100.         }
  101.         
  102.         if (!this.isConnected()) {
  103.           resolve(false)
  104.         }
  105.       })
  106.     })
  107.   }
  108.   // 发送消息
  109.   send(data: string | ArrayBuffer): boolean {
  110.     if (!this.isConnected()) {
  111.       console.error('WebSocket未连接,无法发送消息')
  112.       return false
  113.     }
  114.     this.socketTask.send({
  115.       data: data,
  116.       success: () => {
  117.         console.log('WebSocket消息发送成功')
  118.       },
  119.       fail: (error: any) => {
  120.         console.error('WebSocket消息发送失败:', error)
  121.       }
  122.     })
  123.     return true
  124.   }
  125.   // 断开连接
  126.   disconnect(): void {
  127.     this.clearReconnectTimer()
  128.    
  129.     if (this.socketTask) {
  130.       this.socketTask.close({
  131.         code: 1000,
  132.         reason: '主动断开连接'
  133.       })
  134.       this.socketTask = null
  135.     }
  136.    
  137.     this.isConnecting = false
  138.     this.config = null
  139.     this.callbacks = {}
  140.     this.reconnectAttempts = 0
  141.     console.log('WebSocket连接已断开')
  142.   }
  143.   // 更新回调函数
  144.   updateCallbacks(callbacks: WebSocketCallbacks): void {
  145.     this.callbacks = { ...this.callbacks, ...callbacks }
  146.   }
  147.   // 获取连接状态
  148.   getStatus(): string {
  149.     if (this.isConnected()) return 'connected'
  150.     if (this.isConnecting) return 'connecting'
  151.     return 'disconnected'
  152.   }
  153. }
  154. // 导出单例实例
  155. export const websocketManager = WebSocketManager.getInstance()
  156. // 导出类型
  157. export type { WebSocketConfig, WebSocketCallbacks }
复制代码
使用方式

简单使用
  1. // 基本连接
  2. const connected = await websocketManager.connect({
  3.   url: 'ws://example.com/socket',
  4.   headers: {
  5.     'Authorization': 'Bearer token'
  6.   }
  7. }, {
  8.   onMessage: (event) => {
  9.     console.log('收到消息:', event.data)
  10.   }
  11. })
复制代码
检查连接状态
  1. // 检查是否已连接
  2. if (websocketManager.isConnected()) {
  3.   // 直接使用现有连接
  4.   websocketManager.send('hello')
  5. } else {
  6.   // 需要先连接
  7.   await websocketManager.connect(config, callbacks)
  8. }
复制代码
发送消息
  1. // 发送消息
  2. const success = websocketManager.send(JSON.stringify(data))
  3. if (!success) {
  4.   console.error('发送失败,连接未建立')
  5. }
复制代码
架构优势

性能优化


  • 避免重复连接: 页面切换时复用连接
  • 减少资源消耗: 单例模式减少内存占用
  • 智能重连: 自动处理网络异常
代码简化


  • 统一管理: 所有WebSocket逻辑集中管理
  • 易于维护: 业务代码只需关注配置和回调
  • 类型安全: 完整的TypeScript类型支持
扩展性强


  • 多页面支持: 可在任意页面使用
  • 配置灵活: 支持不同的URL和headers
  • 回调自定义: 每个页面可定义自己的消息处理逻辑
3、websocket的设计优化

基于上面的封装,其实还有一点要考虑,WebSocket连接的断开时机,分了三个维度去考虑这个事情:
连接的断开时机

1. 应用进入后台时断开


  • 时机: onHide 应用生命周期
  • 原因: 节省资源,避免后台保持连接
  • 优势: 系统资源优化,电池续航
2. 用户登出时断开


  • 时机: 用户主动登出
  • 原因: 安全考虑,避免无效连接
  • 优势: 数据安全,连接清理
3. 长时间无活动时断开


  • 时机: 设置定时器检测活动
  • 原因: 避免僵尸连接
  • 优势: 资源优化
所以对上面的WebSocketManager做了调整。
  1. class WebSocketManager {
  2.   private static instance: WebSocketManager
  3.   private socketTask: any = null
  4.   private config: WebSocketConfig | null = null
  5.   private pageCallbacks: Map<string, WebSocketCallbacks> = new Map()
  6.   private currentPageId: string = ''
  7.   private connecting = false
  8.   private reconnectTimer: any = null
  9.   private reconnectAttempts = 0
  10.   private maxReconnectAttempts = 5
  11.   private reconnectInterval = 3000
  12.   
  13.   // 连接管理相关
  14.   private lastActivityTime: number = Date.now()
  15.   private activityTimer: any = null
  16.   private inactivityTimeout = 30 * 60 * 1000 // 30分钟无活动自动断开
  17.   private isAppInBackground = false
  18.   // 发送消息
  19.   send(data: string | ArrayBuffer): boolean {
  20.     if (!this.isConnected()) {
  21.       console.error('WebSocket未连接,无法发送消息')
  22.       return false
  23.     }
  24.     // 记录用户活动
  25.     this.recordActivity()
  26.     this.socketTask.send({
  27.       data: data,
  28.       success: () => {
  29.         console.log('WebSocket消息发送成功')
  30.       },
  31.       fail: (error: any) => {
  32.         console.error('WebSocket消息发送失败:', error)
  33.       }
  34.     })
  35.     return true
  36.   }
  37.   // 记录用户活动
  38.   recordActivity(): void {
  39.     this.lastActivityTime = Date.now()
  40.     this.resetActivityTimer()
  41.   }
  42.   // 重置活动计时器
  43.   private resetActivityTimer(): void {
  44.     if (this.activityTimer) {
  45.       clearTimeout(this.activityTimer)
  46.     }
  47.    
  48.     this.activityTimer = setTimeout(() => {
  49.       console.log('WebSocket长时间无活动,自动断开连接')
  50.       this.disconnect()
  51.     }, this.inactivityTimeout)
  52.   }
  53.   // 应用进入后台
  54.   onAppHide(): void {
  55.     console.log('应用进入后台,断开WebSocket连接')
  56.     this.isAppInBackground = true
  57.     this.disconnect()
  58.   }
  59.   // 应用回到前台
  60.   onAppShow(): void {
  61.     console.log('应用回到前台')
  62.     this.isAppInBackground = false
  63.   }
  64.   // 用户登出时断开连接
  65.   onUserLogout(): void {
  66.     console.log('用户登出,断开WebSocket连接')
  67.     this.disconnect()
  68.   }
  69.   // 断开连接
  70.   disconnect(): void {
  71.     this.clearReconnectTimer()
  72.     this.clearActivityTimer()
  73.    
  74.     if (this.socketTask) {
  75.       this.socketTask.close({
  76.         code: 1000,
  77.         reason: '主动断开连接'
  78.       })
  79.       this.socketTask = null
  80.     }
  81.    
  82.     this.connecting = false
  83.     this.config = null
  84.     this.pageCallbacks.clear()
  85.     this.currentPageId = ''
  86.     this.reconnectAttempts = 0
  87.     console.log('WebSocket连接已断开')
  88.   }
  89.   // 清理活动计时器
  90.   private clearActivityTimer(): void {
  91.     if (this.activityTimer) {
  92.       clearTimeout(this.activityTimer)
  93.       this.activityTimer = null
  94.     }
  95.   }
  96. }
复制代码
增加生命周期管理类
  1. /**
  2. * 应用生命周期管理
  3. * 处理WebSocket连接的智能断开和重连
  4. */
  5. import { websocketManager } from './websocket'
  6. class AppLifecycleManager {
  7.   private static instance: AppLifecycleManager
  8.   private isInitialized = false
  9.   // 初始化应用生命周期监听
  10.   init(): void {
  11.     if (this.isInitialized) {
  12.       console.log('应用生命周期管理已初始化')
  13.       return
  14.     }
  15.     console.log('初始化应用生命周期管理')
  16.     // 监听应用隐藏(进入后台)
  17.     uni.onAppHide(() => {
  18.       console.log('应用进入后台')
  19.       websocketManager.onAppHide()
  20.     })
  21.     // 监听应用显示(回到前台)
  22.     uni.onAppShow(() => {
  23.       console.log('应用回到前台')
  24.       websocketManager.onAppShow()
  25.     })
  26.     // 监听网络状态变化
  27.     uni.onNetworkStatusChange((res) => {
  28.       console.log('网络状态变化:', res)
  29.       if (!res.isConnected) {
  30.         console.log('网络断开,断开WebSocket连接')
  31.         websocketManager.disconnect()
  32.       }
  33.       // 网络恢复时不自动重连,等待用户操作
  34.     })
  35.     this.isInitialized = true
  36.   }
  37.   // 用户登出时调用
  38.   onUserLogout(): void {
  39.     console.log('用户登出,清理WebSocket连接')
  40.     websocketManager.onUserLogout()
  41.   }
  42. }
  43. // 导出单例实例
  44. export const appLifecycleManager = AppLifecycleManager.getInstance()
复制代码
最后,是断开连接的用法。
  1. import { defineStore } from 'pinia';
  2. import { appLifecycleManager } from '@/utils/app-lifecycle';
  3. export const useUserStore = defineStore('user', {
  4.   actions: {
  5.     // 退出登录
  6.     logout() {
  7.       this.userInfo = null;
  8.       this.token = '';
  9.       this.isLoggedIn = false;
  10.       
  11.       // 清除本地存储
  12.       uni.removeStorageSync('token');
  13.       uni.removeStorageSync('userInfo');
  14.       
  15.       // 断开WebSocket连接
  16.       appLifecycleManager.onUserLogout();
  17.     }
  18.   }
  19. });
复制代码
上面贴了部分核心代码,不过都是以自己后端的角度去考虑的。
最后,呼应上面,再列举不断开连接的情况。
不断开的情况

1. 页面切换时


  • 保持连接: 在home和square页面间切换
  • 原因: 提供流畅的用户体验
  • 优势: 快速响应,无需重新连接
2. 应用回到前台时


  • 不自动重连: 等待用户主动操作
  • 原因: 按需连接,节省资源
  • 优势: 用户控制连接时机
3. 网络恢复时


  • 不自动重连: 等待用户发送消息时重连
  • 原因: 避免不必要的连接
  • 优势: 按需连接
4、WebSocket最后总结

这套封装,使WebSocket连接完全抽离为全局管理,首次进入页面会检查连接状态,有连接就复用,没有就初始化,外部只需要定义URL和请求头即可。
并且,连接也具有完整的智能管理策略,能够在合适的时机自动断开连接,既保证了用户体验,又优化了资源使用。
七、写在最后

对于大模型的集成,本质就是第三方API的调用,刚开始做的时候也有点犯难,不过花时间和心思研究文档之后,其实原理并不算复杂。
所谓套壳大模型的产品,体验上的差距更多在于:开发者对模型能力的理解和运用。有句话现在越来越认可,人工智能时代:模型本身即产品。
  1. 文档仓库:
  2. https://gitee.com/cicadasmile/butte-java-note
  3. 源码仓库:
  4. https://gitee.com/cicadasmile/butte-mound
复制代码
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册