Fragmentación de Documentos con TextSplitter en Langsteam

Clase 17 de 37Curso de LangChain

Contenido del curso

Introducción a LangChain

Manejo de documentos con índices

Embeddings y bases de datos vectoriales

Chats y memoria con LangChain

Resumen

Fragmentar documentos es uno de los pasos más importantes cuando construyes un sistema de búsqueda semántica o un índice de información. Sin una buena estrategia de partición, los modelos de lenguaje no pueden procesar textos extensos de forma eficiente. Aquí se explica cómo usar los Text Splitters de LangChain para convertir documentos grandes en fragmentos manejables, qué hiperparámetros ajustar y cuáles son las recomendaciones de la literatura.

¿Qué es un Text Splitter y por qué lo necesitas?

Una vez que los datos están cargados e importados, el siguiente paso es partir ese "gran libro" en capítulos y subcapítulos más pequeños. Los Text Splitters son document transformers dentro de LangChain: toman documentos completos y los dividen en fragmentos más pequeños y legibles [0:12].

La analogía es clara: si tienes un PDF de dieciocho páginas, cada página es un documento. Pero dieciocho documentos grandes no son prácticos para indexar. Al aplicar el splitter, esos dieciocho documentos se convierten en ciento cuarenta y dos fragmentos más pequeños, listos para ser indexados y consultados con mayor precisión [3:30].

¿Cómo funciona el Recursive Character Text Splitter?

El Recursive Character Text Splitter se importa desde la librería text_splitter de LangChain. Su característica principal es que respeta los límites naturales del texto: intenta no cortar oraciones a la mitad [2:22]. Siempre busca que una oración termine antes de iniciar un nuevo fragmento, lo que hace que cada pedazo de texto sea coherente y comprensible.

python from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, length_function=len )

documents = text_splitter.split_documents(data)

El método split_documents recibe data, que es una lista de objetos document de LangChain. Cada uno de estos objetos tiene dos atributos fundamentales: page_content (el texto) y metadata (información como la fuente del archivo o el número de página) [3:50].

¿Qué significan chunk size y chunk overlap?

Estos son los dos hiperparámetros clave al fragmentar texto [4:30]:

  • Chunk size: define el tamaño máximo de cada fragmento. La length_function determina cómo se mide ese tamaño. Si usas len, cada carácter cuenta como una unidad. También puedes usar funciones más avanzadas, como un tokenizador de OpenAI o de Hugging Face, para contar tokens en lugar de caracteres [1:08].
  • Chunk overlap: establece cuántos caracteres se repiten entre un fragmento y el siguiente. Esto es importante porque a veces la respuesta a una pregunta está justo en el límite entre dos fragmentos. Con el overlap, cada pedazo incluye un poco del texto anterior y del siguiente, creando una conexión entre ellos [1:42].

¿Cuáles son los valores recomendados para fragmentar documentos?

La literatura y la práctica sugieren mantener el chunk size alrededor de quinientos tokens [5:06]. La razón tiene que ver con el paso siguiente en el proceso: la creación de embeddings. Los modelos de embeddings tienen un límite en la cantidad de tokens que aceptan como entrada.

  • En modelos de Sentence Transformers en Hugging Face, el máximo ronda los doscientos cincuenta tokens [5:40].
  • En el caso de OpenAI, el límite es de aproximadamente ocho mil tokens [5:50].
  • Estos números van creciendo con el tiempo, y en el futuro los índices podrán ser más grandes.

Para el chunk overlap, la recomendación es que represente entre un diez y un veinte por ciento del chunk size [6:18]. Esto permite que los documentos no sean demasiado repetitivos, pero mantengan conexión entre sí. Por ejemplo:

  • Chunk size de 500 con overlap de 50.
  • Chunk size de 1000 con overlap de 100.

python text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, length_function=len )

documents = text_splitter.split_documents(data)

Con estos valores, los dieciocho documentos originales se convierten en doscientos cuarenta y uno [7:08]. Cada elemento de la lista resultante sigue siendo un objeto document de LangChain con su page_content y metadata intactos.

¿Cómo explorar los fragmentos generados?

Una vez creados los fragmentos, conviene inspeccionarlos para verificar que todo funcione correctamente:

  • len(documents) muestra cuántos fragmentos se generaron.
  • type(documents) confirma que es una lista.
  • type(documents[0]) verifica que cada elemento es un document.
  • documents[0].page_content muestra el texto del primer fragmento.
  • La metadata indica la fuente original y la página correspondiente [4:00].

Elegir los valores correctos de chunk size y chunk overlap no es una ciencia exacta. Como se menciona, es un proceso de "atínale al precio": hay que experimentar con diferentes combinaciones y evaluar cuál funciona mejor para cada caso de uso. ¿Qué valores has probado en tus proyectos y cuáles te han dado mejores resultados?