DAB: Data Agent Benchmark
🌐 Website & Leaderboard: ucbepic.github.io/DataAgentBench
> 📄 Paper: arxiv.org/abs/2603.20576
> 🔥 DAB is the first benchmark for evaluating data agents on realistic, complex, data-oriented tasks. It is a collaborative effort between UC Berkeley and Hasura PromptQL.
> 🤝 **We welcome contributions to the leaderboard!Submit a Pull Request following the instructions below to share your agent results and see them ranked on DAB.**
DAB captures four core properties of real-world enterprise data workloads across industries:
- Multi-database integration
- Ill-formatted key joins
- Unstructured text transformation
- Domain knowledge

🏆 Leaderboard
Tuned prompt ✓ = the up-front prompt is DAB-specific, built from a close study of DAB's task conventions (domain rules, parsing and interpretation choices, and expected answer shapes).
Hints ✓ = used db_description_withhint.txt.
| Rank | Model | Tuned prompt | Pass@1 ¹ | Trials | Hints | Date | Submission | | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | Datasage (GLM-5.3 + Jev-1.13.0) ⁸ | ✓ | 0.9628 | 5 | ✓ | 2026-10-01 | #115 | | 2 | Camber v2 (Claude-Opus-5, high effort) | ✓ | 0.9542 | 5 | ✓ | 2026-09-22 | #111 | | 3 | Permute EQ (Claude-Opus-5) | ✓ | 0.9467 | 5 | ✓ | 2026-09-11 | #95 | | 4 | Scout (OceanBase Lab) (GLM-5.2) | ✓ | 0.9062 | 5 | ✓ | 2026-09-08 | #96 | | 5 | Camber (Claude-Opus-5, high effort) | ✓ | 0.8790 | 5 | ✓ | 2026-08-27 | #92 | | 6 | DVIndex (GPT-6-Astra, high effort + Jev-1.13.0) | ✓ | 0.8768 | 5 | ✓ | 2026-09-23 | #113 | | 7 | Phoenix-CLI (Claude-Opus-5.5) | | 0.8621 | 5 | ✓ | 2026-09-26 | #114 | | 8 | Sentinel (Actioneer) (Fable-5 + Claude-Opus-4.7) | ✓ | 0.8617 | 5 | ✓ | 2026-07-20 | #73 | | 9 | Permute Core (Claude-Opus-5) | ✓ | 0.8413 | 5 | ✓ | 2026-08-05 | #85 | | 10 | Alkera (Fable-5 + Claude-Opus-4.8) | ✓ | 0.8411 | 5 | ✓ | 2026-07-14 | #70 | | 11 | Sarvam Code v0.36 (GLM-5.2) | ✓ | 0.8208 | 5 | ✓ | 2026-07-28 | #75 | | 12 | DataTrail v1 (Muse-Spark-1.3, medium effort) | ✓ | 0.8201 | 5 | ✓ | 2026-09-13 | #104 | | 13 | SCRIBE (Actioneer) (Claude-Opus-4.7) | ✓ | 0.8185 | 5 | ✓ | 2026-06-26 | #67 | | 14 | Stela (DeepSeek-V4.1-Flash, max effort) | ✓ | 0.8114 | 5 | ✓ | 2026-09-13 | #103 | | 15 | Alkera (Claude-Opus-4.8) | ✓ | 0.8044 | 5 | ✓ | 2026-07-15 | #69 | | 16 | LabRat (Claude-Opus-5 + Cartographer) ⁶ | ✓ | 0.8018 | 5 | ✓ | 2026-08-03 | #84 | | 17 | Spacedock (Recce) (GPT-5.5) | | 0.7850 | 5 | ✓ | 2026-06-23 | #63 | | 18 | DG (GLM-5.3) ⁷ | ✓ | 0.7828 | 5 | ✓ | 2026-09-19 | #108 | | 19 | Sarvam Code v0.35 (GLM-5.2) | ✓ | 0.7812 | 5 | ✓ | 2026-07-27 | #74 | | 20 | LabRat (GPT-5.6-Luna-Max + Cartographer) | | 0.7751 | 5 | ✓ | 2026-07-16 | #72 | | 21 | Altimate Code (GPT-5.5 + Claude Sonnet 4.6) | | 0.7588 | 5 | ✓ | 2026-06-01 | #53 | | 22 | Phoenix-CLI (Claude-Opus-5) | | 0.7556 | 5 | ✓ | 2026-09-04 | #94 | | 23 | AgenDA (Claude-Opus-4.8) | | 0.7244 | 5 | ✓ | 2026-07-10 | #68 | | 24 | Qwen3.8-Flash-Next | | 0.7087 | 5 | ✓ | 2026-09-12 | #99 | | 25 | fabric-rlm (GPT-5.6-Luna-Max) ⁵ | | 0.6956 | 5 | ✓ | 2026-07-31 | #76 | | 26 | Altimate Code (Claude-Sonnet-4.6) | | 0.6822 | 5 | ✓ | 2026-05-10 | #44 | | 27 | Spacedock (Recce) (Claude-Opus-4.8) | | 0.6804 | 5 | ✓ | 2026-06-08 | #55 | | 28 | MinusX (Claude Sonnet 4.6 + GPT5.5-mini + Claude Haiku 4.5) | | 0.6601 | 5 | ✓ | 2026-05-21 | #50 | | 29 | DataBridge (GLM-5.2) | ✓ | 0.6137 | 6 | ✓ | 2026-06-22 | #61 | | 30 | Pi Coding Agent (Claude-Opus-4.6) | | 0.6103 | 5 | ✓ | 2026-04-21 | #31 | | 31 | LabRat (Claude-Sonnet-4.6 + Cartographer) | | 0.6088 | 5 | ✓ | 2026-06-24 | #65 | | 32 | PromptQL (Gemini-3.1-Pro) | | 0.6000 | 5 | ✓ | 2026-03-18 | #24 | | 33 | PromptQL (Claude-Opus-4.6) | | 0.5933 | 5 | ✓ | 2026-03-02 | #23 | | 34 | Spacedock (Recce) (Claude-Opus-4.6) | | 0.5828 | 5 | | 2026-05-08 | #47 | | 35 | Claude-Opus-4.6 | | 0.5551 | 5 | ✓ | 2026-03-18 | #22 | | 36 | LabRat (Claude-Sonnet-4.6) ² | | 0.5138 | 5 | | 2026-06-01 | #54 | | 37 | Oracle Forge — Team PaLM (Gemini-3.1-Pro-Preview) ³ | | 0.4721 | 5 | ✓ | 2026-05-10 | #37 | | 38 | Gemini-3-Pro | | 0.4663 | 50 | ✓ | 2026-03-02 | — | | 39 | nQuery (gpt-oss-safeguard-120b) NGENUX SOLUTIONS PVT LTD | | 0.4547 | 5 | ✓ | 2026-07-02 | #56 | | 40 | Oracle Forge — Tenacious Intelligence (Claude-Sonnet-4.6) ⁴ | | 0.4464 | 5–7 | | 2026-04-21 | #32 | | 41 | GPT-5-mini | | 0.3663 | 50 | ✓ | 2026-03-02 | — | | 42 | GPT-5.2 | | 0.2991 | 50 | ✓ | 2026-03-02 | — | | 43 | Kimi-K2 | | 0.2925 | 50 | ✓ | 2026-03-02 | — | | 44 | Oracle Forge — Team Cohere (Gemini-2.0-Flash) | | 0.1671 | 5 | ✓ | 2026-04-21 | #38 | | 45 | Gemini-2.5-Flash | | 0.1049 | 50 | ✓ | 2026-03-02 | — |
¹ Methodology. DEPS_DEV_V1 query 1 re-scored on 2026-08-18 by re-running its validate.py against a revised validator (accepting any of the 95 packages tied at fifth place on 57779 stars rather than the single tied package recorded in ground_truth.csv, see issue #86), from the same submission JSONs, with no other query changed. All Pass@1 scores recomputed on 2026-06-12 by re-running each query's validate.py against the current validators (including the regenerated PATENTS ground truths), from the submission JSONs stored in this repository (submissions/, leaderboard_submissions/) or in the corresponding submission PR branches (refs/pull/). Pass@1 is the mean over datasets of each dataset's average per-query pass rate.
² LabRat (#54) had 21 contaminated trials counted as non-passes.
³ Team PaLM (#37) covers 49 of 54 queries (missing queries scored 0).
⁴ Tenacious Intelligence (#32) has 5–7 trials per query (per-query denominators used).
⁵ fabric-rlm (#76) had 8 agnews trials counted as non-passes: 4 loaded external gold labels, and 4 submitted the gold value with no derivation in the supplied traces.
⁶ LabRat (#84) is missing 2 of 270 trials (agnews query 4, infra timeouts), counted as non-passes; excluding them gives 0.8102.
⁷ DG (#108) uses author-derived hints. For GITHUB_REPOS query 1 the hint sets the denominator: "4 README rows total; ... NEVER use contents.sample_path-based counts", so the agent counts the 3 README files that give the gold 1/3 instead of the roughly 100 it would otherwise find. For PANCANCER_ATLAS query 1 the hint sets the answer key: "output rows keyed by the ICD-O code", so the agent reports histology codes (9382/3) as the gold does instead of names (Astrocytoma), which the question alone does not say.
⁸ Datasage (#115) gives the agent task-specific tools, for example an exponential moving average helper that returns the earliest peak year (PATENTS queries 1 and 2), an opening-hours schedule filter (googlelocal query 3), a policy-compliance decision tool (crmarenapro queries 2, 6 and 7) and a fuzzy entity-resolution tool (music_brainz_20k).
How to Submit to the Leaderboard
To contribute your agent's results to the DAB leaderboard:
- Collect results from 5 runs on all queries across all datasets.
- Organize all your run results into a single JSON file following this structure:
[
{
"dataset": "<dataset_name>", // e.g., "bookreview"
"query": "<query_id>", // e.g., "1"
"run": "<run_number>", // 0–4 for 5 runs
"answer": "<agent_generated_answer>"
},
...
// Include an entry for every run of every query across all datasets
]
- Submit a Pull Request to this repository including:
- The name of your agent
- Backbone LLM model(s) name and version
- Whether dataset hints were used
- Any additional notes or special settings you want to highlight
⚠️ You must include all 5 runs for each query in your dataset, along with their execution traces. Missing runs or missing traces may result in your submission being rejected from the leaderboard.
We will validate each submission — see SUBMISSION_RUBRIC.md, which we recommend checking locally during your runs.
📚 Table of Contents
* Clone the Repository * Install Dependencies * Setup Docker * Setup Databases * Set Database Configurations * Add API Credentials * Run the Built-in Agent * Execution Logs * Validate Agent Answer * Dataset * Query📊 Benchmark Overview
This benchmark contains 12 datasets and 54 queries across 9 domains and 4 DBMSes:
| Dataset | #DBs | DBMSes | #Tbls | #Queries | | ---------------- | ---- | -------------------------- | ----- | -------- | | agnews | 2 | MongoDB, SQLite | 3 | 4 | | bookreview | 2 | PostgreSQL, SQLite | 2 | 3 | | crmarenapro | 6 | DuckDB, PostgreSQL, SQLite | 27 | 13 | | deps_dev_v1 | 2 | DuckDB, SQLite | 3 | 2 | | github_repos | 2 | DuckDB, SQLite | 6 | 4 | | googlelocal | 2 | PostgreSQL, SQLite | 2 | 4 | | music_brainz_20k | 2 | DuckDB, SQLite | 2 | 3 | | pancancer_atlas | 2 | DuckDB, PostgreSQL | 3 | 3 | | patents | 2 | PostgreSQL, SQLite | 2 | 3 | | stockindex | 2 | DuckDB, SQLite | 2 | 3 | | stockmarket | 2 | DuckDB, SQLite | 2754 | 5 | | yelp | 2 | DuckDB, MongoDB | 5 | 7 |
⚙️ Prerequisites
Before running DAB, please complete the following setup steps.
Clone the Repository
Many datasets in DAB contain large database files exceeding 50MB and are tracked with Git LFS. If you want those files to come down during the clone itself, enable Git LFS before cloning:
git lfs install
Then clone and run the downloader:
git clone https://github.com/ucbepic/DataAgentBench.git
cd DataAgentBench
bash download.sh
download.sh serves two purposes:
- Downloads large datasets that aren't on GitHub. The ~5GB
PATENTSdatabase (patent_publication.db) is too large for the repo, so it's fetched from the Hugging Face mirror. - Repairs failed Git LFS pulls. If Git LFS wasn't enabled before cloning or hit an error, some tracked files end up missing or as pointer stubs. The script checks each file in
dataset_manifest.tsvagainst its sha256 and (re)downloads any mismatch from the Hugging Face Hub mirror.
Install Dependencies
We recommend using a dedicated virtual environment to ensure reproducibility.
Using Conda (recommended):
sudo apt-get install libpq-dev
conda env create -f environment.yaml
conda activate dabench
This will install all required dependencies specified in environment.yaml.
Setup Docker
- Install Docker
Version used in our experiments: 28.4.0
- Build the Docker image:
docker build -t python-data:3.12 .
Setup Databases
DAB evaluates agents across multiple database systems, so you must install and configure the following databases locally.
- PostgreSQL:
- MongoDB:
- SQLite & DuckDB:
Set Database Configurations
After installing all databases, you need to configure connection parameters to match your local setup.
Default configuration values (defined in db_config.py):
|Parameter|Default value| |:-:|:-:| |PG_CLIENT | "psql" | | PG_HOST | "127.0.0.1" | | PG_PORT | 5432 | | PG_USER | "postgres" | | PG_PASSWORD | "" | | PG_DB | "test" | | MONGO_URI | "mongodb://localhost:27017/" | | SQLITE_PATH | "data/mydb.sqlite" | | DUCKDB_PATH | "data/mydb.duckdb" |
Option 1:
Create a .env file in the project root. E.g.,
# PostgreSQL
PG_PASSWORD=your_password
PG_DB=mydb
MongoDB (if authentication is required)
MONGO_URI=mongodb://username:password@localhost:27017/?authSource=admin
Option 2: Modify the defaults in db_config.py.
Add API Credentials
Create a.env file in the project root and add your API keys:
AZURE_API_BASE=
AZURE_API_KEY=
AZURE_API_VERSION=
GEMINI_API_KEY=
TOGETHER_API_KEY=
Currently, we support
- Microsoft Azure API (for GPT models)
- Google Gemini API (for Gemini models)
- Together.AI API (for Kimi models)
# DataAgent.py (from line 76)
if "gpt" in deployment_name.lower():
self.client = AzureOpenAI(
api_key=os.getenv("AZURE_API_KEY"),
api_version=os.getenv("AZURE_API_VERSION"),
azure_endpoint=os.getenv("AZURE_API_BASE")
)
# add a new model here as an elif branch
else:
raise ValueError(f"Unsupported deployment name: {deployment_name}")
and a customized prompt to adapt to the format of your model's tool call ID in prompt_builder.py.
▶️ Run the Benchmark
Run the Built-in Agent on a Single Query
DAB comes with a built-in agent. You can run the agent on a specific query as follows:
Example: Run a single trial of GPT-5-mini on query1 of the bookreview dataset, with up to 100 agent iterations and dataset hints enabled:
python run_agent.py \
--dataset bookreview \
--query_id 1 \
--llm gpt-5-mini \
--iterations 100 \
--use_hints \
--root_name run_0
Execution Logs
Logs for this run will be saved under:
query_bookreview/query1/logs/data_agent/run_0
The log directory has the following structure:
run_0/
├─ exec_tool_work_dir/ <- Working directory for the execute_python tool (Docker)
├─ final_agent.json <- Full agent trajectory and execution statistics
├─ llm_calls.jsonl <- All LLM API calls made by the agent
└─ tool_calls.jsonl <- All tool calls made by the agent
Validate Agent Answer
DAB provides utilities to compute both aggregated Pass@1 accuracy of a dataset and single-run correctness.
Compute Pass@1 (50 Runs)
We provide a script avg_accuracy.py to compute Pass@1 accuracy across 50 runs per query of a dataset.
Before running the script, make sure your run logs are organized under the following directory structure (you may need to first move them from the dataset folder to the results- directory):
results-gpt-5-mini/
└─ query_bookreview/
└─ query1/
└─ data_agent/
├─ run_0/
├─ run_1/
├─ ...
└─ run_49/
Then compute Pass@1 as follows:
from python_script.avg_accuracy import avg_acc
print(avg_acc("bookreview", "gpt-5-mini"))
This will aggregate validation results across runs and queries and report the final Pass@1 accuracy for the dataset.
Validate a Single Run
After an agent run completes, you can validate its final answer against the ground truth:
from pathlib import Path
import json
run_dir = Path("query_bookreview/query1/logs/data_agent/run_0")
with open(run_dir / "final_agent.json", encoding="utf-8") as f:
llm_json = json.load(f)
llm_answer = llm_json["final_result"]
term_reason = llm_json["terminate_reason"]
if term_reason == "no_tool_call":
validation_result = {"is_valid": False}
else:
validation_result = validate(query_dir, llm_answer, term_reason)
The validation result follows this structure:
{
"timestamp": "YYYYMMDD_HHMMSS",
"query_name": "query1",
"is_valid": True/False, # Whether the agent’s answer matches the ground truth
"reason": "...", # Explanation for success or failure
"ground_truth": "...", # The ground-truth answer
"llm_answer": "...", # The agent's final answer
}
📝 Datasets and Queries
Dataset
A dataset in DAB is organized as a folder under the project root. For example, for dataset bookreview:
query_bookreview/
├─ query_dataset/ <- All database files
│ ├─ books_info.sql
│ └─ review_query.db
├─ query1/ <- Each query stored in a separate folder
├─ db_config.yaml <- Database connection configuration
├─ db_description.txt <- Description of the database schemas
└─ db_description_with_hint.txt <- Optional hints for queries
Query
Each query is stored within its corresponding dataset folder:
query_1/
├─ query.json <- The query as a double-quoted string
├─ ground_truth.csv <- The ground-truth answer in plain text
└─ validate.py <- Python script to validate an agent's output
validate.py defines a validate function with the following signature:
def validate(llm_output: str):
"""
Validate if the ground truth is present in the agent's answer.
Returns:
(True, "OK") – if the answer matches the ground-truth
(False, reason) – if it does not match
"""
🤖 Create Your Customized Agents
DAB allows you to implement and run your own agents while leveraging built-in tools for database querying and Python execution. These utilities, located under tools/, provide:
- 🔗 Automatic Database Connection
db_config.yaml for each dataset.
* No need to manually connect to PostgreSQL, MySQL, MongoDB, SQLite, or DuckDB — all connections are handled automatically via db_utils.
- 🛡️ Read-only Database Querying
- 🐳 Safe Python Execution Environment
pandas, and pyarrow pre-installed.
* Protects your local machine from unsafe operations by the agent.
- 📄 Agent Reference Implementation
DataAgent.py is a fully functional built-in agent.
* Use it as a template to implement and test your own agent.
📖 Citation
If you use DAB in your research, please cite our paper:
@article{ma2026can,
title={Can AI Agents Answer Your Data Questions? A Benchmark for Data Agents},
author={Ma, Ruiying and Shankar, Shreya and Chen, Ruiqi and Lin, Yiming and Zeighami, Sepanta and Ghosh, Rajoshi and Gupta, Abhinav and Gupta, Anushrut and Gopal, Tanmai and Parameswaran, Aditya G},
journal={arXiv preprint arXiv:2603.20576},
year={2026}
}