Uruchamianie rurociągów Docling przez HTTP: od konfiguracji projektu do indeksowanych fragmentów
Przejdź krok po kroku przez REST API Docling Pipelines: uruchom serwer, odkryj operatorów, zweryfikuj i uruchom DAG do pobierania danych oraz przeczytaj informacje telemetryczne dotyczące jego wykonywania.
Źródła: **A Hands-On Guide to the Docling Pipelines REST API**
Zmiana foldera plików PDF i Word na wyszukiwalne wektorowe fragmenty zazwyczaj wymaga kodu pomocniczego do wydobywania danych, dzielenia ich na fragmenty, wgrzewania oraz tworzenia indeksów. Docling Pipelines pakuje te etapy jako operatory działające za pomocą serwera REST opartego na FastAPI, dzięki czemu każdy klient – takie jak usługa Node.js czy interfejs administracyjny – może tworzyć modułowe łańcuchy zadań typu DAG, weryfikować je oraz uruchamiać ich asynchroniczne wykonywanie przez HTTP. Ten przewodnik pokazuje, jak uruchomić serwer przy użyciu Ollamy i OpenSearch, oraz omawia cały cykl życia żądania, od utworzenia projektu po odczytanie statystyk wykonywania zadań na poszczególnych węzłach.
Prygotowanie usług tła
Server koordynuje prace, ale procesy wgrzewania danych i ich przechowywanie odbywają się gdzie indziej: tutaj mowa o Ollamie do obsługi modeli oraz OpenSearch jako magazynie wektorów. Najpierw należy je uruchomić.
Najprostszym sposobem jest plik QUICKSTART.md projektu, który w ciągu kilku minut skryptowo konfiguruje Ollamę, bazę wektorową oraz niezbędne kontenery. Agent do programowania oparty na AI, taki jak Cursor, Claude Code lub Copilot, również może przeprowadzić konfigurację i weryfikację; w obu przypadkach należy upewnić się, że każda z usług odpowiada.
Wybór magazynu wektorów
To decyzja architektoniczna. OpenSearch nadaje się, gdy chcesz użyć hybrydowego wyszukiwania łączącego dopasowywanie słów kluczowych z wektorami gęstymi. Milvus jest odpowiedni dla dedykowanej, wysoce skalowalnej infrastruktury przeznaczonej do przechowywania bardzo dużych zbiorów wektorów. W tym przewodniku użyto OpenSearch.
Rozpoczęcie działania serwera API
Aktywuj środowisko wirtualne, w którym zainstalowany jest pakiet, i uruchom dostarczony polecenie:
source .venv/bin/activate
docling-pipelines-api
Aby umożliwić szybkie ładowanie podczas rozwoju, uruchom aplikację bezpośrednio za pomocą uvicorn, skonfigurowanego do obsługi wszystkich interfejsów na porcie 8080:
uvicorn docpipe.api.main:app --reload --host 0.0.0.0 --port 8080
Dostępne są następujące cztery adresy URL:
http://localhost:8080/healthdo sprawdzania stanu aplikacji;http://localhost:8080/api/v1/docsdo interaktywnego interfejsu Swagger UI;http://localhost:8080/api/v1/redocdo dokumentacji ReDoc;http://localhost:8080/api/v1/openapi.jsondo surowego schematu OpenAPI.
W TypeScript można przekazać dokument OpenAPI do generatora klienta zamiast ręcznie definiować typy żądań.
Zmienne środowiskowe wpływające na serwer
Ustaw je przed uruchomieniem, aby dostosować zachowanie aplikacji:
DS_LOG_LEVELokreśla poziom szczegółowości logów. Jego domyślną wartością jestINFO, a może przyjmować wartościDEBUG,INFO,WARNINGlubERROR.DOCPIPE_STORAGE_BACKENDdecyduje o miejscu przechowywania metadanych:duckdb(domyślnie, lokalnie) lubpostgres.CORS_ORIGINSwymienia adresy, z których frontend w przeglądarce może wywoływać API. Jego domyślną wartością jesthttp://localhost:3000.OLLAMA_HOSTskierowuje operatory embedding i LLM do Ollamy. Domyślną wartością jesthttp://localhost:11434; należy ją zmienić, jeśli Ollama działa na innej porcie lub maszynie.
Eksplorowanie punktów końcowych w Swagger UI
Otwórz w przeglądarce http://localhost:8080/api/v1/docs; lokalnie nie jest wymagane logowanie. Rozwiń odpowiedni punkt końcowy, kliknij Przetestuj i wyślij poniższe dane bez pisania klienta.
Zarys cyklu życia żądania
Pełny obieg obejmuje siedem wywołań, od utworzenia projektu do podsumowania jego działania:
1. Create Project ──▶ 2. Discover Operators ──▶ 3. Validate Flow ──▶ 4. Create Flow ──▶ 5. Execute Run ──▶ 6. Fetch Logs ──▶ 7. Summary
Krok 1: utworzenie projektu
Projekty grupują różne procesy i śledzą ich łączną statystykę działania. Utwórz jeden za pomocą POST /api/v1/projects:
{
"name": "Sample Docling Pipeline Project",
"description": "Flows for processing invoice documents",
"tags": ["finance", "pdf", "q3"]
}
Pola:
nameto obowiązkowy ciąg znaków o długości od 1 do 255 znaków, który unikalnie identyfikuje projekt.descriptionto opcjonalne krótkie wyjaśnienie celu projektu.tagsto opcjonalny tabliczka ciągów znaków służąca do kategoryzacji.
W przypadku sukcesu zwracany jest kod 201 Created wraz z wygenerowanym project_id, wartością flow_count równą zero, datami oraz adresem href do zasobu:
{
"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"
}
Krok 2: odkrywanie operatorów i modeli
Zamiast zgadywać nazwy i opcje operatorów, zapytaj serwer.
Metryki operatora
Zapytanie GET /api/v1/operators/metadata zwraca szczegółowy schemat każdego operatora, obejmujący ponad 20 wbudowanych opcji oraz wszystkie zewnętrzne operatorze, które zarejestrowałeś. Parametr zapytania internal_features ma domyślną wartość false.
W każdym wpisie features opisuje kolumny, które generuje operator, required_features – kolumny, których potrzebuje od źródła, a attributes – jego opcje wraz z typami i wartościami domyślnymi. Operator extract emituje content oraz doc_id_hash; natomiast chunker wymaga 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"
}
}
}
}
Porównanie required_features z wynikami z źródła pozwala przed wysłaniem potwierdzić, że każdy węzeł otrzyma potrzebne mu kolumny.
Modele dostawców
GET /api/v1/providers/{provider}/models wysyła zapytanie do aktywnego dostawcy (ollama lub watsonx), więc brakujący model lub błędnie wpisany tag zostają wykryte przed uruchomieniem:
curl -s http://localhost:8080/api/v1/providers/ollama/models | jq
Każdy model jest wymieniony wraz z nazwą, tagiem, datą modyfikacji oraz rozmiarem w bajtach:
{
"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
}
]
}
Krok 3: walidacja przepływu przed jego zapisaniem
POST /api/v1/validation/validate_flow sprawdza graf DAG pod kątem błędnych parametrów i uszkodzonych zależności, bez konieczności przechowywania go lub jego uruchamiania.
global_config ustala opcje stosowane w całym procesie (kolumna dokumentu, lokalne wykonywanie, przechowywanie w pamięci, wymuszone ponowne przetworzenie). flow przedstawia węzły, z których każdy ma type, unikalne name, config oraz tablicę depends_on określającą zależności wsteczne. Proces przetwarzania wygląda następująco:
- przeczytuje pliki PDF, TXT i DOCX z katalogu
./sample_documentsna lokalnym systemie plików; - wyodrębnia tekst z tych plików za pomocą biblioteki Docling, pomijając jednocześnie wyodrębnianie elementów semantycznych;
- dzieli treść na fragmenty po 512 jednostek, przy zachowaniu nakładania się o długość 50 jednostek;
- wbudowuje każdy fragment za pośrednictwem LiteLLM, kierując się do zgodnego z OpenAI endpointu Ollamy wykorzystującego model
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"]
}
]
}
Niektóre szczegóły są ważne. vector_dimension (768) musi odpowiadać rozmiarowi wyjściowemu modelu embeddingowego. Dane uwierzytelniające występują jako miejsca zastąpień w stylu ${OPENSEARCH_USERNAME} i <ollama-api-key>; prawdziwe hasła należy przechowywać w zmiennych środowiskowych lub specjalnych magazynach haseł, a nie w zapisanych procesach. Wyłączenie use_ssl i verify_certs jest w porządku lokalnie, ale nie na klastrze współdzielonym. Ponadto narzędzie do dzielenia na fragmenty używa chunk_type: „simple”, podczas gdy dokumentacja metadanych określa chunker_type jako fixed, semantic lub hybrid; sprawdź, co zwraca twój serwer.
Prawidłowa definicja zwraca 200 OK, is_valid: true, puste pola errors i warnings, a także liczbę węzłów:
{
"is_valid": true,
"errors": [],
"warnings": [],
"node_count": 5
}
Krok 4: rejestracja przepływu
Zapisz zweryfikowaną definicję za pomocą żądania POST /api/v1/flows (is_elyra ma domyślną wartość false). Ciało żądania zawiera tę samą strukturę DAG wraz z opisem i tagami:
{
"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"]
}
]
}
Tutaj istotne są dwie ustawienia globalne:
execute_type: „local”uruchamia pipeline wewnątrz procesu serwera.force_ingest: trueprzetwarza ponownie wcześniej zaimportowane dokumenty: przydatne podczas iteracji, marnotrawne w stanie stabilnym.
Odpowiedź to 201 Created z nowym flow_id oraz zapisanymi ustawieniami:
{
"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"
}
Krok 5: rozpoczęcie wykonywania
Wykonania są asynchroniczne. POST /api/v1/job_runs przyjmuje ID i nazwę przepływu:
{
"flow_id": "e2c31e42-7719-482a-a53d-2490b830d971",
"flow_name": "complete-document-pipeline"
}
Od razu zwraca 201 Created wraz z job_run_id i stanem Starting, podczas gdy praca trwa w tle:
{
"job_run_id": "99ecd646-bb8e-494a-a0c5-86b40c1d4f90",
"status": "Starting",
"message": "Job run created successfully"
}
Krok 6: sprawdzanie stanu, metryk i logów
Sprawdzaj GET /api/v1/job_runs/{job_run_id}, dodając parametr include_logs=true w celu uzyskania logów poszczególnych węzłów, aż stan osiągnie wartość końcową (np. Completed), najlepiej z coraz większymi opóźnieniami.
Długa odpowiedź 200 OK zawiera node_sequence (kolejność wykonywania), job_stats (liczniki dla całego procesu, wraz z node_stats dla poszczególnych węzłów i batch_node_stats dla poszczególnych partii) oraz tablicę node_metadata na najwyższym poziomie. W tym przypadku dwa pliki tekstowe przeszły przez wszystkie pięć węzłów, co dało cztery fragmenty, wszystkie oznaczone indeksami:
{
"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"
}
}
]
}
Ten przykład nie jest w pełni spójny: job_run_id w job_stats różni się od ID z kroku 5, a flow_id ma wartość unknown. Powiąż procesy za pomocą ID otrzymanego na początku.
Co czytać najpierw w odpowiedzi
job_statsdostarcza liczniki na wysokim poziomie, takie jaktotal_docs,processed_docs,completed_docsorazduration.
node_stats pokazuje czas trwania i stan każdego kroku; sprawdź go najpierw, gdy proces jest wolny lub zawodzi.include_logs=true formatowane logi są dodawane u szczytu odpowiedzi, oznaczone nazwą każdego węzła (od węzła pobierania po magazyn OpenSearch).Interpretacja metadanych węzła
Każdy operator raportuje dane telemetryczne w sekcji node_metadata: przepustowość, błędy oraz liczba przekształceń na każdym etapie. Główne atrybuty to:
documents_in_scope: całkowita liczba surowych dokumentów znalezionych i załadowanych przez operatora pobierania; stanowi podstawę do porównań.processed_docs: całkowita liczba dokumentów, które ten operator zdołał przetworzyć pomyślnie podczas procesu; jest równadocuments_in_scope, gdy nie wystąpiły żadne błędy.failed_docs_count: całkowita liczba dokumentów, które napotkały tu błędy.
failed_docs: tablica, której elementy zawierają id, oryginalną nazwę pliku name, reason błędu oraz document_url (pusty, gdy pliki pochodzą z dysku lokalnego).skipped_docs_count: całkowita liczba dokumentów celowo pominiętych, na przykład w wyniku usuwania duplikatów, logiki związanej z gałęziami lub wykonywania procesów w trybie inkrementalnym.skipped_docs: tablica o strukturze podobnej do failed_docs, gdzie reason wyjaśnia powód pominięcia, na przykład "Filtered by branch condition".page_type_stats: podawana wyłącznie przez operatora ekstrakcji, to słownik mapujący rozszerzenia plików na liczbę przetworzonych stron, na przykład {"pdf": 45, "docx": 12, "txt": 3}.total_pages_converted to całkowita liczba stron we wszystkich formatach, obliczana na podstawie naturalnych liczb dla plików cyfrowych oraz liczb uzyskanych przez OCR dla skanów.Szybka weryfikacja stanu: porównaj documents_in_scope przy pobieraniu z processed_docs w ostatnim węźle; failed_docs i skipped_docs wyjaśniają ewentualne różnice.
Krok 7: przegląd procesów i historii wykonywań projektu
GET /api/v1/projects/{project_id}/flows wyświetla procesy projektu wraz z podsumowaniem wykonań (łączna liczba wykonań, ID ostatniego wykonywania, status i czas rozpoczęcia, liczby według statusu), paginowane za pomocą total_count, offset i 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
}
W tym przykładzie last_run_start_time wygląda na wartości w milisekundach, podczas gdy wartości start_time dla wykonywania zadań są w sekundach, więc należy je znormalizować przed porównaniem.
Główne wnioski
API oferuje bezinterfejsową architekturę do przetwarzania dokumentów od początku do końca. Kilka nawyków zapewnia jego niezawodność:
- Używaj
/operators/metadataoraz/providers/{provider}/models, aby programowo odkrywać pola operatorów i dostępne tagi modeli, zamiast wpisywać je ręcznie. - Przeprowadzaj każdą definicję DAG przez
/validation/validate_flow, aby przed uruchomieniem wykryć błędne typy parametrów oraz uszkodzone połączenia węzłów. - Traktuj procesy jako zadania asynchroniczne: przechowuj
job_run_id, sprawdzaj stan zadania za pomocąinclude_logs=true, a także czytajnode_statsinode_metadata, aby zlokalizować błędy w poszczególnych etapach. - Unikaj przechowywania danych uwierzytelniających w definicjach przepływów i upewnij się, że
vector_dimensionjest zgodny z twoim modelem embeddingów.
Aby to wypróbować, uruchom Ollamę i OpenSearch (lub Milvus), zainstaluj docling-pipelines-api, otwórz Swagger UI i przejdź przez następującą sekwencję: projekt, przepływ, walidacja, uruchomienie, logi.
Literatura pokrewna
- Doskonałe dostosowanie LLM: Marshrutyzacja, wyświetlanie i ewaluacja na podstawie rozmiaru modelu — Dowiedz się, jak wybierać między małymi a dużymi modelami językowymi w zależności od obciążenia, mierzyć koszt za udane zadanie oraz najpierw wykorzystywać marshrutyzację, RAG, cache i walidację.
- Jak w rzeczywistości działają bazy danych wektorowych: od embeddingów do wyszukiwania hybrydowego — Wyjaśnia, w jaki sposób embeddingi kodują znaczenie, jak skalują się wyszukiwanie podobieństw i indeksowanie oraz kiedy wyszukiwanie hybrydowe i bazy danych wektorowych nadają się do systemów AI w przedsiębiorstwach.