docetldocument-processingllm-pipelinesagentic-workflowsdata-engineeringragtutorial

DocETL: Agentic Complex Document Processing Guide

DocETL Architecture: Declarative Semantic Operators, Agentic Query Optimizer, 13 Rewrite Directives, and High-Fidelity Data Extraction

The Problem: The Scalability & Accuracy Limits of Naive Document Pipelines

In modern enterprise automation, automated research systems, and web data extraction engines like AiFetchly, data teams are tasked with processing massive corpora of heterogeneous, unstructured documents. Whether analyzing thousands of SEC financial disclosures, clinical trial protocols, customer incident post-mortems, or scraped regulatory filings, organizations need to extract structured, actionable facts from raw text.

Historically, software engineering teams turned to two standard architectures to parse complex document collections with Large Language Models (LLMs):

  1. Retrieval-Augmented Generation (RAG): Indexing text chunks into a vector database and performing top-$k$ semantic search.
  2. Naive Map-Reduce Pipelines: Writing manual prompt loops that process each document individually (map), concatenate intermediate answers, and summarize the combined outputs (reduce).

While functional for elementary tasks, both approaches collapse when confronted with complex document processing tasks—such as multi-hop reasoning, cross-document entity alignment, and corpus-wide thematic synthesis.

The Naive LLM Document Processing Breakdown: Corpus: 500 Unstructured Multi-Page Incident Reports │ ├─► Approach 1: Monolithic Stuffing (1M+ Tokens into Long-Context LLM) │ ❌ Catastrophic "Lost-in-the-Middle" attention dilution │ ❌ Silent hallucination of missing causal links │ ❌ $50-$100+ API cost per single query run! │ ├─► Approach 2: Standard Vector RAG (Top-K Chunks) │ ❌ Tunnel vision: Only finds local keyword matches │ ❌ Cannot answer: "What recurring root causes span 80% of outages?" │ ❌ Ignores cross-document temporal sequences │ └─► Approach 3: Heuristic Map-Reduce Script ❌ Token limit overflow during the Reduce phase ❌ Entity mismatch: "Corp X", "Company-X", and "X Inc" treated as 3 entities ❌ Brittle prompt chains that fail silently on schema drift

1. The Context Dilution and “Lost in the Middle” Failure in Monolithic Prompts

Even with 1M+ token context windows in models like Gemini 1.5 Pro and Claude 3.5 Sonnet, stuffing hundreds of multi-page documents into a single prompt produces severe cognitive dilution:

  • Attention Degradation: LLM attention mechanisms suffer from the well-documented “Lost in the Middle” phenomenon, reliably prioritizing facts placed near the beginning or end of the prompt while missing subtle details embedded in intermediate documents.
  • Economic Inefficiency: Passing 500k tokens per query to answer a single analytical question is economically unsustainable in high-throughput data extraction workflows.

2. The Fragility of Naive Map-Reduce Over Heterogeneous Corpora

When developers build custom Map-Reduce scripts:

  • The Reduce Overflow Wall: If each of 500 documents generates a 200-word summary, the intermediate output totals 100,000 words. Attempting to feed this intermediate stream into a single reduce LLM prompt overflows context limits or degrades output quality.
  • Context Bleed and Boundary Splitting: Important domain concepts, acronyms, or party definitions introduced on page 1 of a contract are missing when page 15 is processed in isolation during a parallel map step.

3. Cross-Document Entity Disconnect and Quadratic Cost Explosion

Real-world document collections reference the same real-world entities under slightly different names, abbreviations, or typos:

  • For example, an incident report corpus may refer to the same database outage as “Aurora Prod US-East”, “AWS RDS Primary”, or “Cluster 04”.
  • Without explicit entity resolution, downstream aggregation splits metrics across fragmented buckets.
  • However, attempting to perform pairwise entity matching with an LLM incurs a quadratic cost of $O(N^2)$, resulting in tens of thousands of redundant LLM calls.

Engineering teams need a declarative, semantics-aware data processing system that models document workflows as composable primitives and autonomously optimizes execution plans for cost and accuracy.

The Solution: DocETL Declarative Operators and Agentic Optimization

Developed by the EPIC Data Lab at UC Berkeley (VLDB 2025), DocETL is a breakthrough system designed specifically for complex document processing powered by Large Language Models.

DocETL introduces two transformative architectural pillars:

  1. Declarative Semantic Operators: A rich set of database-inspired operators—including map, reduce, filter, resolve, gather, unnest, and equijoin—that express complex extraction, cleaning, and aggregation logic in a concise YAML configuration.
  2. The Agentic Query Optimizer: An intelligent LLM-driven query planner that analyzes the user’s initial pipeline, generates semantically equivalent execution rewrites (using 13 specialized rewrite directives), benchmarks them on sample data, and selects the optimal cost-accuracy frontier.
The DocETL Architectural Workflow: User Specification (High-Level Declarative Pipeline YAML) │ ▼ ┌────────────────────────────────────────────────────────┐ │ DocETL Agentic Query Optimizer │ │ • Inspects document schemas and prompt semantics │ │ • Applies 13 Rewrite Directives: │ │ - Map-Decomposition (Splits complex prompts) │ │ - Hierarchical Reduce (Clusters before aggregation) │ │ - Semantic Blocking for Entity Resolution │ │ • Benchmarks candidate plans on synthetic validation │ └────────────────────────────────────────────────────────┘ │ (Optimal Compiled Execution Plan) ▼ ┌────────────────────────────────────────────────────────┐ │ Parallel Execution Engine │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Map Worker 1 │ │ Map Worker 2 │ │ Map Worker N │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────────────────────────┐ │ │ │ Semantic Resolve & Clustering │ │ │ └──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────┐ │ │ │ Hierarchical Multi-Tier Reduce │ │ │ └──────────────────────────────────┘ │ └────────────────────────────────────────────────────────┘ │ ▼ Structured Analytical Dataset (Parquet / DuckDB / SQL)

The Core Semantic Operators of DocETL

DocETL moves beyond simple map-reduce scripts by providing specialized semantic primitives:

1. Map: Granular Per-Document Extraction

The map operator applies an LLM prompt to each document or chunk independently. In DocETL, map tasks output strictly typed JSON schemas (e.g., extracting dates, participants, severity levels, and specific financial figures) rather than arbitrary prose.

2. Reduce: Keyed and Global Semantic Aggregation

The reduce operator aggregates multiple inputs into a consolidated output. DocETL supports:

  • Keyed Reduce: Groups items sharing an exact attribute (e.g., grouping by department or vendor_name) before executing the aggregation prompt.
  • Global Reduce: Aggregates the entire corpus when computing high-level thematic trends across all documents.

3. Resolve: Automated Cross-Document Entity Disambiguation

One of DocETL’s most powerful native operators is resolve:

  • Identifies and clusters heterogeneous text mentions that refer to the same underlying entity (e.g., resolving “Anthropic PBC”, “Anthropic”, and “Anthropic AI”).
  • Uses smart semantic blocking (embeddings or rule-based hashing) to eliminate $O(N^2)$ comparisons, evaluating only plausible matches with targeted LLM comparison prompts.

4. Gather and Filter: Scoped Grouping and Semantic Pruning

  • filter: Discards irrelevant documents early in the pipeline using lightweight LLM classification or exact metadata predicates.
  • gather: Re-assembles fragmented document chunks (e.g., pages or paragraphs) belonging to the same document into a unified context before downstream extraction.

Deep Dive: How the Agentic Query Optimizer Rewrites Pipelines

In classical relational databases (like PostgreSQL or DuckDB), cost-based optimizers rewrite SQL queries using relational algebra (such as pushing down filters or reordering joins).

DocETL pioneers Agentic Query Optimization for LLM Pipelines. The optimizer is an autonomous agent that understands the semantic failure modes of LLMs and restructures naive operator sequences into resilient execution plans.

DocETL Agentic Rewrite Example: Transforming a Naive Map-Reduce Naive User Plan: [Raw Documents] ──► [Complex Map Prompt] ──► [Massive Monolithic Reduce] DocETL Optimized Plan: [Raw Documents] │ ▼ [Decomposed Map 1: Fact Extraction] (Low-cost fast model) │ ▼ [Decomposed Map 2: Entity Classification & Validation] │ ▼ [Semantic Resolve: Entity Disambiguation & Canonicalization] │ ▼ [Clustering Step: Group into Thematic Sub-Clusters] │ ▼ [Hierarchical Reduce: Reduce Clusters Independently] │ ▼ [Final Meta-Synthesis: Combine Clean Cluster Summaries] Result: 40% higher accuracy, 65% lower token cost, zero context overflow!

1. The 13 Rewrite Directives: From Map-Decomposition to Hierarchical Reduction

DocETL implements 13 formal rewrite directives that systematically address LLM bottlenecks:

  1. Map-Decomposition: When an extraction task is overly complex (e.g., “Extract all medical symptoms, dosages, adverse reactions, and pre-existing conditions”), the LLM frequently suffers from cognitive fatigue. DocETL decomposes the prompt into sequential, focused sub-maps, significantly boosting recall.
  2. Hierarchical Reduce (Cluster-then-Reduce): Rather than passing all items directly into a single massive reduce prompt, DocETL clusters items into semantically coherent groups using embeddings, runs an intermediate reduce on each group, and synthesizes the final meta-output.
  3. Map-Before-Reduce: If a reduce task requires synthesizing information from long documents, DocETL inserts an intermediate map operator that filters out irrelevant paragraphs first, drastically reducing the token volume passed into the reduce stage.
  4. Semantic Blocking for Resolve: Breaks entity resolution candidates into small, high-probability buckets before running LLM pairwise verifications, transforming an intractable $O(N^2)$ operation into scalable $O(N)$ execution.
  5. Validation and Retry Injection: Automatically inserts synthetic evaluation assertions to detect when an LLM hallucinated empty arrays or violated formatting constraints.

2. Plan Generation, Validation Benchmarking, and Cost-Accuracy Frontier Selection

The optimization process operates in three phases:

  • Candidate Plan Generation: The optimizer inspects the input data schema and user goals, proposing several candidate rewritten pipelines.
  • Empirical Validation on Subsets: DocETL samples a small fraction of the dataset (e.g., 10-20 documents) and executes each candidate plan.
  • Pareto-Optimal Selection: It scores each candidate based on output accuracy (using an LLM evaluator) and token cost, presenting the engineer with the optimal cost-accuracy trade-off.

Architecture Comparison: DocETL vs. Naive Map-Reduce vs. LangChain vs. Vector RAG

To understand where DocETL fits into the modern enterprise AI stack, the table below compares it against conventional document processing paradigms:

Capability DimensionStandard Vector RAGNaive Python / LangChain ScriptsLlamaIndex WorkflowsUC Berkeley DocETL
Primary WorkloadPoint-fact query lookupLinear sequential prompt chainsDAG-based agent routingComplex analytical document processing (ETL)
Query ParadigmSemantic similarity ($k$-NN)Procedural Python codeGraph/Event-driven stateDeclarative semantic operators (YAML)
Pipeline OptimizationManual chunk size tuningNone (Manual prompt edits)Heuristic query planningAgentic autonomous rewrite optimizer
Entity DisambiguationNone (Splits across chunks)Manual regex / fuzzy matchingCustom prompt agentsNative resolve with semantic blocking
Scalability (1,000s of Docs)High (Vector search)Low (Context window overflow)Moderate (Memory-bound)High (Parallel hierarchical reduction)
Token Cost EfficiencyHigh per queryPoor (Massive redundant tokens)ModerateOptimal (Benchmark-guided Pareto selection)
Hallucination ResilienceFragile on corpus-wide queriesHigh hallucination rateModerateHigh (Decomposed sub-tasks & validation)

Practical Implementation: Building an Optimized Document Pipeline with DocETL

Let us construct a complete, production-grade DocETL pipeline designed to process complex software post-mortem reports scraped from engineering blogs and status pages.

Step 1: Install DocETL and Configure the Environment

Install DocETL and initialize your API credentials:

pip install docetl openai export OPENAI_API_KEY="your-api-key"

Step 2: Define a Declarative Pipeline Specification (YAML)

Create a configuration file named incident_pipeline.yaml. This pipeline ingests raw incident documents, extracts root causes, disambiguates affected infrastructure services via resolve, and summarizes systemic failure modes per department:

datasets: incident_reports: type: file path: 'incident_reports.json' operations: # Step 1: Decomposed Map - Extract structured failure facts - name: extract_incident_facts type: map prompt: | Analyze the following infrastructure incident report and extract structured failure details. Document Content: {{ input.text }} Extract: - root_cause: A concise technical summary of what triggered the outage. - service_name: The primary affected cloud service or internal component. - severity: Outage tier (P0, P1, P2, P3). - downtime_minutes: Duration of customer impact in minutes. output: schema: root_cause: string service_name: string severity: string downtime_minutes: integer # Step 2: Resolve - Canonicalize service names across different naming conventions - name: canonicalize_services type: resolve blocking_keys: - service_name comparison_prompt: | Determine whether the following two service names refer to the same underlying infrastructure component: Service A: {{ input.service_name_1 }} Service B: {{ input.service_name_2 }} Answer YES if they represent the same system, otherwise NO. output: schema: canonical_service_name: string # Step 3: Keyed Reduce - Aggregate recurring root causes per canonical service - name: summarize_systemic_risks type: reduce reduce_key: - canonical_service_name prompt: | Synthesize the recurring failure patterns for the service: {{ input.canonical_service_name }}. Incident Records: {% for item in input.items %} - Severity: {{ item.severity }} | Downtime: {{ item.downtime_minutes }}m | Root Cause: {{ item.root_cause }} {% endfor %} Provide a bulleted synthesis of: 1. Primary technical vulnerabilities. 2. Recommended architectural hardening steps. output: schema: vulnerabilities: list[string] hardening_recommendations: list[string] pipeline: steps: - extract_incident_facts - canonicalize_services - summarize_systemic_risks

Step 3: Run the Agentic Optimizer and Execute the Compiled Plan

Save and execute the following Python script (run_docetl.py):

import json import time from docetl import Dataset, Pipeline def main(): print("Initializing UC Berkeley DocETL Engine...") start_time = time.perf_counter() # Load declarative pipeline specification with open("incident_pipeline.yaml", "r") as f: pipeline_config = f.read() pipeline = Pipeline.from_yaml(pipeline_config) print("Running DocETL Agentic Query Optimizer...") # The optimizer evaluates sample documents and selects optimal rewrites optimized_pipeline = pipeline.optimize( max_cost_budget=5.00, # Cap optimization spend to $5.00 sample_size=10 # Test plans on 10 representative documents ) print(f"Optimal Plan Generated in {(time.perf_counter() - start_time):.2f}s!") print("Executing Optimized Document Processing Pipeline...") execution_start = time.perf_counter() results = optimized_pipeline.run() elapsed = time.perf_counter() - execution_start print(f"\n--- Execution Completed in {elapsed:.2f}s ---") print(f"Successfully processed {len(results)} service clusters.") # Export clean structured data for analytical SQL engines with open("structured_incident_insights.json", "w") as out: json.dump(results, out, indent=2) print("Saved clean structured insights to 'structured_incident_insights.json'.") if __name__ == "__main__": main()

Production Best Practices: Integrating DocETL with Web Scraping and RAG

When pairing DocETL with desktop web scraping and automated extraction engines in AiFetchly, following these enterprise patterns ensures high-throughput reliability:

1. Synergistic Web Ingestion with aiFetchly Scraped Corpora

Autonomous web crawlers and scraping agents frequently extract messy, nested web pages (such as e-commerce catalog reviews, forum discussions, or regulatory bulletins):

  • Use AiFetchly to capture raw HTML, tables, and document links from protected client web sessions.
  • Pipe the raw harvested JSON directly into DocETL pipelines. DocETL’s resolve and filter operators clean tracking artifacts, resolve duplicate product names, and structure the data into high-value relational tables.

2. Automated Semantic Validation with Synthetic Ground Truth Samples

To prevent schema drift in continuous ETL pipelines:

  • Utilize DocETL’s built-in validation generator to maintain a golden dataset of 20 verified documents.
  • Run automated regression evaluations whenever you update foundational LLM model versions (e.g., transitioning from GPT-4o-mini to Claude 3.5 Haiku) to guarantee zero loss in extraction precision.

3. Cold-Start Caching and Parallel Execution Topologies

Executing LLM pipelines across thousands of documents requires robust infrastructure failure handling:

  • Enable Local SQLite Caching: DocETL natively supports operation-level response caching. If an API rate limit or network partition occurs at step 3, subsequent runs resume instantly without re-billing for completed map tasks.
  • Asynchronous Batching: Configure worker concurrency (max_threads: 16) to saturate enterprise LLM tier limits without triggering 429 Too Many Requests HTTP errors.