En «Generación de recuperación aumentada, paso a paso”, analizamos un ejemplo de RAG muy simple. Nuestra pequeña aplicación aumentó un modelo de lenguaje grande (LLM) con nuestros propios documentos, permitiendo que el modelo de lenguaje responda preguntas sobre nuestro propio contenido. Ese ejemplo utilizó un modelo de incrustación de OpenAI, lo que significaba que teníamos que enviar nuestro contenido a los servidores de OpenAI, una posible violación de la privacidad de los datos, según la aplicación. También utilizamos el LLM público de OpenAI.
Esta vez construiremos una versión completamente local de un generación de recuperación aumentada sistema, utilizando un modelo de integración local y un LLM local. Como en el artículo anterior, usaremos LangChain para unir los diversos componentes de nuestra aplicación. En lugar de FAISS (Búsqueda de similitudes de IA en Facebook), usaremos SQLite-vss para almacenar nuestros datos vectoriales. SQLite-vss es nuestro conocido amigo SQLite con una extensión que lo hace capaz de búsqueda de similitud.
Recuerde que la búsqueda de similitud de texto logra una mejor coincidencia en cuanto a significado (o semántica) utilizando incrustaciones, que son representaciones numéricas de palabras o frases en un espacio vectorial. Cuanto más corta sea la distancia entre dos incrustaciones en el espacio vectorial, más cercanas serán el significado de las dos palabras o frases. Por lo tanto, para alimentar nuestros propios documentos a un LLM, primero debemos convertirlos en incrustaciones, que es la única materia prima que un LLM puede tomar como entrada.
Guardamos la incrustación en el almacén de vectores local y luego integramos ese almacén de vectores con nuestro LLM. Usaremos Llama 2 como nuestro LLM, que ejecutaremos localmente usando una aplicación llamada Ser, que está disponible para macOS, Linux y Windows (este último en versión preliminar). Puedes leer sobre la instalación de Ollama en este artículo de InfoWorld.
Aquí está la lista de componentes que necesitaremos para construir un sistema RAG simple y completamente local:
- Un corpus documental. Aquí utilizaremos sólo un documento, el texto de la declaración del presidente Biden. 7 de febrero de 2023, Discurso sobre el Estado de la Unión. Puedes descargar este texto en el siguiente enlace.
- Un cargador para el documento. Este código extraerá texto del documento y lo procesará previamente en fragmentos para generar una incrustación.
- Un modelo de incrustación. Este modelo toma los fragmentos de documentos preprocesados como entrada y genera una incrustación (es decir, un conjunto de vectores que representan los fragmentos de documentos).
- Un almacén de datos vectoriales local con un índice para realizar búsquedas.
- Un LLM optimizado para seguir instrucciones y ejecutarlo en su propia máquina. Esta máquina podría ser una computadora de escritorio, una computadora portátil o una máquina virtual en la nube. En mi ejemplo, es un modelo Llama 2 ejecutándose en Ollama en mi Mac.
- Una plantilla de chat para hacer preguntas. Esta plantilla crea un marco para que el LLM responda en un formato que los seres humanos comprendan.
Ahora el código con más explicaciones en los comentarios.
Archivo de texto del discurso sobre el estado de la Unión del 7 de febrero de 2023 del presidente Biden
Ejemplo de RAG completamente local: código de recuperación
# LocalRAG.py # LangChain is a framework and toolkit for interacting with LLMs programmatically from langchain.embeddings.sentence_transformer import SentenceTransformerEmbeddings from langchain.text_splitter import CharacterTextSplitter from langchain.vectorstores import SQLiteVSS from langchain.document_loaders import TextLoader # Load the document using a LangChain text loader loader = TextLoader("./sotu2023.txt") documents = loader.load() # Split the document into chunks text_splitter = CharacterTextSplitter (chunk_size=1000, chunk_overlap=0) docs = text_splitter.split_documents(documents) texts = [doc.page_content for doc in docs] # Use the sentence transformer package with the all-MiniLM-L6-v2 embedding model embedding_function = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2") # Load the text embeddings in SQLiteVSS in a table named state_union db = SQLiteVSS.from_texts( texts = texts, embedding = embedding_function, table = "state_union", db_file = "/tmp/vss.db" ) # First, we will do a simple retrieval using similarity search # Query question = "What did the president say about Nancy Pelosi?" data = db.similarity_search(question) # print results print(data[0].page_content)
Ejemplo de RAG completamente local: salida de recuperación
Señor Portavoz. Señora Vicepresidenta. Nuestra Primera Dama y Segundo Caballero.
Miembros del Congreso y del Gabinete. Líderes de nuestro ejército.
Sr. Presidente del Tribunal Supremo, Magistrados Asociados y Magistrados jubilados de la Corte Suprema.
Y ustedes, mis compatriotas estadounidenses.
Empiezo esta noche felicitando a los miembros del 118º Congreso y al nuevo Presidente de la Cámara, Kevin McCarthy.
Señor Presidente, espero trabajar juntos.
También quiero felicitar al nuevo líder de los demócratas de la Cámara de Representantes y al primer líder de la minoría de la Casa Negra en la historia, Hakeem Jeffries.
Felicitaciones al líder del Senado con más años de servicio en la historia, Mitch McConnell.
Y felicitaciones a Chuck Schumer por otro mandato como líder de la mayoría del Senado, esta vez con una mayoría aún mayor.
Y quiero dar un reconocimiento especial a alguien que creo será considerada la mejor oradora en la historia de este país, Nancy Pelosi.
Tenga en cuenta que el resultado incluye un fragmento literal de texto del documento que es relevante para la consulta. Es lo que arroja la búsqueda de similitud del base de datos vectorial, pero no es la respuesta a la consulta. La última línea del resultado es la respuesta a la consulta. El resto del resultado es el contexto de la respuesta.
Tenga en cuenta que fragmentos de sus documentos es justo lo que obtendrá si realiza una búsqueda de similitud sin procesar en una base de datos vectorial. A menudo obtendrá más de un fragmento, dependiendo de su pregunta y de cuán amplia o limitada sea. Debido a que nuestra pregunta de ejemplo era bastante limitada, y debido a que solo hay una mención de Nancy Pelosi en el texto, recibimos solo una parte de respuesta.
Ahora usaremos el LLM para ingerir el fragmento de texto que surgió de la búsqueda de similitud y generar una respuesta compacta a la consulta.
Antes de poder ejecutar el siguiente código, se debe instalar Ollama y descargar el modelo llama2:7b. Tenga en cuenta que en macOS y Linux, Ollama almacena el modelo en el subdirectorio .ollama en el directorio de inicio del usuario.
RAG completamente local: código de consulta
# LLM from langchain.llms import Ollama from langchain.callbacks.manager import CallbackManager from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler llm = Ollama( model = "llama2:7b", verbose = True, callback_manager = CallbackManager([StreamingStdOutCallbackHandler()]), ) # QA chain from langchain.chains import RetrievalQA from langchain import hub # LangChain Hub is a repository of LangChain prompts shared by the community QA_CHAIN_PROMPT = hub.pull("rlm/rag-prompt-llama") qa_chain = RetrievalQA.from_chain_type( llm, # we create a retriever to interact with the db using an augmented context retriever = db.as_retriever(), chain_type_kwargs = {"prompt": QA_CHAIN_PROMPT}, ) result = qa_chain({"query": question})
Ejemplo de RAG completamente local: resultado de la consulta
En el contexto recuperado, el presidente Biden se refiere a Nancy Pelosi como
«Alguien que creo será considerado el mejor orador en la historia de este país».
Esto sugiere que el presidente tiene una alta opinión de las habilidades de liderazgo y los logros de Pelosi como presidenta de la Cámara.
Tenga en cuenta la diferencia en el resultado de los dos fragmentos. El primero es un fragmento literal de texto del documento relevante para la consulta. La segunda es una respuesta resumida a la pregunta. En el primer caso no estamos utilizando el LLM. Solo estamos usando el almacén de vectores para recuperar un fragmento de texto del documento. Sólo en el segundo caso utilizamos el LLM, que genera una respuesta compacta a la consulta.
Para utilizar RAG en aplicaciones prácticas, necesitará importar varios tipos de documentos, como PDF, DOCX, RTF, XLSX y PPTX. Ambos LangChain y LlamaIndex (otro marco popular para crear aplicaciones LLM) tienen cargadores especializados para una variedad de tipos de documentos.
Además, es posible que desees explorar otras tiendas de vectores además de FAISS y SQLite-vss. Al igual que los grandes modelos de lenguaje y otras áreas de la IA generativa, el espacio de las bases de datos vectoriales está evolucionando rápidamente. Profundizaremos en otras opciones en todos estos frentes en futuros artículos aquí.
Copyright © 2024 IDG Communications, Inc.