当前位置: 首页 > news >正文

使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用

6462cc77060ce4b6c28954945d4c2b3e.png

68643a4d7c934ec5ea89118c51aa7190.png

vLLM 是一个简单易用的 LLM 推理服务库。加州大学伯克利分校于 2024 年 7 月将 vLLM 作为孵化项目正式捐赠给 LF AI & Data Foundation 基金会。欢迎 vLLM 加入 LF AI & Data 大家庭!🎉

在主流的 AI 应用架构中,大语言模型(LLM)通常与向量数据库配套使用,用于构建检索增强生成(RAG)应用,从而解决 AI 幻觉问题。本文将介绍如何使用 Milvus、vLLM 和 Llama 3.1 构建并运行RAG 应用。我们将详细展示如何将文本信息转换为 Embedding 向量并存储到 Milvus 向量数据库中、如何将 Milvus 作为知识库有效检索与用户问题相关的文本块。最后,我们将通过 vLLM 使用 Meta的Llama 3.1-8B 模型生成答案。

01

Milvus、vLLM 和 Llama 3.1 简介

Milvus 向量数据库

Milvus 是一款开源的分布式向量数据库,可用于存储、索引和搜索向量数据,适用于生成式 AI(GenAI)应用。Milvus 支持 hybrid search、元数据过滤、重排(Reranking),能够高效处理万亿规模的向量,助力开发者搭建 AI 和 ML 应用。您可以在本地运行 Milvus standalone 或 cluster 版本,或者使用全托管的 Milvus 服务——Zilliz Cloud。

vLLM

vLLM 是加州大学伯克利分校 SkyLab 推出的一个开源项目,专注于优化 LLM 服务性能。通过高效的内存管理技术,如 PagedAttention、持续批处理和优化 CUDA 内核,vLLm 与传统方法相比将服务性能提高了多达 24 倍,同时将 GPU 内存用量减少了一半。

根据论文《Efficient Memory Management for Large Language Model Serving with PagedAttention》,KV 缓存使用约 30% 的 GPU 内存,可能会导致内存问题。KV 缓存存储在连续内存(contiguous memory)中,但内存变化可能导致内存碎片化,不利于计算效率。

d680b206e72f6685b07999eec68eec9b.png

通过使用虚拟内存缓存 KV,vLLM 只需要在必要时分配物理 GPU 内存,有效避免了内存碎片化和内存预分配。在测试中,vLLM 的吞吐量比 HuggingFace Transformers (HF) 高出多达 24 倍,比基于NVIDIA A10G 和 A100 GPU 的 Text Generation Inference (TGI) 高出 3.5 倍。

e8e77e8390e9fbbee05becd0ee9799cf.jpeg

Meta Llama 3.1

Meta 于 2024 年 7 月 23 日宣布推出 Llama 3.1,允许用于多种商业用途。其 405B 模型(4050 亿参数)在多个公开的性能测试中均展示出了最出色的性能,并支持 128,000 个输入 Token 的上下文窗口。除了 405B 模型外,Meta 还发布了 Llama3.1 70B(700 亿参数)和 8B(80 亿参数)模型。您可以通过 Meta 官网下载模型权重(model weight)。

需要注意微调生成的数据可以提高模型性能,但低质量的数据可能会降低模型性能。Llama 团队已不断识别和去除这些低质量的数据,使用模型本身及其他辅助模型和工具,进一步优化模型。

02

使用 Milvus 搭建 RAG-Retrieval部分

准备数据

本教程将使用 Milvus 文档作为数据集。我们需要先下载并本地保存 Milvus 文档。

from langchain.document_loaders import DirectoryLoader# Load HTML files already saved in a local directorypath = "../../RAG/rtdocs_new/"global_pattern = '*.html'loader = DirectoryLoader(path=path, glob=global_pattern)docs = loader.load()# Print num documents and a preview.print(f"loaded {len(docs)} documents")print(docs[0].page_content)pprint.pprint(docs[0].metadata)

3545032b6f53a0850df8888c7549ae12.png

下载 Embedding 模型

接着,从 HuggingFace 上下载一个免费的开源 Embedding 模型。

import torchfrom sentence_transformers import SentenceTransformer# Initialize torch settings for device-agnostic code.N_GPU = torch.cuda.device_count()DEVICE = torch.device('cuda:N_GPU' if torch.cuda.is_available() else 'cpu')# Download the model from huggingface model hub.model_name = "BAAI/bge-large-en-v1.5"encoder = SentenceTransformer(model_name, device=DEVICE)# Get the model parameters and save for later.EMBEDDING_DIM = encoder.get_sentence_embedding_dimension()MAX_SEQ_LENGTH_IN_TOKENS = encoder.get_max_seq_length()# Inspect model parameters.print(f"model_name: {model_name}")print(f"EMBEDDING_DIM: {EMBEDDING_DIM}")print(f"MAX_SEQ_LENGTH: {MAX_SEQ_LENGTH}")

d0513a10245cb2df47a3a967fcddea62.png

切分数据并编码为向量

将文档数据切分成固定长度(512 个字符)的文本块,并将切分 overlap 设置为 10%。

from langchain.text_splitter import RecursiveCharacterTextSplitterCHUNK_SIZE = 512chunk_overlap = np.round(CHUNK_SIZE * 0.10, 0)print(f"chunk_size: {CHUNK_SIZE}, chunk_overlap: {chunk_overlap}")# Define the splitter.child_splitter = RecursiveCharacterTextSplitter(chunk_size=CHUNK_SIZE,chunk_overlap=chunk_overlap)# Chunk the docs.chunks = child_splitter.split_documents(docs)print(f"{len(docs)} docs split into {len(chunks)} child documents.")# Encoder input is doc.page_content as strings.list_of_strings = [doc.page_content for doc in chunks if hasattr(doc, 'page_content')]# Embedding inference using HuggingFace encoder.embeddings = torch.tensor(encoder.encode(list_of_strings))# Normalize the embeddings.embeddings = np.array(embeddings / np.linalg.norm(embeddings))# Milvus expects a list of `numpy.ndarray` of `numpy.float32` numbers.converted_values = list(map(np.float32, embeddings))# Create dict_list for Milvus insertion.dict_list = []for chunk, vector in zip(chunks, converted_values):# Assemble embedding vector, original text chunk, metadata.chunk_dict = {'chunk': chunk.page_content,'source': chunk.metadata.get('source', ""),'vector': vector,}dict_list.append(chunk_dict)

235b31787284e54aac9392de962b3b1e.png

将向量数据存储在 Milvus 中

将向量存储到 Milvus 向量数据库中。

# Connect a client to the Milvus Lite server.from pymilvus import MilvusClientmc = MilvusClient("milvus_demo.db")# Create a collection with flexible schema and AUTOINDEX.COLLECTION_NAME = "MilvusDocs"mc.create_collection(COLLECTION_NAME,EMBEDDING_DIM,consistency_level="Eventually",auto_id=True, overwrite=True)# Insert data into the Milvus collection.print("Start inserting entities")start_time = time.time()mc.insert(COLLECTION_NAME,data=dict_list,progress_bar=True)end_time = time.time()print(f"Milvus insert time for {len(dict_list)} vectors: ", end="")print(f"{round(end_time - start_time, 2)} seconds")

5f42e2174c532e9c36b5f09c9df7946f.png

进行向量搜索

输入问题,并在 Milvus 知识库中搜索与问题最相似的文本块。

SAMPLE_QUESTION = "What do the parameters for HNSW mean?"# Embed the question using the same encoder.query_embeddings = torch.tensor(encoder.encode(SAMPLE_QUESTION))# Normalize embeddings to unit length.query_embeddings = F.normalize(query_embeddings, p=2, dim=1)# Convert the embeddings to list of list of np.float32.query_embeddings = list(map(np.float32, query_embeddings))# Define metadata fields you can filter on.OUTPUT_FIELDS = list(dict_list[0].keys())OUTPUT_FIELDS.remove('vector')# Define how many top-k results you want to retrieve.TOP_K = 2# Run semantic vector search using your query and the vector database.results = mc.search(COLLECTION_NAME,data=query_embeddings,output_fields=OUTPUT_FIELDS,limit=TOP_K,consistency_level="Eventually")

搜索结果如下所示:

b5815f45bcb446e84e704b253b0799be.png

03

使用 vLLM 和 Llama 3.1-8B 搭建 RAG-Generation 部分

安装 vLLM 与 HuggingFace 模型

vLLM 默认从 HuggingFace 下载大语言模型。通常情况下,如果您想使用 HuggingFace 上的新模型,需要执行 pip install --update 或 -U。此外,我们还需要 GPU 通过 vLLM 来运行 Meta 的 Llama 3.1 推理模型。

# (Recommended) Create a new conda environment.conda create -n myenv python=3.11 -yconda activate myenv# Install vLLM with CUDA 12.1.pip install -U vllm transformers torch
import vllm, torchfrom vllm import LLM, SamplingParams# Clear the GPU memory cache.torch.cuda.empty_cache()# Check the GPU.!nvidia-smi

获取 HuggingFace token

HuggingFace 上的部分模型(如 Meta Llama 3.1)要求用户在下载前接受其许可证。因此,您必须先创建一个 HuggingFace 帐户,接受模型的许可证,并生成一个 Token。

在 HuggingFace 的 Llama3.1 页上,您会收到一条消息要求您同意条款。单击"Accept License"以接受 Meta 条款,然后再下载模型权重。审批流程通常可以在一天内完成。

审批通过后,需要生成一个新的 HuggingFace token。旧 Token 无法使用。

在安装 vLLM 之前,请使用您的新 Token 登录 HuggingFace。以下示例代码中使用 Colab Secrets 来存储 Token。

# Login to HuggingFace using your new token.from huggingface_hub import loginfrom google.colab import userdatahf_token = userdata.get('HF_TOKEN')login(token = hf_token, add_to_git_credential=True)

运行 RAG-Generation 部分

我们需要 GPU 和较大的内存来运行 Llama-3.1-8B 模型。以下示例是在 Google Colab Pro上使用 A100 GPU 运行的。

# 1. Choose a modelMODELTORUN = "meta-llama/Meta-Llama-3.1-8B-Instruct"# 2. Clear the GPU memory cache, you're going to need it all!torch.cuda.empty_cache()# 3. Instantiate a vLLM model instance.llm = LLM(model=MODELTORUN,enforce_eager=True,dtype=torch.bfloat16,gpu_memory_utilization=0.5,max_model_len=1000,seed=415,max_num_batched_tokens=3000)

17e4ea8d96a1028f0180c0da3ac65bff.png

# Separate all the context together by space.contexts_combined = ' '.join(contexts)# Lance Martin, LangChain, says put the best contexts at the end.contexts_combined = ' '.join(reversed(contexts))# Separate all the unique sources together by comma.source_combined = ' '.join(reversed(list(dict.fromkeys(sources))))SYSTEM_PROMPT = f"""First, check if the provided Context is relevant tothe user's question.  Second, only if the provided Context is strongly relevant, answer the question using the Context.  Otherwise, if the Context is not strongly relevant, answer the question without using the Context. Be clear, concise, relevant.  Answer clearly, in fewer than 2 sentences.Grounding sources: {source_combined}Context: {contexts_combined}User's question: {SAMPLE_QUESTION}"""prompts = [SYSTEM_PROMPT]

使用从 Milvus 中检索获得的上下文和原始提问来编写提示,并生成回答。

# Sampling parameterssampling_params = SamplingParams(temperature=0.2, top_p=0.95)# Invoke the vLLM model.outputs = llm.generate(prompts, sampling_params)# Print the outputs.for output in outputs:prompt = output.promptgenerated_text = output.outputs[0].text# !r calls repr(), which prints a string inside quotes.print()print(f"Question: {SAMPLE_QUESTION!r}")pprint.pprint(f"Generated text: {generated_text!r}")

32c91276542560b35797fd5d449a33ee.png

答案十分准确!

如果您对文本内容感兴趣,欢迎上手亲自尝试和实践。同时,我们欢迎您加入 Milvus 社区,与所有 GenAI 开发者共同交流。

参考

vLLM 官方文档及模型页面

https://docs.vllm.ai/en/latest/getting_started/installation.html

https://docs.vllm.ai/en/latest/models/supported_models.html#supported-models

2023 vLLM 论文

https://arxiv.org/pdf/2309.06180

2023 Ray Summit vLLM 相关演讲

https://www.youtube.com/watch?v=80bIUggRJf4

vLLM 博客: vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention

https://blog.vllm.ai/2023/06/20/vllm.html

介绍如何运行 vLLM server 的博客文章: Deploying vLLM: a Step-by-Step Guide

https://ploomber.io/blog/vllm-deploy/

The Llama 3 Herd of Models | Research - AI at Meta

https://ai.meta.com/research/publications/the-llama-3-herd-of-models/

推荐阅读

d66b5ed0234240d64b2e99c1f2cfedb7.png

a6c5c7393bc5b250991bb7af5fe7ac2a.png

966b8dd21bf0430839de82e09ffd1077.png

cc1c130dbe560d05f6604ee4b5cfcd1d.png

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • STL和C++11
  • vscode设置vue标签不换行
  • 捕获和处理异常非常重要
  • 使用 C++ 获取系统时间
  • 【EI稳定,马来亚大学主办】2024年计算机与信息安全国际会议(WCCIS 2024,9月27-29)
  • 第67期 | GPTSecurity周报
  • 本地安装Ollama+WebUI
  • 基于Linux文件编程实现处理Excel表格的数据
  • 《深入理解 Java 中的继承与方法重写》
  • JavaScript 中 new Function() 和 new function() 的区别
  • 51. 数组中的逆序对
  • HTML中的文字与分区标记
  • Docker高级管理之compose容器编排与私有仓库的部署
  • UE5 对象池
  • 【研赛论文】数学建模2024华为杯论文word/latex模板
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • javascript从右向左截取指定位数字符的3种方法
  • Kibana配置logstash,报表一体化
  • Linux下的乱码问题
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 使用Gradle第一次构建Java程序
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 推荐一个React的管理后台框架
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​linux启动进程的方式
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #git 撤消对文件的更改
  • #pragma multi_compile #pragma shader_feature
  • #进阶:轻量级ORM框架Dapper的使用教程与原理详解
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (八)c52学习之旅-中断实验
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (转)编辑寄语:因为爱心,所以美丽
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • ***详解账号泄露:全球约1亿用户已泄露
  • ../depcomp: line 571: exec: g++: not found
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET MAUI Sqlite数据库操作(二)异步初始化方法
  • .NET 某和OA办公系统全局绕过漏洞分析
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • .NET和.COM和.CN域名区别
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)