ExtractBench - A Benchmark for Schema-Guided Enterprise Document Extraction
See the codeExtractBench is a benchmark for schema-guided extraction from enterprise documents. Given a document and a user-defined JSON Schema, a system must return schema-valid JSON with the correct values, every record of each repeated structure, missing fields marked null rather than invented, and source evidence for each value.
A schema defines one extraction task, and all documents of that type share it: one invoice schema covers invoices from every vendor, however different each one looks. Enterprises write a new schema for almost every workflow, so a system cannot be tuned to a fixed template. It has to handle schemas and documents it has never seen. And because agents increasingly act on extracted values before anyone reviews them, one truncated schedule or one invented value becomes a wrong payment or a wrong decision. The benchmark therefore scores completeness and traceability.
The benchmark covers 370 documents (4,869 pages) across 8 business domains and 67 document types, each type with its own schema. Every document is tagged along five independent axes: task challenge, perception challenge, table structure, length, and business domain, so a low score can be traced to its cause.
Models and prices reflect each provider's official documentation as of September 11, 2026; each system uses its recommended configuration.
Unified value F1 — the headline metric. Every score is an unweighted mean over documents; each document counts once, whatever its length. For raw data including per-split precision and recall, cost, and latency, see leaderboard.csv. Equal displayed Overall scores are ordered by lower cost per page. The best score in each Overall, Short, Medium, and Long column is bold; the second-best distinct score is underlined.
| Rank | Provider | Category | Overall | Short | Medium | Long | ¢ / Page |
|---|---|---|---|---|---|---|---|
| 1 | LlamaExtract Agentic Plus | LlamaExtract | 95.91 | 96.94 | 94.45 | 90.18 | 8.11¢ |
| 2 | Pulse (Effort) | Specialized APIs | 95.91 | 96.46 | 95.01 | 93.51 | 10.50¢ |
| 3 | LlamaExtract Agentic | LlamaExtract | 94.77 | 96.04 | 92.11 | 91.83 | 3.31¢ |
| 4 | Codex (GPT-6 Sol Evidence) | Coding Agents | 94.57 | 95.99 | 92.42 | 87.25 | 9.80¢ |
| 5 | Codex (GPT-5.6 Sol Evidence) | Coding Agents | 93.77 | 96.04 | 90.19 | 82.73 | 21.65¢ |
| 6 | Codex (GPT-5.5) | Coding Agents | 93.57 | 95.68 | 91.15 | 78.88 | 27.83¢ |
| 7 | Codex (GPT-5.5 Evidence) | Coding Agents | 93.35 | 95.59 | 88.72 | 87.97 | 33.63¢ |
| 8 | Pulse (Non-effort) | Specialized APIs | 92.70 | 93.17 | 92.22 | 89.07 | 3.00¢ |
| 9 | LlamaExtract Cost-Effective | LlamaExtract | 92.27 | 94.03 | 89.51 | 83.73 | 1.06¢ |
| 10 | Codex (GPT-5.6 Terra Evidence) | Coding Agents | 92.26 | 95.60 | 86.69 | 77.36 | 9.45¢ |
Top 10 of 47 systems — full table in leaderboard.csv.
Grounding F1 — a field counts only when its value is accepted and it points at the right evidence: at word level the predicted box must overlap an accepted evidence box at IoU 0.5, at page level the cited page must be correct. Scored only over the documents that carry verified box ground truth.
| Rank | Provider | Word-level grounding F1 | Page-level grounding F1 | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Overall | Short | Medium | Long | Overall | Short | Medium | Long | ||
| 1 | Codex (GPT-6 Sol Evidence) | 77.11 | 77.61 | 75.53 | 78.31 | 86.50 | 87.20 | 85.12 | 84.82 |
| 2 | Claude Code (Opus 5.5 Evidence) | 71.55 | 73.57 | 65.54 | 74.87 | 76.95 | 79.27 | 71.36 | 76.47 |
| 3 | Codex (GPT-6 Luna Evidence) | 65.70 | 62.91 | 71.11 | 74.36 | 83.93 | 84.41 | 83.47 | 80.17 |
| 4 | LlamaExtract Agentic Plus | 58.11 | 54.11 | 69.93 | 68.31 | 86.66 | 91.37 | 78.84 | 66.25 |
| 5 | Codex (GPT-5.6 Sol Evidence) | 54.66 | 50.87 | 64.58 | 69.01 | 83.62 | 85.12 | 80.77 | 78.84 |
| 6 | Codex (GPT-5.5 Evidence) | 52.57 | 53.13 | 48.01 | 61.87 | 80.64 | 83.27 | 73.87 | 79.90 |
| 7 | Claude Code (Opus 4.8 Evidence) | 49.48 | 45.31 | 62.35 | 58.43 | 72.52 | 74.84 | 67.38 | 68.03 |
| 8 | LlamaExtract Agentic | 44.47 | 37.41 | 63.83 | 68.08 | 81.30 | 87.68 | 68.27 | 64.56 |
| 9 | Codex (GPT-5.6 Terra Evidence) | 43.68 | 40.48 | 53.32 | 51.17 | 80.52 | 83.51 | 75.18 | 69.32 |
| 10 | Reducto Deep Extract | 43.30 | 42.84 | 45.57 | 41.13 | 71.71 | 72.60 | 70.42 | 67.28 |
Top 10 of 47 systems — full table in leaderboard.csv.
Prerequisites: Create a .env file with the API key for the extraction system you want to evaluate (see Configuration).
# Install from PyPI (pick the extras for the systems you want to run)
pip install "llama-extract-bench[runners]" # every provider SDK
pip install "llama-extract-bench[llamaextract]" # or just one, e.g. llamaextract / openai / anthropic / google
# Or, from a checkout of this repo
uv sync --extra runners
# Quick test run (6 documents — good for trying things out)
# (drop the `uv run` prefix if you installed from PyPI)
uv run extract-bench run llamaextract_agentic --test
# Full benchmark run (replace with any pipeline name, see "Available Pipelines" below)
uv run extract-bench run llamaextract_agentic
# View interactive reports in your browser
uv run extract-bench serve llamaextract_agentic
[!WARNING] A full run is 370 documents / 4,869 pages against a metered API, and costs roughly $10 to $1,677 depending on which system you evaluate. Start with
--test, which runs 6 documents for cents on any hosted system.
Costs use each provider's official listed price as of July 1, 2026.
| Category | One full run | Examples |
|---|---|---|
| Commercial VLM | $10 – $49 | GPT-5.4 Nano ~$10, Gemini 3.5 Flash ~$49 |
| LlamaExtract | $49 – $395 | Cost-Effective ~$49, Agentic ~$152, Agentic Plus ~$395 |
| Specialized APIs | $170 – $1,677 | Datalab ~$170, Extend ~$487, Reducto Deep Extract ~$1,677 |
| Coding agents | $787 – $1,355 | Claude Code (Opus 4.8) ~$787, Codex (GPT-5.5) ~$1,355 |
| Self-hosted open weights | GPU time only | Qwen3.6 35B, Gemma4 26B, NuExtract3, Lift Datalab 9B |
These figures apply the reported mean cost per page to 4,869 pages. Per-system, per-split prices are in leaderboard.csv (Cost_Per_Page, Cost_Short, Cost_Medium, Cost_Long, in dollars per page).
A pipeline is an extraction system or configuration you want to evaluate. Run uv run extract-bench pipelines for the live list, or see docs/pipelines.md.
| Pipeline name | Name in paper |
|---|---|
llamaextract_agentic_plus | LlamaExtract Agentic Plus |
llamaextract_agentic | LlamaExtract Agentic |
llamaextract_cost_effective | LlamaExtract Cost-Effective |
reducto_deep_extract | Reducto Deep Extract |
extend_extract_max | Extend (Max Context) |
datalab_parse_accurate_extract_balanced | Datalab (Accurate + Balanced) |
codex_code_extract_gpt_5_5_low | Codex (GPT-5.5) |
claude_code_extract_opus_4_8 | Claude Code (Opus 4.8) |
qwen3_6_35b_a3b_fp8_vllm_extract_oneshot_structured_output_file | Qwen3.6 35B (self-hosted) |
gemma4_26b_vllm_extract_oneshot_structured_output_file | Gemma4 26B (self-hosted) |
nuextract3_extract | NuExtract3 (self-hosted) |
lift_extract | Lift Datalab 9B (self-hosted) |
gemini_3_5_flash_extract_oneshot_structured_output_file | Google Gemini 3.5 Flash |
openai_gpt_5_4_nano_extract_oneshot_structured_output_file | OpenAI GPT-5.4 Nano |
The four self-hosted pipelines need an endpoint you run yourself; see .env.example. Other configurations of the same systems are registered too (reducto_extract, extend_extract, codex_code_extract_gpt_5_5_high, the two-stage parse baselines, and more). Run uv run extract-bench pipelines for the full roster.
All three LlamaExtract tiers return word-level citation boxes, so both grounding metrics are meaningful on each. llamaextract_agentic_plus does it natively. llamaextract_cost_effective and llamaextract_agentic get there by running a parse at their own tier that emits word boxes, which is a second job. llamaextract_cost_effective_standard_bbox and llamaextract_agentic_standard_bbox are those two tiers without that parse pass: one job instead of two, but citations carry only block-level boxes, so word-level grounding scores near zero.
[!NOTE]
claude_code_extract_*andcodex_code_extract_*run a coding agent on your machine, so they execute local shell commands against benchmark documents. Run them in a container or VM. Every other pipeline is an ordinary API call.
The parse and layout-detection rosters inherited from ParseBench are still registered and runnable by name; list them with extract-bench pipelines --parse, --layout, or --all. They are hidden from the default listing because this benchmark scores extraction; the two-stage extract pipelines use them internally as their parse stage.
Hosted on HuggingFace: llamaindex/ExtractBench
The benchmark is split by document length, with one JSONL row per (document, schema) test case plus the source PDFs:
| Split | File | Documents | Pages | Length |
|---|---|---|---|---|
| Short | short.jsonl | 252 | 615 | ≤10 pages |
| Medium | medium.jsonl | 98 | 2,438 | 11–50 pages |
| Long | long.jsonl | 20 | 1,816 | >50 pages |
| Total | 370 | 4,869 |
The benchmark spans 8 business domains and 67 document types: finance and fund holdings, energy-sector regulatory forms, government procurement and customs, auto valuation, supply chain, healthcare remittance, legal and bankruptcy filings, and real estate.
What each task challenge tests:
A document can carry more than one task challenge.
The other axes are tagged independently of the task challenge:
Sources. All documents come from public records: SEC and regulatory filings, government procurement and customs forms, court and agency exhibits (including tax forms such as W-2, 1040, K-1, and 1099-B), Texas Railroad Commission energy filings, and published business documents. 325 are real; 45 are synthetic long lists rendered from real layouts. PDF metadata has been stripped from every file.
Ground truth uses a method matched to each source: adjudicated agreement across independent extraction systems for real documents, values fixed before rendering for synthetic long lists, and human-verified values and boxes for forms. Each field's ground truth is an evidence list — the expected value plus any alternate acceptable readings, each with its source location — and scoring accepts a match against any listed reading.
The dataset is automatically downloaded when you run a pipeline. To manage it manually:
# Download the full dataset
uv run extract-bench download
# Download a small test dataset (6 documents, good for trying things out)
uv run extract-bench download --test
# Check whether the dataset has been downloaded and show summary statistics
uv run extract-bench status
ExtractBench reports one metric for value accuracy and two for grounding. We score the grounding metrics only on fields that carry verified box ground truth.
null, every scalar field enters both denominators, and a correct null on a blank field is credited. Only repeated records move precision and recall apart, so a gap between them means records were dropped or invented.Failed and missing documents score zero rather than being dropped, so a pipeline cannot raise its average by erroring out on the documents it finds hardest.
The run command runs inference, evaluates against ground truth, and generates reports:
# Evaluate an extraction system on the whole benchmark
uv run extract-bench run <pipeline_name>
# Evaluate a single split only (short, medium, long)
uv run extract-bench run <pipeline_name> --group short
# Skip calling the extraction system — just re-evaluate existing results
uv run extract-bench run <pipeline_name> --skip_inference
# Control how many documents are processed in parallel
uv run extract-bench run <pipeline_name> --max_concurrent 10
# Run on the small test dataset only
uv run extract-bench run <pipeline_name> --test
# View reports in your browser (needed because browsers block PDF rendering from file:// URLs)
uv run extract-bench serve <pipeline_name>
# Compare two extraction systems side-by-side
uv run extract-bench compare <pipeline_a> <pipeline_b>
# Generate a leaderboard across all evaluated systems
uv run extract-bench leaderboard
# Leaderboard for specific systems only
uv run extract-bench leaderboard llamaextract_agentic llamaextract_cost_effective
For fine-grained control over individual steps:
# Run inference only (call the extraction system, don't evaluate)
uv run extract-bench inference run <pipeline_name> data/short --output_dir output
# Run evaluation only (on existing inference results)
uv run extract-bench evaluation run output/<pipeline_name> --test_cases_dir data
# Generate detailed HTML report from evaluation results
uv run extract-bench analysis generate_report --evaluation_dir ./output/<pipeline_name>
To add a new extraction system, use Claude Code:
/integrate-pipeline <name> <API docs or SDK link>
This creates the provider, registers the pipeline, and updates docs. The skill definition lives in .claude/commands/integrate-pipeline.md and can be adapted for other AI coding agents.
Each pipeline calls a specific system's API. You only need the key for the system you want to evaluate. Add it to a .env file at the project root (see .env.example for the full list):
# Only add the keys you need. For example, to evaluate LlamaExtract:
LLAMA_CLOUD_API_KEY=...
# To evaluate OpenAI-based pipelines:
OPENAI_API_KEY=...
# To evaluate Anthropic-based pipelines (including claude_code_extract_*):
ANTHROPIC_API_KEY=...
# To evaluate Google-based pipelines:
GOOGLE_API_KEY=...
# Codex coding-agent pipelines authenticate the codex CLI:
CODEX_API_KEY=...
ExtractBench does not use LLM-as-a-judge; all value scoring is deterministic. Your keys only ever call the extraction system you are evaluating.
| Command | Description |
|---|---|
extract-bench run | Evaluate an extraction system end-to-end (inference + evaluation + reports) |
extract-bench download | Download the benchmark dataset from HuggingFace |
extract-bench status | Check whether the dataset has been downloaded |
extract-bench pipelines | List extraction pipelines (--parse, --layout, --all for the rest) |
extract-bench compare | Compare results from two systems side-by-side |
extract-bench leaderboard | Generate a leaderboard across all evaluated systems |
extract-bench serve | View HTML reports in your browser (with PDF rendering support) |
Advanced subcommands: inference, evaluation, analysis, pipeline, data
output/
├── _leaderboard.html # Cross-pipeline leaderboard
└── <pipeline_name>/
├── short/
│ ├── *.result.json # Inference results
│ ├── _evaluation_report.json # Evaluation summary
│ ├── _evaluation_report_detailed.html # Interactive detailed report
│ ├── _evaluation_results.csv # Per-example CSV
│ └── _evaluation_report.md # Markdown summary
├── medium/ (same structure)
├── long/ (same structure)
├── _errors.json # Per-document inference failures
└── _metadata.json # Run metadata
src/extract_bench/
├── cli.py # Fire CLI entry point
├── pipeline/cli.py # End-to-end pipeline orchestration
├── data/
│ ├── download.py # HuggingFace dataset download
│ └── cli.py # Data management CLI
├── inference/
│ ├── runner.py # Batch inference with concurrency
│ ├── pipelines/ # Pipeline registry (extract, parse, layout)
│ └── providers/ # Provider implementations per product type
├── evaluation/
│ ├── runner.py # Parallel evaluation + failure penalties
│ ├── evaluators/ # Product-specific evaluators
│ ├── metrics/extract/ # Unified value F1, grounding, record matching
│ └── reports/ # CSV, HTML, markdown export
├── analysis/
│ ├── detailed_report.py # Interactive per-split HTML report
│ └── comparison.py # Pipeline comparison
├── test_cases/
│ ├── loader.py # Load test cases (JSONL or sidecar .test.json)
│ └── schema.py # TestCase types (Extract, Parse, LayoutDetection)
└── schemas/
├── pipeline_io.py # InferenceRequest, InferenceResult
├── evaluation.py # EvaluationResult, EvaluationSummary
└── product.py # ProductType enum
@misc{zhang2026extractbenchbenchmarkschemaguidedenterprise,
title={ExtractBench: A Benchmark for Schema-Guided Enterprise Document Extraction},
author={Boyang Zhang and Adrian Lyjak and Eli Stewart and Zhaoqi Li and Simon Suo},
year={2026},
eprint={2607.29677},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2607.29677},
}
Python
96.8%
JavaScript
2.2%
ExtractBench - A Benchmark for Schema-Guided Enterprise Document Extraction
See the codeExtractBench is a benchmark for schema-guided extraction from enterprise documents. Given a document and a user-defined JSON Schema, a system must return schema-valid JSON with the correct values, every record of each repeated structure, missing fields marked null rather than invented, and source evidence for each value.
A schema defines one extraction task, and all documents of that type share it: one invoice schema covers invoices from every vendor, however different each one looks. Enterprises write a new schema for almost every workflow, so a system cannot be tuned to a fixed template. It has to handle schemas and documents it has never seen. And because agents increasingly act on extracted values before anyone reviews them, one truncated schedule or one invented value becomes a wrong payment or a wrong decision. The benchmark therefore scores completeness and traceability.
The benchmark covers 370 documents (4,869 pages) across 8 business domains and 67 document types, each type with its own schema. Every document is tagged along five independent axes: task challenge, perception challenge, table structure, length, and business domain, so a low score can be traced to its cause.
Models and prices reflect each provider's official documentation as of September 11, 2026; each system uses its recommended configuration.
Unified value F1 — the headline metric. Every score is an unweighted mean over documents; each document counts once, whatever its length. For raw data including per-split precision and recall, cost, and latency, see leaderboard.csv. Equal displayed Overall scores are ordered by lower cost per page. The best score in each Overall, Short, Medium, and Long column is bold; the second-best distinct score is underlined.
| Rank | Provider | Category | Overall | Short | Medium | Long | ¢ / Page |
|---|---|---|---|---|---|---|---|
| 1 | LlamaExtract Agentic Plus | LlamaExtract | 95.91 | 96.94 | 94.45 | 90.18 | 8.11¢ |
| 2 | Pulse (Effort) | Specialized APIs | 95.91 | 96.46 | 95.01 | 93.51 | 10.50¢ |
| 3 | LlamaExtract Agentic | LlamaExtract | 94.77 | 96.04 | 92.11 | 91.83 | 3.31¢ |
| 4 | Codex (GPT-6 Sol Evidence) | Coding Agents | 94.57 | 95.99 | 92.42 | 87.25 | 9.80¢ |
| 5 | Codex (GPT-5.6 Sol Evidence) | Coding Agents | 93.77 | 96.04 | 90.19 | 82.73 | 21.65¢ |
| 6 | Codex (GPT-5.5) | Coding Agents | 93.57 | 95.68 | 91.15 | 78.88 | 27.83¢ |
| 7 | Codex (GPT-5.5 Evidence) | Coding Agents | 93.35 | 95.59 | 88.72 | 87.97 | 33.63¢ |
| 8 | Pulse (Non-effort) | Specialized APIs | 92.70 | 93.17 | 92.22 | 89.07 | 3.00¢ |
| 9 | LlamaExtract Cost-Effective | LlamaExtract | 92.27 | 94.03 | 89.51 | 83.73 | 1.06¢ |
| 10 | Codex (GPT-5.6 Terra Evidence) | Coding Agents | 92.26 | 95.60 | 86.69 | 77.36 | 9.45¢ |
Top 10 of 47 systems — full table in leaderboard.csv.
Grounding F1 — a field counts only when its value is accepted and it points at the right evidence: at word level the predicted box must overlap an accepted evidence box at IoU 0.5, at page level the cited page must be correct. Scored only over the documents that carry verified box ground truth.
| Rank | Provider | Word-level grounding F1 | Page-level grounding F1 | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Overall | Short | Medium | Long | Overall | Short | Medium | Long | ||
| 1 | Codex (GPT-6 Sol Evidence) | 77.11 | 77.61 | 75.53 | 78.31 | 86.50 | 87.20 | 85.12 | 84.82 |
| 2 | Claude Code (Opus 5.5 Evidence) | 71.55 | 73.57 | 65.54 | 74.87 | 76.95 | 79.27 | 71.36 | 76.47 |
| 3 | Codex (GPT-6 Luna Evidence) | 65.70 | 62.91 | 71.11 | 74.36 | 83.93 | 84.41 | 83.47 | 80.17 |
| 4 | LlamaExtract Agentic Plus | 58.11 | 54.11 | 69.93 | 68.31 | 86.66 | 91.37 | 78.84 | 66.25 |
| 5 | Codex (GPT-5.6 Sol Evidence) | 54.66 | 50.87 | 64.58 | 69.01 | 83.62 | 85.12 | 80.77 | 78.84 |
| 6 | Codex (GPT-5.5 Evidence) | 52.57 | 53.13 | 48.01 | 61.87 | 80.64 | 83.27 | 73.87 | 79.90 |
| 7 | Claude Code (Opus 4.8 Evidence) | 49.48 | 45.31 | 62.35 | 58.43 | 72.52 | 74.84 | 67.38 | 68.03 |
| 8 | LlamaExtract Agentic | 44.47 | 37.41 | 63.83 | 68.08 | 81.30 | 87.68 | 68.27 | 64.56 |
| 9 | Codex (GPT-5.6 Terra Evidence) | 43.68 | 40.48 | 53.32 | 51.17 | 80.52 | 83.51 | 75.18 | 69.32 |
| 10 | Reducto Deep Extract | 43.30 | 42.84 | 45.57 | 41.13 | 71.71 | 72.60 | 70.42 | 67.28 |
Top 10 of 47 systems — full table in leaderboard.csv.
Prerequisites: Create a .env file with the API key for the extraction system you want to evaluate (see Configuration).
# Install from PyPI (pick the extras for the systems you want to run)
pip install "llama-extract-bench[runners]" # every provider SDK
pip install "llama-extract-bench[llamaextract]" # or just one, e.g. llamaextract / openai / anthropic / google
# Or, from a checkout of this repo
uv sync --extra runners
# Quick test run (6 documents — good for trying things out)
# (drop the `uv run` prefix if you installed from PyPI)
uv run extract-bench run llamaextract_agentic --test
# Full benchmark run (replace with any pipeline name, see "Available Pipelines" below)
uv run extract-bench run llamaextract_agentic
# View interactive reports in your browser
uv run extract-bench serve llamaextract_agentic
[!WARNING] A full run is 370 documents / 4,869 pages against a metered API, and costs roughly $10 to $1,677 depending on which system you evaluate. Start with
--test, which runs 6 documents for cents on any hosted system.
Costs use each provider's official listed price as of July 1, 2026.
| Category | One full run | Examples |
|---|---|---|
| Commercial VLM | $10 – $49 | GPT-5.4 Nano ~$10, Gemini 3.5 Flash ~$49 |
| LlamaExtract | $49 – $395 | Cost-Effective ~$49, Agentic ~$152, Agentic Plus ~$395 |
| Specialized APIs | $170 – $1,677 | Datalab ~$170, Extend ~$487, Reducto Deep Extract ~$1,677 |
| Coding agents | $787 – $1,355 | Claude Code (Opus 4.8) ~$787, Codex (GPT-5.5) ~$1,355 |
| Self-hosted open weights | GPU time only | Qwen3.6 35B, Gemma4 26B, NuExtract3, Lift Datalab 9B |
These figures apply the reported mean cost per page to 4,869 pages. Per-system, per-split prices are in leaderboard.csv (Cost_Per_Page, Cost_Short, Cost_Medium, Cost_Long, in dollars per page).
A pipeline is an extraction system or configuration you want to evaluate. Run uv run extract-bench pipelines for the live list, or see docs/pipelines.md.
| Pipeline name | Name in paper |
|---|---|
llamaextract_agentic_plus | LlamaExtract Agentic Plus |
llamaextract_agentic | LlamaExtract Agentic |
llamaextract_cost_effective | LlamaExtract Cost-Effective |
reducto_deep_extract | Reducto Deep Extract |
extend_extract_max | Extend (Max Context) |
datalab_parse_accurate_extract_balanced | Datalab (Accurate + Balanced) |
codex_code_extract_gpt_5_5_low | Codex (GPT-5.5) |
claude_code_extract_opus_4_8 | Claude Code (Opus 4.8) |
qwen3_6_35b_a3b_fp8_vllm_extract_oneshot_structured_output_file | Qwen3.6 35B (self-hosted) |
gemma4_26b_vllm_extract_oneshot_structured_output_file | Gemma4 26B (self-hosted) |
nuextract3_extract | NuExtract3 (self-hosted) |
lift_extract | Lift Datalab 9B (self-hosted) |
gemini_3_5_flash_extract_oneshot_structured_output_file | Google Gemini 3.5 Flash |
openai_gpt_5_4_nano_extract_oneshot_structured_output_file | OpenAI GPT-5.4 Nano |
The four self-hosted pipelines need an endpoint you run yourself; see .env.example. Other configurations of the same systems are registered too (reducto_extract, extend_extract, codex_code_extract_gpt_5_5_high, the two-stage parse baselines, and more). Run uv run extract-bench pipelines for the full roster.
All three LlamaExtract tiers return word-level citation boxes, so both grounding metrics are meaningful on each. llamaextract_agentic_plus does it natively. llamaextract_cost_effective and llamaextract_agentic get there by running a parse at their own tier that emits word boxes, which is a second job. llamaextract_cost_effective_standard_bbox and llamaextract_agentic_standard_bbox are those two tiers without that parse pass: one job instead of two, but citations carry only block-level boxes, so word-level grounding scores near zero.
[!NOTE]
claude_code_extract_*andcodex_code_extract_*run a coding agent on your machine, so they execute local shell commands against benchmark documents. Run them in a container or VM. Every other pipeline is an ordinary API call.
The parse and layout-detection rosters inherited from ParseBench are still registered and runnable by name; list them with extract-bench pipelines --parse, --layout, or --all. They are hidden from the default listing because this benchmark scores extraction; the two-stage extract pipelines use them internally as their parse stage.
Hosted on HuggingFace: llamaindex/ExtractBench
The benchmark is split by document length, with one JSONL row per (document, schema) test case plus the source PDFs:
| Split | File | Documents | Pages | Length |
|---|---|---|---|---|
| Short | short.jsonl | 252 | 615 | ≤10 pages |
| Medium | medium.jsonl | 98 | 2,438 | 11–50 pages |
| Long | long.jsonl | 20 | 1,816 | >50 pages |
| Total | 370 | 4,869 |
The benchmark spans 8 business domains and 67 document types: finance and fund holdings, energy-sector regulatory forms, government procurement and customs, auto valuation, supply chain, healthcare remittance, legal and bankruptcy filings, and real estate.
What each task challenge tests:
A document can carry more than one task challenge.
The other axes are tagged independently of the task challenge:
Sources. All documents come from public records: SEC and regulatory filings, government procurement and customs forms, court and agency exhibits (including tax forms such as W-2, 1040, K-1, and 1099-B), Texas Railroad Commission energy filings, and published business documents. 325 are real; 45 are synthetic long lists rendered from real layouts. PDF metadata has been stripped from every file.
Ground truth uses a method matched to each source: adjudicated agreement across independent extraction systems for real documents, values fixed before rendering for synthetic long lists, and human-verified values and boxes for forms. Each field's ground truth is an evidence list — the expected value plus any alternate acceptable readings, each with its source location — and scoring accepts a match against any listed reading.
The dataset is automatically downloaded when you run a pipeline. To manage it manually:
# Download the full dataset
uv run extract-bench download
# Download a small test dataset (6 documents, good for trying things out)
uv run extract-bench download --test
# Check whether the dataset has been downloaded and show summary statistics
uv run extract-bench status
ExtractBench reports one metric for value accuracy and two for grounding. We score the grounding metrics only on fields that carry verified box ground truth.
null, every scalar field enters both denominators, and a correct null on a blank field is credited. Only repeated records move precision and recall apart, so a gap between them means records were dropped or invented.Failed and missing documents score zero rather than being dropped, so a pipeline cannot raise its average by erroring out on the documents it finds hardest.
The run command runs inference, evaluates against ground truth, and generates reports:
# Evaluate an extraction system on the whole benchmark
uv run extract-bench run <pipeline_name>
# Evaluate a single split only (short, medium, long)
uv run extract-bench run <pipeline_name> --group short
# Skip calling the extraction system — just re-evaluate existing results
uv run extract-bench run <pipeline_name> --skip_inference
# Control how many documents are processed in parallel
uv run extract-bench run <pipeline_name> --max_concurrent 10
# Run on the small test dataset only
uv run extract-bench run <pipeline_name> --test
# View reports in your browser (needed because browsers block PDF rendering from file:// URLs)
uv run extract-bench serve <pipeline_name>
# Compare two extraction systems side-by-side
uv run extract-bench compare <pipeline_a> <pipeline_b>
# Generate a leaderboard across all evaluated systems
uv run extract-bench leaderboard
# Leaderboard for specific systems only
uv run extract-bench leaderboard llamaextract_agentic llamaextract_cost_effective
For fine-grained control over individual steps:
# Run inference only (call the extraction system, don't evaluate)
uv run extract-bench inference run <pipeline_name> data/short --output_dir output
# Run evaluation only (on existing inference results)
uv run extract-bench evaluation run output/<pipeline_name> --test_cases_dir data
# Generate detailed HTML report from evaluation results
uv run extract-bench analysis generate_report --evaluation_dir ./output/<pipeline_name>
To add a new extraction system, use Claude Code:
/integrate-pipeline <name> <API docs or SDK link>
This creates the provider, registers the pipeline, and updates docs. The skill definition lives in .claude/commands/integrate-pipeline.md and can be adapted for other AI coding agents.
Each pipeline calls a specific system's API. You only need the key for the system you want to evaluate. Add it to a .env file at the project root (see .env.example for the full list):
# Only add the keys you need. For example, to evaluate LlamaExtract:
LLAMA_CLOUD_API_KEY=...
# To evaluate OpenAI-based pipelines:
OPENAI_API_KEY=...
# To evaluate Anthropic-based pipelines (including claude_code_extract_*):
ANTHROPIC_API_KEY=...
# To evaluate Google-based pipelines:
GOOGLE_API_KEY=...
# Codex coding-agent pipelines authenticate the codex CLI:
CODEX_API_KEY=...
ExtractBench does not use LLM-as-a-judge; all value scoring is deterministic. Your keys only ever call the extraction system you are evaluating.
| Command | Description |
|---|---|
extract-bench run | Evaluate an extraction system end-to-end (inference + evaluation + reports) |
extract-bench download | Download the benchmark dataset from HuggingFace |
extract-bench status | Check whether the dataset has been downloaded |
extract-bench pipelines | List extraction pipelines (--parse, --layout, --all for the rest) |
extract-bench compare | Compare results from two systems side-by-side |
extract-bench leaderboard | Generate a leaderboard across all evaluated systems |
extract-bench serve | View HTML reports in your browser (with PDF rendering support) |
Advanced subcommands: inference, evaluation, analysis, pipeline, data
output/
├── _leaderboard.html # Cross-pipeline leaderboard
└── <pipeline_name>/
├── short/
│ ├── *.result.json # Inference results
│ ├── _evaluation_report.json # Evaluation summary
│ ├── _evaluation_report_detailed.html # Interactive detailed report
│ ├── _evaluation_results.csv # Per-example CSV
│ └── _evaluation_report.md # Markdown summary
├── medium/ (same structure)
├── long/ (same structure)
├── _errors.json # Per-document inference failures
└── _metadata.json # Run metadata
src/extract_bench/
├── cli.py # Fire CLI entry point
├── pipeline/cli.py # End-to-end pipeline orchestration
├── data/
│ ├── download.py # HuggingFace dataset download
│ └── cli.py # Data management CLI
├── inference/
│ ├── runner.py # Batch inference with concurrency
│ ├── pipelines/ # Pipeline registry (extract, parse, layout)
│ └── providers/ # Provider implementations per product type
├── evaluation/
│ ├── runner.py # Parallel evaluation + failure penalties
│ ├── evaluators/ # Product-specific evaluators
│ ├── metrics/extract/ # Unified value F1, grounding, record matching
│ └── reports/ # CSV, HTML, markdown export
├── analysis/
│ ├── detailed_report.py # Interactive per-split HTML report
│ └── comparison.py # Pipeline comparison
├── test_cases/
│ ├── loader.py # Load test cases (JSONL or sidecar .test.json)
│ └── schema.py # TestCase types (Extract, Parse, LayoutDetection)
└── schemas/
├── pipeline_io.py # InferenceRequest, InferenceResult
├── evaluation.py # EvaluationResult, EvaluationSummary
└── product.py # ProductType enum
@misc{zhang2026extractbenchbenchmarkschemaguidedenterprise,
title={ExtractBench: A Benchmark for Schema-Guided Enterprise Document Extraction},
author={Boyang Zhang and Adrian Lyjak and Eli Stewart and Zhaoqi Li and Simon Suo},
year={2026},
eprint={2607.29677},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2607.29677},
}
Python
96.8%
JavaScript
2.2%