Creación y manejo de bases de datos vectoriales con OpenAI Embeddings
Resumen
¿Cómo utilizar embeddings de OpenAI en bases de datos vectoriales?
Iniciar en el mundo del procesamiento de lenguaje natural (NLP) puede ser una odisea, especialmente si todo te suena a tecnicismos complejos. Hoy te mostraré cómo puedes transformar documentos en números usando embeddings y almacenarlos en bases de datos vectoriales, específicamente con el uso de OpenAI, Langchain y la base de datos Chroma.
¿Qué son los embeddings y cómo se usan en OpenAI?
Los embeddings son representaciones numéricas de información. En el contexto de este tutorial, los embeddings se generan a partir de documentos de texto, permitiendo que las máquinas procesen estos datos de una manera más eficiente. Aquí utilizamos el modelo Text Embedding Ada 002 de OpenAI para convertir textos en embeddings.
Para empezar, es fundamental asegurarte de tener una llave API de OpenAI. Esta llave permitirá generar los embeddings necesarios. Desde la terminal o al escribir tu código en Visual Studio Code, sigue estos pasos:
Importación de la clave API: Asegúrate de tener la función getOpenAIAPIKey() lista para comprobar que la llave esté disponible como una variable de ambiente.
Creación de la instancia de embeddings:
from langchain.embeddings import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")
Esta instancia procesará tus documentos para convertirlos en datos numéricos.
¿Cómo integrar los embeddings en una base de datos vectorial Chroma?
La siguiente fase es almacenar estos embeddings en una base de datos que pueda manejar operaciones complejas. Aquí es donde entra Chroma:
Inicialización de Chroma:
from langchain.vectorstores import Chroma
vector_store_chroma = Chroma.from_documents(docs, embeddings, persist_directory="chromaDocs")
Esta función toma los documentos y embeddings, y los guarda en una ubicación específica para su uso posterior.
Configuración para recrear o cargar BBDD: Es importante decidir si deseas crear una nueva base de datos cada vez o cargar una existente. Implementa una función que maneje esta lógica según tus necesidades:
El uso eficiente de cualquier base de datos y herramientas como Langchain se centra en optimizar la carga y consulta de documentos. Aquí unos consejos prácticos:
Licencias y apis: Asegúrate de que las claves API están correctas antes de ejecutar cualquier script.
Variables de entorno: Gestiona tus configuraciones delicadas como claves de API usando variables de entorno.
Persistencia del directorio: Asegúrate de que el directorio donde persistes los datos es seguro y estable.
Visualización de resultados: Aunque parezca trivial, visualizar los datos que estamos manejando retroalimenta y asegura que el proceso es correcto:
console = Console()console.print(f"Documentos en vectorStoreChroma: {len(docs)}", style="green")
Este flujo te proporciona una estructura sólida para gestionar documentos de texto y procesarlos como vectores numéricos en Chroma, maximizando el potencial de OpenAI embeddings. Aprende a integrar, manipular y sacar ventaja de estos datos ajustándolos a necesidades reales de negocio. La ciencia de datos, el machine learning, y el futuro de la IA se están construyendo sobre estos principios. ¡Sigamos explorando juntos estas formidables herramientas!
Si alguien es usuario gratuito de OpenAI no podrá cargar los datos desde la API dado el rate limit que tiene la plataforma (3 query por minuto y 200 por día). Intenté por cielo y tierra slicear los documentos, reducir el dataset y todo lo demás, pero no funcionó, se satura con 3 Documents a la vez (y el dataset genera más de 1000).
La solución será cargar el JSONL a una instancia de Colab y usar el embedding Instructor para inscrustar el dataset entero desde allí, luego lo persistiremos y descargaremos el contenido del folder a nuestro repo local.
También pueden correr el Instructor local en un tamaño menor (el base) en cpu o gpu, tomará bastante tiempo pero se ahorrarán el problema de trasladar las cosas del colab al proyecto. Se carga así
Y todo el resto del código funcionará igual, esa es la magia de LangChain.
Hola Sebastian. Estoy a torado y quisiera ver si puedes ayudarme. Hice el embedding de huggingface que sugeriste pero tengo el siguiente error. Intenté instalando con pip el paquete 'InstructorEmbedding' dentro del ambiente de poetry pero me sigue dando el mismo error. ¿Qué crees que sea?
Traceback(most recent call last):File"D:\Github\curso-langchain\hashira\conversation_ai.py", line 57,in<module>main()File"D:\Github\curso-langchain\hashira\conversation_ai.py", line 44,in main
embedding =HuggingFaceInstructEmbeddings(File"C:\Users\Miguel\AppData\Local\pypoetry\Cache\virtualenvs\hashira-twXMOMRH-py3.9\lib\site-packages\langchain\embeddings\huggingface.py", line 141,in __init__
raise ValueError("Dependencies for InstructorEmbedding not found.")from e
ValueError:DependenciesforInstructorEmbedding not found.
Muy interesante. Se me ocurre como ejercicio hacer un sistema de identificación de entradas.
Esto con la intención de obtener valores cuantitativos de entradas cualitativas en encuestas.
Por ejemplo, encuesta abierta sobre opinión del servicio.
Las posibilidades son 'quejas', 'agradecimientos', 'satisfacción', y 'critica constructiva'. Al momento de recibir valores abiertos como un comentario 'Me gusto la clase, pero me he perdido un poco en los comentarios, hay un error que no me deja hacer scroll.'
El valor obtenido no es puramente cuantitativo, pero teniendo una base con ejemplo. El modelo puede interpretar semanticamente donde encaja más y dar como resultado un porcentaje de en que respuesta esta más cercana. Con esto podemos parametrizar un dato tan ambiguo como 'que opina la gente'.
a Jan 2025:
Algunas librerías fueron deprecadas con este comando las pueden actualizar:
Dejo mi código con algunas mejoras. Para filtrar a que documentos tiene acceso el retriver y como eliminar archivos para hacer un pipeline de carga de datos al agregar archivos o actualizarlos
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
# Create an OpenAI embedding model to generate vector embeddings from textembeddings = OpenAIEmbeddings(model="text-embedding-3-small")vs_path ="vector_store"ifnot os.path.isdir(vs_path):# Create a Chroma vectorstore from a list of documents and embeddings vs = Chroma.from_documents( documents=documents, embedding=embeddings, persist_directory=vs_path
)else: vs = Chroma( embedding_function=embeddings, persist_directory=vs_path
)# Define metadata to search (filter by the field 'id')metadata_filter ={'id':2}docs = vs.similarity_search("doc", k=3,filter=metadata_filter)docs
# Convert the vectorstore into a retrievermetadata_filter ={'id':4}retriever = vs.as_retriever(search_kwargs={"k":3,"filter": metadata_filter})retriever.invoke("documentos")# Access the documents and metadata from the vectorstoreall_data = vs._collection.get()# Extract the IDs and metadataids = all_data['ids']metadatas = all_data['metadatas']# Function to filter metadata using a dictionary of attributesdeffilter_by_metadata(metadata, filter_dict):"""
Check if all key-value pairs in the filter_dict match the metadata.
If all conditions are met, return True.
"""returnall( metadata.get(key)== value
for key, value in filter_dict.items())# Dictionary with the filters to apply (multiple attributes)filter_dict ={"source":'/content/documents.jsonl',"seq_num":1}# Filter the IDs based on the filter dictionary attributesfiltered_ids =[ doc_id
for doc_id, meta inzip(ids, metadatas)if filter_by_metadata(meta, filter_dict)]# Delete the filtered IDsvs.delete(filtered_ids)print('documents:',len(vs._collection.get()['documents']))print('metadatas:',len(vs._collection.get()['metadatas']))print('ids:',len(vs._collection.get()['ids']))```from langchain.embeddings import OpenAIEmbeddingsfrom langchain.vectorstores import Chroma
\# Create an OpenAI embedding model to generate vector embeddings from textembeddings = OpenAIEmbeddings(model="text-embedding-3-small")vs\_path ="vector\_store"ifnot os.path.isdir(vs\_path):# Create a Chroma vectorstore from a list of documents and embeddings vs = Chroma.from\_documents( documents=documents, embedding=embeddings, persist\_directory=vs\_path )else: vs = Chroma( embedding\_function=embeddings, persist\_directory=vs\_path )
En los primeros tiers de la api de OpenAi hay una limitación de tokens por petición de 300.000 y generará error.
La solución es sencilla, hay que ir al model de embeddings y añadir un parametro "chunk_size"