Tuyaux Docling : Création de tuyaux de données RAG de niveau entreprise
Comment docling-pipelines remplace les scripts fragiles par des opérateurs composables et des flux JSON : ingestion, extraction, contrôles de qualité, embeddings et stockage vectoriel.
Sources: Introducing Docling Pipelines: Building Enterprise-Grade RAG Data Pipelines
Où le code de collage échoue
Imaginez un disque partagé contenant 10 000 PDF, un site SharePoint rempli de fichiers Word, ainsi qu’une pile de appels clients enregistrés. L’équipe de développement en amont souhaite que tout cela soit stocké dans un entrepôt vectoriel, consultable et divisé en blocs, avec les données personnelles supprimées et les doublons éliminés.
La réponse habituelle des ingénieurs consiste à utiliser un script, puis un deuxième script. Quelques bibliothèques sont intégrées, un notebook Pandas les relie entre eux, une tâche cron exécute tout cela chaque nuit, et le système est prêt à l’emploi. Ça fonctionne, pendant un certain temps.
Trois mois plus tard, quelqu’un demande pourquoi de nouveaux documents manquent. L’enquête mène à un changement de schéma dans une colonne ultérieure, et le script a discrètement éliminé ces lignes. Personne ne s’en est aperçu, car rien n’était visible. Après la correction, une nouvelle exécution a lieu, et c’est alors que l’on se rend compte qu’il n’existe aucun enregistrement indiquant quels documents ont déjà été traités, si bien que les 10 000 documents sont tous traités à nouveau.
Telle est la vie typique d’un élément de liaison dans un pipeline de documents. Il commence simplement et se détériore progressivement, puis brusquement. Des tentatives de réexécution sont ajoutées en urgence, le filtrage de qualité arrive en dernier, et il n’y a pas de suivi des dépendances entre les étapes ; par conséquent, le succès dépend du fait que les scripts s’exécutent par hasard dans le bon ordre. Les mises à jour incrémentales sont difficiles sans une identité stable des documents. Ce qui reste, c’est un enchevêtrement que seul son auteur peut déboguer, et même l’auteur n’en est plus sûr.
Qu’est-ce que les pipelines docling
Docling-pipelines est un framework modulaire basé sur des opérateurs pour le traitement de documents, conçu pour construire des pipelines de données RAG complets. Son champ d’application couvre tout le cycle de vie, en commençant par l’ingestion depuis des sources locales ou cloud, puis l’extraction de texte et d’entités, le filtrage de qualité, le découpage et l’incorporation dans des embeddings, pour se terminer par l’écriture dans une base de données vectorielle. C’est la voie standard, et la plupart des pipelines en production en sont une variation.
Il s’installe en tant que package Python ordinaire :
bash
pip install docling-pipelines
Il fonctionne partout où Python le fait. Pour une utilisation de base, il n’a besoin d’aucune infrastructure externe : pas de Kafka, pas de cluster Spark, rien à installer. Un pipeline est décrit dans un fichier JSON, l’interface en ligne de commande est orientée vers ce fichier, et l’exécution commence.
Il existe trois manières d’y accéder. L’CLI convient aux exécutions ponctuelles et au développement local. La bibliothèque Python, centrée sur DocpipeFlowManager, permet de déclencher des pipelines depuis du code d’application ou des notebooks. L’REST API est destiné aux pipelines exécutés en tant que service partagé utilisé par plusieurs équipes. Tous ces trois aspects sont abordés ci-dessous.
Le projet est open source, et sa première version, v0.1.0, est sortie en juillet 2025.
L’idée principale : opérateurs et flux
Tout nouveau venu dans ce framework devrait consacrer le plus de temps ici, car le reste devient clair une fois cela compris.
L’opérateur est l’unité de base. Un opérateur est une classe Python qui accepte une table de documents et renvoie une table, éventuellement transformée. Chaque fonctionnalité du framework, que ce soit l’ingestion, l’extraction, la détection de langue, le découpage ou les embeddings, est un opérateur.
Les obligations sont peu nombreuses :
short_name: la chaîne de caractères que JSON Flow utilise pour faire référence à l’opérateurtransform(table): prend unpa.Tableet renvoie une liste de tables ainsi qu’un dictionnaire de métadonnéesget_metadata(): une méthode@staticmethodqui renvoie les métadonnées de l’opérateur afin qu’il puisse être découvertget_required_features(): indique quels colonnes l’opérateur nécessite en entréevalidate(): un crochet optionnel qui vérifie la configuration au démarrage
Un squelette minimal ressemble à ceci :
from docpipe.core.operators.abstract_operator import AbstractOperator, OperatorCategory
import pyarrow as pa
class MyOperator(AbstractOperator):
short_name = "my_operator"
category = OperatorCategory.Quality
def __init__(self, config: dict) -> None:
super().__init__(config)
def transform(self, table: pa.Table) -> tuple[list[pa.Table], dict]:
metadata = self.create_base_metadata(total_docs_count=len(table))
# … process table …
return [table], metadata
@staticmethod
def get_metadata() -> dict:
return {"short_name": "my_operator", "description": "…"}
La mise en œuvre de ces méthodes permet d’obtenir un composant de première classe qui peut être combiné avec n’importe quel autre opérateur de l’écosystème.
Les tables PyArrow stockent les données. Chaque opérateur reçoit un objet pa.Table et en renvoie un. C’est un choix délibéré, car le format colonne par colonne de PyArrow est efficace et typé, et il permet de transférer les données entre les étapes sans les copier. Les chaînes de caractères brutes et les dictionnaires Python ne sont jamais transférés d’une étape à l’autre.
La conséquence intéressante est que les colonnes s’accumulent au fur et à mesure que les données avancent. L’étape d’ingestion ajoute les colonnes id, name, path et source. L’étape d’extraction ajoute la colonne content. L’étape de segmentation ajoute chunked_content, tandis que l’étape d’incorporation d’embeddings ajoute embeddings. Lorsqu’une ligne arrive dans le stockage vectoriel, elle contient un enregistrement complet, avec toutes ses colonnes et métadonnées, prêt à être indexé.
Un opérateur ne touche que les colonnes qui l’intéressent, et tout le reste passe à côté sans être modifié. Un nouvel opérateur peut donc être inséré n’importe où sans affecter ses voisins.
Un flux est un DAG. Le pipeline est stocké dans un fichier JSON. Chaque nœud définit un type (le nom abrégé de l’opérateur), un name unique au sein du graphe, un bloc config ainsi qu’une liste depends_on. Lors du démarrage, le moteur résout le graphe de dépendances et exécute les nœuds dans un ordre topologique, les branches parallèles s’exécutant en même temps.
Ainsi, la structure du pipeline est constituée de données et non de code. Elle peut être versionnée, comparée, validée statiquement et remplacée sans toucher au Python. L’option --validate signale les violations de dépendances, les colonnes manquantes et les erreurs de configuration avant même que le moindre document ne soit traité.
Pourquoi le modèle fonctionne. Deux avantages se distinguent dans la pratique.
Le premier est la composabilité. Un opérateur peut suivre n’importe quel autre à condition que les opérateurs précédents aient généré les colonnes qu’il liste dans get_required_features(). Le moteur vérifie cela au démarrage et indique la colonne manquante exacte ainsi que le nœud qui aurait dû la fournir, tout cela avant le début de l’exécution.
Le second avantage est la testabilité. Chaque opérateur se comporte comme une fonction pure d’une table à l’autre, ce qui permet de le tester individuellement : il suffit de créer une pa.Table avec les colonnes nécessaires, d’appeler transform() et de vérifier le résultat. Aucun mock, aucun effet secondaire et aucun pipeline en temps réel ne sont requis.
Présentation des opérateurs
Il existe 22 opérateurs intégrés répartis en cinq catégories. Il s’agit d’un aperçu rapide.
Ingestion. IngestSource est le seul opérateur d’ingestion, couvrant à la fois les sources locales et les sources cloud. Un chemin local utilise le fournisseur filesystem, et le même nœud peut passer à n’importe lequel des huit fournisseurs cloud (S3, IBM COS, SharePoint, OneDrive, Google Drive, Box, fichiers CSV et pages web) sans que rien d’autre dans le flux ne change. Il génère une ligne par fichier ne contenant que des métadonnées, sans contenu pour l’instant. L’étape d’extraction récupère ensuite le contenu, ce qui permet une ingestion rapide et peu gourmande en mémoire, même à grande échelle.
Extraction. Extract transforme les fichiers bruts en texte structuré. Les fichiers PDF, DOCX, HTML, images, audio et vidéo deviennent tous du markdown grâce à Docling, soit en mode bibliothèque (local, sans appel réseau), soit via Docling Serve en mode API, ce qui convient pour déléguer les tâches d’extraction lourdes à un service dédié.
L’extraction d’entités est optionnelle en plus de cela, avec trois fournisseurs : LiteLLM (qui redirige vers plus de 100 fournisseurs de modèles), IBM watsonx.ai, et l’extraction basée sur des modèles de Docling. Le choix dépend de l’accès aux modèles et des coûts associés.
ACLOperator fait partie de l’étape d’extraction. Il extrait les métadonnées de contrôle d’accès des documents dans une colonne distincte, permettant ainsi aux systèmes suivants d’appliquer des mesures de sécurité au niveau du document sans avoir à consulter à nouveau le fichier source.
Functionnel. Cette catégorie comprend la logique du pipeline : des opérateurs qui transforment, redirigent et restructurent les données plutôt que de les enrichir.
ChunkerOperator divise le texte extrait en blocs en utilisant l’une de trois stratégies : simple (taille de caractère fixe, chevauchement configurable), sémantique (basée sur le contenu) ou hybride (blocage natif de Docling qui conserve la structure du document). Il peut également résumer chaque bloc à l’aide d’un LLM, ce qui offre une représentation plus riche pour la récupération des informations.
EmbeddingsOperator crée des embeddings vectoriels pour chaque bloc. Il fonctionne avec des modèles HuggingFace exécutés localement, LiteLLM (plus de 100 fournisseurs cloud) et IBM watsonx.ai, et le changement de modèle d’embedding se fait en une seule ligne dans le fichier JSON de flux.
BranchingOperator est là où les flux deviennent intéressants. Il divise les documents en sous-processus distincts en fonction des valeurs des colonnes, de conditions de type SQL ou de labels de classification. Chaque branche fonctionne de manière indépendante et est référencée par son nom dans depends_on à l’aide de notation avec point, par exemple "depends_on": ["branch_node.branch_name"].
MergeOperator réunit à nouveau les flux issus des branches, soit en empilant les lignes, soit en joignant les colonnes, en fonction des attentes des opérateurs suivants.
DocIdHashOperator génère un ID de hachage déterministe et stable à partir du contenu de chaque document. Cet ID est à la base de la suppression des doublons et du traitement incrémentiel : le même document reçoit toujours le même ID, où qu’il soit et quand qu’il ait été ingéré.
EntityCurationOperator et NOOPOperator complètent cet ensemble. Le premier s’occupe du nettoyage des entités après extraction, tandis que le second est un nœud de passage qui facilite la connexion des éléments au sein du DAG.
Qualité. Les opérateurs de ce groupe marquent la différence entre disposer simplement d’un pipeline et en avoir un fiable.
LanguageDetect identifie la langue d’un document à l’aide de fastText et ajoute une colonne lang_name qui permet de mettre en œuvre des filtres, des routages ou des étiquetages.
ReadabilityOperator évalue chaque document selon cinq critères de lisibilité : la facilité de lecture selon Flesch, le niveau de difficulté selon Flesch-Kincaid, le Gunning Fog, le Dale-Chall, ainsi que le nombre de mots difficiles. Ces évaluations fournissent des indications utiles pour le routage, par exemple afin de distinguer la documentation technique du contenu général avant de choisir une stratégie de segmentation.
PIIAndHAPAnnotator utilise une détection basée sur des modèles de langage pour identifier et masquer les informations personnelles (adresses e-mail, numéros de téléphone, numéros de sécurité sociale, numéros de carte, comptes bancaires, adresses IP), ainsi que les contenus haineux, abusifs ou obscènes, des seuils étant définis pour chaque catégorie.
RedactionOperator s’occupe du masquage basé sur des motifs, lorsque les formats sont connus, tels que des identifiants internes, des codes de produit ou tout ce que des expressions régulières peuvent reconnaître.
EdedupOperator supprime les doublons exacts au sein de l’ensemble de documents, en utilisant la colonne doc_id_hash pour le faire de manière déterministe.
SQLFilterOperator compte parmi les éléments les plus sous-estimés. Il filtre les lignes en utilisant une condition SQL WHERE basée sur les valeurs des colonnes, de sorte que "docq_total_words > 100 AND lang_name = 'en'" constitue un mécanisme de contrôle de qualité complet sans aucune utilisation de Python. Associé aux scores de lisibilité et à la détection de langue, il permet un routage assez complexe sans écrire de code.
DocumentClassifierOperator classe les documents dans des catégories configurables. DocQuality calcule des métriques de qualité pour l’ensemble du corpus, tandis que MLEnrichmentOperator ajoute des prédictions issues de l’apprentissage automatique en tant que colonnes supplémentaires. Ce que soulignent également d’autres descriptions de pipelines, c’est que la qualité des données a souvent un impact bien plus important sur les résultats RAG que le choix du modèle lui-même.
VectorDB et stockage. VectorDBOperator écrit des documents fragmentés et intégrés dans un stockage vectoriel, avec OpenSearch et Milvus comme backends pris en charge. Les mappages de champs, les paramètres d’indexation et la normalisation des métadonnées sont tous définis dans le JSON du flux.
DocumentSetOperator enregistre la table traitée dans un ensemble de documents géré par DuckDB. Cela est utile lorsque les documents traités doivent pouvoir être consultés sans stockage vectoriel, ou lorsqu’on souhaite un point de contrôle durable au milieu du pipeline.
StorageOutputOperator écrit les documents vers des destinations externes (S3, SharePoint, Google Drive ou le système de fichiers local), sous forme traitée ou originale, ce qui convient aux schémas de type « traiter et archiver ».
Tous ces éléments peuvent être assemblés dans n’importe quel ordre tant que les dépendances en amont sont remplies, de sorte que le pipeline n’est pas contraint par une structure fixe.
Un flux réel
Voici le flux de démarrage canonique, un pipeline complet allant de l’ingestion au stockage vectoriel qui utilise Ollama pour les embeddings et OpenSearch pour le stockage :
{
"flow_name": "complete-document-pipeline",
"global_config": {
"doc_column": "content",
"storage": "in-memory"
},
"flow": [
{
"type": "ingest_source",
"name": "ingest_local_folder",
"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"
},
"entity_extraction": {
"provider": "none"
}
},
"depends_on": [
"ingest_local_folder"
]
},
{
"type": "chunker",
"name": "simple_chunker",
"config": {
"chunk_type": "simple",
"chunk_size": 512,
"chunk_overlap": 50
},
"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"
},
"embeddings_column": "embeddings"
},
"depends_on": [
"simple_chunker"
]
},
{
"type": "vectordb",
"name": "opensearch_vector_store",
"config": {
"provider": "opensearch",
"doc_id_column": "doc_id_hash",
"embeddings_column": "embeddings",
"provider_config": {
"index_name": "sample-documents-index",
"host": "localhost",
"port": 9200
}
},
"depends_on": [
"ollama_embeddings"
]
}
]
}
Passage nod par nod :
- ingest_local_folder parcourt
./sample_documentsà la recherche de fichiers PDF, de texte et DOCX au moyen deingest_sourceet de son fournisseur de système de fichiers. Chaque fichier devient une ligne contenant l’ID, le nom, le chemin et la source. Le contenu n’est pas lu à ce stade, ce qui rend l’opération rapide : il s’agit simplement de trouver les fichiers sans les charger. - extract_with_docling prend ces lignes de métadonnées, lit chaque fichier avec Docling et ajoute une colonne
contentcontenant le markdown extrait. C’est à ce moment que les PDF se transforment en texte structuré et consultable. Le fournisseurdocling_librarys’exécute entièrement en interne, il n’est donc pas nécessaire d’utiliser de service externe.
chunked_content, une liste structurée d’objets de bloc contenant chacun leur texte et leur position dans le document source.embeddings. Il s’agit simplement de LiteLLM adapté à Ollama ; en modifiant model_id et api_base, on le redirige vers l’un des plus de 100 fournisseurs pris en charge par LiteLLM, sans autre modification.doc_id_hash comme clé primaire. Par conséquent, une exécution ultérieure ne crée jamais de doublons.Quelques points structurels méritent une attention particulière. depends_on est le seul lien requis : il n’y a ni transmission explicite de données, ni enregistrement de fonction de rappel, ni état partagé, car le moteur résout le graphe et transfère les données. Le bloc global_config définit des valeurs par défaut que chaque opérateur hérite. doc_column indique quelle colonne contient le texte principal, et storage: "in-memory" conserve les tables intermédiaires en RAM entre les étapes, ce qui convient à la plupart des exécutions et peut être remplacé par un stockage externe pour de gros ensembles de données.
Tout le pipeline s’exécute avec une seule commande :
docling-pipelines - flow-file pipeline.json
Modèles avancés
Les flux n’ont pas nécessairement à être des chaînes linéaires. Trois modèles se retrouvent fréquemment dans les déploiements réels.
Départementalisation et fusion. La départementalisation envoie des documents vers différentes sous-pipelines selon des critères configurables. Chaque branche représente une sortie nommée que les nœuds suivants référencent à l’aide de la notation avec point dans depends_on. Une branche de routage basée sur le score de lisibilité ressemble à ceci :
{
"name": "quality_branching",
"type": "branching",
"config": {
"branches": {
"high_quality_branch": {
"link_name": "High Quality Documents",
"criteria_json": {
"criteria_list": [
{
"variable": "flesch_reading_ease",
"operator": ">",
"value": 60
}
],
"logical_operator": "AND"
}
},
"low_quality_branch": {
"link_name": "Low Quality Documents",
"criteria_json": {
"criteria_list": [
{
"variable": "flesch_reading_ease",
"operator": "<=",
"value": 60
}
],
"logical_operator": "AND"
}
}
}
},
"depends_on": [
"readability"
]
}
La branche de haute qualité peut être soumise à un enrichissement par apprentissage automatique avant l’incorporation, tandis que la branche de faible qualité passe par un autre SQLFilterOperator qui élimine les documents ne contenant aucun mot avant l’incorporation. Les deux finissent dans des index OpenSearch distincts, et MergeOperator peut récombiner ces flux par la suite lorsque la logique ultérieure nécessite une vue unique.
Routeur contrôlé par la qualité. L’idée consiste à exécuter d’abord des opérateurs de qualité peu coûteux, puis à laisser SQLFilterOperator éliminer les lignes avant toute étape coûteuse impliquant un LLM. Un système de contrôle complet peut ressembler à ceci :
lang_detect → ededup → doc_quality → readability → sql_filter → embeddings
La condition sql_filter n’est rien d’autre qu’une clause SQL WHERE exprimée sous forme de données :
{
"criteria_list": [
{
"variable": "docq_total_words",
"operator": ">",
"value": 100
},
{
"variable": "lang_name",
"operator": "=",
"value": "en"
}
],
"logical_operator": "AND"
}
Il n’y a ni Python ni opérateur personnalisé, seulement une condition dans le JSON, et chaque ligne qui ne la satisfait pas n’atteint jamais l’appel d’embedding.
Enrichissement en plusieurs étapes. La séquence « classer, diriger, extraire, enrichir, stocker » apparaît constamment en environnement de production. Les documents peuvent d’abord être classés, les documents techniques étant acheminés vers un extracteur d’entités adapté au contenu technique, tandis que les documents de politique sont acheminés vers un autre extracteur. Chaque branche ajoute des colonnes d’enrichissement spécifiques à son type, et les flux se fusionnent avant le chunking et l’embedding afin que le reste du pipeline soit partagé.
Chaque étape ajoute des colonnes, et les opérateurs suivants disposent d’une table de plus en plus riche. Rien de tout cela ne dépend de modes ou de flags spéciaux. Il s’agit d’opérateurs ordinaires assemblés ensemble, ce qui constitue l’avantage du modèle d’opérateurs.
Trois façons de l’exécuter
Ce framework est bien plus qu’un outil CLI et s’adapte à divers contextes d’ingénierie.
CLI. C’est le moyen le plus rapide pour mettre en marche un pipeline :
docling-pipelines - flow-file pipeline.json
docling-pipelines - flow-file pipeline.json - validate # validate without running
docling-pipelines - list-operators - verbose # discover all registered operators
--validate s’avère utile pendant le développement d’un flux : les violations de dépendance, l’absence de colonnes requises ainsi que les erreurs de type de configuration apparaissent avant même que quoi que ce soit ne soit lu ou écrit. Il est bon d’exécuter cette commande dans l’environnement CI avant de déployer des modifications de flux.
Bibliothèque Python. Lorsque les pipelines doivent être déclenchés depuis du code d’application :
from docpipe.lib.docpipe_flow_manager import DocpipeFlowManager
manager = DocpipeFlowManager(flow_file="pipeline.json")
manager.execute()
Cela convient aux codes intégrés dans une application plus grande, un notebook, ou un script d’orchestration qui doit gérer le cycle de vie de l’exécution lui-même.
REST API. Pour fonctionner en tant que service à long terme :
uvicorn docpipe.api.main:app - host 0.0.0.0 - port 8000
Le serveur FastAPI expose trois groupes de routes : /api/v1/flows pour gérer les flux, /api/v1/job_runs pour contrôler les exécutions de tâches, et /api/v1/operators pour découvrir les opérateurs. Les utilisateurs s’authentifient via LDAP ou OAuth2/OIDC en utilisant des tokens JWT, et la documentation OpenAPI/Swagger est générée automatiquement à l’adresse /docs. Il s’agit de l’interface d’un service partagé utilisé par plusieurs équipes, déclenché par des événements externes, et auquel d’autres équipes consultent l’état et les résultats.
Extension avec des opérateurs personnalisés
Pour une adoption durable au sein des organisations réelles, c’est sans doute la partie la plus importante du design.
Le contrat est suffisamment compact pour qu’un opérateur occupe environ 30 lignes. Une classe Python est éligible si elle hérite de AbstractOperator et implémente transform(), get_metadata() ainsi que get_required_features(). Elle peut être combinée avec tous les opérateurs intégrés, apparaît dans la sortie de --list-operators, et le JSON de flux fait référence à elle via short_name, tout comme pour un opérateur intégré.
L’enregistrement se fait de trois manières, en fonction de l’étape de développement.
Chemin du système de fichiers est utilisé pour le développement. Pointez une variable d’environnement vers un répertoire local :
DOCPIPE_CUSTOM_OPERATORS=./my_operators docling-pipelines - flow-file pipeline.json
Tout ce qui se trouve dans ce répertoire est importé au démarrage. Aucune installation n’est nécessaire, ce qui rend l’itération rapide.
Le package Python est destiné à la distribution. Publiez les opérateurs en tant que package pip avec le bon point d’entrée, installez-le dans le même environnement, et ils s’enregistreront automatiquement. C’est ainsi que les opérateurs atteignent d’autres équipes sans que quiconque ait à toucher au code de base.
L’URI S3 représente l’option d’entreprise. Pointez DOCPIPE_CUSTOM_OPERATORS vers un package d’opérateur distant, et le framework le téléchargera et l’enregistrera en temps de exécution. Cela permet une gestion centralisée des opérateurs sur de nombreuses déploiements : une seule source de mise à jour, et chaque déploiement intègre les modifications lors de son prochain démarrage.
La logique spécifique aux entreprises reste donc en dehors du noyau. Les traitements de conformité, les extracteurs d’entités propres à un domaine et les modèles de notation propriétaires peuvent tous être encapsulés en opérateurs, composés avec les éléments intégrés du JSON de flux et déployés sans avoir à modifier le framework.
Problématiques opérationnelles
Une question légitime concernant un outil de ce type est de savoir s’il s’agit d’un bon prototype ou d’un outil véritablement adapté à l’environnement de production. Les détails suivent.
Observabilité. Un support natif d’OpenTelemetry est intégré, et chaque exécution d’opérateur génère un span. Les journaux sont des JSON structurés avec une corrélation des traces, contenant trace_id et span_id dans chaque ligne. Cela fonctionne avec Jaeger, Grafana Tempo, Datadog et AWS X-Ray sans aucune configuration du côté de l’application, et la charge supplémentaire est nulle lorsque la telemétrie est désactivée.
Traitement incrémental. Le pipeline utilise l’ID déterministe fourni par DocIdHashOperator pour suivre ce qui a déjà été traité. Lors d’une exécution répétée, seuls les documents nouveaux ou modifiés sont pris en charge ; un même document soumis deux fois reçoit le même hash et est ignoré. Définir force_ingest: true dans global_config annule cette règle et fait retraiter tout le contenu. Les métadonnées relatives aux exécutions incrémentales peuvent être stockées dans DuckDB (par défaut), PostgreSQL ou le système de fichiers.
Sécurité. ACLOperator affiche les métadonnées de permission sous forme de colonne afin d’en assurer l’application ultérieure, tandis que PIIAndHAPAnnotator détecte et masque le contenu sensible avant qu’il n’atteigne le stockage vectoriel. Les secrets présents dans la configuration du flux peuvent provenir de HashiCorp Vault : une adresse telle que vault://path/to/secret écrite dans le JSON est résolue par le moteur au cours de l’exécution. L’accès à l’API REST est protégé par LDAP ainsi que par OAuth2/OIDC.
Échelle. L’exécution se déroule en trois modes, allant d’un ordinateur portable à une flotte distribuée. Par défaut, on utilise un pool de threads en mémoire, qui est rapide, simple et ne dépend d’aucun élément externe. Un pool de processus exécute les opérateurs dans des processus distincts pour les tâches gourmandes en CPU sur un seul nœud. Pour les charges de travail de production distribuées, un pool de travail Prefect exécute des conteneurs Docker, ce qui permet une échelle horizontale et une gestion centralisée des exécutions. Les paramètres de micro-groupering contrôlent l’utilisation de la mémoire dans chaque mode, ce qui est important lorsque de grands documents sont traités par extraction via des LLM.
Que faire ensuite
Le projet est hébergé sur GitHub au sein de l’organisation IBM, et son guide de démarrage rapide constitue le moyen le plus rapide pour mettre en place un pipeline fonctionnel. Les domaines qui méritent une étude plus approfondie incluent la couche d’extraction (intégration avec Docling, pipelines VLM pour les documents riches en images, ASR pour l’audio et la vidéo), l’écriture d’un opérateur personnalisé avec une logique complexe, depuis la déclaration initiale jusqu’aux tests, à l’enregistrement et au déploiement, l’exécution de Prefect avec Docker pour des charges de travail volumineuses, ainsi que les options de mappage des champs et de modèles de schéma de VectorDBOperator pour OpenSearch.
Lectures complémentaires
- Notes pratiques : Création d’un pipeline RAG local de niveau production — 100 % gratuit, sans — Guide pas à pas des Notes pratiques : Création d’un pipeline RAG local de niveau production — 100 % gratuit, sans : contrats, vérifications et emplacements de code prêts à l’emploi pour les équipes qui implémentent ce modèle.
- Recherche hybride dans Postgres pour un assistant de santé : schéma, segmentation en chunks, RRF et évaluations — Construction de la couche de récupération d’informations pour un assistant de santé dans Postgres : segmentation en chunks tenant compte de la structure, recherche hybride avec pgvector et RRF, quantification binaire, seuils et évaluations.