Spaces:
Sleeping
Sleeping
| # Dataset switching + DataAgentBench integration | |
| How the agent moves off the bundled PKDD dataset, and how | |
| [DataAgentBench](https://github.com/ucbepic/DataAgentBench) (DAB) plugs | |
| into the benchmark harness. | |
| --- | |
| ## 1. How dataset switching works | |
| Every dataset the agent can query is a `DatasetHandle` (one DuckDB file | |
| behind it). Switching datasets = building a new handle and assigning it | |
| to `ctx.dataset`. After that, `inspect_data` / `run_sql` / the modelling | |
| tools all operate against the new dataset — because they go through | |
| `ctx.duck()`, which opens `ctx.dataset.duckdb_path`. | |
| | Kind | Loader | Substrate | | |
| |---|---|---| | |
| | `bundled` | `load_pkdd_handle()` | shipped `artifacts/financial.duckdb` | | |
| | `upload` | `load_upload_handle(UploadSpec)` | per-session DuckDB, one table per CSV/Parquet | | |
| | `connector` | `load_s3_connector_handle(S3ConnectorSpec)` | per-session DuckDB with `read_parquet(s3://…)` views | | |
| | `attached` | `load_attached_handle([AttachSpec…])` | per-session DuckDB with several sqlite/duckdb DBs **materialized** into it | | |
| **Runtime switch (the agent does it itself):** the `connect_datalake` | |
| tool builds an S3 handle and sets `ctx.dataset = handle` mid-run — the | |
| only tool with that side-effect. The DAB loader reuses the exact same | |
| contract: build a handle, assign it. No new switching machinery. | |
| **Why `attached` materializes instead of ATTACH-ing live:** `ATTACH` | |
| is connection-scoped, but each tool opens its own `ctx.duck()` | |
| connection. The S3 path survives reopen because `read_parquet(s3://…)` | |
| views are self-contained. sqlite/duckdb sources have no equivalent | |
| self-contained view (a duckdb file can only be read via ATTACH), so | |
| `load_attached_handle` copies each source table into the session file | |
| as `<alias>_<table>`. The session file is then self-contained — fresh | |
| connections just work. Trade-off: a one-time copy at load (≈5 s for a | |
| 660k-row sqlite table); after that, single-DB-speed joins. | |
| --- | |
| ## 2. DataAgentBench at a glance | |
| DAB tests data agents on **multi-database** enterprise tasks: 17 | |
| datasets across sqlite / duckdb / postgres / mongo. Each task is: | |
| ``` | |
| query_<dataset>/ | |
| db_config.yaml # which DBs, what type, file path | |
| db_description.txt # schema prose for the agent | |
| query<N>/ | |
| query.json # the question (a JSON-quoted string) | |
| ground_truth.csv # the reference answer | |
| validate.py # def validate(llm_output) -> (bool, reason) | |
| ``` | |
| Scoring is **Pass@1**: run the agent, take its final answer string, call | |
| the task's own `validate(answer)` — which checks the ground truth is | |
| present in the answer (substring / name-near-value match). We reuse | |
| DAB's `validate.py` verbatim rather than reimplementing it. | |
| --- | |
| ## 3. What we can run today | |
| `load_attached_handle` folds **all four** DB systems DAB uses into one | |
| session DuckDB (needs the `connectors` extra for the last two): | |
| | Source | How it's materialized | | |
| |---|---| | |
| | sqlite / duckdb | `ATTACH` the file → `CREATE TABLE AS SELECT` | | |
| | **postgres** | restore the pg_dump `.sql` into an embedded **`pgserver`** (no Docker) → postgres scanner `ATTACH` → copy | | |
| | **mongo** | read the mongodump `.bson` server-lessly via **`bson`** → flatten (nested → JSON text) → copy | | |
| So **17 of 17** datasets are loadable (was 5). All db_types reduce to the | |
| same `<alias>_<table>` shape in one DuckDB, so cross-system joins are | |
| ordinary SQL — verified on `cve` (sqlite+duckdb+postgres+mongo, 8 tables, | |
| ~2M rows, ~4s). | |
| Note: DAB ships most DB files in-repo and a few via `download.sh` / | |
| git-lfs (PATENTS is a 5 GB Drive download). `build_handle` raises | |
| `FileNotFoundError` naming the missing file if a DB isn't present — only | |
| PATENTS is missing locally today. Install the deps with | |
| `uv sync --extra connectors`. | |
| --- | |
| ## 4. Running it | |
| ```bash | |
| # 1. Clone DataAgentBench somewhere + pull its DB files | |
| git clone https://github.com/ucbepic/DataAgentBench /tmp/DataAgentBench | |
| # 2. Run the agent against one dataset (needs the Lexsi text env for a | |
| # real planner; --llm stub just exercises the wiring) | |
| export SDK_ACCESS_TOKEN=… LEXSI_WORKSPACE_NAME=… LEXSI_TEXT_PROJECT_NAME=… | |
| python -m benchmark.dab.runner \ | |
| --dab-root /tmp/DataAgentBench \ | |
| --dataset DEPS_DEV_V1 \ | |
| --llm lexsi \ | |
| --iterations 1 | |
| ``` | |
| Output: | |
| ``` | |
| DAB DEPS_DEV_V1: bound 3 table(s): ['package_database_packageinfo', | |
| 'project_database_project_info', 'project_database_project_packageversion'] | |
| DAB DEPS_DEV_V1/query1: pass@1=1/1 (All name-version pairs validated…) | |
| === DAB results === | |
| [PASS] DEPS_DEV_V1/query1 steps=6 All name-version pairs validated… | |
| total: 1/1 passed | |
| ``` | |
| Omit `--query` to run all tasks in the dataset; bump `--iterations` for | |
| a real Pass@1 over N runs. | |
| --- | |
| ## 5. Code map | |
| | File | Role | | |
| |---|---| | |
| | `lexsi_ds/agent/datasource.py` → `load_attached_handle` | multi-DB fold-in; dispatches sqlite/duckdb/postgres/mongo. Live-DB loaders `load_postgres_connector_handle` / `load_mongo_connector_handle` reuse the same copy/flatten helpers | | |
| | `benchmark/dab/adapter.py` | parse `db_config.yaml` (`db_path`/`sql_file`/`dump_folder`) → `AttachSpec`s → `DatasetHandle` | | |
| | `benchmark/dab/runner.py` | per-task: run agent → `validate(final_answer)` → Pass@1 | | |
| | `lexsi_ds/agent/table_index.py` + `tools/find_relevant_tables.py` | schema linking for big many-table DBs (text_to_sql auto-caps too) | | |
| | `tests/test_dab_adapter.py`, `tests/test_pg_mongo_materialize.py` | self-contained (synthetic sqlite/duckdb/pg/mongo dumps), no external checkout | | |
| --- | |
| ## 6. Extending coverage | |
| Postgres + Mongo are **done** (embedded `pgserver` / server-less `bson`; | |
| the same helpers back the live `connect_datalake` connectors). Remaining: | |
| - **PATENTS data** — its Postgres dump is a 5 GB Drive download not pulled | |
| locally; everything else runs. `build_handle` reports it cleanly. | |
| - **UI dataset picker** — the Gradio app hardcodes `load_pkdd_handle()` | |
| in `_build_ui_ctx`. A dropdown swapping the handle would expose | |
| switching (and now `connect_datalake` postgres/mongo) to users. | |
| - **DAB as a bench tier** — wire the runner's Pass@1 into the scoreboard | |
| alongside PKDD-Curated (see [`v1_benchmarking.md`](v1_benchmarking.md) §4.2). | |