Criação de RAG com Milvus, vLLM e Llama 3.1

A Universidade da Califórnia - Berkeley doou vLLM, uma biblioteca rápida e fácil de usar para inferência e serviço LLM, à LF AI & Data Foundation como um projeto em fase de incubação em julho de 2024. Como um projeto de membro companheiro, gostaríamos de dar as boas-vindas ao vLLM que se junta à família LF AI & Data! 🎉
Modelos de Linguagem Grandes (LLMs) e bases de dados vectoriais são normalmente emparelhados para construir Retrieval Augmented Generation (RAG), uma arquitetura de aplicação de IA popular para abordar AI Hallucinations. Este blogue irá mostrar-lhe como construir e executar um RAG com Milvus, vLLM e Llama 3.1. Mais especificamente, mostrarei como incorporar e armazenar informações de texto como vetor embeddings no Milvus e utilizar este armazenamento de vectores como uma base de conhecimentos para recuperar eficazmente pedaços de texto relevantes para as perguntas dos utilizadores. Finalmente, utilizaremos o vLLM para servir o modelo Llama 3.1-8B do Meta para gerar respostas aumentadas pelo texto recuperado. Vamos mergulhar de cabeça!
Introdução ao Milvus, vLLM e Llama 3.1 do Meta
Banco de dados vetorial do Milvus
A Milvus é uma base de dados vetorial distribuída, de código aberto, criada para o efeito, para armazenar, indexar e pesquisar vectores para cargas de trabalho de IA generativa (GenAI). A sua capacidade para efetuar pesquisa híbrida, filtragem de metadados, reranking e tratar eficientemente triliões de vectores faz do Milvus uma escolha de eleição para cargas de trabalho de IA e aprendizagem automática. O Milvus pode ser executado localmente, num cluster ou alojado no Zilliz Cloud totalmente gerido.
vLLM
vLLM é um projeto de código aberto iniciado no UC Berkeley SkyLab focado na otimização do desempenho do serviço LLM. Ele usa gerenciamento eficiente de memória com PagedAttention, batching contínuo e kernels CUDA otimizados. Em comparação com os métodos tradicionais, o vLLM melhora o desempenho da veiculação em até 24 vezes, reduzindo o uso de memória da GPU pela metade.
De acordo com o documento "Efficient Memory Management for Large Language Model Serving with PagedAttention", o cache KV usa cerca de 30% da memória da GPU, levando a possíveis problemas de memória. A cache KV é armazenada em memória contígua, mas a alteração do tamanho pode causar fragmentação da memória, o que é ineficiente para a computação.
Imagem 1. Gestão da memória cache KV nos sistemas existentes (2023 Paged Attention paper)
Ao usar a memória virtual para o cache KV, o vLLM aloca apenas a memória física da GPU conforme necessário, eliminando a fragmentação da memória e evitando a pré-alocação. Em testes, o vLLM superou o desempenho do HuggingFace Transformers (HF) e do Text Generation Inference (TGI), alcançando uma taxa de transferência até 24x maior que o HF e 3,5x maior que o TGI nas GPUs NVIDIA A10G e A100.
Imagem 2. O vLLM atinge uma taxa de transferência 8,5x-15x superior à do HF e 3,3x-3,5x superior à do TGI (2023 blog do vLLM).
Lhama do Meta 3.1
O Meta's Llama 3.1 foi anunciado em 23 de julho de 2024. O modelo 405B oferece desempenho de ponta em vários benchmarks públicos e tem uma janela de contexto de 128.000 tokens de entrada com vários usos comerciais permitidos. Juntamente com o modelo de 405 mil milhões de parâmetros, a Meta lançou uma versão actualizada do Llama3 70B (70 mil milhões de parâmetros) e 8B (8 mil milhões de parâmetros). Os pesos dos modelos estão disponíveis para descarregar [no sítio Web da Meta] (https://info.deeplearning.ai/e3t/Ctc/LX+113/cJhC404/VWbMJv2vnLfjW3Rh6L96gqS5YW7MhRLh5j9tjNN8BHR5W3qgyTW6N1vHY6lZ3l8N8htfRfqP8DzW72mhHB6vwYd2W77hFt886l4_PV22X226RPmZbW67mSH08gVp9MW2jcZvf24w97BW207Jmf8gPH0yW20YPQv261xxjW8nc6VW3jj-nNW6XdRhg5HhZk_W1QS0yL9dJZb0W818zFK1w62kdW8y-_4m1gfjfNW2jswrd3xbv-yW5mrvdk3n-KqyW45sLMF21qDrwW5TR3vr2MYxZ9W2hWhq23q-nQdW4blHqh3JlZWfW937hlZ58-KJCW82Pgv9384MbYW7yp56M6pvzd6f77wnH004).
Uma das principais conclusões foi que o ajuste fino dos dados gerados pode aumentar o desempenho, mas exemplos de baixa qualidade podem degradá-lo. A equipa do Llama trabalhou exaustivamente para identificar e remover estes maus exemplos utilizando o próprio modelo, modelos auxiliares e outras ferramentas.
Construir e executar o RAG-Retrieval com Milvus
Prepare o seu conjunto de dados
Usei a [documentação oficial do Milvus] (https://milvus.io/docs/) como conjunto de dados para esta demonstração, que descarreguei e guardei localmente.
from langchain.document_loaders import DirectoryLoader
# Carrega arquivos HTML já salvos em um diretório local
caminho = "../../RAG/rtdocs_new/"
padrão_global = '*.html'
loader = DirectoryLoader(path=path, glob=global_pattern)
docs = loader.load()
# Imprimir documentos numéricos e uma pré-visualização.
print(f "carregou {len(docs)} documentos")
print(docs[0].page_content)
pprint.pprint(docs[0].metadata)
carregado 22 docs
Descarregar um modelo de incorporação
A seguir, descarregue um embedding model gratuito e de código aberto da HuggingFace.
import torch
from sentence_transformers import SentenceTransformer
# Inicializar as configurações do torch para código agnóstico de dispositivo.
N_GPU = torch.cuda.device_count()
DEVICE = torch.device('cuda:N_GPU' if torch.cuda.is_available() else 'cpu')
# Descarregar o modelo do hub de modelos huggingface.
nome_do_modelo = "BAAI/bge-large-en-v1.5"
codificador = SentenceTransformer(nome_do_modelo, dispositivo=DEVICE)
# Obter os parâmetros do modelo e guardá-los para mais tarde.
EMBEDDING_DIM = encoder.get_sentence_embedding_dimension()
MAX_SEQ_LENGTH_IN_TOKENS = encoder.get_max_seq_length()
# Inspecionar os parâmetros do modelo.
print(f "nome_do_modelo: {nome_do_modelo}")
print(f "EMBEDDING_DIM: {EMBEDDING_DIM}")
print(f "MAX_SEQ_LENGTH: {MAX_SEQ_LENGTH}")
Agrupa e codifica seus dados personalizados como vetores.
Eu vou usar um comprimento fixo de 512 caracteres com 10% de sobreposição.
from langchain.text_splitter import RecursiveCharacterTextSplitter
TAMANHO_DO_CONJUNTO = 512
sobreposição_de_cachos = np.round(CHUNK_SIZE * 0.10, 0)
print(f "tamanho_do_conjunto: {Tamanho_do_conjunto}, sobreposição_do_conjunto: {sobreposição_do_conjunto}")
# Definir o divisor.
child_splitter = RecursiveCharacterTextSplitter(
tamanho_do_cachorro=tamanho_do_cachorro,
sobreposição_de_cachos=sobreposição_de_cachos)
# Separa os documentos em pedaços.
chunks = child_splitter.split_documents(docs)
print(f"{len(docs)} documentos divididos em {len(chunks)} documentos filhos.")
# A entrada do codificador é doc.page_content como strings.
list_of_strings = [doc.page_content for doc in chunks if hasattr(doc, 'page_content')]
# Inferência de incorporação utilizando o codificador HuggingFace.
embeddings = torch.tensor(encoder.encode(list_of_strings))
# Normalizar os embeddings.
incrustações = np.array(incrustações / np.linalg.norm(incrustações))
# Milvus espera uma lista de `numpy.ndarray` de números `numpy.float32`.
valores_convertidos = list(map(np.float32, embeddings))
# Criar dict_list para inserção no Milvus.
lista_dit = []
for chunk, vetor in zip(chunks, converted_values):
# Montar o vetor de incorporação, o pedaço de texto original e os metadados.
ditado_de_cachos = {
'pedaço': pedaço.conteúdo_da_página,
'fonte': chunk.metadata.get('fonte', ""),
'vetor': vetor,
}
lista_dit.append(pedaço_dict)
Guardar os vectores em Milvus
Ingerir a incorporação do vetor codificado na base de dados de vectores Milvus.
# Conectar um cliente ao servidor Milvus Lite.
from pymilvus import MilvusClient
mc = MilvusClient("milvus_demo.db")
# Criar uma coleção com um esquema flexível e AUTOINDEX.
COLLECTION_NAME = "MilvusDocs"
mc.create_collection(COLLECTION_NAME,
EMBEDDING_DIM,
consistency_level="Eventually",
auto_id=True,
overwrite=True)
# Inserir dados na coleção Milvus.
print("Iniciar a inserção de entidades")
start_time = time.time()
mc.insert(
NOME_DA_COLECÇÃO,
data=dict_list,
progress_bar=True)
end_time = time.time()
print(f "Milvus insere tempo para {len(dict_list)} vectores: ", end="")
print(f"{round(end_time - start_time, 2)} segundos")
Efetuar uma pesquisa vetorial
Faça uma pergunta e procure os pedaços vizinhos mais próximos da sua base de conhecimentos em Milvus.
SAMPLE_QUESTION = "O que significam os parâmetros de HNSW?"
# Incorporar a pergunta utilizando o mesmo codificador.
query_embeddings = torch.tensor(encoder.encode(SAMPLE_QUESTION))
# Normalizar os embeddings para comprimento unitário.
query_embeddings = F.normalize(query_embeddings, p=2, dim=1)
# Converter os embeddings em lista de lista de np.float32.
embeddings_consulta = list(map(np.float32, embeddings_consulta))
# Definir campos de metadados que podem ser filtrados.
OUTPUT_FIELDS = list(dict_list[0].keys())
OUTPUT_FIELDS.remove('vetor')
# Definir o número de resultados top-k que pretende obter.
TOP_K = 2
# Execute a pesquisa vetorial semântica utilizando a sua consulta e a base de dados vetorial.
resultados = mc.search(
NOME_DA_COLECÇÃO,
data=query_embeddings,
output_fields=OUTPUT_FIELDS,
limit=TOP_K,
consistency_level="Eventually")
O resultado recuperado é como mostrado abaixo.
Construir e executar a geração RAG com vLLM e Llama 3.1-8B
Instale o vLLM e os modelos do HuggingFace
O vLLM baixa grandes modelos de linguagem do HuggingFace por padrão. Em geral, sempre que você quiser usar um novo modelo no HuggingFace, você deve fazer um pip install--update ou -U. Além disso, você precisará de uma GPU para executar a inferência dos modelos Llama 3.1 do Meta com vLLM.
Para uma lista completa de todos os modelos suportados pelo vLLM, veja esta página de documentação.
# (Recomendado) Crie um novo ambiente conda.
conda create -n myenv python=3.11 -y
conda activate myenv
# Instale o vLLM com CUDA 12.1.
pip install -U vllm transformers torch
importar vllm, torch
from vllm import LLM, SamplingParams
# Limpar a cache de memória da GPU.
torch.cuda.empty_cache()
# Verifica a GPU.
!nvidia-smi
Para aprender mais sobre como instalar o vLLM, veja sua página installation.
Obter um token HuggingFace
Alguns modelos no HuggingFace, como o Meta Llama 3.1, requerem que o usuário aceite sua licença antes de poder baixar os pesos. Portanto, você deve criar uma conta no HuggingFace, aceitar a licença do modelo, e gerar um token.
Ao visitar esta [página do Llama3.1] (https://huggingface.co/meta-llama/Meta-Llama-3.1-70B) no HuggingFace, você receberá uma mensagem pedindo para concordar com os termos. Clique em "Accept License" para aceitar os termos do Meta antes de descarregar os pesos do modelo. A aprovação geralmente leva menos de um dia.
**Depois de receber a aprovação, tem de gerar um novo token HuggingFace. Os seus tokens antigos não funcionarão com as novas permissões.
Antes de instalar o vLLM, faça login no HuggingFace com seu novo token. Abaixo, eu usei Colab secrets para armazenar o token.
# Faça login no HuggingFace usando seu novo token.
from huggingface_hub import login
from google.colab import userdata
hf_token = userdata.get('HF_TOKEN')
login(token = hf_token, add_to_git_credential=True)
Executar a geração de RAGs
Na demonstração, nós rodamos o modelo Llama-3.1-8B, que requer GPU e memória considerável para rodar. O exemplo a seguir foi executado no Google Colab Pro (US$ 10/mês) com uma GPU A100. Para saber mais sobre como executar o vLLM, pode consultar a [Quickstart documentation] (https://docs.vllm.ai/en/latest/getting_started/quickstart.html).
# 1. Escolha um modelo
MODELTORUN = "meta-llama/Meta-Llama-3.1-8B-Instruct"
# 2. Limpa a cache de memória da GPU, vais precisar de tudo!
torch.cuda.empty_cache()
# 3. Instanciar uma instância do modelo vLLM.
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)
Escreve um texto utilizando contextos e fontes retirados do Milvus.
# Separa todos os contextos por um espaço.
contextos_combinados = ' '.join(contextos)
# Lance Martin, LangChain, diz para colocar os melhores contextos no final.
contextos_combinados = ' '.join(reversed(contextos))
# Separa todas as fontes únicas por vírgula.
source_combined = ' '.join(reversed(list(dict.fromkeys(sources))))
SYSTEM_PROMPT = f"""Primeiro, verifique se o contexto fornecido é relevante para a
a pergunta do utilizador. Em segundo lugar, apenas se o Contexto fornecido for fortemente relevante, responder à pergunta utilizando o Contexto. Caso contrário, se o contexto não for muito relevante, responda à pergunta sem utilizar o contexto.
Seja claro, conciso e relevante. Responda claramente, em menos de 2 frases.
Fontes de fundamentação: {source_combined}
Contexto: {contextos_combinados}
Pergunta do utilizador: {SAMPLE_QUESTION}
"""
prompts = [SYSTEM_PROMPT]
Agora, gere uma resposta usando os pedaços recuperados e a pergunta original inserida no prompt.
# Parâmetros de amostragem
parâmetros_amostragem = parâmetros_amostragem(temperatura=0.2, top_p=0.95)
# Invocar o modelo vLLM.
outputs = llm.generate(prompts, sampling_params)
# Imprime os outputs.
for output in outputs:
prompt = output.prompt
texto_gerado = output.outputs[0].text
# !r chama repr(), que imprime uma string entre aspas.
print()
print(f "Pergunta: {SAMPLE_QUESTION!r}")
pprint.pprint(f "Texto gerado: {texto_gerado!r}")
A resposta acima parece-me perfeita!
Se estiveres interessado nesta demonstração, podes experimentá-la e dizer-nos o que pensas. Também podes juntar-te à nossa comunidade Milvus no Discord para conversares diretamente com todos os criadores do GenAI.
Referências
vLLM documentação oficial e página de modelo.
Apresentação do vLLM 2023](https://www.youtube.com/watch?v=80bIUggRJf4) na Ray Summit
Blogue do vLLM: vLLM: Serviço LLM fácil, rápido e barato com PagedAttention
Blog útil sobre como executar o servidor vLLM: Implantando o vLLM: um guia passo a passo
- Introdução ao Milvus, vLLM e Llama 3.1 do Meta
- Construir e executar o RAG-Retrieval com Milvus
- Construir e executar a geração RAG com vLLM e Llama 3.1-8B
- Referências
Conteúdo
Comece grátis, escale facilmente
Experimente o banco de dados totalmente gerenciado, construído para seus aplicativos GenAI.
Experimente o Zilliz Cloud grátisContinue lendo

Data Deduplication at Trillion Scale: How to Solve the Biggest Bottleneck of LLM Training
Explore how MinHash LSH and Milvus handle data deduplication at the trillion-scale level, solving key bottlenecks in LLM training for improved AI model performance.

Why Not All VectorDBs Are Agent-Ready
Explore why choosing the right vector database is critical for scaling AI agents, and why traditional solutions fall short in production.

Empowering Innovation: Highlights from the Women in AI RAG Hackathon
Over the course of the day, teams built working RAG-powered applications using the Milvus vector database—many of them solving real-world problems in healthcare, legal access, sustainability, and more—all within just a few hours.
