# How to Use Docling for OCR and Document Parsing in OpenRAG

> Learn how to use Docling for OCR and document parsing in OpenRAG. This guide explains how OpenRAG delegates these tasks to the local docling-serve HTTP service.

- Repository: [Langflow/openrag](https://github.com/langflow-ai/openrag)
- Tags: how-to-guide
- Published: 2026-03-13

---

**OpenRAG delegates OCR and document parsing to docling-serve, a local HTTP service managed by the DoclingManager and consumed via the DoclingClient utility.**

OpenRAG does not bundle its own OCR engine. Instead, it integrates with Docling through a lightweight service architecture that handles document conversion and text extraction. This guide explains how to configure, start, and use Docling for OCR and document parsing in OpenRAG based on the actual implementation in the `langflow-ai/openrag` repository.

## Architecture Overview

The integration relies on three core components that communicate with a running `docling-serve` instance:

- **DoclingClient** ([`src/utils/docling_client.py`](https://github.com/langflow-ai/openrag/blob/main/src/utils/docling_client.py)) – Async HTTP wrapper that sends files to the `/v1/convert/file` endpoint and returns parsed JSON.
- **DoclingManager** ([`src/tui/managers/docling_manager.py`](https://github.com/langflow-ai/openrag/blob/main/src/tui/managers/docling_manager.py)) – Singleton process manager that starts, monitors, and persists the `docling-serve` subprocess across TUI sessions.
- **Docling API Proxy** ([`src/api/docling.py`](https://github.com/langflow-ai/openrag/blob/main/src/api/docling.py)) – FastAPI health check endpoint that forwards requests to the running service.

## Starting and Managing the Docling Service

### Using the CLI Controller

OpenRAG provides a command-line interface for managing the Docling service lifecycle through [`scripts/docling_ctl.py`](https://github.com/langflow-ai/openrag/blob/main/scripts/docling_ctl.py):

```bash

# Start docling-serve on default port 5001

python -m scripts.docling_ctl start

# Start with multiple workers and UI enabled

python -m scripts.docling_ctl start --workers 2 --enable-ui

# Check service status

python -m scripts.docling_ctl status

# Stop the service

python -m scripts.docling_ctl stop

```

### Process Persistence and Lifecycle Management

The `DoclingManager` class handles process persistence by writing the PID to `~/.openrag/tui/.docling.pid`. When starting, it checks for an existing PID and reattaches to running processes rather than spawning duplicates. This allows the OCR service to survive across multiple TUI sessions without reinstalling heavy dependencies.

For CI pipelines, use the warmup script to block until healthy:

```bash
python warm_up_docling.py

```

This script polls the health endpoint until `docling-serve` responds or the timeout (controlled by `DOCLING_WARMUP_TIMEOUT`) expires.

## Converting Documents with DoclingClient

### Converting Local Files

The `convert_file()` function in [`src/utils/docling_client.py`](https://github.com/langflow-ai/openrag/blob/main/src/utils/docling_client.py) handles async HTTP POST requests to the Docling service:

```python
import httpx
from utils.docling_client import convert_file, DoclingServeError

async def parse_pdf(file_path: str):
    async with httpx.AsyncClient() as client:
        try:
            result = await convert_file(
                file_path, 
                httpx_client=client
            )
            # result contains the parsed DoclingDocument JSON

            return result
        except DoclingServeError as e:
            print(f"Conversion failed: {e}")

```

### Processing In-Memory Bytes

For streams or uploaded files already in memory, use `convert_bytes()`:

```python
from utils.docling_client import convert_bytes

async def parse_bytes(content: bytes, filename: str):
    async with httpx.AsyncClient() as client:
        document = await convert_bytes(
            content, 
            filename, 
            httpx_client=client
        )
        return document

```

Both methods post to `{DOCLING_SERVICE_URL}/v1/convert/file` and return the JSON content extracted by the OCR engine.

## Health Monitoring and API Proxy

The OpenRAG frontend checks service availability through a proxy endpoint rather than contacting `docling-serve` directly:

```javascript
// Frontend health check
fetch("/api/docling/health")
  .then(r => r.json())
  .then(data => console.log("Service status:", data));

```

The proxy in [`src/api/docling.py`](https://github.com/langflow-ai/openrag/blob/main/src/api/docling.py) forwards this to the underlying service and handles timeouts gracefully, returning HTTP 503 with `{status: "unhealthy"}` if the service is unreachable.

## Configuration and Environment Variables

Control the Docling integration through these environment variables:

| Variable | Description | Default |
|----------|-------------|---------|
| `DOCLING_SERVE_URL` | Base URL for existing docling-serve instance | Auto-detected |
| `DOCLING_OCR_ENGINE` | OCR engine selection (`tesseract`, `easyocr`, etc.) | None (OCR disabled) |
| `DOCLING_WORKERS` | Concurrent worker processes | `1` |
| `DOCLING_BIND_HOST` | Network interface binding | `0.0.0.0` |
| `DOCLING_WARMUP_TIMEOUT` | Health check wait duration (seconds) | `120` |

Setting `DOCLING_SERVE_URL` bypasses the local process management and connects to an external service, useful for containerized deployments.

## Summary

- OpenRAG uses **docling-serve** as an external HTTP service rather than embedding OCR directly.
- The **DoclingManager** ([`src/tui/managers/docling_manager.py`](https://github.com/langflow-ai/openrag/blob/main/src/tui/managers/docling_manager.py)) handles process lifecycle and PID persistence across sessions.
- The **DoclingClient** ([`src/utils/docling_client.py`](https://github.com/langflow-ai/openrag/blob/main/src/utils/docling_client.py)) provides `convert_file()` and `convert_bytes()` for async document conversion.
- Environment variables like `DOCLING_SERVE_URL` and `DOCLING_OCR_ENGINE` control service location and OCR behavior.
- Health monitoring flows through the API proxy ([`src/api/docling.py`](https://github.com/langflow-ai/openrag/blob/main/src/api/docling.py)) to provide frontend visibility into service status.

## Frequently Asked Questions

### How do I enable OCR when starting the Docling service?

Set the `DOCLING_OCR_ENGINE` environment variable to your preferred engine before starting the service. For example, `export DOCLING_OCR_ENGINE=tesseract` enables Tesseract OCR. If this variable is unset, docling-serve runs without OCR capabilities and extracts only embedded text.

### Can I use an existing Docling server instead of letting OpenRAG manage the process?

Yes. Set the `DOCLING_SERVE_URL` environment variable to the base URL of your running instance (e.g., `http://docling-service:5001`). When this variable is present, OpenRAG skips the auto-start logic in `DoclingManager` and connects directly to the specified endpoint for all conversion requests.

### What happens if the Docling service crashes during a conversion?

The `DoclingClient` raises a `DoclingServeError` exception when it encounters connection failures, timeouts, or non-200 HTTP responses. Your application code should catch this exception and handle retries or fallback logic. The `DoclingManager` status command can verify if the process is still running before you attempt reconversion.

### How do I process documents already loaded in memory rather than files on disk?

Use the `convert_bytes()` function from [`src/utils/docling_client.py`](https://github.com/langflow-ai/openrag/blob/main/src/utils/docling_client.py) instead of `convert_file()`. Pass the byte content and a filename string (used for content-type detection) along with your `httpx.AsyncClient` instance. This approach works for uploaded files, generated reports, or any binary stream without writing to the filesystem.