Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Saiba por que o MongoDB foi selecionado como um líder no 2024 Gartner_Magic Quadrupnt()
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
Atlaschevron-right

Como criar um sistema RAG com LlamaIndex, OpenAI e MongoDB Vector Database

Richmond Alake10 min read • Published Feb 16, 2024 • Updated Feb 16, 2024
IAPythonAtlas
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Introdução

Os modelos de linguagem grandes (LLMs) beneficiam significativamente os aplicativos de negócios, especialmente em casos de uso que envolvem a produtividade. Embora os LLMs e suas aplicações sejam, sem dúvida, vantajosos, confiar apenas no conhecimento paramétrico dos LLMs para responder às entradas e solicitações do usuário se mostra insuficiente para dados privados ou queries dependentes de dados em tempo real. É por isso que uma fonte de conhecimento segura não paramétrica que contém dados confidenciais e pode ser atualizada periodicamente é necessária para aumentar as entradas do usuário para LLMs com informações atuais e relevantes.
A geração aumentada de recuperação (RAG) é um padrão de design de sistema que usa técnicas de recuperação de informações e modelos de AI generativa para fornecer respostas precisas e relevantes às queries do usuário, recuperando dados semanticamente relevantes para complementar as queries do usuário com contexto adicional, combinado como entrada nos LLMs.
RAG_STACK_POLM Principais conclusões:
  • Visão geral da RAG
  • Entendendo a pilha de IA
  • Como criar um sistema RAG de ponta a ponta com MongoDB, LlamaIndex e OpenAI

O que é uma pilha de IA?

Este tutorial implementará um sistema RAG de ponta a ponta usando a pilha de IA OLM (OpenAI, LlamaIndex e MongoDB) ou POLM (Python, OpenAI, LlamaIndex, MongoDB). A pilha de IA, ou pilha GenAI, refere-se à composição de modelos, bancos de dados, bibliotecas e frameworks usados para criar e desenvolver aplicativos modernos com funcionalidades de IA generativa.
Uma pilha de AI típica implementa uma infraestrutura que aproveita o conhecimento paramétrico do LLM e o conhecimento não paramétrico de dados para aumentar as queries do usuário. Os componentes da pilha de AI incluem modelos, orquestradores ou integradores e banco de dados operacionais e banco de dados vetorial. Neste tutorial, o MongoDB atuará como banco de dados operacional e banco de dados vetorial.
Componente de pilha de IAPilha OLM/POLM
LinguagemP ython
Provedor modeloO penAI (GPT-3.5, GPT-4)
Orquestrador LLML lamaIndex
Banco de dados operacional e vetorialM ongoDB Atlas
GenAI-Stack
Todas as etapas de implementação descritas neste artigo podem ser encontradas no repositório. O conteúdo das etapas a seguir explica em detalhes as classes, os métodos e os processos da biblioteca que são usados para atingir o objetivo de implementar um sistema RAG.

Etapa 1: instalar bibliotecas

O trecho de código abaixo instala várias bibliotecas que fornecerão funcionalidades para acessar LLMs, reordenar modelos, banco de dados e métodos de coleção, abstraindo as complexidades associadas à codificação extensiva em algumas linhas e chamadas de método.
  • LlamaIndex: framework de dados que oferece funcionalidades para conectar fontes de dados (arquivos, PDFs, website ou fonte de dados) a grandes modelos de linguagem fechados (OpenAI, Cohere) e de código aberto (Llama); o framework LlamaIndex abstrai complexidades associadas à ingestão de dados, implementação de pipeline RAG e desenvolvimento de aplicativos LLM (chatbots, agentes etc.).
  • LlamaIndex (MongoDB): biblioteca de extensão LlamaIndex que importa todos os métodos necessários para se conectar e operar com o banco de dados MongoDB Atlas.
  • LlamaIndex (OpenAI): biblioteca de extensão do LlamaIndex que importa todos os métodos necessários para acessar os modelos de incorporação do OpenAI.
  • PyMongo: uma biblioteca Python para interagir com o MongoDB que habilita funcionalidades para se conectar a um cluster e consultar dados armazenados em coleções e documentos.
  • Conjuntos de dados do Hugging Face: a biblioteca do Hugging Face contém conjuntos de dados de áudio, visão e texto.
  • Pandas : fornece estrutura de dados para processamento e análise eficientes de dados usando o Python.
1!pip install llama-index
2
3!pip install llama-index-vector-stores-mongodb
4
5!pip install llama-index-embeddings-openai
6
7!pip install pymongo
8
9!pip install datasets
10
11!pip install pandas

Etapa 2: fonte de dados e configuração da chave OpenAI

O comando abaixo atribui uma chave de API OpenAI à variável de ambiente OPENAI_API_KEY. Isso garante que o LlamaIndex crie um cliente OpenAI com a chave de API OpenAI fornecida para acessar recursos como modelos LLM (GPT-3, GPT-3).5-turbo e GPT-4) e modelos de incorporação (text-embedding-ada-002, text-embedding-3-small e text-embedding-3-large).
1%env OPENAI\_API\_KEY=openai\_key\_here
Os dados usados neste tutorial são provenientes dos conjuntos de dados do Hugging Face, especificamente o conjunto de dados AIatMongoDB/embedded_movies. Um ponto de dados dentro do conjunto de dados de filmes contém informações correspondentes a um determinado filme; enredo, gênero, elenco, duração e outros são capturados para cada ponto de dados. Depois de carregar o conjunto de dados no ambiente de desenvolvimento, ele é convertido em um objeto de quadro de dados do Pandas, o que permite a manipulação e a análise da estrutura de dados com relativa facilidade.
1from datasets import load_dataset
2
3importpandasaspd
4
5# https://huggingface.co/datasets/AIatMongoDB/embedded\_movies
6
7dataset=load_dataset("AIatMongoDB/embedded\_movies")
8
9# Convert the dataset to a pandas dataframe
10
11dataset_df=pd.DataFrame(dataset['train'])
12
13dataset_df.head(5)

Etapa 3: limpeza, preparação e carregamento de dados

As operações dentro desta etapa se concentram em reforçar a integridade e a qualidade dos dados. O primeiro processo garante que o atributo plot de cada ponto de dados não esteja vazio, pois esses são os dados primários que usamos no processo de incorporação. Esta etapa também garante a remoção do atributo plot_embedding de todos os pontos de dados, pois ele será substituído por novas incorporações criadas com um modelo diferente, o text-embedding-3-small.
1# Remove data point where plot column is missing
2
3dataset_df=dataset_df.dropna(subset=['plot'])
4
5print("\nNumber of missing values in each column after removal:")
6
7print(dataset_df.isnull().sum())
8
9# Remove the plot_embedding from each data point in the dataset as we are going to create new embeddings with the new OpenAI embedding Model "text-embedding-3-small"
10
11dataset_df=dataset_df.drop(columns=['plot_embedding'])
12
13dataset_df.head(5)
Um objeto incorporado é inicializado a partir do modelo OpenAIEmbedding, parte do módulo llama_index.embeddings. Especificamente, o modelo OpenAIEmbedding usa dois parâmetros: o nome do modelo de incorporação, text-embedding-3-small para este tutorial, e as dimensões da incorporação vetorial.
O trecho de código abaixo configura o modelo de incorporação e o LLM usado em todo o ambiente de desenvolvimento. O LLM usado para responder às queries do usuário é o modelo padrão do OpenAI ativado pelo LlamaIndex e é inicializado com a classe OpenAI(). Para garantir a consistência em todos os consumidores de LLMs e sua configuração, o LlamaIndex forneceu o módulo "Settings", que permite uma configuração global dos LLMs e dos modelos de incorporação usados no ambiente.
1from llama_index.core.settings import Settings
2
3from llama_index.llms.openai import OpenAI
4
5from llama_index.embeddings.openai import OpenAIEmbedding
6
7embed_model=OpenAIEmbedding(model="text-embedding-3-small",dimensions=256)
8
9llm=OpenAI()
10
11Settings.llm=llm
12
13Settings.embed_model=embed_model
Em seguida, é crucial formatar adequadamente o conjunto de dados e seu conteúdo para a ingestão do MongoDB. Nas próximas etapas, transformaremos a estrutura atual do conjunto de dados, dataset_df – atualmente um objeto DataFrame – em uma string JSON. Essa conversão de conjunto de dados é feita na linha documents = dataset_df.to_json(orient='records'), que atribui o formato JSON aos documentos.
Ao especificar orient='records', cada linha do DataFrame é convertida em um objeto JSON separado.
A etapa seguinte cria uma lista de dicionários Python, documents_list, cada um representando um registro individual do DataFrame original. A etapa final desse processo é converter cada dicionário em documentos construídos manualmente, que são cidadãos de primeira classe que contêm informações extraídas de uma fonte de dados. Os documentos no LlamaIndex contêm informações, como metadados, que são utilizadas em estágios de processamento e ingestão posteriores em um pipeline RAG.
Um ponto importante a ser observado é que, ao criar um documento LlamaIndex manualmente, é possível configurar os atributos dos documentos que são usados quando passados como entrada para modelos de incorporação e LLMs. Os argumentos excluded_llm_metadata_keys e excluded_embed_metadata_keys no construtor da classe de documentos usam uma lista de atributos a serem ignorados ao gerar entradas para processos downstream dentro de um pipeline RAG. Uma razão para fazer isso é limitar o contexto usado dentro dos modelos de incorporação para recuperações mais relevantes e, no caso de LLMs, isso é usado para controlar as informações de metadados combinadas com queries de usuários. Sem a configuração de nenhum dos dois argumentos, um documento, por padrão, usa todo o conteúdo em seus metadados como incorporação e entrada LLM.
No final dessa etapa, uma lista Python contém vários documentos correspondentes a cada ponto de dados no conjunto de dados pré-processado.
1import json
2from llama_index.core import Document
3from llama_index.core.schema import MetadataMode
4
5# Convert the DataFrame to a JSON string representation
6documents_json = dataset_df.to_json(orient='records')
7# Load the JSON string into a Python list of dictionaries
8documents_list = json.loads(documents_json)
9
10llama_documents = []
11
12for document in documents_list:
13
14 # Value for metadata must be one of (str, int, float, None)
15 document["writers"] = json.dumps(document["writers"])
16 document["languages"] = json.dumps(document["languages"])
17 document["genres"] = json.dumps(document["genres"])
18 document["cast"] = json.dumps(document["cast"])
19 document["directors"] = json.dumps(document["directors"])
20 document["countries"] = json.dumps(document["countries"])
21 document["imdb"] = json.dumps(document["imdb"])
22 document["awards"] = json.dumps(document["awards"])
23
24
25 # Create a Document object with the text and excluded metadata for llm and embedding models
26 llama_document = Document(
27 text=document["fullplot"],
28 metadata=document,
29 excluded_llm_metadata_keys=["fullplot", "metacritic"],
30 excluded_embed_metadata_keys=["fullplot", "metacritic", "poster", "num_mflix_comments", "runtime", "rated"],
31 metadata_template="{key}=>{value}",
32 text_template="Metadata: {metadata_str}\n-----\nContent: {content}",
33 )
34
35 llama_documents.append(llama_document)
36
37# Observing an example of what the LLM and Embedding model receive as input
38print(
39 "\nThe LLM sees this: \n",
40 llama_documents[0].get_content(metadata_mode=MetadataMode.LLM),
41)
42print(
43 "\nThe Embedding model sees this: \n",
44 llama_documents[0].get_content(metadata_mode=MetadataMode.EMBED),
45)
A etapa final do processamento antes de ingerir os dados para o armazenamento vetorial do MongoDB é converter a lista de documentos LlamaIndex em outra estrutura de dados de primeira classe conhecida como nós. Depois de termos os nós gerados a partir dos documentos, a próxima etapa é gerar dados de incorporação para cada nó usando o conteúdo nos atributos de texto e metadados.
1from llama_index.core.node_parser import SentenceSplitter
2
3parser = SentenceSplitter()
4nodes = parser.get_nodes_from_documents(llama_documents)
5
6for node in nodes:
7 node_embedding = embed_model.get_text_embedding(
8 node.get_content(metadata_mode="all")
9 )
10 node.embedding = node_embedding
11

Etapa 4: configuração e conexão do banco de dados

Antes de prosseguir, certifique-se de que os seguintes pré-requisitos sejam atendidos:
  • Cluster do banco de dados configurado no MongoDB Atlas
  • Obteve o URI para seu cluster
Para obter ajuda com a configuração do MongoDB cluster e obter o URI, consulte nosso guia para configurar um MongoDB clustere nosso guia para obter sua string. Como alternativa, siga a Etapa 5 deste artigo sobre como usar incorporações em um RAG, que oferece instruções detalhadas sobre como configurar e configurar o MongoDB cluster.
Depois de criar um MongoDB Atlas cluster, crie o banco de dados e a coleção dentro do MongoDB Atlas cluster clicando em + Criar banco de dados. O banco de dados será denominado moviese a coleção será chamada de movies_records.
Criando um banco de dados e coleção via MongoDB Atlas
Armazene com segurança o URI em seu ambiente de desenvolvimento depois de configurar o banco de dados e obter o URI de conexão do cluster do Atlas.
Este guia usa o Google Colab, que oferece um recurso para armazenamento seguro de segredos do ambiente. Esses segredos podem então ser acessados no ambiente de desenvolvimento. Especificamente, o código mongo_uri = userdata.get('MONGO_URI') recupera o URI do armazenamento seguro.
O trecho de código abaixo também usa o PyMongo para criar um objeto de cliente MongoDB, representando a conexão com o cluster e permitindo o acesso aos seus bancos de dados e coleções.
1import pymongo
2from google.colab import userdata
3
4def get_mongo_client(mongo_uri):
5 """Establish connection to the MongoDB."""
6 try:
7 client = pymongo.MongoClient(mongo_uri)
8 print("Connection to MongoDB successful")
9 return client
10 except pymongo.errors.ConnectionFailure as e:
11 print(f"Connection failed: {e}")
12 return None
13
14mongo_uri = userdata.get('MONGO_URI_2')
15if not mongo_uri:
16 print("MONGO_URI not set in environment variables")
17
18mongo_client = get_mongo_client(mongo_uri)
19
20DB_NAME="movies"
21COLLECTION_NAME="movies_records"
22
23db = mongo_client[DB_NAME]
24collection = db[COLLECTION_NAME]
O código a seguir garante que a coleção de banco de dados atual esteja vazia executando a operação delete_many() na coleção.
1# To ensure we are working with a fresh collection
2# delete any existing records in the collection
3
4collection.delete_many({})

Etapa 5: criação do índice de pesquisa vetorial

A criação de um índice de pesquisa vetorial na coleção movies_records é essencial para a recuperação eficiente de documentos do MongoDB em nosso ambiente de desenvolvimento. Para conseguir isso, consulte o guia oficial sobre criação de índice de pesquisa vetorial.
Na criação de um índice de pesquisa vetorial usando o editor JSON no MongoDB Atlas, certifique-se de que seu índice de pesquisa vetorial seja denominado vector_index e que a definição do índice de pesquisa vetorial seja a seguinte:
1{
2 "fields": [
3 {
4 "numDimensions": 256,
5 "path": "embedding",
6 "similarity": "cosine",
7 "type": "vector"
8 }
9 ]
10}
Depois de configurar o índice de pesquisa vetorial, os dados podem ser ingeridos e recuperados de forma eficiente. A ingestão de dados é um processo simples alcançado com menos de três linhas ao usar o LlamaIndex.

Etapa 6: ingestão de dados no banco de dados vetorial

Até este ponto, fizemos o seguinte com sucesso:
  • Dados carregados obtidos do Hugging Face
  • Fornecemos cada ponto de dados com incorporação usando o modelo de incorporação OpenAI
  • Configurar um MongoDB database projetado para armazenar incorporações de vetor
  • Estabelecemos uma conexão com esse banco de dados a partir de nosso ambiente de desenvolvimento
  • Definimos um índice de pesquisa vetorial para consulta eficiente de incorporações vetoriais
O trecho de código abaixo também inicializa um objeto de armazenamento vetorial do MongoDB Atlas por meio do construtor LlamaIndex MongoDBAtlasVectorSearch. É importante observar que, nesta etapa, referenciamos o nome do índice de pesquisa vetorial criado anteriormente por meio da interface do MongoDB Cloud Atlas. Para este caso de uso específico, o nome do índice é vector_index.
O método crucial que executa a ingestão de nós em um armazenamento de vetores especificado é o .add() da instância LlamaIndex MongoDB.
1from llama_index.vector_stores.mongodb import MongoDBAtlasVectorSearch
2
3vector_store = MongoDBAtlasVectorSearch(mongo_client, db_name=DB_NAME, collection_name=COLLECTION_NAME, index_name="vector_index")
4vector_store.add(nodes)
A última linha no trecho de código acima cria um índice LlamaIndex. No LlamaIndex, quando documentos são carregados em qualquer uma das classes de abstração do índice — SummaryIndex, ``TreeIndex, KnowledgeGraphIndex, and especially VectorStoreIndex``` — um índice que armazena uma representação do documento original é criado em um armazenamento vetorial de memória que também armazena incorporações.
Mas como o banco de dados de vetorial do MongoDB Atlas é utilizado nesse sistema RAG para armazenar as incorporações e também o índice de nosso documento, o LlamaIndex permite a recuperação do índice do Atlas por meio do método from_vector_store da classe VectorStoreIndex.
1from llama_index.core import VectorStoreIndex, StorageContext
2index = VectorStoreIndex.from_vector_store(vector_store)

Etapa 7: lidando com queries de usuários

A próxima etapa envolve a criação de um mecanismo de query LlamaIndex. O mecanismo de query habilita a funcionalidade de usar linguagem natural para recuperar informações relevantes e contextualmente apropriadas de um índice de dados. O método as_query_engine fornecido pela LlamaIndex abstrai as complexidades de engenheiros e desenvolvedores de AI que escrevem o código de implementação para processar queries adequadamente para extrair informações de uma fonte de dados.
Para nosso caso de uso, o mecanismo de query satisfaz o requisito de criar um aplicativo de perguntas e respostas. No entanto, o LlamaIndex fornece a capacidade de construir um aplicativo semelhante a um chat com a funcionalidade Chat Engine.
1import pprint
2from llama_index.core.response.notebook_utils import display_response
3
4query_engine = index.as_query_engine(similarity_top_k=3)
5query = "Recommend a romantic movie suitable for the christmas season and justify your selecton"
6response = query_engine.query(query)
7display_response(response)
8pprint.pprint(response.source_nodes)

Conclusão

A incorporação de padrões de projeto de arquitetura RAG melhora o desempenho do LLM em aplicativos modernos de AI generativa e introduz uma abordagem econômica para construir uma infraestrutura de AI robusta. Construir um sistema RAG robusto com implementação mínima de código com componentes como MongoDB como banco de dados vetorial e LlamaIndex como orquestrador LLM é um processo simples, como demonstra este artigo.
Em particular, este tutorial abordou a implementação de um sistema RAG que aproveita os recursos combinados do Python, OpenAI, LlamaIndex e o banco de dados vetorial do MongoDB, também conhecido como pilha de IA POLM.
Deve-se mencionar que o ajuste fino ainda é uma estratégia viável para melhorar as capacidades dos LLMs e atualizar seus conhecimentos paramétricos. No entanto, para engenheiros de AI que consideram a economia de construção e manutenção de aplicativos com GenAI, vale a pena considerar a exploração de métodos econômicos que melhorem as capacidades do LLM, mesmo que de forma experimental.
O custo associado de fonte de dados, a aquisição de aceleradores de hardware e a experiência de domínio necessária para ajustar LLMs e modelos básicos geralmente envolvem investimentos significativos, tornando a exploração de métodos mais econômicos, como sistemas RAG, uma alternativa interessante.
Notadamente, as implicações de custo do ajuste fino e do treinamento de modelos ressaltam a necessidade de os engenheiros e desenvolvedores de AI adotarem uma mentalidade de economia de custos desde os estágios iniciais de um projeto de AI. A maioria dos aplicativos hoje já tem, ou terá, alguma forma de capacidade de IA generativa suportada por uma infraestrutura de AI. Nesse ponto, torna-se um aspecto fundamental da função de um engenheiro de AI comunicar e expressar o valor da exploração de soluções econômicas para as partes interessadas e os principais tomadores de decisão ao desenvolver a infraestrutura de AI.
Todo o código apresentado neste artigo está no GitHub. Bom hacking!

Perguntas frequentes

P: O que é um sistema de geração aumentada de recuperação (RAG)?
A geração aumentada de recuperação (RAG) é um padrão de design que melhora as capacidades dos LLMs usando modelos de recuperação para buscar informações semanticamente relevantes de um banco de dados. Esse contexto adicional é combinado com a query do usuário para gerar respostas mais precisas e relevantes de LLMs.
P: Quais são os principais componentes de uma pilha de IA em um sistema RAG?
Os componentes essenciais incluem modelos (como GPT-3.5, GPT-4 ou Llama), orquestradores ou integradores para gerenciar interações entre LLMs e fontes de dados, e bancos de dados operacionais e vetoriais para armazenar e recuperar dados de forma eficiente.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.
Iniciar a conversa

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Como distribuir o Vector Search, o Atlas Search e os nós de pesquisa com o Atlas Kubernetes Operator


Dec 20, 2024 | 10 min read
Tutorial

Gerenciando uma arquitetura de metadados de catálogo de produtos inteligentes com MongoDB Atlas e Google Cloud Platform Google Cloud Platform


Dec 16, 2024 | 9 min read
Tutorial

Como fazer semantic search no MongoDB utilizando o Atlas Vector Search


Sep 18, 2024 | 8 min read
Tutorial

Como Migrar PostgreSQL para MongoDB com Confluent Kafka


Aug 30, 2024 | 10 min read
Sumário