大型语言模型的应用需要服务器和推理卡硬件的支持,同时需要CUDA、PyTorch等计算支持软件,此外,还需要包括大语言模型、Transformers库、服务程序和客户端程序在内的完整组件集。本章将详细讨论这些组件的部署方式、协同工作机制,并介绍典型大语言模型应用的工作流程。
大语言模型通常使用的硬件部分包括服务端与客户端的硬件运行环境,这两端一般是分离的。服务端可细分为模型API服务、应用服务和Web服务,这些服务可以分开部署,也可以部署到同一台物理服务器或虚拟机上。其中,模型API服务提供支撑大语言模型的装载、运行和提供大模型API服务;应用服务除了支持客户端的大模型调用外,还提供文件上传接收、WebSocket或其他应用服务;而Web服务提供页面服务。
客户端硬件包括个人计算机、笔记本计算机和移动端设备。它们通过浏览器访问Web服务器返回页面、提交数据和显示交互结果。
对于互联网应用,客户端与服务端之间还需要架设防火墙,Web服务器需要绑定SSL证书以提供安全的HTTPS通道。
硬件部署结构如图3-1所示。
图3-1 大语言模型硬件部署结构
大语言模型应用软件,主要分为三部分。首先,模型API服务由Python编写 。其次,应用服务一般也由Python编写。如果应用场景比较简单,那么这部分服务可以与模型API服务合并,比如,在一个函数中既能响应客户端的HTTP请求,又能调用大模型的推理服务。再次,Web服务既可以使用Python开发,也可以使用类似React.js的JavaScript框架开发。如果客户端是原生App,则Web服务承担的是提供SSL证书、负载均衡、请求路径代理等功能。本书中的开发实例基本上是围绕这三部分构建的。应用软件部署结构如图3-2所示。
图3-2 大语言模型应用软件部署结构
大语言模型应用的服务端分为模型API服务和应用服务,应用服务一般就是传统的HTTP服务,提供了GET或POST服务响应客户端的请求,没有太多特殊之处,所以本节重点描述模型API服务的工作模式和运行过程。
与传统的HTTP服务不同,模型API服务依赖AI算力,处于上层的服务程序要想调用GPU算力,就需要通过Transformers库、PyTorch、Python运行环境、CUDA、推理卡驱动等组件来一级一级地调用,过程比较复杂。得益于Transformers库的良好封装,实际的开发工作主要是与Transformers库打交道,但了解以上这些组件的工作方式是很有必要的。因为即使是调用Transformers库的方法,其入参过程也会涉及CUDA,调试程序过程中要关注PyTorch的工作状态,程序报错可能会直接指向CUDA库文件,服务运行过程中还要通过推理卡驱动提供的命令监控性能指标。图3-3描述了各个组件的层级关系。
图3-3 大语言模型API服务工作模式
①基础计算:包括服务器的CPU、内存、硬盘、网络等,由操作系统协调提供基本的计算服务。
②AI算力硬件:由一块或多块推理卡组成,在服务运行过程中,使用驱动提供的“nvidia-smi”命令监控GPU计算单元的使用率、内存占用、温度、耗电等指标。
③AI算力软件:由CUDA协调推理卡工作,将计算过程落实到具体的推理卡上。
④Python虚拟化层:通过Anaconda隔离不同的项目的Python和依赖库,虚拟环境具体是由Anaconda的conda命令进行创建和激活的。
⑤Transformers库依赖环境:大模型服务程序一般只与Transformers库交互,而具体执行计算任务的是Transformers库背后的PyTorch、TensorFlow和微调库PEFT。这些库使用pip库管理命令安装。
⑥大语言模型运行时:服务程序运行在Anaconda隔离出来的Python环境中,调用Transformers库函数装载权重和Tokenizer,接收客户端的API调用请求进行推理并返回生成结果。
由于Transformers库的封装隔离,服务程序一般只能直接依赖该库,这使得服务程序开发的关注点相对集中,主要是服务的启动和推理过程。
大语言模型API服务的启动过程如下。
①装载Tokenizer。Tokenizer(分词标记器) 用来对文本进行预处理,将输入的文本分割成token序列,再将token序列转换成数字表示方式。具体过程包括:首先从指定的目录加载Tokenizer的配置文件,根据配置文件,实例化一个相应的分词标记器类(如BERTTokenizer、GPTTokenizer);再将加载的分词标记器配置文件应用到实例化的分词标记器中,以确保分词标记器与预训练模型一致。
②装载权重。将模型的权重文件按配置载入GPU的内存用于推理计算。首先从指定目录加载预训练模型的配置文件,根据配置文件实例化一个相应的模型类(如BERT、GPT、LLaMA等);再将装载的模型配置文件应用到实例化的模型中,以确保模型结构与预训练模型一致。在有GPU的情况下,要将模型移动到GPU上以加速计算。
③设定模型为评估模式。将模型实例设置为评估模式后,其权重将不再更新,这与其在训练模式下不同。尽管在评估模式下,模型会进行梯度计算并存储梯度信息,但不会执行反向传播。换句话说,该模式下模型处于锁定状态,不会因推理过程而导致参数发生变化。
大语言模型API服务的推理过程如下。
①使用HTTP服务监听客户端的入参。这些参数里一般会包括模型名称、历史会话Messages、预测参数(temperature、top_p、max_tokens等),以及是否采用“流”的方式返回等信息。
②将入参中的Messages文本进行Tokenizer预处理,将其转化为数字表示形式后送入模型推理计算。
③将返回结果返回给客户端。如果客户端调用时要求用“流”方式返回,那么还要使用SSE主动向客户端推送结果。
大语言模型API服务的启动和推理过程见图3-4。
图3-4 大语言模型API服务的启动和推理过程
与一般的Web应用不同,大语言模型应用输出的结果是推理生成的,而非查询数据库获得的。文本生成的过程往往相对耗时,而采用请求/响应的交互方法会导致用户体验较差,这表现在用户问一个问题后,需要等待数秒或数十秒,服务器才会一次性返回生成的结果。
大语言模型的推理是一个分步预测的过程,模型一次生成一定量的token,逐步构建完整答案。只要将这个生成过程反映到客户端,就可避免用户长时间的等待。为此,OpenAI兼容接口引入了SSE技术。SSE是一种HTML5技术,允许服务器向客户端推送数据,不需要客户端主动请求,当服务端有新消息时,会实时将消息推送到前端,从而实现动态的聊天效果。从客户端来看,结果是一段一段生成的,不但生成过程无卡顿,而且能使用户体验打字的视觉效果,就像人工智能在不断地打字回答用户的问题。这样既减少了用户对大语言模型的性能焦虑,又提高了用户体验,还减轻了API服务的并发压力。SSE的原理见图3-5。
图3-5 SSE原理
针对后端提供的SSE类型的接口,前端也需要采用与之匹配的接口调用方式。以React.js开发场景中使用的openai-node组件为例,其接口调用过程如下: