Este tutorial demonstra como aprimorar seus aplicativos RAG adicionando memória de conversação e cache semântico usando a integração LangChain com MongoDB.
A memória permite manter o contexto da conversa em várias interações com o usuário.
O cache semântica reduz a latência da resposta ao armazenar em cache queries semanticamente semelhantes.
Trabalhe com uma versão executável deste tutorial como um bloco de anotações Python.
Pré-requisitos
Antes de começar, certifique-se de ter o seguinte:
Um dos seguintes tipos de cluster MongoDB :
Um cluster do Atlas executando MongoDB versão 6.0.11, 7.0.2 ou posterior. Garanta que seu endereço IP esteja incluído na lista de acessodo seu projeto Atlas.
Um sistema local do Atlas criado utilizando o Atlas CLI. Para saber mais, consulte Criar uma implantação de Atlas local.
Um cluster MongoDB Community ou Enterprise com Search e Vector Search instalados.
Uma chave de API da Voyage AI. Para criar uma conta e uma chave de API, consulte o site da Voyage AI.
Uma chave de API da OpenAI. Você deve ter uma conta da OpenAI com créditos disponíveis para solicitações de API. Para aprender mais sobre como registrar uma conta OpenAI, consulte o website de API OpenAI.
Um ambiente para executar blocos de anotações interativos do Python, como o CoLab.
Dica
Recomendamos concluir o tutorial de Introdução para aprender como criar uma implementação de RAG ingênua antes de concluir este tutorial.
Use o MongoDB como um armazenamento de vetores
Nesta seção, você cria uma instância de armazenamento de vetor usando seu cluster MongoDB como um banco de dados de vetor.
Configure o ambiente.
Configure o ambiente para este tutorial. Crie um bloco de anotações Python interativo salvando um arquivo com a extensão .ipynb. Este bloco de anotações permite que você execute trechos de código Python individualmente, e você o usará para executar o código neste tutorial.
Para configurar seu ambiente de bloco de anotações:
Execute o seguinte comando no seu notebook:
pip install --quiet --upgrade langchain langchain-community langchain-core langchain-mongodb langchain-voyageai langchain-openai pypdf Defina variáveis de ambiente.
Execute o seguinte código para definir as variáveis de ambiente para este tutorial. Forneça sua chave de API Voyage, chave de API OpenAI e a string de conexão SRV do cluster MongoDB.
import os os.environ["OPENAI_API_KEY"] = "<openai-key>" os.environ["VOYAGE_API_KEY"] = "<voyage-key>" MONGODB_URI = "<connection-string>" Observação
Substitua
<connection-string>pela string de conexão do seu cluster do Atlas ou da implantação local do Atlas.Sua string de conexão deve usar o seguinte formato:
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net Para saber mais, consulte Conectar a um cluster via drivers.
Sua string de conexão deve usar o seguinte formato:
mongodb://localhost:<port-number>/?directConnection=true Para saber mais, consulte Connection strings.
Instancie o armazenamento de vetores.
Cole e execute o seguinte código no seu bloco de anotações para criar uma instância do armazenamento de vetor denominada vector_store utilizando o namespace langchain_db.rag_with_memory no MongoDB:
from langchain_mongodb import MongoDBAtlasVectorSearch from langchain_voyageai import VoyageAIEmbeddings # Use the voyage-3-large embedding model embedding_model = VoyageAIEmbeddings(model="voyage-3-large") # Create the vector store vector_store = MongoDBAtlasVectorSearch.from_connection_string( connection_string = MONGODB_URI, embedding = embedding_model, namespace = "langchain_db.rag_with_memory" )
Adicione dados ao armazenamento de vetores.
Cole e execute o código a seguir em seu bloco de anotações para inserir um PDF de amostra que contém um relatório de rendimentos recente do MongoDB no armazenamento de vetores.
Este código utiliza um divisor de texto para dividir os dados do PDF em documentos pai menores. Ele especifica o tamanho da parte (número de caracteres) e a sobreposição da parte (número de caracteres sobrepostos entre partes consecutivas) para cada documento.
from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # Load the PDF loader = PyPDFLoader("https://investors.mongodb.com/node/13176/pdf") data = loader.load() # Split PDF into documents text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20) docs = text_splitter.split_documents(data) # Add data to the vector store vector_store.add_documents(docs)
Dica
Depois de executar esse código, se estiver usando o Atlas, poderá verificar suas incorporações vetoriais navegando até o namespace langchain_db.rag_with_memory na interface do usuário do Atlas.
Crie o índice do MongoDB Vector Search .
Execute o código a seguir para criar o índice do MongoDB Vector Search para o armazenamento de vetores e ativar a pesquisa vetorial em seus dados:
# Use LangChain helper method to create the vector search index vector_store.create_vector_search_index( dimensions = 1024 # The dimensions of the vector embeddings to be indexed )
O índice deve levar cerca de um minuto para ser criado. Enquanto ele é compilado, o índice está em um estado de sincronização inicial. Quando a construção estiver concluída, você poderá começar a fazer query nos dados em sua coleção.
Implementar o RAG com memória
Esta seção demonstra como implementar o RAG com memória de conversação utilizando a integração do LangChain com o MongoDB.
Defina uma função para obter o histórico de mensagens de bate-papo.
Para manter o histórico de conversas em várias interações, use a classe MongoDBChatMessageHistory. Ela permite armazenar mensagens de chat em um banco de dados MongoDB e integrá-las à sua cadeia RAG para gerenciar o contexto da conversa.
Cole e execute o código a seguir no seu notebook para criar uma função chamada get_session_history que retorna uma instância MongoDBChatMessageHistory. Essa instância recupera o histórico de bate-papo para uma sessão específica.
from langchain_mongodb.chat_message_histories import MongoDBChatMessageHistory from langchain_core.runnables.history import RunnableWithMessageHistory from langchain_core.prompts import MessagesPlaceholder def get_session_history(session_id: str) -> MongoDBChatMessageHistory: return MongoDBChatMessageHistory( connection_string=MONGODB_URI, session_id=session_id, database_name="langchain_db", collection_name="rag_with_memory" )
Crie uma cadeia RAG que lide com o histórico de mensagens de chat.
Cole e execute os seguintes trechos de código para criar a cadeia RAG:
Especificar o LLM a ser usado.
from langchain_openai import ChatOpenAI # Define the model to use for chat completion llm = ChatOpenAI(model = "gpt-4o") Defina um prompt que resuma o histórico do chat para o recuperador.
from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # Create a prompt to generate standalone questions from follow-up questions standalone_system_prompt = """ Given a chat history and a follow-up question, rephrase the follow-up question to be a standalone question. Do NOT answer the question, just reformulate it if needed, otherwise return it as is. Only return the final standalone question. """ standalone_question_prompt = ChatPromptTemplate.from_messages( [ ("system", standalone_system_prompt), MessagesPlaceholder(variable_name="history"), ("human", "{question}"), ] ) # Parse output as a string parse_output = StrOutputParser() question_chain = standalone_question_prompt | llm | parse_output Construa uma cadeia de recuperação que processe o histórico do chat e recupere documentos.
from langchain_core.runnables import RunnablePassthrough # Create a retriever retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={ "k": 5 }) # Create a retriever chain that processes the question with history and retrieves documents retriever_chain = RunnablePassthrough.assign(context=question_chain | retriever | (lambda docs: "\n\n".join([d.page_content for d in docs]))) Defina um prompt para gerar uma resposta com base no histórico de conversas e no contexto recuperado.
# Create a prompt template that includes the retrieved context and chat history rag_system_prompt = """Answer the question based only on the following context: {context} """ rag_prompt = ChatPromptTemplate.from_messages( [ ("system", rag_system_prompt), MessagesPlaceholder(variable_name="history"), ("human", "{question}"), ] ) Implemente o RAG com memória.
Combine os componentes que você definiu em uma cadeia RAG completa:
# Build the RAG chain rag_chain = ( retriever_chain | rag_prompt | llm | parse_output ) # Wrap the chain with message history rag_with_memory = RunnableWithMessageHistory( rag_chain, get_session_history, input_messages_key="question", history_messages_key="history", )
Teste sua implementação RAG.
Invoque a cadeia para responder a perguntas. Essa cadeia mantém o contexto da conversa e retorna respostas relevantes que consideram as interações anteriores. Suas respostas podem variar.
# First question response_1 = rag_with_memory.invoke( {"question": "What was MongoDB's latest acquisition?"}, {"configurable": {"session_id": "user_1"}} ) print(response_1)
MongoDB's latest acquisition was Voyage AI, a pioneer in state-of-the-art embedding and reranking models for next-generation AI applications.
# Follow-up question that references the previous question response_2 = rag_with_memory.invoke( {"question": "Why did they do it?"}, {"configurable": {"session_id": "user_1"}} ) print(response_2)
MongoDB acquired Voyage AI to enable organizations to easily build trustworthy AI applications by integrating advanced embedding and reranking models into their technology. This acquisition aligns with MongoDB's goal of helping businesses innovate at "AI speed" using its flexible document model and seamless scalability.
Adicionar cache semântico
Esta seção adiciona cache semântico sobre a sua cadeia RAG. O cache semântico é uma forma de cache que recupera prompts armazenados em cache com base na similaridade semântica entre as queries.
Observação
Você pode usar o cache semântico independentemente da memória de conversação, mas para este tutorial, você usará os dois recursos juntos.
Para assistir a um tutorial em vídeo sobre esse recurso, consulte Aprenda assistindo.
Configure o cache semântica.
Execute o seguinte código para configurar o cache semântico utilizando a classe MongoDBAtlasSemanticCache:
from langchain_mongodb.cache import MongoDBAtlasSemanticCache from langchain_core.globals import set_llm_cache # Configure the semantic cache set_llm_cache(MongoDBAtlasSemanticCache( connection_string = MONGODB_URI, database_name = "langchain_db", collection_name = "semantic_cache", embedding = embedding_model, index_name = "vector_index", similarity_threshold = 0.5 # Adjust based on your requirements ))
Teste o cache semântico com sua cadeia RAG.
O cache semântico armazena automaticamente seus prompts. Execute as consultas de exemplo a seguir, onde você deverá observar uma redução significativa no tempo de resposta para a segunda query. As respostas e os tempos de resposta podem variar.
Dica
Você pode visualizar suas solicitações em cache na coleção semantic_cache. O cache semântica armazena em cache apenas a entrada no LLM. Ao usá-lo em cadeias de recuperação, observe que os documentos recuperados podem ser alterados entre as execuções, resultando em falhas de cache para queries semanticamente semelhantes.
%%time # First query (not cached) rag_with_memory.invoke( {"question": "What was MongoDB's latest acquisition?"}, {"configurable": {"session_id": "user_2"}} )
CPU times: user 54.7 ms, sys: 34.2 ms, total: 88.9 ms Wall time: 7.42 s "MongoDB's latest acquisition was Voyage AI, a pioneer in state-of-the-art embedding and reranking models that power next-generation AI applications."
%%time # Second query (cached) rag_with_memory.invoke( {"question": "What company did MongoDB acquire recently?"}, {"configurable": {"session_id": "user_2"}} )
CPU times: user 79.7 ms, sys: 24 ms, total: 104 ms Wall time: 3.87 s 'MongoDB recently acquired Voyage AI.'
Aprenda assistindo
Siga este tutorial em vídeo para aprender mais sobre cache semântico com LangChain e MongoDB.
Duração: 30 minutos