Generación aumentada por recuperación en documentos de Notion mediante LangChain
Este artículo se publicó originalmente en The Sequence y se vuelve a publicar aquí con permiso.
¿Tienes documentos de Notion que quieres pedirle a un modelo de lenguaje que consulte por ti? Construyamos una aplicación básica de tipo generación aumentada por recuperación (RAG) usando LangChain y Milvus. Usamos LangChain como marco operativo y Milvus como motor de similitud. Puedes encontrar el notebook de este blog en colab.
En este tutorial abordamos lo siguiente:
Revisión de Self Querying de LangChain
Trabajar con documentos de Notion en LangChain
Ingerir tus documentos de Notion
Almacenar tus documentos de Notion
Consultar tus documentos de Notion
Resumen de cómo consultar documentos de Notion con LangChain y Milvus
Revisión de self querying de LangChain
Recientemente cubrimos cómo usar LangChain para consultar una base de datos vectorial, una introducción a lo que LangChain denomina “self-querying”. Entre bastidores, la funcionalidad de self-querying en LangChain construye una arquitectura RAG básica como la que se muestra a continuación.
Trabajar con documentos de Notion en LangChain
Dividiré esto en tres pasos: ingesta, almacenamiento y consulta. La ingesta cubre obtener tus documentos de Notion y cargar el contenido en memoria. El almacenamiento cubre poner en marcha una base de datos vectorial (Milvus), vectorizar los documentos, colocarlos en la base de datos vectorial, y la consulta cubre hacer una pregunta sobre tus documentos de Notion.
Ingerir tus documentos de Notion
Usamos el NotionDirectoryLoader de LangChain para cargar los documentos en memoria. Proporcionamos la ruta a nuestros documentos y llamamos a la función load para obtenerlos. Una vez que los documentos se cargan en memoria, tomamos el archivo markdown, en este caso, solo uno.
A continuación, usamos el divisor de texto de encabezados markdown de LangChain. Le proporcionamos una lista de separadores sobre los que dividir y luego pasamos el md_file nombrado anteriormente para obtener nuestras divisiones. Cuando definas tu lista headers_to_split_on, asegúrate de usar los encabezados que usas en tu documento de Notion, no solo los ejemplos que proporcioné.
# Load Notion page as a markdownfile file
from langchain.document_loaders import NotionDirectoryLoader
path='./notion_docs'
loader = NotionDirectoryLoader(path)
docs = loader.load()
md_file=docs[0].page_content
# Let's create groups based on the section headers in our page
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers_to_split_on = [
("##", "Section"),
]
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
md_header_splits = markdown_splitter.split_text(md_file)
En el código siguiente, realizamos y examinamos nuestras divisiones. Usamos el RecursiveCharacterTextSplitter de LangChain, que prueba algunos caracteres diferentes sobre los que dividir. Los cuatro caracteres predeterminados que comprueba son un salto de línea, un doble salto de línea, un espacio o ningún espacio. También puedes optar por pasar los tuyos propios con un parámetro separators, que no usamos esta vez.
Los dos hiperparámetros esenciales que debes definir al fragmentar tu documento de Notion son el tamaño del fragmento y el solapamiento del fragmento. Para este ejemplo, usamos un tamaño de fragmento de 64 y un solapamiento de 8. En el futuro, cubriremos cómo probar estos valores y encontrar buenos valores. Una vez que definimos el divisor de texto, llamamos a sus funciones split_documents para obtener todas nuestras divisiones de Document.
# Definir nuestro divisor de texto
from langchain.text_splitter import RecursiveCharacterTextSplitter
chunk_size = 64
chunk_overlap = 8
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
all_splits = text_splitter.split_documents(md_header_splits)
all_splits
La imagen de abajo muestra algunos objetos Document de la división anterior. Observa que incluye el contenido de la página y los metadatos, que incluyen la sección de la que se extrae el contenido.
Almacenar tus documentos de Notion
Con todos los documentos cargados y divididos, es hora de almacenar esas divisiones. Primero, iniciamos nuestra base de datos vectorial directamente en nuestro notebook usando Milvus Lite. También necesitamos obtener los módulos necesarios de LangChain: Milvus y OpenAIEmbeddings.
Después de las importaciones y de poner en marcha la base de datos vectorial, usamos el módulo Milvus de LangChain para crear una colección a partir de nuestros documentos. Necesitamos pasarle la lista de documentos, los embeddings a usar, los parámetros de conexión y (opcionalmente) un nombre de colección.
from milvus import default_server
default_server.start()
from langchain.vectorstores import Milvus
from langchain.embeddings import OpenAIEmbeddings
vectordb = Milvus.from_documents(documents=all_splits,
embedding=OpenAIEmbeddings(),
connection_args={"host": "127.0.0.1", "port": default_server.listen_port},
collection_name="EngineeringNotionDoc")
Consultar tus documentos de Notion
Todo está configurado y listo para realizar consultas. Para esta sección, necesitamos tres importaciones más de LangChain: OpenAI para acceder a GPT, el SelfQueryRetriever para crear nuestro RAG básico, y el objeto “Attribute info” para pasar los metadatos. Para empezar, definimos algunos metadatos. Para este ejemplo, solo las secciones que hemos estado usando hasta ahora.
También le damos al recuperador de autoconsulta una descripción de los documentos. En este caso, simplemente “secciones principales del documento”. Justo antes de instanciar nuestro recuperador de autoconsulta, configuramos una versión de GPT con temperatura 0 en una variable llm. Con el LLM, la base de datos vectorial, la descripción del documento y los campos de metadatos listos, definimos el recuperador de autoconsulta.
from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
metadata_fields_info = [
AttributeInfo(
name="Section",
description="Part of the document that the text comes from",
type="string or list[string]"
),
]
document_content_description = "Major sections of the document"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(llm, vectordb, document_content_description, metadata_fields_info, verbose=True)
retriever.get_relevant_documents("What makes a distinguished engineer?")
Mi ejemplo elegido es “¿Qué hace a un ingeniero distinguido?” A partir de la respuesta en la imagen de abajo, podemos ver los fragmentos más similares semánticamente devueltos. Como podemos ver, el hecho de que sean las respuestas más similares semánticamente no significa que sean las correctas. En futuras entregas, cubriremos cómo experimentar con la fragmentación y otras técnicas para mejorar nuestras respuestas.
Resumen de la consulta de documentos de Notion en LangChain
En este tutorial, cubrimos cómo cargar y analizar un documento de Notion en secciones para consultarlo en una arquitectura RAG básica. Usamos LangChain como marco de orquestación y Milvus como nuestra base de datos vectorial. LangChain une las piezas, y Milvus impulsa la búsqueda por similitud.
Para llevar este tutorial más allá, hay muchas cosas que podemos probar. Ejemplos de dos hiperparámetros que conviene comprobar son el tamaño del fragmento y el tamaño de solapamiento entre fragmentos. Podemos usarlos para ajustar nuestras respuestas y su apariencia. Además del ajuste, también necesitamos evaluar las respuestas.
En futuros tutoriales, veremos diferentes estrategias de fragmentación. No solo eso, sino que también profundizaremos en las incrustaciones, las estrategias de división y la evaluación.
Sigue leyendo
Stop Building AI Data Infra for the Wrong Stage
Learn how AI data infrastructure should evolve from prototype to enterprise scale, and when Vector Lakebase becomes the right architecture for AI apps.

Similarity Metrics for Vector Search
Exploring five similarity metrics for vector search: L2 or Euclidean distance, cosine distance, inner product, and hamming distance.

Building RAG Pipelines for Real-Time Data with Cloudera and Milvus
explore how Cloudera can be integrated with Milvus to effectively implement some of the key functionalities of RAG pipelines.



