Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Build a distributed RAG pipeline with Ray Data on OpenShift AI

July 28, 2026
Ana Biazetti Bryan Keane Saad Zaher
Related topics:
Artificial intelligenceAI inferenceData sciencePython
Related products:
Red Hat OpenShift AI

    Most retrieval-augmented generation (RAG) tutorials show you how to parse a handful of documents, embed them, and stuff them into a vector database. That's fine for a demomstration. It doesn't hold up when you point it at a real document corpus—thousands of PDF files with complex layouts, tables, and multi-column formatting that simple text extractors mangle.

    If you've ever tried to scale a RAG pipeline, you know the frustration: your expensive GPUs sit idle while a single-threaded CPU parser slowly grinds through a mountain of complex PDFs. Running these stages sequentially means you're stuck waiting hours for a job that should take minutes.

    A corpus taking hours to parse then sits idle while the system generates embeddings, and not a single vector reaches the database until both stages finish. Organizations end up stuck between "works in a notebook" and "runs in production"—often defaulting to proprietary managed services to close the gap.

    We built and tested a distributed ingestion pipeline addressing this directly, processing all three stages in parallel using Ray Data's streaming execution. We show how it works, why streaming changes the performance equation, and how to run it yourself on Red Hat OpenShift AI.

    This blog post focuses on the indexing pipeline, the most compute-intensive of the three pipelines making up a production RAG system (indexing, retrieval, and maintenance). Getting indexing right at scale is the foundation everything else depends on.

    This post picks up where two earlier pieces left off. A Red Hat blog post, Breaking the RAG bottleneck, introduced the idea of combining Ray Data and Docling for scalable document processing. A follow-up post, Scaling document ingestion with Docling and Ray on Red Hat OpenShift AI, showed how to distribute Docling parsing across a Ray cluster for batch document conversion. Neither of those covered the full pipeline. This post does: from raw PDFs through structured parsing, embedding generation, and vector storage, all running as a single streaming job.

    What you'll build

    The distributed pipeline has three stages: parse and chunk documents with Docling, generate vector embeddings, and write vectors to a vector database (Milvus in this example). Instead of completing each stage before starting the next, Ray Data's streaming execution overlaps all three. Data flows through the distributed pipeline the way water flows through connected pipes. The first chunks reach the embedding stage while the parser is still working through the document queue. Similarly, the first vectors land in the vector database while embedding is still running, all while Ray Data distributes the workload across multiple worker nodes and actors.

    The entire distributed ingestion pipeline starts as a single Python script submitted as a Ray job using the CodeFlare software development kit (SDK). You configure it through environment variables, point it at a directory of PDFs, and it handles distribution, fault tolerance, and stage coordination. A second notebook deploys a large language model (LLM) inference endpoint and demonstrates RAG against the ingested data. Two notebooks, zero external orchestration frameworks, following the three-stage architecture shown in Figure 1.

    PDF documents flow through streaming stages—Docling parsing, repartitioning, vector embedding, and database writing—into a Milvus vector database.
    Figure 1: The three-stage ingestion pipeline streams data between stages so parsing, embedding, and storage overlap in time.

    Why streaming execution matters

    In a conventional pipeline, you would parse every document, collect all the chunks, embed them, and write them to the database. Each stage waits for the previous stage to finish completely. Total wall-clock time is the sum of all three stages.

    Ray Data's streaming execution changes this. Each stage processes data in blocks, and downstream stages begin consuming blocks as soon as upstream stages produce them. The practical result is wall-clock time approaches the duration of the slowest stage rather than the sum of all three, as shown in Figure 2.

    Timeline comparison showing sequential processing running stages one after another versus streaming execution overlapping parsing, embedding, and writing.
    Figure 2: Streaming execution overlaps the three stages, so total time approaches the slowest stage rather than the sum of all three.

    Streaming execution also keeps memory usage bounded. Only a window of data is in flight at any point. You don't need enough memory to hold every parsed chunk before embedding begins. GPU utilization stays high because the embedding stage doesn't sit idle waiting for parsing to finish. Time-to-first-insert drops from "after all documents are parsed and embedded" to "minutes after the job starts."

    The performance difference is structural, not incremental. In sequential execution, a three-stage pipeline taking T1 to parse, T2 to embed, and T3 to write has a total wall-clock time of T1 + T2 + T3. With streaming execution, that total approaches max(T1, T2, T3) because stages overlap. For CPU-intensive parsing workloads, where parsing typically dominates, this can reduce end-to-end time significantly. Throughput also scales linearly with workers. Doubling the number of Docling parsing actors doubles parsing throughput, while the streaming executor keeps downstream embedding and write stages continuously fed instead of waiting for the full parsing phase to complete.

    Stage 1: Structure-aware parsing with Docling

    The first stage uses Docling to parse PDF documents and the Docling HybridChunker to segment content into chunks. This isn't naive text extraction. Docling understands document structure: tables, headings, lists, and layout elements. When you run a simpler PDF parser, a table might get flattened into a paragraph or split across two chunks, losing the structure that makes it meaningful. Docling preserves that structure, and the HybridChunker respects structural boundaries when creating chunks. That's why parser selection is critical in the indexing pipeline—if the parser can't handle your source documents, nothing downstream will compensate. Docling addresses this for enterprise document types across PDFs, HTML, PPTX, and other formats.

    Each parsing actor is implemented as a Ray actor class. During initialization, it loads Docling's machine learning models once and reuses them across every document it processes. Reusing models amortizes the initialization cost, which would otherwise dominate processing time if repeated for every document. The actors run on CPU workers and process documents in configurable batches. Docling parsing is CPU-intensive, so this stage typically has the most actors allocated to it.

    Between the parsing stage and the embedding stage, the pipeline repartitions the data. This step spreads chunks evenly across the available embedding workers, preventing hot spots where one worker gets a disproportionate share of the data.

    Stage 2: Dual-mode embedding

    As shown in Figure 3, the embedding stage supports two execution modes, selectable with a single environment variable.

    Flowchart showing an environment variable selecting CPU local mode with sentence-transformers or GPU service mode with vLLM for embedding.
    Figure 3: The same embedding model runs in two modes. Switch between CPU-only and GPU-accelerated execution with one environment variable.

    In local mode, sentence-transformers run on CPU actors. No GPU is required. Running in local mode is practical for testing the pipeline, validating your document processing, or running against smaller document sets.

    In service mode, the pipeline uses vLLM, a high-throughput model serving engine, through Ray Data's LLM processor API. vLLM is an open source model serving engine designed to deliver high-throughput inference. This runs on GPU workers with automatic batching and GPU memory management. The throughput increase is substantial for production-scale ingestion.

    Both modes use the same embedding model. The example defaults to IBM Granite embedding, but any sentence-transformers-compatible model works. Your vectors are identical regardless of which mode produced them. You can develop and test with local mode, then switch to service mode for production runs without changing anything else in the pipeline.

    Stage 3: Writing to the vector database

    The final stage batch-inserts vectors into a vector database (Milvus) collection. Each write actor manages its own connection to the database and inserts vectors in configurable batches. The actors include retry logic for transient network failures and truncation handling for chunks exceeding field size limits.

    Because this stage is input/output (I/O)-bound rather than compute-bound, it rarely becomes the bottleneck. A small number of write actors can typically keep up with the embedding stage's output. The streaming executor keeps them fed with a steady flow of embedded vectors from stage 2.

    Resource scheduling and the CPU headroom question

    When you configure the pipeline, you decide how many CPU actors to allocate for Docling parsing. Here's the easy-to-miss constraint: Ray Data's streaming executor itself needs CPU resources to coordinate data movement between stages. If you allocate every available CPU to Docling actors, the executor starves and the pipeline stalls. This situation looks like a deadlock, but it's a resource scheduling issue.

    To prevent this, you need to leave headroom. The example README documents a sizing approach that reserves a portion of total cluster CPUs for the streaming executor, vector database writers, and GPU worker overhead. When in doubt, start with fewer Docling actors and scale up. The pipeline reports per-stage timing metrics, so you can see which stage is the bottleneck and adjust accordingly.

    Best practices

    • Start with fewer Docling actors than you think you need and scale up based on per-stage timing. Over-allocating parsing actors starves the streaming executor.
    • Use local embedding mode during development and testing. Switch to service mode only when you're ready for production-scale ingestion.
    • Monitor per-stage metrics after each run. The pipeline reports timing and throughput for each stage, which makes bottleneck identification straightforward.
    • Size your vector database collection before ingestion. Pre-creating the collection with the expected schema avoids runtime errors and lets the write actors batch-insert efficiently.

    The technology stack

    Figure 4 outlines the full technology stack. At the application layer, Docling handles structure-aware PDF parsing and table extraction, while PyTorch and Transformers power the sentence-transformers library for embedding generation. The vector database (Milvus) stores embeddings and serves similarity searches during retrieval.

    Three-tier architecture with data tools on top, distributed workload tools in the middle, and Red Hat OpenShift AI components forming the platform foundation.
    Figure 4: Full technology stack from application components through the platform layer.

    The workloads layer handles distributed execution. Ray Data provides streaming parallel execution across worker pods, orchestrated through the CodeFlare SDK's Python API for RayCluster creation. vLLM serves two roles: GPU-accelerated embedding generation during ingestion and OpenAI-compatible LLM inference for the query path. Notebooks provide the interactive environment for submitting pipeline jobs and running queries.

    OpenShift AI provides the platform foundation, and this is where it goes beyond hosting the example. A distributed RAG pipeline like this one creates platform requirements difficult to solve on vanilla Kubernetes: managing Ray cluster lifecycles across diverse CPU and GPU node pools, scheduling GPU resources fairly across teams, serving multiple model endpoints with autoscaling, and giving data scientists a self-service environment to iterate without writing infrastructure YAML.

    OpenShift AI addresses these directly. The KubeRay operator manages Ray cluster creation, scaling, and teardown, including ephemeral clusters spinning up for a job and releasing resources on completion. Kueue manages workload queuing, fair-sharing, and quota management across varied CPU and GPU node pools. This is critical when multiple teams compete for GPU capacity, allowing the platform to dynamically schedule Docling CPU workers alongside GPU embedding workers without manual node affinity rules. KServe hosts the embedding and LLM inference endpoints with built-in autoscaling and health monitoring. The CodeFlare SDK lets users create and configure Ray clusters programmatically from notebooks, removing the need for manual cluster provisioning.

    As a result, AI engineers can focus on the RAG pipeline logic while the platform handles distributed infrastructure, GPU allocation, model serving, and cluster lifecycle management.

    Verifying the pipeline: The query path

    The example includes a query notebook validating the retrieval pipeline—confirming the indexed data works for retrieval-augmented generation. It programmatically deploys a language model (Granite 8B in the default configuration, though any compatible model works) as a KServe inference endpoint directly from the notebook using helper functions in the example code. No pre-deployed model is needed, and no manual KServe configuration is required.

    The notebook then runs a side-by-side comparison: the same question answered with and without retrieval context. The RAG path embeds the user's question with the same Granite embedding model used during ingestion, searches the vector database (Milvus) for relevant chunks above a similarity threshold, formats the results with source citations, and sends them alongside the question to the LLM. You can see exactly where the model's answer improves with access to your ingested documents, and which source documents contributed to the answer.

    This setup is deliberately lightweight. The ingestion pipeline is the focus of this example. The query notebook exists to prove the pipeline's output is usable, not to demonstrate a production query architecture.

    What makes this different from typical RAG tutorials

    Most RAG examples process documents sequentially on a single machine. They work for a proof of concept but don't address what happens when you have hundreds or thousands of documents. This pipeline is distributed from the start, with streaming execution, structure-aware parsing, and platform-managed infrastructure on OpenShift AI.

    The pipeline also includes built-in performance reporting. After each run, you get per-stage timing, throughput metrics, and document processing statistics. These metrics make capacity planning concrete rather than guesswork.

    Get started

    The full example, including both notebooks, the pipeline script, setup instructions, cluster sizing, and configuration options for both embedding modes, is available in the Red Hat AI examples repository.You'll need an OpenShift AI environment with the KubeRay operator installed and a vector database (Milvus) instance deployed.

    Learn more

    See how Red Hat OpenShift AI handles the heavy lifting of cluster management and GPU scheduling so you can focus on building.

    If you want to understand the foundational concepts before diving into the code, start with the earlier post on breaking the RAG bottleneck with Ray Data and Docling.

    For more on the technologies used, see Ray, KubeRay and codeflare-sdk on OpenShift AI, the Docling project, and Ray Data documentation. You can also check out the new e-book, Engineering RAG for the Enterprise.

    Related Posts

    • Scale document ingestion with Docling and Ray on OpenShift AI

    • Boring RAG: When similarity is just a SQL query

    • Synthetic data for RAG evaluation: Why your RAG system needs better testing

    • Deploy an enterprise RAG chatbot with Red Hat OpenShift AI

    • Fine-tune a RAG model with Feast and Kubeflow Trainer

    • Stop chunking tables: How we built an agentic GraphRAG for financial disclosures with Docling

    Recent Posts

    • Build a distributed RAG pipeline with Ray Data on OpenShift AI

    • OSFT explained: Prevent catastrophic forgetting in LLM fine-tuning

    • Enrich OpenShift compliance results with custom metadata

    • How we designed customizable dashboards in OpenShift

    • Standardize project context with AGENTS.md and Agent Skills

    What’s up next?

    Learning Path RHOS_Elasticsearch_RAG_featured_image

    Demystify RAG with OpenShift AI and Elasticsearch

    Understand how retrieval-augmented generation (RAG) works and how users can...
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Chat Support

    Please log in with your Red Hat account to access chat support.