Gérer les pipelines Docling via HTTP : de la configuration du projet aux blocs indexés
Découvrez pas à pas l’API REST Docling Pipelines : lancez le serveur, identifiez les opérateurs, validez et exécutez un DAG d’ingestion, puis consultez les données de telemétrie relatives à son exécution.
Sources: **A Hands-On Guide to the Docling Pipelines REST API**
Transformer un dossier de fichiers PDF et Word en blocs vectoriels recherchables nécessite généralement du code d’intermédiation pour l’extraction, le découpage, l’incorporation et l’indexation. Docling Pipelines regroupe ces étapes en opérateurs au sein d’un serveur REST basé sur FastAPI, permettant ainsi à n’importe quel client, qu’il s’agisse d’un service Node.js ou d’une interface admin, de créer des pipelines DAG modulaires, de les valider et de déclencher leurs exécutions asynchrones via HTTP. Cette présentation montre comment démarrer le serveur avec Ollama et OpenSearch, puis suit l’intégralité du cycle de vie d’une requête, depuis la création d’un projet jusqu’à la lecture des statistiques d’exécution par nœud.
Préparation des services de base
Le serveur orchestre les tâches, mais l’incorporation des données vectorielles et leur stockage ont lieu ailleurs : ici, Ollama pour les modèles et OpenSearch en tant que stockage vectoriel. Démarrez-les d’abord.
Le chemin le plus rapide est le QUICKSTART.md du projet, qui met en œuvre Ollama, une base de données vectorielle ainsi que les conteneurs nécessaires en quelques minutes. Un agent de codage IA tel que Cursor, Claude Code ou Copilot peut également effectuer la configuration et la vérification ; dans tous les cas, assurez-vous que chaque service répond.
Sélection d’un stockage vectoriel
C’est une décision architecturale. OpenSearch convient lorsque vous souhaitez une recherche hybride, combinant la correspondance par mots-clés avec des vecteurs denses. Milvus est adapté à une infrastructure dédiée et hautement scalable pour de très grandes collections vectorielles. Ce guide utilise OpenSearch.
Démarrage du serveur API
Activez l’environnement virtuel où le paquet est installé et exécutez la commande fournie :
source .venv/bin/activate
docling-pipelines-api
Pour le rechargement en temps réel pendant le développement, exécutez l’application directement via uvicorn, en la liant à toutes les interfaces sur le port 8080 :
uvicorn docpipe.api.main:app --reload --host 0.0.0.0 --port 8080
Quatre URLs sont alors disponibles :
http://localhost:8080/healthpour les vérifications d’état ;http://localhost:8080/api/v1/docspour l’interface interactive Swagger UI ;http://localhost:8080/api/v1/redocpour la documentation ReDoc ;http://localhost:8080/api/v1/openapi.jsonpour le schéma OpenAPI brut.
Avec TypeScript, vous pouvez fournir le document OpenAPI à un générateur de clients au lieu d’écrire manuellement les types de requête.
Variables d’environnement qui influencent le serveur
Définissez-les avant le lancement pour ajuster le comportement :
DS_LOG_LEVELdéfinit le niveau de détail des journaux. Sa valeur par défaut estINFO, et il accepte les valeursDEBUG,INFO,WARNINGouERROR.DOCPIPE_STORAGE_BACKENDchoisit l’endroit où sont stockés les métadonnées :duckdb(par défaut, local) oupostgres.CORS_ORIGINSliste les origines autorisées à appeler l’API depuis une interface frontale en navigateur. Sa valeur par défaut esthttp://localhost:3000.OLLAMA_HOSToriente les opérateurs d’incorporation et de LLM vers Ollama. La valeur par défaut esthttp://localhost:11434; modifiez-la si Ollama fonctionne sur un autre port ou une autre machine.
Découverte des points d’entrée dans Swagger UI
Ouvrez http://localhost:8080/api/v1/docs dans un navigateur ; aucun login n’est nécessaire localement. Développez une extrémité d’API, cliquez sur Essayer, et envoyez les données ci-dessous sans écrire de client.
Le cycle de vie d’une requête en un coup d’œil
Un aller-retour complet comprend sept appels, de la création du projet à le résumé de son exécution :
1. Create Project ──▶ 2. Discover Operators ──▶ 3. Validate Flow ──▶ 4. Create Flow ──▶ 5. Execute Run ──▶ 6. Fetch Logs ──▶ 7. Summary
Étape 1 : créer un projet
Les projets regroupent les flux et en suivent les statistiques d’exécution agrégées. Créez-en un avec POST /api/v1/projects :
{
"name": "Sample Docling Pipeline Project",
"description": "Flows for processing invoice documents",
"tags": ["finance", "pdf", "q3"]
}
Les champs :
nameest une chaîne obligatoire de 1 à 255 caractères qui identifie de manière unique le projet.descriptionest une explication courte facultative sur l’objectif du projet.tagsest un tableau facultatif de chaînes pour la catégorisation.
Le succès renvoie 201 Created accompagné d’un project_id généré, d’un flow_count égal à zéro, de timestamps ainsi que d’une href menant au resource :
{
"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"
}
Étape 2 : découvrir les opérateurs et les modèles
Au lieu de deviner les noms et les options des opérateurs, demandez-les au serveur.
Métadonnées des opérateurs
GET /api/v1/operators/metadata renvoie un schéma détaillé pour chaque opérateur, couvrant les plus de 20 opérateurs intégrés ainsi que tous les opérateurs externes que vous avez enregistrés. Le paramètre de requête internal_features a pour valeur par défaut false.
Dans chaque entrée, features décrit les colonnes produites par un opérateur, required_features celles dont il a besoin en provenance des sources externes, et attributes ses options avec leurs types et valeurs par défaut. L’opérateur d’extraction émet content et doc_id_hash ; le fragmentateur a besoin de 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"
}
}
}
}
En comparant required_features avec les sorties des sources externes, on peut s’assurer, avant soumission, que chaque nœud recevra bien les colonnes nécessaires.
Modèles de fournisseurs
GET /api/v1/providers/{provider}/models interroge un fournisseur en temps réel (ollama ou watsonx) ; ainsi, tout modèle manquant ou toute étiquette mal saisie est détecté avant l’exécution :
curl -s http://localhost:8080/api/v1/providers/ollama/models | jq
Chaque modèle est listé avec son nom, son étiquette, la date de modification et sa taille en octets :
{
"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
}
]
}
Étape 3 : valider le flux avant de le sauvegarder
POST /api/v1/validation/validate_flow vérifie un DAG à la recherche de paramètres incorrects et de dépendances brisées sans le stocker ni l’exécuter.
global_config définit des options applicables à l’ensemble du processus (colonne de document, exécution locale, stockage en mémoire, ré-ingestion forcée). flow liste les nœuds, chacun disposant d’un type, d’un name unique, d’une config ainsi que d’un tableau depends_on indiquant ses dépendances en amont. Le pipeline :
- ingère des fichiers PDF, TXT et DOCX provenant de
./sample_documentssur le système de fichiers local ; - extrait leur texte à l’aide de la bibliothèque Docling et omet l’extraction d’entités ;
- découpe le contenu en blocs de 512 unités avec une superposition de 50 unités ;
- incorpore chaque bloc via LiteLLM, en se référant à l’endpoint compatible OpenAI d’Ollama utilisant le modèle
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"]
}
]
}
Certains détails sont importants. vector_dimension (768) doit correspondre à la taille de sortie du modèle d’embedding. Les identifiants se présentent sous forme de placeholders tels que ${OPENSEARCH_USERNAME} et <ollama-api-key> ; conservez les secrets réels dans des variables d’environnement ou un stockage sécurisé, et non dans les flux enregistrés. Désactiver use_ssl et verify_certs est acceptable en local, mais pas sur un cluster partagé. De plus, le chunker utilise chunk_type: "simple", tandis que les extraits de métadonnées décrivent chunker_type comme fixed, semantic ou hybrid ; vérifiez ce que votre serveur renvoie.
200 OK, is_valid: true, des champs errors et warnings vides, ainsi que le comptage des nœuds :
{
"is_valid": true,
"errors": [],
"warnings": [],
"node_count": 5
}
Étape 4 : enregistrer le flux
Enregistrez la définition validée via POST /api/v1/flows (is_elyra vaut par défaut false). Le corps de la requête contient le même DAG accompagné d’une description et de des tags :
{
"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"]
}
]
}
Deux paramètres globaux sont importants ici :
execute_type: "local"exécute le pipeline à l’intérieur du processus serveur.force_ingest: trueretraite les documents déjà ingérés : utile lors de l’itération, mais gaspilleur en situation stable.
La réponse est 201 Created, accompagnée d’un nouveau flow_id ainsi que des paramètres enregistrés :
{
"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"
}
Étape 5 : lancer une exécution
Les exécutions sont asynchrones. POST /api/v1/job_runs prend l’ID et le nom du flux :
{
"flow_id": "e2c31e42-7719-482a-a53d-2490b830d971",
"flow_name": "complete-document-pipeline"
}
Il renvoie immédiatement 201 Created accompagné d’un job_run_id et d’un statut Starting, tandis que le travail se poursuit en arrière-plan :
{
"job_run_id": "99ecd646-bb8e-494a-a0c5-86b40c1d4f90",
"status": "Starting",
"message": "Job run created successfully"
}
Étape 6 : vérifier le statut, les métriques et les journaux
Vérifier GET /api/v1/job_runs/{job_run_id}, en ajoutant include_logs=true pour les journaux par nœud, jusqu’à ce que le statut devienne final (comme Completed), de préférence avec des délais croissants.
La longue réponse 200 OK contient node_sequence (ordre d’exécution), job_stats (compteurs applicables à toute l’opération, avec des node_stats par nœud et des batch_node_stats par lot) ainsi qu’un tableau node_metadata de niveau supérieur. Deux fichiers texte ont été transmis à tous les cinq nœuds, générant quatre blocs, tous indexés :
{
"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"
}
}
]
}
Cet exemple n’est pas entièrement cohérent : le job_run_id dans job_stats diffère de l’ID de l’étape 5 et flow_id indique unknown. Corrigez les correspondances en vous basant sur l’ID que vous avez reçu au début.
Que lire en premier dans la réponse
job_statsfournit des compteurs de haut niveau tels quetotal_docs,processed_docs,completed_docsetduration.
node_stats affiche la durée et l’état de chaque étape ; vérifiez-le en premier lorsqu’une exécution est lente ou échoue.include_logs=true, des journaux formatés sont ajoutés à la racine de la réponse, identifiés par le nom de chaque nœud (depuis le nœud d’ingestion jusqu’à l’archive OpenSearch).Interprétation des métadonnées des nœuds
Chaque opérateur rapporte des données de télémétrie sous node_metadata : débit, erreurs et conversions par étape. Les principaux attributs sont :
documents_in_scope: un nombre entier indiquant le nombre de documents bruts trouvés et chargés par l’opérateur d’ingestion ; c’est votre référence de base.processed_docs: un nombre entier indiquant le nombre de documents que cet opérateur a traités avec succès lors de l’exécution ; il est égal àdocuments_in_scopelorsque rien ne fait défaut.failed_docs_count: un nombre entier indiquant le nombre de documents qui ont généré une erreur ici.
failed_docs : un tableau dont les éléments contiennent un id, le name du fichier d’origine, une reason d’erreur et un document_url (vide lorsque les fichiers proviennent du disque local).skipped_docs_count : un nombre entier indiquant le comptage des documents intentionnellement ignorés, par exemple en raison de la suppression des doublons, de la logique de branche ou d’exécutions incrémentielles.skipped_docs : un tableau de la même structure que failed_docs, où la valeur reason explique pourquoi le document a été ignoré, comme par exemple "Filtered by branch condition".page_type_stats : rapporté uniquement par l’opérateur d’extraction, un dictionnaire reliant l’extension du fichier au nombre de pages analysées, par exemple {"pdf": 45, "docx": 12, "txt": 3}.total_pages_converted représente la somme entière des pages selon les différents formats, en utilisant le comptage natif pour les fichiers numériques et celui obtenu via l’OCR pour les scans.Vérification rapide de l’état : comparez documents_in_scope au moment de l’ingestion avec processed_docs au dernier nœud ; failed_docs et skipped_docs expliquent toute différence.
Étape 7 : examiner les flux et l’historique des exécutions d’un projet
GET /api/v1/projects/{project_id}/flows liste les flux d’un projet accompagnés d’un résumé des exécutions (nombre total d’exécutions, ID de la dernière exécution, statut et heure de début, comptage par statut), paginé selon total_count, offset et 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
}
Dans cet exemple, last_run_start_time semble indiquer des valeurs en millisecondes tandis que les valeurs de start_time pour les exécutions des tâches sont en secondes ; il convient donc de normaliser ces valeurs avant de les comparer.
Points clés
L’API propose une interface headless pour le traitement complet des documents. Quelques bonnes pratiques permettent d’en assurer la fiabilité :
- Utilisez
/operators/metadataet/providers/{provider}/modelspour découvrir de manière programmative les champs des opérateurs et les étiquettes des modèles disponibles, plutôt que de les coder manuellement. - Faites passer chaque définition DAG par
/validation/validate_flowafin de détecter les types de paramètres incorrects et les connexions de nœuds défectueuses avant l’exécution. - Considérez les exécutions comme des tâches asynchrones : conservez le
job_run_id, effectuez des requêtes de suivi avecinclude_logs=true, et liseznode_statsainsi quenode_metadatapour identifier les échecs par étape. - Évitez de stocker les identifiants dans les définitions de flux, et vérifiez que
vector_dimensioncorrespond bien à votre modèle d’incorporation.
Pour essayer, lancez Ollama et OpenSearch (ou Milvus), exécutez docling-pipelines-api, ouvrez l’interface Swagger UI, et suivez la séquence : projet, flux, validation, exécution, journaux.