Este tutorial demonstra como aprimorar seus aplicativos RAG adicionando memória de conversa e cache semântica usando a integração LangChain 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.
Pré-requisitos
Antes de começar, certifique-se de ter o seguinte:
Um dos seguintes tipos de cluster MongoDB :
Um cluster do Atlas executando a versão 6.0.11 do MongoDB, 7.0.2, ou posterior. Certifique-se de que seu endereço IP esteja incluído na lista de acesso do seu projeto Atlas.
Um sistema local do Atlas criado usando Python e Docker. Instale
atlas-local-lib-pyopip install atlas-local-lib-py() para criar e gerenciar implantações locais programaticamente. Para saber mais, consulte o repositório atlas-local-lib-py .Um cluster MongoDB Community com Search e pesquisa vetorial instalados.
Uma chave de API do Voyage AI. Para criar uma chave de API, consulte Gerenciar chaves de API do modelo 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 saber mais sobre como registrar uma conta OpenAI, consulte o site da API OpenAI.
Um ambiente para executar notebooks Python interativos, 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 langgraph langgraph-checkpoint-mongodb 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-se a um cluster por meio de bibliotecas de clientes.
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_splitters 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 criar. Enquanto constrói, o índice está em um estado de sincronização inicial. Quando terminar de ser criado, você poderá começar a consultar os 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.
Configure o Checkpointer do MongoDB.
Para manter o histórico de conversa em várias interações, use o ponto de verificação LangGraph MongoDBSaver. Um checkpointer salva o estado de uma conversa no MongoDB após cada etapa e o restaura na próxima interação, o que permite que seu aplicação RAG manipule o contexto da conversa.
O LangGraph identifica cada conversa por um thread_id. O checkpointer grava o estado nas coleções checkpoints e checkpoint_writes no banco de dados que você especificar.
Cole e execute o código a seguir no seu bloco de anotações para criar um checkpointer denominado checkpointer que armazena o estado da conversa no banco de dados langchain_db.
from langgraph.checkpoint.mongodb import MongoDBSaver from pymongo import MongoClient # Connect to your MongoDB cluster mongo_client = MongoClient(MONGODB_URI) # Create the checkpointer to persist conversation state checkpointer = MongoDBSaver(mongo_client, db_name="langchain_db")
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, MessagesPlaceholder 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 ) Em seguida, envolva a cadeia em um grafo LangGraph e compile-o com o checkpointer. O grafo contém um único nó que lê o estado da conversa, passa a pergunta mais recente e as mensagens anteriores para a cadeia e anexa a resposta ao estado:
from langgraph.graph import StateGraph, START, END, MessagesState from langchain_core.messages import AIMessage # Define the node that runs the RAG chain def call_rag_chain(state: MessagesState): question = state["messages"][-1].content history = state["messages"][:-1] answer = rag_chain.invoke( {"question": question, "history": history} ) return {"messages": [AIMessage(content=answer)]} # Build the graph workflow = StateGraph(MessagesState) workflow.add_node("rag", call_rag_chain) workflow.add_edge(START, "rag") workflow.add_edge("rag", END) # Compile the graph with the checkpointer rag_with_memory = workflow.compile(checkpointer=checkpointer)
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( {"messages": [("human", "What was MongoDB's latest acquisition?")]}, {"configurable": {"thread_id": "user_1"}} ) print(response_1["messages"][-1].content)
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( {"messages": [("human", "Why did they do it?")]}, {"configurable": {"thread_id": "user_1"}} ) print(response_2["messages"][-1].content)
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( {"messages": [("human", "What was MongoDB's latest acquisition?")]}, {"configurable": {"thread_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( {"messages": [("human", "What company did MongoDB acquire recently?")]}, {"configurable": {"thread_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