Ejecutar pipelines de Docling a través de HTTP: desde la configuración del proyecto hasta los fragmentos indexados
Recorra paso a paso la API REST de Docling Pipelines: inicie el servidor, descubra los operadores, valide y ejecute un DAG de ingestión, y lea su telemetría de ejecución.
Fuentes: **A Hands-On Guide to the Docling Pipelines REST API**
Conviertir una carpeta de archivos PDF y Word en fragmentos vectoriales buscables generalmente requiere código especial para la extracción, división en fragmentos, incrustación e indexación. Docling Pipelines agrupa estas etapas como operadores detrás de un servidor REST basado en FastAPI, de modo que cualquier cliente, como un servicio Node.js o una interfaz de administración, pueda crear pipelines modulares en formato DAG, validarlos y activar ejecuciones asíncronas a través de HTTP. Esta guía inicia el servidor con Ollama y OpenSearch y sigue todo el ciclo de vida de una solicitud, desde la creación de un proyecto hasta la lectura de las estadísticas de ejecución por nodo.
Preparación de los servicios de soporte
El servidor orquesta el trabajo, pero las incrustaciones y el almacenamiento se realizan en otro lugar: aquí, Ollama para los modelos y OpenSearch como almacén vectorial. Enciéndalos primero.
La ruta más rápida es el QUICKSTART.md del proyecto, que mediante scripts configura Ollama, una base de datos vectorial y los contenedores necesarios en pocos minutos. Un agente de programación basado en IA como Cursor, Claude Code o Copilot también puede encargarse de la configuración y verificación; en cualquier caso, hay que confirmar que cada servicio responde.
Elegir un almacén de vectores
Se trata de una decisión arquitectónica. OpenSearch es adecuado cuando se desea una búsqueda híbrida, que combine la coincidencia de palabras clave con vectores densos. Milvus es ideal para infraestructuras dedicadas y altamente escalables destinadas a colecciones de vectores muy grandes. Esta guía utiliza OpenSearch.
Iniciar el servidor API
Active el entorno virtual donde está instalado el paquete y ejecute la orden incluida:
source .venv/bin/activate
docling-pipelines-api
Para el recargue en tiempo real durante el desarrollo, ejecute la aplicación directamente a través de uvicorn, vinculada a todas las interfaces en el puerto 8080:
uvicorn docpipe.api.main:app --reload --host 0.0.0.0 --port 8080
Luego hay cuatro URLs disponibles:
http://localhost:8080/healthpara las verificaciones de estado;http://localhost:8080/api/v1/docspara la interfaz interactiva de Swagger UI;http://localhost:8080/api/v1/redocpara la documentación de ReDoc;http://localhost:8080/api/v1/openapi.jsonpara el esquema OpenAPI en formato raw.
Desde TypeScript, puede pasar el documento OpenAPI a un generador de clientes en lugar de escribir manualmente los tipos de solicitud.
Variables de entorno que configuran el servidor
Establezca estas antes de iniciar la aplicación para ajustar su comportamiento:
DS_LOG_LEVELdetermina el nivel de detalle de los registros. Su valor por defecto esINFOy acepta los valoresDEBUG,INFO,WARNINGoERROR.DOCPIPE_STORAGE_BACKENDselecciona dónde se almacenarán los metadatos:duckdb(el valor por defecto, local) opostgres.CORS_ORIGINSenumera los orígenes a los que se permite hacer llamadas a la API desde una interfaz frontal basada en navegador. Su valor por defecto eshttp://localhost:3000.OLLAMA_HOSTdirige a los operadores de incrustación y LLM hacia Ollama. El valor por defecto eshttp://localhost:11434; cámbielo si Ollama se ejecuta en otro puerto o máquina.
Explorando los puntos de extremo en Swagger UI
Abra http://localhost:8080/api/v1/docs en un navegador; localmente no se necesita iniciar sesión. Expanda un endpoint, haga clic en Pruébalo y envíe los datos a continuación sin escribir un cliente.
El ciclo de vida de la solicitud de un vistazo
Un viaje completo consta de siete llamadas, desde la creación del proyecto hasta el resumen de ejecución:
1. Create Project ──▶ 2. Discover Operators ──▶ 3. Validate Flow ──▶ 4. Create Flow ──▶ 5. Execute Run ──▶ 6. Fetch Logs ──▶ 7. Summary
Paso 1: crear un proyecto
Los proyectos agrupan flujos y registran sus estadísticas de ejecución acumuladas. Cree uno con POST /api/v1/projects:
{
"name": "Sample Docling Pipeline Project",
"description": "Flows for processing invoice documents",
"tags": ["finance", "pdf", "q3"]
}
Los campos:
namees una cadena obligatoria de 1 a 255 caracteres que identifica de forma única al proyecto.descriptiones una explicación breve opcional sobre el propósito del proyecto.tagses un array opcional de cadenas para su categorización.
El éxito devuelve 201 Created junto con un project_id generado, un flow_count de cero, marcas de tiempo y un href hacia el recurso:
{
"project_id": "84c718b2-5f36-4d2c-9a4f-561234bcde01",
"name": "Sample Docling Pipeline Project",
"description": "Flows for processing invoice documents",
"tags": ["finance", "pdf", "q3"],
"flow_count": 0,
"created_on": "2026-09-07T10:00:00Z",
"modified_on": "2026-09-07T10:00:00Z",
"href": "/api/v1/projects/84c718b2-5f36-4d2c-9a4f-561234bcde01"
}
Paso 2: descubrir operadores y modelos
En lugar de adivinar los nombres y opciones de los operadores, pregúntele al servidor.
Metadatos de los operadores
GET /api/v1/operators/metadata devuelve un esquema detallado para cada operador, que incluye los más de 20 integrados además de cualquier operador externo que haya registrado. El parámetro de consulta internal_features tiene como valor por defecto false.
En cada entrada, features describe las columnas que genera un operador, required_features las columnas que necesita de fuentes externas, y attributes sus opciones con tipos y valores predeterminados. El operador extracto emite content y doc_id_hash; el chunker, por su parte, requiere content:
{
"extract_operator": {
"label": "Extract Operator",
"category": "Extract",
"description": "Extracts structured content from documents using Docling",
"features": {
"content": {
"name": "Document Content",
"description": "The markdown content extracted from the document",
"type": "string",
"required": true
},
"doc_id_hash": {
"name": "Hash ID",
"description": "Hash ID of the document row",
"type": "string",
"required": true
}
},
"required_features": [],
"attributes": {
"text_extraction_mode": {
"type": "string",
"description": "Text extraction strategy (docling_library or docling_serve)",
"required": true,
"default": "docling_library"
},
"entity_extraction_mode": {
"type": "string",
"description": "Entity extraction strategy (litellm, watsonx, docling, or none)",
"required": false,
"default": "none"
}
}
},
"chunker": {
"label": "Chunker Operator",
"category": "Functional",
"description": "Splits documents into smaller semantic or fixed-size passages",
"features": {
"content": { "name": "Chunk Content", "type": "string", "required": true }
},
"required_features": ["content"],
"attributes": {
"chunker_type": {
"type": "string",
"description": "Chunking strategy (fixed, semantic, or hybrid)",
"required": false,
"default": "hybrid"
}
}
}
}
Al comparar required_features con los resultados de las fuentes externas, se puede confirmar, antes de enviar el flujo, que cada nodo recibirá las columnas que necesita.
Modelos de proveedores
GET /api/v1/providers/{provider}/models consulta a un proveedor en tiempo real (ollama o watsonx), por lo que cualquier modelo faltante o etiqueta mal escrita se detectará antes de que se ejecute el proceso:
curl -s http://localhost:8080/api/v1/providers/ollama/models | jq
Cada modelo se lista con su nombre, etiqueta, fecha de modificación y tamaño en bytes:
{
"provider": "ollama",
"models": [
{
"name": "nomic-embed-text:latest",
"model": "nomic-embed-text:latest",
"modified_at": "2026-08-15T12:00:00Z",
"size": 274302450
},
{
"name": "llama3:8b",
"model": "llama3:8b",
"modified_at": "2026-08-20T14:30:00Z",
"size": 4661224676
}
]
}
Paso 3: validar el flujo antes de guardarlo
POST /api/v1/validation/validate_flow verifica si un DAG contiene parámetros incorrectos o dependencias dañadas sin almacenarlo ni ejecutarlo.
global_config establece opciones aplicables a toda la ejecución (columna de documento, ejecución local, almacenamiento en memoria, reingestión forzada). flow enumera los nodos, cada uno con un type, un name único, una config y un array depends_on que indica sus dependencias anteriores. El pipeline es el siguiente:
- Ingresa archivos PDF, TXT y DOCX desde
./sample_documentsen el sistema de archivos local; - Extrae su texto con la biblioteca Docling y omite la extracción de entidades;
- Divide el contenido en fragmentos de 512 unidades con una superposición de 50 unidades;
- Incrusta cada fragmento mediante LiteLLM, apuntando al endpoint compatible con OpenAI de Ollama con el modelo
nomic-embed-text.
feature_mappings.{
"flow_name": "complete-document-pipeline",
"global_config": {
"doc_column": "content",
"disable_validation": true,
"force_ingest": true,
"storage": "in-memory",
"execute_type": "local"
},
"flow": [
{
"type": "ingest_source",
"name": "ingest_source_filesystem",
"config": {
"provider": "filesystem",
"connection_params": {
"paths": ["./sample_documents"]
},
"include_filter": "pdf,txt,docx"
}
},
{
"type": "extract_operator",
"name": "extract_with_docling",
"config": {
"text_extraction": {
"provider": "docling_library",
"doc_column": "content"
},
"entity_extraction": {
"provider": "none"
}
},
"depends_on": ["ingest_source_filesystem"]
},
{
"type": "chunker",
"name": "simple_chunker",
"config": {
"chunk_type": "simple",
"chunk_size": 512,
"chunk_overlap": 50,
"retain_original_content": false
},
"depends_on": ["extract_with_docling"]
},
{
"type": "embeddings",
"name": "ollama_embeddings",
"config": {
"provider": "litellm",
"provider_config": {
"model_id": "openai/nomic-embed-text",
"api_base": "http://localhost:11434/v1",
"api_key": "<ollama-api-key>"
},
"embeddings_column": "embeddings",
"overlap_ratio": 0.1
},
"depends_on": ["simple_chunker"]
},
{
"type": "vectordb",
"name": "opensearch_vector_store",
"config": {
"provider": "opensearch",
"doc_id_column": "doc_id_hash",
"embeddings_column": "embeddings",
"vector_dimension": 768,
"create_index": true,
"provider_config": {
"index_name": "sample-documents-index",
"host": "localhost",
"port": 9200,
"username": "${OPENSEARCH_USERNAME}",
"password": "${OPENSEARCH_PASSWORD}",
"use_ssl": false,
"verify_certs": false,
"batch_size": 100,
"engine": "faiss",
"algorithm": "hnsw",
"space_type": "l2"
},
"feature_mappings": [
{ "feature_name": "doc_id_hash", "mapped_column_name": "pk" },
{ "feature_name": "content", "mapped_column_name": "text" },
{ "feature_name": "name", "mapped_column_name": "doc_name" },
{ "feature_name": "path", "mapped_column_name": "file_path" },
{ "feature_name": "embeddings", "mapped_column_name": "vector_embeddings" },
{ "feature_name": "chunk_id", "mapped_column_name": "chunk_id" },
{ "feature_name": "chunk_index", "mapped_column_name": "chunk_index" }
]
},
"depends_on": ["ollama_embeddings"]
}
]
}
Algunos detalles son importantes. vector_dimension (768) debe coincidir con el tamaño de salida del modelo de embedding. Las credenciales aparecen como marcadores de posición del estilo ${OPENSEARCH_USERNAME} y <ollama-api-key>; guarde los secretos reales en variables de entorno o en un almacén de secretos, no en los flujos almacenados. Desactivar use_ssl y verify_certs está bien en entornos locales, pero no en un clúster compartido. Además, el chunker utiliza chunk_type: "simple", mientras que los documentos de metadatos indican chunker_type como fixed, semantic o hybrid; verifique qué devuelve su servidor.
Una definición válida devuelve 200 OK, is_valid: true, errors y warnings vacíos, además del recuento de nodos:
{
"is_valid": true,
"errors": [],
"warnings": [],
"node_count": 5
}
Paso 4: registrar el flujo
Almacene la definición validada mediante POST /api/v1/flows (is_elyra tiene como valor por defecto false). El cuerpo contiene la misma estructura DAG más una descripción y etiquetas:
{
"flow_name": "complete-document-pipeline",
"description": "Complete document processing pipeline: Ingest -> Extract -> Chunk -> Embed -> Store in OpenSearch",
"tags": ["docling", "embeddings", "opensearch"],
"global_config": {
"doc_column": "content",
"disable_validation": true,
"force_ingest": true,
"storage": "in-memory",
"execute_type": "local"
},
"flow": [
{
"type": "ingest_source",
"name": "ingest_source_filesystem",
"config": {
"provider": "filesystem",
"connection_params": { "paths": ["./sample_documents"] },
"include_filter": "pdf,txt,docx"
}
},
{
"type": "extract_operator",
"name": "extract_with_docling",
"config": {
"text_extraction": { "provider": "docling_library", "doc_column": "content" },
"entity_extraction": { "provider": "none" }
},
"depends_on": ["ingest_source_filesystem"]
},
{
"type": "chunker",
"name": "simple_chunker",
"config": {
"chunk_type": "simple",
"chunk_size": 512,
"chunk_overlap": 50,
"retain_original_content": false
},
"depends_on": ["extract_with_docling"]
},
{
"type": "embeddings",
"name": "ollama_embeddings",
"config": {
"provider": "litellm",
"provider_config": {
"model_id": "openai/nomic-embed-text",
"api_base": "http://localhost:11434/v1",
"api_key": "<ollama-api-key>"
},
"embeddings_column": "embeddings",
"overlap_ratio": 0.1
},
"depends_on": ["simple_chunker"]
},
{
"type": "vectordb",
"name": "opensearch_vector_store",
"config": {
"provider": "opensearch",
"doc_id_column": "doc_id_hash",
"embeddings_column": "embeddings",
"vector_dimension": 768,
"create_index": true,
"provider_config": {
"index_name": "sample-documents-index",
"host": "localhost",
"port": 9200,
"username": "${OPENSEARCH_USERNAME}",
"password": "${OPENSEARCH_PASSWORD}",
"use_ssl": false,
"verify_certs": false,
"batch_size": 100,
"engine": "faiss",
"algorithm": "hnsw",
"space_type": "l2"
},
"feature_mappings": [
{ "feature_name": "doc_id_hash", "mapped_column_name": "pk" },
{ "feature_name": "content", "mapped_column_name": "text" },
{ "feature_name": "name", "mapped_column_name": "doc_name" },
{ "feature_name": "path", "mapped_column_name": "file_path" },
{ "feature_name": "embeddings", "mapped_column_name": "vector_embeddings" },
{ "feature_name": "chunk_id", "mapped_column_name": "chunk_id" },
{ "feature_name": "chunk_index", "mapped_column_name": "chunk_index" }
]
},
"depends_on": ["ollama_embeddings"]
}
]
}
Hay dos configuraciones globales importantes aquí:
execute_type: "local"ejecuta la pipeline dentro del proceso del servidor.force_ingest: truevuelve a procesar los documentos ya ingeridos: útil durante la iteración, pero ineficiente en estado estable.
La respuesta es 201 Created con un nuevo flow_id y las configuraciones almacenadas:
{
"flow_id": "e2c31e42-7719-482a-a53d-2490b830d971",
"flow_name": "complete-document-pipeline",
"description": "Complete document processing pipeline: Ingest -> Extract -> Chunk -> Embed -> Store in OpenSearch",
"tags": ["docling", "embeddings", "opensearch"],
"global_config": {
"doc_column": "content",
"disable_validation": true,
"force_ingest": true,
"storage": "in-memory",
"execute_type": "local"
},
"created_on": "2026-09-07T10:05:00Z",
"modified_on": "2026-09-07T10:05:00Z"
}
Paso 5: iniciar una ejecución
Las ejecuciones son asíncronas. POST /api/v1/job_runs recibe el ID y el nombre del flujo:
{
"flow_id": "e2c31e42-7719-482a-a53d-2490b830d971",
"flow_name": "complete-document-pipeline"
}
Devuelve inmediatamente 201 Created junto con un job_run_id y el estado Starting, mientras el trabajo continúa en segundo plano:
{
"job_run_id": "99ecd646-bb8e-494a-a0c5-86b40c1d4f90",
"status": "Starting",
"message": "Job run created successfully"
}
Paso 6: consultar el estado, las métricas y los registros
Consultar GET /api/v1/job_runs/{job_run_id}, añadiendo include_logs=true para obtener los registros de cada nodo, hasta que el estado sea final (como Completed), idealmente con retrasos cada vez mayores.
La larga respuesta 200 OK contiene node_sequence (orden de ejecución), job_stats (contadores globales del proceso, con node_stats por nodo y batch_node_stats por lote) además de un array de nivel superior node_metadata. En este caso, dos archivos de texto pasaron por los cinco nodos, generando cuatro fragmentos, todos indexados:
{
"node_sequence": [
"ca564648-1715-45c3-be67-7c654344a99c",
"49f285b0-3afa-40eb-8111-3ec6a57c4904",
"447e0511-5125-4ffb-8396-edb972976080",
"2636f8b6-ef9a-4805-bda0-9fcaa853e16a",
"0c773955-f1c7-4b68-b157-38966382cb9c"
],
"job_stats": {
"job_id": "9be63026-c08c-49c1-ba12-600838f3b22f",
"job_run_id": "13bd4219-7947-4977-bc69-1ae6628567d3",
"status": "Completed",
"message": "",
"start_time": 1788943163,
"end_time": 1788943166,
"duration": 3,
"heartbeat_timestamp": 0,
"total_docs": 2,
"processed_docs": 2,
"completed_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"deleted_doc_count": 0,
"total_pages_processed": 2,
"page_type_stats": {
"txt": 2
},
"execution_time": 0,
"orchestrator": "Python",
"container_kind": null,
"container_id": "",
"flow_id": "unknown",
"user_id": null,
"account_id": null,
"user_entitlements": {},
"report_status": "NOT_AVAILABLE",
"report_generation_started_at": null,
"report_generation_completed_at": null,
"node_stats": {
"ca564648-1715-45c3-be67-7c654344a99c": {
"id": "ca564648-1715-45c3-be67-7c654344a99c",
"name": "extract_with_docling",
"node_status": "Completed",
"error": "",
"start_time": 1788943163,
"end_time": 1788943163,
"time_taken": 0,
"col_names": [
"content",
"doc_id_hash",
"document_format",
"id",
"metadata",
"modified_time",
"name",
"pages_processed",
"path",
"source_id"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"node_metadata": {
"failed_docs": [],
"processed_docs": 2,
"node_status": "Completed",
"total_pages_converted": 2,
"page_type_stats": {
"txt": 2
},
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
},
"id": "ca564648-1715-45c3-be67-7c654344a99c",
"operator": "extract_with_docling"
},
"batch_id": null,
"batch_num": null
},
"49f285b0-3afa-40eb-8111-3ec6a57c4904": {
"id": "49f285b0-3afa-40eb-8111-3ec6a57c4904",
"name": "ingest_source_filesystem",
"node_status": "Completed",
"error": "",
"start_time": 1788943163,
"end_time": 1788943163,
"time_taken": 0,
"col_names": [
"id",
"name",
"document_format",
"metadata",
"source_id",
"path",
"modified_time"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"id": "49f285b0-3afa-40eb-8111-3ec6a57c4904",
"operator": "ingest_source_filesystem",
"node_metadata": {
"documents_in_scope": 2,
"processed_docs": 2,
"failed_docs_count": 0,
"failed_docs": [],
"skipped_docs_count": 0,
"skipped_docs": [],
"node_status": "Completed"
}
},
"batch_id": null,
"batch_num": null
},
"447e0511-5125-4ffb-8396-edb972976080": {
"id": "447e0511-5125-4ffb-8396-edb972976080",
"name": "simple_chunker",
"node_status": "Completed",
"error": "",
"start_time": 1788943163,
"end_time": 1788943164,
"time_taken": 1,
"col_names": [
"chunked_content",
"doc_id_hash",
"document_format",
"id",
"metadata",
"modified_time",
"name",
"pages_processed",
"path",
"source_id"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"node_metadata": {
"failed_docs": [],
"total_chunks": 4,
"processed_docs": 2,
"node_status": "Completed",
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
},
"id": "447e0511-5125-4ffb-8396-edb972976080",
"operator": "simple_chunker"
},
"batch_id": null,
"batch_num": null
},
"2636f8b6-ef9a-4805-bda0-9fcaa853e16a": {
"id": "2636f8b6-ef9a-4805-bda0-9fcaa853e16a",
"name": "ollama_embeddings",
"node_status": "Completed",
"error": "",
"start_time": 1788943164,
"end_time": 1788943164,
"time_taken": 0,
"col_names": [
"chunked_content",
"doc_id_hash",
"document_format",
"embeddings",
"id",
"metadata",
"modified_time",
"name",
"pages_processed",
"path",
"source_id"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"node_metadata": {
"failed_docs": [],
"processed_docs": 2,
"node_status": "Completed",
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
},
"id": "2636f8b6-ef9a-4805-bda0-9fcaa853e16a",
"operator": "ollama_embeddings"
},
"batch_id": null,
"batch_num": null
},
"0c773955-f1c7-4b68-b157-38966382cb9c": {
"id": "0c773955-f1c7-4b68-b157-38966382cb9c",
"name": "opensearch_vector_store",
"node_status": "Completed",
"error": "",
"start_time": 1788943164,
"end_time": 1788943165,
"time_taken": 1,
"col_names": [
"chunked_content",
"doc_id_hash",
"document_format",
"embeddings",
"id",
"metadata",
"modified_time",
"name",
"pages_processed",
"path",
"source_id"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"node_metadata": {
"failed_docs": [],
"chunks_indexed_successfully": 4,
"processed_docs": 2,
"total_chunks_to_index": 4,
"node_status": "Completed",
"chunks_failed_to_index": 0,
"number_of_batches": 1,
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
},
"id": "0c773955-f1c7-4b68-b157-38966382cb9c",
"operator": "opensearch_vector_store"
},
"batch_id": null,
"batch_num": null
}
},
"batch_node_stats": {
"2636f8b6-ef9a-4805-bda0-9fcaa853e16a": {
"d9467158-dc5a-422e-92f7-d389776f8e50": {
"id": "2636f8b6-ef9a-4805-bda0-9fcaa853e16a",
"name": "ollama_embeddings",
"node_status": "Completed",
"error": "",
"start_time": 1788943164,
"end_time": 1788943164,
"time_taken": 0,
"col_names": [
"id",
"name",
"document_format",
"metadata",
"source_id",
"path",
"modified_time",
"pages_processed",
"chunked_content",
"embeddings",
"doc_id_hash"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"id": "2636f8b6-ef9a-4805-bda0-9fcaa853e16a",
"operator": "ollama_embeddings",
"node_metadata": {
"documents_in_scope": 2,
"processed_docs": 2,
"failed_docs_count": 0,
"failed_docs": [],
"skipped_docs_count": 0,
"skipped_docs": [],
"node_status": "Completed"
}
},
"batch_id": "d9467158-dc5a-422e-92f7-d389776f8e50",
"batch_num": 0
}
},
"0c773955-f1c7-4b68-b157-38966382cb9c": {
"d9467158-dc5a-422e-92f7-d389776f8e50": {
"id": "0c773955-f1c7-4b68-b157-38966382cb9c",
"name": "opensearch_vector_store",
"node_status": "Completed",
"error": "",
"start_time": 1788943164,
"end_time": 1788943165,
"time_taken": 1,
"col_names": [
"id",
"name",
"document_format",
"metadata",
"source_id",
"path",
"modified_time",
"pages_processed",
"chunked_content",
"embeddings",
"doc_id_hash"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"id": "0c773955-f1c7-4b68-b157-38966382cb9c",
"operator": "opensearch_vector_store",
"node_metadata": {
"documents_in_scope": 2,
"processed_docs": 2,
"failed_docs_count": 0,
"failed_docs": [],
"skipped_docs_count": 0,
"skipped_docs": [],
"node_status": "Completed",
"number_of_batches": 1,
"total_chunks_to_index": 4,
"chunks_indexed_successfully": 4,
"chunks_failed_to_index": 0
}
},
"batch_id": "d9467158-dc5a-422e-92f7-d389776f8e50",
"batch_num": 0
}
},
"447e0511-5125-4ffb-8396-edb972976080": {
"d9467158-dc5a-422e-92f7-d389776f8e50": {
"id": "447e0511-5125-4ffb-8396-edb972976080",
"name": "simple_chunker",
"node_status": "Completed",
"error": "",
"start_time": 1788943163,
"end_time": 1788943164,
"time_taken": 1,
"col_names": [
"id",
"name",
"document_format",
"metadata",
"source_id",
"path",
"modified_time",
"pages_processed",
"doc_id_hash",
"chunked_content"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"id": "447e0511-5125-4ffb-8396-edb972976080",
"operator": "simple_chunker",
"node_metadata": {
"documents_in_scope": 2,
"processed_docs": 2,
"failed_docs_count": 0,
"failed_docs": [],
"skipped_docs_count": 0,
"skipped_docs": [],
"node_status": "Completed",
"total_chunks": 4
}
},
"batch_id": "d9467158-dc5a-422e-92f7-d389776f8e50",
"batch_num": 0
}
},
"ca564648-1715-45c3-be67-7c654344a99c": {
"d9467158-dc5a-422e-92f7-d389776f8e50": {
"id": "ca564648-1715-45c3-be67-7c654344a99c",
"name": "extract_with_docling",
"node_status": "Completed",
"error": "",
"start_time": 1788943163,
"end_time": 1788943163,
"time_taken": 0,
"col_names": [
"id",
"name",
"document_format",
"metadata",
"source_id",
"path",
"modified_time",
"content",
"pages_processed",
"doc_id_hash"
],
"total_docs": 2,
"failed_docs": 0,
"skipped_docs": 0,
"docs_completed": 2,
"docs_completed_count": 2,
"node_metadata": {
"id": "ca564648-1715-45c3-be67-7c654344a99c",
"operator": "extract_with_docling",
"node_metadata": {
"documents_in_scope": 2,
"processed_docs": 2,
"failed_docs_count": 0,
"failed_docs": [],
"skipped_docs_count": 0,
"skipped_docs": [],
"node_status": "Completed",
"page_type_stats": {
"txt": 2
},
"total_pages_converted": 2
}
},
"batch_id": "d9467158-dc5a-422e-92f7-d389776f8e50",
"batch_num": 0
}
}
}
},
"node_metadata": [
{
"id": "ca564648-1715-45c3-be67-7c654344a99c",
"operator": "extract_with_docling",
"node_metadata": {
"failed_docs": [],
"processed_docs": 2,
"node_status": "Completed",
"total_pages_converted": 2,
"page_type_stats": {
"txt": 2
},
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
}
},
{
"id": "49f285b0-3afa-40eb-8111-3ec6a57c4904",
"operator": "ingest_source_filesystem",
"node_metadata": {
"documents_in_scope": 2,
"processed_docs": 2,
"failed_docs_count": 0,
"failed_docs": [],
"skipped_docs_count": 0,
"skipped_docs": [],
"node_status": "Completed"
}
},
{
"id": "447e0511-5125-4ffb-8396-edb972976080",
"operator": "simple_chunker",
"node_metadata": {
"failed_docs": [],
"total_chunks": 4,
"processed_docs": 2,
"node_status": "Completed",
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
}
},
{
"id": "2636f8b6-ef9a-4805-bda0-9fcaa853e16a",
"operator": "ollama_embeddings",
"node_metadata": {
"failed_docs": [],
"processed_docs": 2,
"node_status": "Completed",
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
}
},
{
"id": "0c773955-f1c7-4b68-b157-38966382cb9c",
"operator": "opensearch_vector_store",
"node_metadata": {
"failed_docs": [],
"chunks_indexed_successfully": 4,
"processed_docs": 2,
"total_chunks_to_index": 4,
"node_status": "Completed",
"chunks_failed_to_index": 0,
"number_of_batches": 1,
"failed_docs_count": 0,
"skipped_docs": [],
"documents_in_scope": 2,
"skipped_docs_count": 0,
"completed_docs_count": 2,
"Progress": "1 of 1 batches (100.0%) | Completed: 1"
}
}
]
}
Esta muestra no es completamente coherente: el job_run_id en job_stats difiere del ID del paso 5 y flow_id muestra el valor unknown. Correlacione las ejecuciones con el ID que recibió al inicio.
Qué leer primero en la respuesta
job_statsproporciona contadores de alto nivel comototal_docs,processed_docs,completed_docsyduration.
node_stats muestra la duración y el estado de cada paso; revíselo primero cuando una ejecución es lenta o falla.include_logs=true, los registros formateados se añaden en la raíz de la respuesta, identificados por el nombre de cada nodo (desde el nodo de ingestión hasta el almacén OpenSearch).Interpretación de los metadatos del nodo
Cada operador informa sobre la telemetría a través de node_metadata: rendimiento, errores y conversiones por etapa. Los atributos principales son:
documents_in_scope: un conteo entero de documentos en bruto que encontró y cargó el operador de ingestión; su punto de referencia.processed_docs: un conteo entero de documentos que este operador procesó con éxito en la ejecución; es igual adocuments_in_scopecuando no hay fallos.failed_docs_count: un conteo entero de documentos que presentaron errores aquí.failed_docs: un array cuyas entradas contienen unid, elnamedel archivo original, unareasonde error y undocument_url(vacío cuando los archivos provienen del disco local).skipped_docs_count: un conteo entero de documentos que se omitieron intencionalmente, por ejemplo mediante eliminación de duplicados, lógica de ramas o ejecuciones incrementales.skipped_docs: un array con la misma estructura quefailed_docs, dondereasonexplica el motivo de la omisión, como por ejemplo"Filtered by branch condition".page_type_stats: informado únicamente por el operador de extracción, un diccionario que relaciona la extensión del archivo con el conteo de páginas analizadas, por ejemplo{"pdf": 45, "docx": 12, "txt": 3}.- También de tipo extract-only,
total_pages_convertedrepresenta la suma entera de páginas en todos los formatos, utilizando los conteos nativos para los archivos digitales y los conteos OCR para las escaneos.
Una rápida verificación del estado: compare documents_in_scope al momento de la ingesta con processed_docs en el último nodo; failed_docs y skipped_docs explican cualquier diferencia.
Paso 7: revisar los flujos y el historial de ejecuciones de un proyecto
GET /api/v1/projects/{project_id}/flows muestra los flujos de un proyecto junto con un resumen de ejecuciones (total de ejecuciones, ID de la última ejecución, estado y hora de inicio, conteos por estado), paginado mediante total_count, offset y limit:
{
"flows": [
{
"flow_id": "e2c31e42-7719-482a-a53d-2490b830d971",
"name": "complete-document-pipeline",
"tags": ["docling", "embeddings", "opensearch"],
"created_on": "2026-09-07T10:05:00Z",
"job_run_summary": {
"total_runs": 1,
"last_run_id": "99ecd646-bb8e-494a-a0c5-86b40c1d4f90",
"last_run_status": "Completed",
"last_run_start_time": 1788775200000,
"status_counts": { "Completed": 1 }
}
}
],
"total_count": 1,
"offset": 0,
"limit": 100
}
En este ejemplo, last_run_start_time parece estar en milisegundos mientras que los valores de start_time de las ejecuciones son en segundos, por lo que es necesario normalizarlos antes de comparar.
Puntos clave
La API ofrece una interfaz sin cabeza para el procesamiento de documentos de extremo a extremo. Algunos hábitos la hacen fiable:
- Use
/operators/metadatay/providers/{provider}/modelspara descubrir de forma programática los campos de los operadores y las etiquetas de modelo disponibles, en lugar de codificarlos manualmente. - Ejecute cada definición de DAG a través de
/validation/validate_flowpara detectar tipos de parámetros incorrectos y conexiones de nodos dañadas antes de la ejecución. - Trate las ejecuciones como tareas asíncronas: guarde el
job_run_id, realice consultas coninclude_logs=truey leanode_statsynode_metadatapara localizar los fallos por etapa. - No incluya credenciales en las definiciones de flujos almacenadas y verifique que
vector_dimensioncoincida con su modelo de embedding.
Para probarlo, inicie Ollama y OpenSearch (o Milvus), ejecute docling-pipelines-api, abra la interfaz Swagger UI y siga la secuencia: proyecto, flujo, validación, ejecución y registros.
Lecturas relacionadas
- Dimensionamiento adecuado de LLMs: Enrutamiento, recuperación y evaluación según el tamaño del modelo — Aprenda cómo elegir entre modelos de lenguaje pequeños y grandes según la carga de trabajo, medir el costo por tarea completada con éxito y utilizar primero el enrutamiento, RAG, caché y validación.
- Cómo funcionan realmente las bases de datos vectoriales: desde los incrustados hasta la búsqueda híbrida — Explica cómo los incrustados codifican el significado, cómo escalan la búsqueda de similitud y el indexado, y cuándo la búsqueda híbrida y las bases de datos vectoriales son adecuadas para los sistemas de IA empresariales.