Clase Document en LangChain
En el ecosistema de LangChain, toda la información textual se estructura utilizando la clase Document
, que actúa como el contenedor fundamental para trabajar con textos en aplicaciones de RAG. Esta clase proporciona una interfaz estandarizada que permite a LangChain procesar, indexar y recuperar información de manera consistente, independientemente del origen de los datos.
La clase Document
se encuentra en el módulo langchain_core.documents
y representa la unidad básica de información con la que trabajaremos a lo largo de todo el módulo. Cada documento encapsula tanto el contenido textual como los metadatos asociados, creando una estructura rica en información que facilita las operaciones posteriores de búsqueda y recuperación.
from langchain_core.documents import Document
# Crear un documento básico
documento = Document(
page_content="LangChain es un framework para desarrollar aplicaciones con modelos de lenguaje.",
metadata={"fuente": "documentacion_oficial", "fecha": "2024-01-15"}
)
print(f"Contenido: {documento.page_content}")
print(f"Metadatos: {documento.metadata}")
Estructura interna de Document
La clase Document
está diseñada con una arquitectura minimalista pero efectiva. Internamente, mantiene dos atributos principales que definen completamente la información que contiene. Esta simplicidad no es casual, sino que responde a la necesidad de crear una estructura que sea fácil de serializar, transmitir y procesar por diferentes componentes del sistema.
El diseño inmutable de los documentos garantiza la integridad de los datos durante todo el pipeline de procesamiento. Una vez creado un documento, sus propiedades fundamentales no pueden modificarse accidentalmente, lo que previene errores comunes en aplicaciones complejas donde múltiples componentes manipulan la misma información.
# Explorar la estructura de un documento
documento = Document(
page_content="Python es un lenguaje de programación versátil y potente.",
metadata={
"autor": "Guido van Rossum",
"año": 1991,
"tipo": "lenguaje_programacion",
"paradigmas": ["orientado_objetos", "funcional", "imperativo"]
}
)
# Acceder a los atributos principales
print(f"Tipo de page_content: {type(documento.page_content)}")
print(f"Tipo de metadata: {type(documento.metadata)}")
print(f"Claves de metadata: {list(documento.metadata.keys())}")
Creación de documentos desde diferentes fuentes
La flexibilidad de la clase Document
permite crear instancias desde múltiples tipos de fuentes de información. Esta capacidad es fundamental para construir sistemas RAG que puedan integrar datos heterogéneos de manera uniforme.
Desde texto simple:
# Documento con contenido mínimo
doc_simple = Document(page_content="Este es un texto de ejemplo.")
# Documento con metadatos básicos
doc_con_metadata = Document(
page_content="Las funciones lambda en Python permiten crear funciones anónimas.",
metadata={"tema": "programacion", "dificultad": "intermedio"}
)
Desde estructuras de datos complejas:
# Simular datos de una API o base de datos
datos_articulo = {
"titulo": "Introducción a Machine Learning",
"contenido": "El aprendizaje automático es una rama de la inteligencia artificial...",
"autor": "Dr. Ana García",
"fecha_publicacion": "2024-03-10",
"tags": ["ML", "IA", "Python"],
"categoria": "tecnologia"
}
# Crear documento estructurado
documento_articulo = Document(
page_content=f"{datos_articulo['titulo']}\n\n{datos_articulo['contenido']}",
metadata={
"autor": datos_articulo["autor"],
"fecha": datos_articulo["fecha_publicacion"],
"tags": datos_articulo["tags"],
"categoria": datos_articulo["categoria"],
"tipo_documento": "articulo"
}
)
Manipulación y transformación de documentos
Los documentos en LangChain están diseñados para ser inmutables en su estructura básica, pero esto no impide crear nuevas versiones modificadas cuando sea necesario. Esta aproximación garantiza la trazabilidad y previene modificaciones accidentales durante el procesamiento.
# Documento original
doc_original = Document(
page_content="FastAPI es un framework web moderno para Python.",
metadata={"framework": "FastAPI", "lenguaje": "Python"}
)
# Crear una versión enriquecida
doc_enriquecido = Document(
page_content=doc_original.page_content,
metadata={
**doc_original.metadata, # Mantener metadatos originales
"version": "0.104.1",
"fecha_actualizacion": "2024-01-20",
"rendimiento": "alto"
}
)
print(f"Metadatos originales: {len(doc_original.metadata)} elementos")
print(f"Metadatos enriquecidos: {len(doc_enriquecido.metadata)} elementos")
Trabajando con colecciones de documentos
En aplicaciones RAG reales, raramente trabajamos con documentos individuales. La clase Document
está optimizada para funcionar eficientemente en colecciones grandes, donde cada documento mantiene su identidad pero puede procesarse junto con otros de manera coordinada.
# Crear una colección de documentos relacionados
documentos_python = [
Document(
page_content="Las listas en Python son estructuras de datos mutables y ordenadas.",
metadata={"tema": "estructuras_datos", "tipo": "lista", "nivel": "basico"}
),
Document(
page_content="Los diccionarios permiten almacenar pares clave-valor de manera eficiente.",
metadata={"tema": "estructuras_datos", "tipo": "diccionario", "nivel": "basico"}
),
Document(
page_content="Las clases en Python implementan el paradigma de programación orientada a objetos.",
metadata={"tema": "poo", "tipo": "clase", "nivel": "intermedio"}
)
]
# Operaciones sobre la colección
temas_unicos = set(doc.metadata.get("tema") for doc in documentos_python)
documentos_basicos = [doc for doc in documentos_python if doc.metadata.get("nivel") == "basico"]
print(f"Temas encontrados: {temas_unicos}")
print(f"Documentos básicos: {len(documentos_basicos)}")
Serialización y persistencia
La clase Document
incluye métodos nativos para serialización, lo que facilita el almacenamiento y la transmisión de documentos entre diferentes componentes del sistema. Esta capacidad es esencial para construir aplicaciones escalables que requieran persistir grandes volúmenes de documentos.
import json
# Crear documento para serializar
documento = Document(
page_content="Django es un framework web de alto nivel para Python.",
metadata={
"framework": "Django",
"tipo": "web",
"licencia": "BSD",
"primera_version": "2005-07-15"
}
)
# Serializar a diccionario
doc_dict = {
"page_content": documento.page_content,
"metadata": documento.metadata
}
# Convertir a JSON
doc_json = json.dumps(doc_dict, ensure_ascii=False, indent=2)
print("Documento serializado:")
print(doc_json)
# Deserializar desde JSON
doc_desde_json = json.loads(doc_json)
documento_restaurado = Document(
page_content=doc_desde_json["page_content"],
metadata=doc_desde_json["metadata"]
)
print(f"\nDocumento restaurado correctamente: {documento_restaurado.page_content[:50]}...")
La clase Document
establece los cimientos sobre los que se construye todo el sistema de procesamiento de información en LangChain. Su diseño simple pero robusto permite manejar desde casos de uso básicos hasta aplicaciones empresariales complejas, manteniendo siempre la consistencia y la integridad de los datos.
page_content y metadata
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
Los dos atributos fundamentales de la clase Document
definen completamente la información que contiene cada instancia. El page_content almacena el texto principal que será procesado por los modelos de lenguaje, mientras que metadata proporciona contexto adicional que enriquece la información y facilita operaciones avanzadas como filtrado y clasificación.
El atributo page_content
El page_content
es una cadena de texto que contiene la información principal del documento. Este atributo debe ser tratado como el contenido que será directamente procesado por los modelos de lenguaje durante las operaciones de búsqueda y generación de respuestas.
from langchain_core.documents import Document
# Ejemplo básico de page_content
documento = Document(page_content="Las funciones en Python pueden recibir argumentos por defecto.")
# Acceder al contenido
print(f"Contenido: {documento.page_content}")
print(f"Longitud: {len(documento.page_content)} caracteres")
print(f"Tipo: {type(documento.page_content)}")
El contenido puede incluir texto estructurado con saltos de línea, lo que es especialmente útil cuando trabajamos con documentos que mantienen formato específico:
# Documento con estructura de párrafos
contenido_estructurado = """Título: Programación Funcional en Python
La programación funcional es un paradigma que trata la computación como la evaluación de funciones matemáticas.
Características principales:
- Inmutabilidad de datos
- Funciones como ciudadanos de primera clase
- Ausencia de efectos secundarios"""
documento_estructurado = Document(
page_content=contenido_estructurado,
metadata={"tipo": "tutorial", "formato": "texto_plano"}
)
print(documento_estructurado.page_content)
El atributo metadata
Los metadatos proporcionan información contextual sobre el documento que no forma parte del contenido principal pero resulta crucial para el procesamiento inteligente. Este atributo es un diccionario Python que puede contener cualquier información adicional relevante.
# Ejemplo completo de metadatos
documento_completo = Document(
page_content="NumPy es la biblioteca fundamental para computación científica en Python.",
metadata={
"biblioteca": "NumPy",
"lenguaje": "Python",
"categoria": "computacion_cientifica",
"version_minima": "1.21.0",
"dependencias": ["Python >= 3.8"],
"fecha_creacion": "2024-01-15",
"autor": "Equipo NumPy",
"nivel_dificultad": "intermedio",
"palabras_clave": ["arrays", "matrices", "vectorizacion"]
}
)
# Explorar los metadatos
print("Metadatos disponibles:")
for clave, valor in documento_completo.metadata.items():
print(f" {clave}: {valor}")
Tipos de datos en metadata
Los metadatos pueden contener diversos tipos de datos Python, lo que proporciona flexibilidad para almacenar información estructurada:
# Metadatos con diferentes tipos de datos
documento_mixto = Document(
page_content="Flask es un microframework web para Python.",
metadata={
"nombre": "Flask", # string
"es_microframework": True, # boolean
"año_creacion": 2010, # integer
"popularidad": 8.5, # float
"frameworks_relacionados": [ # list
"Django", "FastAPI", "Bottle"
],
"configuracion": { # dict anidado
"debug": True,
"puerto": 5000,
"host": "localhost"
},
"tags": {"web", "python", "micro"}, # set (se convierte a list)
"ultima_actualizacion": None # None
}
)
# Acceder a diferentes tipos
print(f"Es microframework: {documento_mixto.metadata['es_microframework']}")
print(f"Frameworks relacionados: {documento_mixto.metadata['frameworks_relacionados']}")
print(f"Puerto por defecto: {documento_mixto.metadata['configuracion']['puerto']}")
Patrones comunes de metadata
Existen patrones establecidos para organizar metadatos que facilitan el procesamiento posterior y la integración con otros componentes de LangChain:
Información de origen:
documento_origen = Document(
page_content="La documentación oficial de Python está disponible en docs.python.org",
metadata={
"fuente": "docs.python.org",
"url": "https://docs.python.org/3/tutorial/",
"fecha_acceso": "2024-01-20",
"seccion": "tutorial",
"idioma": "es"
}
)
Clasificación y categorización:
documento_clasificado = Document(
page_content="Los decoradores en Python permiten modificar el comportamiento de funciones.",
metadata={
"categoria": "programacion",
"subcategoria": "python_avanzado",
"dificultad": "intermedio",
"tiempo_lectura": 5, # minutos
"prerequisitos": ["funciones", "closures"]
}
)
Información de procesamiento:
documento_procesado = Document(
page_content="Machine Learning es una rama de la inteligencia artificial.",
metadata={
"procesado_en": "2024-01-20T10:30:00Z",
"version_procesador": "1.0.2",
"tokens_estimados": 12,
"idioma_detectado": "es",
"confianza_idioma": 0.95
}
)
Manipulación avanzada de metadata
Los metadatos pueden ser modificados y enriquecidos durante el procesamiento, creando nuevas versiones de documentos con información adicional:
# Documento base
doc_base = Document(
page_content="Pandas facilita la manipulación y análisis de datos en Python.",
metadata={"biblioteca": "Pandas", "lenguaje": "Python"}
)
# Función para enriquecer metadatos
def enriquecer_documento(documento, informacion_adicional):
return Document(
page_content=documento.page_content,
metadata={
**documento.metadata,
**informacion_adicional,
"enriquecido": True,
"timestamp_enriquecimiento": "2024-01-20T15:45:00Z"
}
)
# Aplicar enriquecimiento
doc_enriquecido = enriquecer_documento(doc_base, {
"casos_uso": ["analisis_datos", "limpieza_datos", "visualizacion"],
"complejidad": "media",
"documentacion_url": "https://pandas.pydata.org/docs/"
})
print("Metadatos enriquecidos:")
for clave, valor in doc_enriquecido.metadata.items():
print(f" {clave}: {valor}")
Filtrado por metadata
Una de las ventajas principales de mantener metadatos estructurados es la capacidad de filtrar colecciones de documentos de manera eficiente:
# Colección de documentos con metadatos diversos
documentos_biblioteca = [
Document(
page_content="Requests simplifica las peticiones HTTP en Python.",
metadata={"biblioteca": "Requests", "categoria": "http", "dificultad": "basico"}
),
Document(
page_content="SQLAlchemy es un ORM potente para bases de datos en Python.",
metadata={"biblioteca": "SQLAlchemy", "categoria": "base_datos", "dificultad": "avanzado"}
),
Document(
page_content="Beautiful Soup facilita el web scraping en Python.",
metadata={"biblioteca": "Beautiful Soup", "categoria": "web_scraping", "dificultad": "intermedio"}
)
]
# Filtrar por dificultad
docs_basicos = [doc for doc in documentos_biblioteca
if doc.metadata.get("dificultad") == "basico"]
# Filtrar por categoría
docs_web = [doc for doc in documentos_biblioteca
if "web" in doc.metadata.get("categoria", "")]
print(f"Documentos básicos: {len(docs_basicos)}")
print(f"Documentos web: {len(docs_web)}")
# Filtrado más complejo
def filtrar_documentos(documentos, **criterios):
resultado = []
for doc in documentos:
coincide = True
for clave, valor in criterios.items():
if doc.metadata.get(clave) != valor:
coincide = False
break
if coincide:
resultado.append(doc)
return resultado
# Aplicar filtro personalizado
docs_filtrados = filtrar_documentos(
documentos_biblioteca,
categoria="http",
dificultad="basico"
)
print(f"Documentos HTTP básicos: {len(docs_filtrados)}")
La separación clara entre contenido y metadatos en la clase Document
permite construir sistemas RAG sofisticados donde la información contextual juega un papel tan importante como el contenido textual en la recuperación y generación de respuestas precisas.
Aprendizajes de esta lección
- Comprender la estructura y propósito de la clase Document en LangChain.
- Aprender a crear documentos desde texto simple y datos estructurados.
- Entender la importancia y uso de los atributos page_content y metadata.
- Conocer cómo manipular, enriquecer y filtrar colecciones de documentos.
- Familiarizarse con la serialización y persistencia de documentos para aplicaciones escalables.
Completa LangChain y certifícate
Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs