Contenido del curso

Introducción a LangChain

Chats y memoria con LangChain

Cargador JSONL personalizado en LangChain

Resumen

Cuando trabajas con LangChain y tus archivos no caben en los formatos soportados por defecto, necesitas un cargador de datos personalizado en LangChain. Esta guía muestra cómo construir un loader propio para archivos JSON Lines (JSONL), un formato que la librería aún no soporta de forma nativa, y cómo controlar la metadata exactamente como tú la quieres.

¿Por qué construir tu propio loader en LangChain?

LangChain trae cargadores listos para PDF, CSV, Word y otros formatos, pero deja afuera casos comunes como JSONL. Crear tu propia clase resuelve dos problemas concretos: cargar formatos no soportados y guardar la metadata con la estructura exacta que tu pipeline necesita.

¿Qué es un archivo JSONL? Es un archivo donde cada línea es un diccionario JSON independiente. Si tienes tres líneas, tienes tres diccionarios separados, uno por renglón.

En el ejemplo se usa la documentación de Transformers de Hugging Face como fuente. Cada línea del JSONL contiene un fragmento de documentación con campos como text, title, repo_owner y repo_name [00:24].

¿Cómo se estructura la clase Transformer JSONL Loader?

La clase se construye en Python con la lógica mínima de un loader de LangChain: un constructor que recibe la ruta del archivo y un método load que devuelve una lista de objetos Document.

¿Qué hace el método init del loader?

El constructor __init__ pide un único argumento, file_paths, tipado como string. Lo guarda en self.file_paths para que el método load pueda usarlo después. Nada más, nada menos [01:30].

¿Cómo funciona el método load para JSONL?

El método load retorna una lista de Document de LangChain. Para tipar bien la salida se importa List desde la librería typing. Luego se abre el archivo con jsonlines.open(self.file_paths) y se itera línea por línea con un objeto llamado reader, que es la convención del paquete [02:30].

Dentro del loop, cada línea se trata como un diccionario de Python. La extracción de campos sigue tres pasos:

  • Extraer el page_content con object.get("text", ""), que devuelve string vacío si la clave no existe.
  • Construir un diccionario metadata con title, repo_owner y repo_name, también con .get() para evitar errores cuando falte una clave.
  • Crear un Document(page_content=page_content, metadata=metadata) y agregarlo a la lista documents.

Usar el método .get() de los diccionarios es la clave para que el loader no truene cuando una línea del JSONL viene incompleta. En lugar de lanzar un KeyError, devuelve un valor vacío y sigue.

¿Cómo se prueba el loader con la documentación de Transformers?

Una vez definida la clase, instancias el loader pasando la ruta al archivo transformers_docs.jsonl y llamas a load(). El resultado se guarda en data, que es la lista de documentos lista para usar en cualquier pipeline de LangChain.

python from langchain.schema import Document import jsonlines from typing import List

class TransformerDocsJSONLLoader: def init(self, file_paths: str): self.file_paths = file_paths

def load(self) -> List[Document]: documents = [] with jsonlines.open(self.file_paths) as reader: for object in reader: page_content = object.get("text", "") metadata = { "title": object.get("title", ""), "repo_owner": object.get("repo_owner", ""), "repo_name": object.get("repo_name", ""), } documents.append( Document(page_content=page_content, metadata=metadata) ) return documents

loader = TransformerDocsJSONLLoader("transformers_docs.jsonl") data = loader.load()

¿Por qué falla si paso los argumentos sin nombre? Porque Document espera argumentos con nombre. Si los pasas por posición, Python lanza un error. Siempre usa page_content= y metadata= de forma explícita [05:40].

¿Cómo se ve la metadata personalizada en el resultado?

Al recorrer data con un for doc in data: print(doc), cada documento muestra primero el page_content con la documentación cruda, donde aparecen derechos, URL y luego el contenido específico de cada sección. Al final, la metadata aparece con tres campos exactos:

  • title: por ejemplo, la documentación de Accelerate.
  • repo_owner: Hugging Face.
  • repo_name: Transformers.

Ese control sobre la metadata es lo que justifica escribir un loader propio. Puedes agregar más campos, renombrarlos o transformarlos antes de que entren al Document, algo que un loader genérico no te permite hacer con tanta libertad.

¿Qué habilidades técnicas se trabajan en este loader?

Más allá de LangChain, este ejercicio integra varios conceptos prácticos de Python aplicados a datos para LLMs:

  • Programación orientada a objetos con clases, __init__ y métodos de instancia [01:20].
  • Type hints con typing.List y anotaciones de retorno para que el código sea más legible y fácil de mantener.
  • Manejo de diccionarios con .get(), una práctica que evita excepciones cuando trabajas con datos heterogéneos.
  • Uso del paquete jsonlines, que abre archivos JSONL como un iterador y entrega cada línea ya parseada como diccionario.
  • El objeto Document de LangChain, que es la unidad básica que viaja por toda la cadena de retrieval, embeddings y generación.

La idea grande detrás de todo esto: si LangChain no tiene el loader que necesitas, puedes construirlo en menos de 20 líneas y mantener el control total sobre cómo entran tus datos al pipeline. ¿Qué formato te gustaría cargar con tu propio loader? Cuéntame en los comentarios.