使用 OpenLLM 构建和部署大模型应用
1. LLM 爆发与部署背景
2023 年见证了大语言模型(LLM)的繁荣发展。从商用的 Claude、GPT 到开源的小模型,参数量从几个 B 到几百个 B 不等。BentoML 在与客户互动时发现,许多开发者在开发过程中利用 OpenAI 的能力进行推理,但在将模型部署到生产环境时面临挑战。
1.1 核心诉求
大部分客户有以下诉求:
- 高可控性/灵活性:期望通过自行训练或微调,利用积累的用户数据得到属于自己的模型,实现更灵活的推理需求。
- 数据安全性:私有数据输入公共网络模型可能导致泄露,企业级应用需要本地化部署。
- 成本效益:商业模型按 Token 计费,庞大的 Prompt 会导致成本增加。拥有自己的大模型应用可仅涉及硬件费用,且小模型可能达到相同准确度。
1.2 生产环境部署挑战
自主部署大语言模型通常面临以下挑战:
- 可操作性:硬件成本高,如 13B 参数模型需约 26GB 显存,单卡 A10G 难以应对,需多卡或多机部署。
- 可扩展性:包括硬件扩展(自动启用多卡/多机)和软件扩展(方便在不同模型间切换测试)。
- 吞吐量:LLM 推理输入非同时到达,输出非同时产生,传统批处理模式不适用。
- 延迟:延迟与吞吐量往往相互制衡,需优化平衡。
2. OpenLLM 介绍与应用
OpenLLM 于 2023 年 6 月开源,是一个用于部署大语言模型的框架。GitHub 星标超过 6800 个。其初衷是通过一行代码轻松在不同的大语言模型之间切换。
2.1 支持模型
OpenLLM 目前支持几乎所有常用的开源大语言模型,包括 ChatGLM、百川、Dolly-V2 等。对于每个模型,框架提供多个不同的参数量和部署 ID 供选择。
2.2 快速启动示例
启动一个 LLM 服务非常简单。安装工具后运行以下命令即可启动应用:
start dolly-v2
如果计算机上未下载过该模型,它将自动下载。启动后,可以通过命令行直接与服务交互:
地球的重量是多少?
若需提升准确度,可切换模型,例如使用 LlaMA2:
start llama2
尽管使用方法一致,但不同模型的回答质量会有所差异。LlaMA2 相比 Dolly-V2 通常能提供更准确的答案。
2.3 API 与 SDK
在实际部署中,应用需要提供 HTTP 或 gRPC 接口。OpenLLM 框架支持内置的开箱即用的 HTTP API。在服务首页显示 Swagger 页面,列出所有支持的 HTTP 端点,可直接进行测试。
此外,OpenLLM 提供了 Python SDK,允许在 Python 代码中直接与服务交互:
from openllm.client import Client
client = Client('http://localhost:3000')
response = client.generate(prompt='地球的重量是多少?')
print(response)
这使得在 Python 环境中集成和使用 OpenLLM 的服务更加便捷。
3. OpenLLM 核心优势与优化
使用 OpenLLM 具有以下显著优势:
- 模型切换:用户能够方便地在不同的模型之间进行切换。
- 内置优化技术:
- 量化:减少参数精度以降低内存使用,适用于大型语言模型。
- Token Streaming:允许边产生边接收答案,词汇逐个生成,适合聊天机器人场景。
- Continuous Batching(持续批跑):优化 GPU 利用率。
- Paged Attention:优化 KVcache 内存碎片问题。
- 多卡支持:指定多个 GPU 并根据需要选择运行方式。
- 模型表现监测:基于 BentoML 支持 Metrics 测量和性能指标监控。
- 微调推理支持:支持 Fine-tune 及 LoRA Layer 推理。
- 生态集成:与 LangChain、Hugging Face 等 AI 工具集成良好。
3.1 Continuous Batching 详解
在大型语言模型推理中,输入强度不同。如果不进行优化,当一个输入完成时,整个过程需等待其他输入,导致 GPU 时间浪费。
Continuous Batching 优化可以在一个推理结束时立即引入下一个推理任务。例如,假设 S3 先完成,S5 立即加入;S1 完成后,S6 立即加入。这确保在每个时间片上都有推理任务运行,最大程度利用 GPU 资源,减少空闲时间。
3.2 Paged Attention 详解
Transformer 框架中存在重复计算,KVcache 用于缓存结果。但内存分配无法准确预估,易产生内存碎片。
Paged Attention 将内存拆分成一个个 block,按 block 分配。任务完成后,block 可被释放供下一个任务使用。通过 block table 存储物理位置和逻辑序号映射,有效减少内存碎片,提高内存使用效率。
4. BentoML 集成与部署
除了模型推理,AI 应用还需考虑数据收集、验证、配置部署指标等问题。BentoML 是一个专注于解决部署后事项的开源 AI 部署框架。
4.1 BentoML 核心特性
- 版本控制:模型像 GitHub 提交一样进行版本控制,便于追踪和回退。
- 可观察性:内置 Metrics、Traces 和 Logs,监测模型性能。
- 容器化:支持将整个机器学习应用打包为标准的 OCI 镜像。
- 分布式部署:支持多种部署目标(如 AWS),支持 Serverless 部署(BentoCloud)。
4.2 Runner 架构
BentoML 的 Runner 将模型封装成远程对象,独立于应用部署。这种设计允许模型独立扩容,GPU 资源专注于模型推理,CPU 资源用于预处理和 IO 操作。
4.3 完整应用示例
以下演示如何使用 LangChain 和 OpenLLM 实现广告词生成功能,并使用 BentoML 部署。
4.3.1 定义输入结构
使用 Pydantic 定义输入验证结构体:
from pydantic import BaseModel
class Query(BaseModel):
industry: str
productName: str
keywords: list[str]
4.3.2 模型切换 Helper
定义辅助函数快速切换模型 ID:
def get_llm_model(model_id: str = 'dolly-v2'):
pass
4.3.3 定义服务接口
通过指定输入输出类型,将函数作为服务接口。启动服务时会生成两个独立服务:API 接口层和 LLM Runner。
@bentoml.api(input=JsonInput(), output=TextOutput())
def generate_ad(query: Query) -> str:
llm = get_llm_model()
prompt = f"行业:{query.industry}, 产品:{query.productName}"
return llm.predict(prompt)
4.3.4 构建与部署
开发及本地测试完成后,使用 BentoML 的 Build 命令制作 Bento 包:
bentoml build
随后可选择:
- 容器化:打包成镜像,用于后续部署。
- 推送到 Cloud:自动执行后续部署操作,转化为 Kubernetes 上的容器。
在 BentoCloud 上,可指定扩容方式,分别为 API 指定节点数,或为每个 Runner 指定 GPU 数量。
5. 总结
OpenLLM 是一个开源的大语言模型开发框架,支持多种开源 LLM 模型,具有内建的关键优化技术以优化内存使用。它与 LangChain 和 BentoML 集成良好,能够快速构建和部署大语言模型应用。
通过结合 OpenLLM 的模型管理能力与 BentoML 的工程化部署能力,开发者可以高效地解决 LLM 在生产环境中的部署、监控、扩展及成本优化问题,实现从实验到生产的平滑过渡。