Docling para RAG

Del documento a chunks listos para retrieval: qué chunker elegir, cómo dimensionar con el tokenizer correcto, cómo sobreviven tablas y citas, qué integración encaja y qué vector store emparejar — verificado contra los conceptos oficiales de chunking y la referencia de serialización.

1
Step 1

1. ¿Qué vía RAG te encaja?

SituaciónVíaPor qué
Ya usas LangChainlangchain-docling DoclingLoaderLoader oficial; modo DOC_CHUNKS trocea nativo, modo MARKDOWN + splitter de cabeceras como fallback.
Ya usas LlamaIndexDoclingReader + Docling Node ParserEl Reader carga JSON sin pérdida o Markdown con pérdida; el parser los vuelve Nodes.
Ya usas HaystackConversor docling-haystackDocling como componente conversor de Haystack.
Sin framework / store propioHybridChunker directoControl total: trocea, contextualiza, incrusta y sube donde sea (Qdrant, Milvus, Chroma, Pinecone…).
Necesitas ficheros de chunks yaCLI --to chunksSin Python: chunks híbridos o jerárquicos desde el terminal.
Ingesta masiva a escalaData Prep Kit + DoclingPipelines de chunk + tokenize para grandes corpus.
2
Step 2

2. Dónde encaja Docling en RAG

Un pipeline RAG tiene seis etapas; Docling posee las tres primeras — las que deciden la calidad antes de que exista ningún embedding. Dos filosofías: exportar a Markdown y redividir (p. ej. MarkdownHeaderTextSplitter de LangChain), o trocear nativo sobre el DoclingDocument. Lo nativo preserva tablas, cabeceras y procedencia que el redividido Markdown pierde en silencio: prefiérelo salvo motivo.

  • Parseo — layout, orden de lectura, tablas, fórmulas, imágenes → un DoclingDocument estructurado.
  • Serialización / chunking — chunks con estructura, cabeceras, captions y procedencia (o exportación Markdown/HTML/JSON para redividir).
  • Enriquecer textocontextualize() antepone contexto de cabeceras para que cada chunk valga solo.
  • Embeddings → store → retrieval → generación — tu modelo, tu store y tu framework; agnósticos a Docling.
3
Step 3

3. Conversión: conserva el DoclingDocument

Para un pipeline programático, convierte en Python y conserva el objeto documento — los chunkers operan sobre él, no sobre ficheros:

docling convert report.pdf --to md
from docling.document_converter import DocumentConverter

converter = DocumentConverter()
result = converter.convert("report.pdf")
document = result.document
4
Step 4

4. Elige exportación: Markdown, JSON, HTML, DocTags

Las exportaciones son atajos sobre serializadores (MarkdownDocSerializer etc.). Para RAG la elección importa sobre todo en tablas. Si las celdas combinadas de cabecera deciden respuestas, prefiere HTML o JSON a Markdown — o mantén Markdown pero repite cabeceras al trocear (sección 7). Los serializadores se personalizan: subclasifica BaseTableSerializer y afines para control total (ver ejemplo avanzado de chunking y serialización).

ExportaciónSpans de tablaUso RAG
export_to_markdown()Aplanados — sin sintaxis de spans; celdas combinadas salen vacíasVía de texto por defecto; bien salvo que importen cabeceras combinadas.
export_to_html()Preservados — rowspan/colspan nativosMejor exportación de texto cuando las celdas combinadas importan.
export_to_dict() / JSONPreservados sin pérdida — TableData completo con spansVía sin pérdida (modo JSON del Reader LlamaIndex); payloads más pesados.
DocTags / Docling LanguagePreservados — tokens de continuación OTSLFormato compacto que preserva estructura para tooling nativo Docling.
5
Step 5

5. Comparativa de chunkers

Todos los chunkers nativos implementan BaseChunker (chunk() → flujo de chunks, contextualize() → texto enriquecido), así que integraciones estilo LlamaIndex aceptan cualquier chunker propio, personalizado o de terceros por la misma interfaz.

ChunkerEstrategiaCuándo
HybridChunker (defecto)Estructura jerárquica + división consciente de tokens si sobra + fusión si faltaDefecto para RAG. Equilibrado, consciente de cabeceras y tablas.
HierarchicalChunkerUn chunk por elemento; fusiona ítems de lista (opt-out con merge_list_items)Granularidad fina por elemento, con metadatos completos.
LineBasedTokenChunkerRespeta líneas; solo parte una línea si ella sola supera el límiteTablas, código, logs, listas: todo lo orientado a líneas.
TrivialChunkerTroceado mínimo de baseDepuración y benchmarks, no retrieval en producción.
Redivisión MarkdownExporta a Markdown y redivide (p. ej. MarkdownHeaderTextSplitter)Solo cuando un componente downstream exige entrada Markdown.
6
Step 6

6. HybridChunker a fondo (por defecto)

Cómo funciona: parte de chunks jerárquicos; una pasada solo divide los sobredimensionados (consciente de tokens) y otra solo fusiona peers infradimensionados sucesivos con mismas cabeceras y captions. Parámetros clave:

Incrusta el texto contextualizado, no chunk.text:

Dos notas operativas: el aviso transformers «Token indices sequence length …» al trocear es una falsa alarma documentada (ver FAQ oficial), y define TOKENIZERS_PARALLELISM=false para silenciar avisos de fork en servidores.

  • tokenizer — alinéalo al tokenizer de tu modelo de embeddings (sección 9). Por defecto deriva límites del tokenizer.
  • max_tokens — tope por chunk; debe caber la forma enriquecida (contextualizada).
  • merge_peers=True — fusiona peers pequeños; pon False para divisiones estrictas.
  • repeat_table_header=True — cada chunk de tabla empieza con la fila de cabecera (sección 7).
  • omit_header_on_overflow=False — omite la cabecera en filas que caben sin ella pero desbordan con ella (tablas anchas, presupuestos estrictos).
  • serializer_provider — p. ej. tablas Markdown vía ChunkingSerializerProvider para controlar la forma del texto.
from docling.chunking import HybridChunker

chunker = HybridChunker()
chunks = list(chunker.chunk(document))
print(len(chunks), chunks[0].text[:120])
for chunk in chunker.chunk(document):
    enriched = chunker.contextualize(chunk)  # cabeceras antepuestas — INCRUSTA ESTO
    vector = embed(enriched)
7
Step 7

7. Tablas en RAG: cabeceras, spans, formatos

Demos resueltas: chunking híbrido (incl. repetición en CSV ancho), chunking por líneas, extracción de tablas.

docling convert data.csv --to md
  • Repite cabeceras (repeat_table_header=True, defecto): cada chunk de una tabla dividida empieza con la fila de cabecera, así cada chunk se autodescribe ante el modelo.
  • Escape de desborde (omit_header_on_overflow=True): en tablas anchas, las filas que caben sin cabecera pero desbordan con ella la omiten: eficiencia sin romper filas.
  • Celdas combinadas: Markdown aplana spans; si importan, trocea desde serialización HTML/JSON o un serializador de tablas propio.
  • Alternativa por líneas: LineBasedTokenChunker con prefijo repetido mantiene filas tipo CSV intactas, con la misma lógica de desborde vía omit_prefix_on_overflow.
8
Step 8

8. Metadatos y citas (DocMeta)

Cada chunk trae dl_meta: consérvalo en el payload vectorial; convierte «una respuesta» en «una respuesta con fuente». La procedencia incluye páginas y bounding boxes por ítem: basta para citas «página 3» o resaltado de la región (ver visual grounding). Nunca recortes metadatos por «ahorrar»: sin ellos, citar es imposible.

CampoContieneÚsalo para
headingsRuta de cabeceras, p. ej. ["3.2 AI models"]Etiquetas de sección, prefijos de contexto, filtros.
originMimetype, nombre, hash binarioIdentidad del documento, dedup, enlaces fuente.
doc_itemsSelf refs, etiquetas, procedencia: page_no, bbox, charspanCitas de página, resaltado bbox, visual grounding.
9
Step 9

9. Tokenizers: iguala tu modelo de embeddings

La regla es absoluta: mide los chunks con el tokenizer de tu modelo de embeddings. Tokenizers dispares dimensionan mal en silencio y rompen decisiones de fusión/división. A gran escala, el pipeline chunk+tokenize de Data Prep Kit aplica lo mismo en batch.

TokenizerInstalaciónNotas
HuggingFace (HuggingFaceTokenizer)pip install "docling-core[chunking]"Vía por defecto. max_tokens opcional: derivado del tokenizer. Ejemplo: sentence-transformers/all-MiniLM-L6-v2 (también defecto CLI).
OpenAI / tiktoken (OpenAITokenizer)pip install "docling-core[chunking-openai]"Requiere max_tokens explícito (ventana de contexto, p. ej. 128 * 1024 para gpt-4o).
from transformers import AutoTokenizer
from docling_core.transforms.chunker.tokenizer.huggingface import HuggingFaceTokenizer
from docling.chunking import HybridChunker

EMBED_MODEL_ID = "sentence-transformers/all-MiniLM-L6-v2"
tokenizer = HuggingFaceTokenizer(
    tokenizer=AutoTokenizer.from_pretrained(EMBED_MODEL_ID),
    max_tokens=512,
)
chunker = HybridChunker(tokenizer=tokenizer, merge_peers=True)
10
Step 10

10. Integraciones con frameworks

LangChain — langchain-docling: Dos modos: DOC_CHUNKS (defecto: un Document LangChain por chunk nativo, metadatos intactos) y MARKDOWN (un Document por fichero; divide después, p. ej. con MarkdownHeaderTextSplitter en #/##/###). Flujo completo en el ejemplo oficial RAG LangChain (Milvus + Mixtral) y la guía LangChain.

LlamaIndex — Reader + Node Parser: DoclingReader puebla Documents LlamaIndex (JSON sin pérdida o Markdown con pérdida); el Docling Node Parser los convierte en Nodes conociendo el formato. Cualquier BaseChunker encaja en la misma interfaz. Ver ejemplo oficial RAG LlamaIndex.

Haystack y resto: Haystack trae Docling como componente conversor (ejemplo, docs de integración). Más allá de los tres grandes: txtai, Kotaemon, DocETL, Vectara, Semantica, Hector, haiku.rag, Bee, CrewAI, Langflow, Open WebUI, spaCy, NVIDIA, RAG del cookbook Granite y Data Prep Kit integran Docling: explora el índice oficial de integraciones.

pip install langchain-docling langchain-huggingface langchain_milvus
pip install llama-index-readers-docling llama-index-node-parser-docling
pip install docling-haystack
from transformers import AutoTokenizer
from docling_core.transforms.chunker.tokenizer.huggingface import HuggingFaceTokenizer
from docling.chunking import HybridChunker
from langchain_docling import DoclingLoader
from langchain_docling.loader import ExportType

tokenizer = HuggingFaceTokenizer(
    tokenizer=AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
)
loader = DoclingLoader(
    file_path=["https://arxiv.org/pdf/2408.09869"],
    export_type=ExportType.DOC_CHUNKS,  # chunks nativos (defecto)
    chunker=HybridChunker(tokenizer=tokenizer),
)
docs = loader.load()  # un Document LangChain por chunk, dl_meta en metadata
from llama_index.readers.docling import DoclingReader

reader = DoclingReader(export_type="json")  # sin pérdida; "markdown" con pérdida
documents = reader.load_data("report.pdf")
11
Step 11

11. Vector stores: ejemplos resueltos

El store nunca afecta a Docling: chunks + embeddings caben en cualquiera. Ejemplos oficiales para:

StoreEjemploNotas
MilvusRAG con MilvusTambién el store del ejemplo LangChain (docling.db local, índice FLAT).
WeaviateRAG con WeaviateBúsqueda vectorial + híbrida nativas.
QdrantRetrieval con QdrantReceta enfocada a retrieval.
OpenSearchRAG con OpenSearchBúsqueda + vector en un motor.
MongoDB + VoyageAIRAG con MongoDBAtlas Vector Search + embeddings VoyageAI.
Azure AI SearchRAG con Azure AI SearchRetrieval gestionado en Azure.
Chroma / Pinecone / otrosSin receta oficial; mismo patrón: incrusta contextualize(chunk), sube texto + DocMeta.
12
Step 12

12. Chunks desde el CLI (sin Python)

--chunks-type acepta hybrid (defecto) o hierarchical; el tokenizer por defecto es sentence-transformers/all-MiniLM-L6-v2. La conversión remota (docling convert-remote / docling-serve) soporta las mismas opciones en servidor. Ver el buscador de comandos.

docling convert report.pdf --to chunks --chunks-type hybrid
docling convert report.pdf --to chunks --chunks-type hybrid --chunks-max-tokens 512 --chunks-tokenizer sentence-transformers/all-MiniLM-L6-v2
13
Step 13

13. Checklist de ingesta en producción

  • Tokenizer == modelo de embeddings. Siempre. Revísalo en cada cambio de modelo.
  • Incrusta la salida de contextualize(); guarda chunk.text aparte para mostrar.
  • Conserva DocMeta (headings, page_no, bbox, origin) en el payload para citas.
  • Repite cabeceras de tabla; para tablas con celdas combinadas usa fuente HTML/JSON.
  • Recorta coste de conversión: --no-ocr en PDF digitales, omite enrichments que no uses, convierte en batch y pre-descarga modelos (docling-tools models download --all).
  • Escala: chunk+tokenize de Data Prep Kit para corpus; /v1/convert/source de docling-serve con --to chunks tras una cola para servicios.
  • PII primero: detecta y ofusca PII antes de incrustar (ver ejemplo PII): una fuga no se puede des-incrustar.
14
Step 14

14. Solución de problemas de ingesta RAG

  • Respuestas sin contexto / chunks «huérfanos» — incrustaste chunk.text; cambia a contextualize() y confirma cabeceras.
  • Tablas mal respondidas — activa repeat_table_header; revisa celdas combinadas (Markdown aplana spans → usa HTML/JSON).
  • Aviso transformers de longitud — falsa alarma documentada, ignorable (FAQ oficial).
  • Chunks grandes/pequeños para el modelo — desajuste de tokenizers; fija el del modelo y ajusta max_tokens.
  • Sin citas posibles — metadatos perdidos al subir; persiste dl_meta (page_no, headings, origin).
  • Ingesta lenta — ver conversión lenta: apaga OCR/enrichments sobrantes, usa GPU, batch.
15
Step 15

15. FAQ de RAG

¿Con qué chunker empiezo?
HybridChunker con el tokenizer de tu modelo de embeddings. Defecto con motivo: estructura, tamaño, cabeceras y tablas. Solo cambia a Hierarchical (por elemento) o LineBased (contenido lineal) por necesidad concreta.
¿chunk.text o contextualize() — qué incrusto?
Siempre chunker.contextualize(chunk) para embeddings. Antepone la ruta de cabeceras y vuelve el chunk autocontenido. Guarda chunk.text para mostrar.
¿Necesito LangChain / LlamaIndex / Haystack?
No. Son comodidades: loaders, readers y conversores sobre los mismos chunkers. Una docena de líneas de HybridChunker + tu llamada de embeddings + cualquier store es un pipeline completo.
¿Exportación Markdown + splitter o chunking nativo?
Lo nativo preserva tablas, cabeceras, procedencia y spans que la exportación Markdown aplana o pierde. Redivisión Markdown solo cuando un componente exija entrada Markdown.
¿Cómo sobrevive la estructura de tablas?
Repite cabeceras (repeat_table_header), cuida el desborde (omit_header_on_overflow) y fuentea tablas desde HTML/JSON si importan celdas combinadas. LineBasedTokenChunker es el especialista en datos por filas.
¿Cómo citan páginas las respuestas?
Persiste el dl_meta de cada chunk (headings, page_no, bbox, origin) en el payload y devuélvelo con los hits. La procedencia sostiene citas hasta resaltado bbox.
¿Qué vector store funciona con Docling?
Cualquiera. Docling produce chunks + metadatos; los stores solo guardan vectores. Recetas oficiales cubren Milvus, Weaviate, Qdrant, OpenSearch, MongoDB y Azure AI Search; Chroma, Pinecone y demás siguen el mismo patrón.
¿Cómo escalo la ingesta?
Conversión batch, modelos pre-descargados, GPU para layout/OCR, sin enrichments sobrantes; más chunk+tokenize de Data Prep Kit para corpus o salida chunks de docling-serve tras una cola para servicios.

Verificado con Docling v2.129.0 · Última comprobación 2026-09-22 · Fuente oficial