Carga y división de documentos de LangChain

En artículos anteriores ingresábamos texto manualmente, pero en proyectos reales, los documentos pueden provenir de PDF, páginas web, archivos Markdown, etc.

Esta sección explica cómo usar Document Loader para cargar varios tipos de documentos y cómo usar Text Splitter para dividir los documentos en fragmentos pequeños adecuados para la recuperación.


Document Loader——Cargar documentos

LangChain ofrece decenas de cargadores de documentos que cubren formatos de archivo comunes:

LoaderOrigenPaquete de instalación
TextLoaderArchivo .txtlangchain (integrado)
PyPDFLoaderArchivo PDFlangchain-community + pypdf
WebBaseLoaderURL weblangchain-community + beautifulsoup4
CSVLoaderArchivo CSVlangchain-community
UnstructuredMarkdownLoaderArchivo Markdownlangchain-community + unstructured

Ejemplo

# Cargar archivo de texto (integrado, sin instalación adicional)
from langchain_community.document_loaders import TextLoader

loader = TextLoader("knowledge.txt", encoding="utf-8")
docs = loader.load()

print(f"Se cargaron {len(docs)} documentos")
print(f"Vista previa del contenido: {docs)

# Cargar página web
# pip install langchain-community beautifulsoup4
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://www.example.com/python/python-tutorial.html")
docs = loader.load()
print(f"\n"Contenido web: {docs)

Text Splitter——División de documentos

Los documentos suelen ser demasiado largos; es necesario dividirlos en fragmentos pequeños (chunks) para una recuperación eficaz. La estrategia de división afecta directamente el resultado de RAG:

Ejemplo

from langchain_text_splitters import RecursiveCharacterTextSplitter

# Crear el divisor
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,         # Máximo 500 caracteres por fragmento
    chunk_overlap=50,       # Superposición de 50 caracteres entre fragmentos
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""],
    # Dividir primero por párrafos, luego por oraciones y finalmente por caracteres
)

# Documento de ejemplo
long_text = """Tutorial para novatos (EJEMPLO) es una plataforma gratuita de aprendizaje de programación.

La plataforma ofrece completos tutoriales de lenguajes de programación, incluyendo, entre otros:
- Tutorial de Python: desde sintaxis básica hasta análisis de datos
- Tutorial de Java: desde programación orientada a objetos hasta el framework Spring
- Tutorial de front-end: HTML, CSS, JavaScript y sus frameworks

Todos los tutoriales incluyen ejemplos de código detallados y un entorno de ejecución en línea.
Los estudiantes pueden dominar rápidamente habilidades de programación aprendiendo y practicando simultáneamente."""


# Dividir documento
chunks = text_splitter.split_text(long_text)

print(f"Longitud del texto original: {len(long_text)} caracteres")
print(f"Después de dividir: {len(chunks)} fragmentos"\n")

for i, chunk in enumerate(chunks):
    print(f"--- Fragmento {i+1} ({len(chunk)} caracteres) ---")
    print(chunk)
    print()

Resultado de ejecución:

Longitud original: 153 字
Fragmentos tras dividir: 3 块

--- 块 1 (54 字) ---
Ejemplo es una plataforma gratuita de aprendizaje de programación.
平台提供了丰富的编程语言教程,包括但不限于:

--- 块 2 (49 字) ---
- Python 教程:从基础语法到数据分析
- Java 教程:面向对象编程到 Spring 框架

--- 块 3 (50 字) ---
- 前端教程:HTML、CSS、JavaScript 及其框架
所有教程都配有详细的代码示例和在线运行环境。

chunk_overlap es muy importante. Si no hay superposición entre fragmentos, una oración completa puede cortarse por la mitad, provocando la omisión de información clave durante la recuperación. Una superposición de 50-100 caracteres es una configuración común.


Guía de configuración de parámetros de división

Escenariochunk_sizechunk_overlapRazón
Preguntas frecuentes (FAQ)200~50020~50Los pares de preguntas y respuestas son cortos, bastan fragmentos pequeños
Documentación técnica500~100050~100El contenido técnico requiere más contexto
Artículos largos/trabajos académicos1000~2000100~200Es necesario preservar la integridad de los párrafos
Base de código500~15000~50Funciones/clases como límites naturales

Proceso completo: Carga → División → Vectorización

Ejemplo

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
# from langchain_community.document_loaders import TextLoader


# Proceso 1: Carga
# loader = TextLoader("ejemplo_knowledge.txt", encoding="utf-8")
# docs = loader.load()

# Para la demostración, se utiliza texto de ejemplo directamente
docs = [
    "Tutorial para novatos (EJEMPLO) es un sitio web gratuito de aprendizaje de programación.",
    "El sitio ofrece tutoriales de varios lenguajes de programación como Python, Java, HTML, etc.",
    "El tutorial básico de Python3 tiene 30 capítulos, adecuado para principiantes sin conocimientos previos.",
    "El tutorial básico de HTML tiene 25 capítulos, incluye formularios, multimedia, etc.",
    "Todos los tutoriales básicos de Tutorial para novatos son gratuitos.",
]

# Proceso 2: División
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=20,
)
chunks = text_splitter.create_documents(docs)

# Proceso 3: Almacenamiento vectorial
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./ejemplo_db",
)

print(f"Índice creado: {len(chunks)} fragmentos de documentos")

# Proceso 4: Recuperación
results = vector_store.similarity_search("¿Cuántos capítulos tiene el tutorial de Python?", k=2)
for doc in results:
    print(f"Resultado de la recuperación: {doc.page_content}")

Resultado de ejecución:

Índice creado:5 个文档块
Resultado de búsqueda: Python3 基础教程共 30 章,适合零基础入门学习。
Resultado de búsqueda: Ejemplo es un sitio web gratuito de aprendizaje de programación.
Otras extensiones