Cargadores de documentos en LangChain: cómo meter archivos y páginas en un pipeline RAG
Cómo los cargadores convierten PDF, texto, CSV y páginas web en objetos Document, qué cargador de PDF elegir y cuándo la carga diferida ahorra memoria en carpetas grandes.
Un LLM no puede recorrer tus carpetas y absorber los archivos por su cuenta. La generación aumentada por recuperación (RAG) existe porque los modelos no conocen tus datos privados, no saben nada reciente y a veces se inventan cosas cuando les falta contexto. La solución es traer el texto adecuado en el momento de la consulta. Pero antes de todo eso, algo tiene que meter un PDF, una página web, un CSV o un archivo de Word en el pipeline. Ese trabajo le toca al cargador de documentos, una pieza fácil de pasar por alto que conviene hacer bien.
Qué hace un cargador
Un cargador lee datos de alguna fuente y los convierte a un formato que LangChain entiende. Hace de traductor. Tu material puede estar en cualquiera de estos sitios:
- Archivos de texto plano
- Archivos CSV
- Sitios web
- Documentos de Word
- Bases de datos
Todo lo que viene después del cargador espera una única forma estándar, y la función del cargador es cerrar esa brecha.
Por qué un PDF no puede ir directo al chunking
Quien empieza suele imaginar el flujo así:
PDF → Chunking → Embeddings
La realidad es más desordenada. Un PDF no es texto. Dentro hay fuentes, imágenes, datos de maquetación, tablas, encabezados y pies de página, y metadatos. Un chunker solo trabaja con texto, así que primero alguien tiene que sacar las palabras. El flujo real se parece más a esto:
PDF → Document Loader → Text Extraction → Chunking → Embeddings
El cargador extrae el texto y lo empaqueta en un formato común.
Los cargadores que más vas a ver
LangChain trae cargadores para muchas fuentes. La entrada cambia, pero el principio no: leer de algún sitio y producir Documents de LangChain. Estos son los que usarás con más frecuencia:
- TextLoader se encarga de archivos .txt planos.
- PyPDFLoader se encarga de los PDF.
- WebBaseLoader se encarga de páginas web y URL.
- CSVLoader se encarga de archivos CSV.
- DirectoryLoader se encarga de muchos archivos dentro de una carpeta.
Un solo tipo de salida: Document
Sea cual sea el cargador, casi siempre recibes una lista de objetos Document. Cada uno lleva un texto y algunos datos sobre su procedencia:
Document(
page_content="Employees are eligible for 24 paid leaves per year.",
metadata={
"source": "employee_policy.pdf",
"page": 5
}
)
Hay dos campos clave. page_content es el texto en sí, y metadata describe la fuente, aquí el nombre del archivo y el número de página. Esta forma estándar resulta práctica porque a las etapas posteriores no les importa de dónde salieron los datos. Un cargador de PDF y uno web te dan Documents, y el paso de chunking los trata igual.
TextLoader
La opción más sencilla lee archivos de texto plano. Primero, impórtalo:
from langchain_community.document_loaders import TextLoader
Luego apúntalo a un archivo, cárgalo e imprime el resultado:
loader = TextLoader("notes.txt")documents = loader.load()print(documents)
Obtienes una lista:
[
Document(...)
]
Incluso con un solo archivo recibes una lista, lo que mantiene la interfaz coherente. Cada elemento es un Document.
Úsalo cuando tus datos ya son texto: logs, notas, exportaciones de texto o datasets limpios. Eso sí, es muy básico. No sabe analizar PDF, leer tablas, entender la maquetación ni extraer imágenes. Si la fuente no es texto, elige otra cosa.
PyPDFLoader
Los PDF son probablemente la fuente más habitual en proyectos RAG, y PyPDFLoader es el punto de partida típico. Impórtalo:
from langchain_community.document_loaders import PyPDFLoader
Después carga un informe:
loader = PyPDFLoader("annual_report.pdf")documents = loader.load()
Supón que el archivo tiene 25 páginas. Si cuentas el resultado:
len(documents)
obtienes:
25
Cada página se convierte en su propio Document. Si miras el primero:
documents[0]
verás esto:
Document(
page_content="Page 1 text...",
metadata={
"source": "annual_report.pdf",
"page": 0
}
)
Así que un PDF de 25 páginas da 25 Documents. Por debajo, este cargador usa la biblioteca PyPDF. Funciona bien con PDF sencillos, pero sufre con maquetaciones complejas, páginas a varias columnas, tablas y escaneos, y por eso importa qué cargador de PDF eliges.
Cómo elegir un cargador de PDF
No hay un cargador que sea el mejor para todos los archivos. Un mapa aproximado:
- PyPDFLoader va bien con PDF sencillos basados en texto.
- PDFPlumberLoader encaja con PDF que tienen tablas y maquetación estructurada.
- PyMuPDFLoader es rápido y una buena opción de uso general.
- UnstructuredPDFLoader apunta a documentos empresariales complejos.
- AmazonTextractPDFLoader cubre escaneos y trabajos con mucho OCR.
Una regla práctica: empieza con PyPDF. Si el texto extraído sale mal, pasa a PyMuPDF o Unstructured. Si el documento es un escaneo, usa un servicio de OCR como Textract.
DirectoryLoader
Cargar un archivo es trivial. Cargar a mano 5.000 PDF o 10.000 archivos de texto no lo es, y para eso existe DirectoryLoader. Impórtalo:
from langchain_community.document_loaders import DirectoryLoader
Luego pásale una carpeta y un patrón glob:
loader = DirectoryLoader(
"data/",
glob="**/*.pdf"
)documents = loader.load()
Con eso recoge todos los PDF del directorio. Imagina una estructura como esta:
data/
├── report1.pdf
├── report2.pdf
├── report3.pdf
El cargador recorre cada archivo que coincide y lo carga, y obtienes:
[
Document(...),
Document(...),
...
]
En una carpeta grande pueden ser cientos o miles de Documents.
El problema de las carpetas enormes
Imagina 20.000 PDF, o 100.000 archivos de texto, y esta llamada:
documents = loader.load()
LangChain lo lee todo en memoria de golpe. Es la carga ansiosa (eager). Es fácil de usar y sirve para datasets pequeños, pero consume mucha memoria y ralentiza el arranque.
Ansiosa frente a diferida
Hay una alternativa:
loader.lazy_load()
Con la versión ansiosa, todo se carga a la vez:
documents = loader.load()
y el tipo de retorno es:
List[Document]
La versión diferida (lazy) solo produce documentos cuando hacen falta:
documents = loader.lazy_load()
y devuelve un generador:
Generator[Document]
Piensa en el streaming de vídeo. Un servicio no descarga la película entera antes de que pulses play; te va enviando los datos según los necesitas. La carga diferida funciona igual.
Usa load() para colecciones pequeñas o medianas y para prototipos. Usa lazy_load() para colecciones grandes y entornos con poca memoria.
WebBaseLoader
No todo el conocimiento vive en archivos. A veces está en un sitio web, y de eso se encarga WebBaseLoader. Impórtalo:
from langchain_community.document_loaders import WebBaseLoader
Luego pásale una URL:
loader = WebBaseLoader(
"https://python.langchain.com"
)documents = loader.load()
Internamente usa BeautifulSoup para analizar el HTML y sacar el texto, lo que sirve para blogs, documentación, artículos, bases de conocimiento y webs corporativas.
Donde mejor funciona es en páginas estáticas. Los sitios cargados de JavaScript, el contenido dinámico y el renderizado en el cliente le dan problemas. Para esos casos, SeleniumURLLoader puede renderizar la página en un navegador antes de extraer nada.
CSVLoader
Los datos estructurados suelen llegar en CSV. Toma un pequeño archivo de empleados:
employee_id,name,department
1,John,Engineering
2,Sarah,HR
Importa el cargador:
from langchain_community.document_loaders import CSVLoader
Y carga el archivo:
loader = CSVLoader(
file_path="employees.csv"
)documents = loader.load()
Cada fila se convierte en un Document, con los nombres de las columnas y sus valores escritos como texto y el número de fila guardado en los metadatos:
Document(
page_content="""
employee_id: 1
name: John
department: Engineering
""",
metadata={
"source": "employees.csv",
"row": 0
}
)
Encaja con catálogos de productos, registros de clientes, inventario, registros financieros y datos de negocio parecidos.
Tres ideas para quedarse
- Todo pipeline RAG empieza por la carga. Antes del chunking, los embeddings o la recuperación, los datos tienen que entrar.
- Cada fuente necesita su cargador: los archivos de texto usan TextLoader, los PDF PyPDFLoader, las webs WebBaseLoader, los CSV CSVLoader y las carpetas DirectoryLoader.
- Casi todo acaba siendo un objeto Document, y esa forma común permite que el resto del pipeline funcione de manera coherente.
El catálogo completo de cargadores está en la documentación de integraciones de LangChain.
Una vez cargados los documentos, el siguiente rompecabezas es cómo dividirlos: por caracteres, palabras, frases, párrafos o tokens, y con qué tamaño para un archivo de 100 páginas. Si cortas demasiado pequeño, pierdes contexto. Si cortas demasiado grande, recuperas ruido. Esa decisión merece un análisis propio y cuidadoso, porque es el arte de trocear documentos sin romper tu sistema RAG.