Spaces:
Sleeping
Sleeping
File size: 9,891 Bytes
4131399 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | # DataAgentBench failure analysis β runs of 2026-06-05
Trajectory analysis of full `--all` sweeps, scored with DAB's own
per-task `validate.py`. Captured with `--log-dir` (full per-turn prompts,
raw LLM responses, tool args, and untruncated results); diagnoses below
cite those traces.
## Run config
```
python -m benchmark.dab.runner --all --llm lexsi --log-dir artifacts/dab_runs/new_tool
```
- 5 of 17 datasets runnable (sqlite/duckdb); 12 skipped (postgres/mongo).
- **Score: 10/17 tasks passed** β `consolidate_tables` (fix B) recovered
stockmarket/query4 + query5 over the pre-tool baseline of 8/17 (both
confirmed using the tool; see Β§B).
> **Measurement note.** Single-run pass@1 carries per-task sampling
> noise β any system-prompt change re-rolls multi-step trajectories, so a
> few tasks can flip run-to-run. Use `--iterations 3` (majority vote) to
> pin a stable number before trusting a future delta.
## Results
β
= pass, β = fail, π― = recovered by `consolidate_tables`.
| Dataset | Query | Result | Validator reason / note |
|---|---|---|---|
| DEPS_DEV_V1 | query1 | β | Missing name `@dmrvos/infrajs>0.0.6>typescript` (Β§C/Β§D) |
| DEPS_DEV_V1 | query2 | β | Missing project `mui-org/material-ui` (Β§D) |
| GITHUB_REPOS | query1 | β | No value rounds to 0.33 β wrong join (Β§A note) |
| GITHUB_REPOS | query2 | β
| Fuzzy matched `swiftandroid/swift` |
| GITHUB_REPOS | query3 | β
| Found 1077 |
| GITHUB_REPOS | query4 | β
| All repo names matched |
| music_brainz_20k | query1 | β
| Ground truth found |
| music_brainz_20k | query2 | β
| Ground truth found |
| music_brainz_20k | query3 | β | Wrong song (`Zo gaat het levenβ¦`) (Β§D) |
| stockindex | query1 | β
| `399001.SZ` primary |
| stockindex | query2 | β | `IXIC` not in first 200 chars (Β§C) |
| stockindex | query3 | β
| All name-country pairs matched |
| stockmarket | query1 | β
| 18.44 β 18.44 |
| stockmarket | query2 | β | Missing number 31 β consolidated, but count SQL still wrong (Β§B) |
| stockmarket | query3 | β | `Apex Global Brands Inc` β consolidated, but avg-volume SQL still wrong (Β§B) |
| stockmarket | query4 | π―β
| `MFA Financial, Inc` found β **recovered via `consolidate_tables`** |
| stockmarket | query5 | π―β
| `Synthesis Energy Systems, Inc` found β **recovered via `consolidate_tables`** |
**Total: 10/17** β 8 baseline passers + 2 π― recoveries via `consolidate_tables`.
---
## Failure taxonomy
### A. Harness bug β history truncates tool-call args, agent thinks its SQL is broken (1 task, systemic)
**GITHUB_REPOS/query1.** The agent wrote a complete 960-char query and
`run_sql` **executed it fine** (returned `1 row Γ 3 cols`). But the loop
echoes each tool call into the observation history truncated to 400
chars ([loop.py:236](../lexsi_ds/agent/loop.py#L236)):
```python
f"TOOL CALL: {tool_name}({json.dumps(args_obj, default=str)[:400]})\n"
```
The 400-char cut lands mid-`JOIN`, and the appended `)` makes the echo
read as a query that ends `β¦JOIN artifacts_database_contents c ON c)` β
i.e. **truncated mid-join**. The agent re-read this, concluded the
tooling was broken, re-ran the same query 10 times, and gave up:
> "every `run_sql` execution shown is truncated mid-join
> (`JOIN artifacts_database_contents c ON c)`), which causes the query
> to effectively fail" β *agent's final answer*
So a runnable task was lost to a display artifact, not a real error.
(The SQL logic was also likely wrong β proportion β 0.33 β but the agent
never got far enough to find out.)
**Fix (done).** [loop.py](../lexsi_ds/agent/loop.py) now echoes args via
`_echo_args()`: full up to an 8000-char cap, and when it must truncate
it appends an explicit `β¦ [+N chars truncated for display only; the full
args above were executed]` marker β so a display cut can never read as a
broken statement. The 960-char query that triggered this is now echoed
in full.
### B. Scale β per-shard table explosion vs the 12-step budget (4 tasks) β FIXED via `consolidate_tables`
**The problem.** stockmarket materializes **2753 `stocktrade_database_<ticker>`
tables** (one per symbol, identical schema `Date,Open,High,Low,Close,
Adj Close,Volume`, ~410 rows each) plus one `stockinfo` table. The shard
key (ticker) lives in the **table name, not a column**. A question like
"across all NYSE stocksβ¦" is a `GROUP BY ticker` that can only be
expressed as a 2753-way `UNION ALL` β unwriteable in a 12-step budget.
All four tasks hit step 13 and surrendered:
> "the query requires scanning/UNIONing thousands of
> `stocktrade_database_<ticker>` tables, and I ran out of allowed tool
> calls" β *query3, baseline*
**The fix (done): a generic `consolidate_tables` tool**
([consolidate_tables.py](../lexsi_ds/agent/tools/consolidate_tables.py)).
It folds a sharded family into one table in a single call β the giant
`UNION ALL BY NAME` is generated in our code, never against the agent's
step budget:
```json
{"tool": "consolidate_tables",
"args": {"pattern": "stocktrade_database_*", "into": "stocktrade", "key_column": "ticker"}}
```
It auto-derives the key from the pattern's literal prefix (β bare
tickers), schema-guards (unions only same-schema shards, reports the
rest), and defaults to a cheap VIEW. Generic by design: per-ticker,
per-day, per-region β any BYO datalake with sharded tables. Planner
rule 14 tells the agent to reach for it when `inspect_data` shows many
same-prefix tables.
**Measured:** 2753 tables β one 6.47M-row view in **1.2s**; the
previously-timed-out cross-ticker query runs in **~1s**. On the
`new_tool/` sweep the agent called it in all 4 stockmarket tasks and
**recovered query4 + query5** (the name-lookup tasks). query2 (count off
by the "31") and query3 (avg-volume per company) still fail: the tool
removes the *structural* blocker, but the agent must still write correct
analytical SQL on top β which it nailed for q4/q5 and missed for q2/q3
(the latter compounded by Β§E coded values).
### C. Output format / "primary answer" expectations (2 tasks)
- **stockindex/query2** β the answer was **correct** (`IXIC`: 44 up / 31
down) but the validator requires the target index in the first 200
chars as the *primary* answer; the agent buried it after a prose
preamble and a markdown table, and added a second index (`GSPTSE`).
Penalized on presentation, not correctness.
- **DEPS_DEV_V1/query1** β the agent's query *did* surface the
composite-key rows (`@dmrvos/infrajs>0.0.5>typescript`) but (a) chose
version **0.0.5**, not the ground-truth **0.0.6** ("latest release"
logic wrong β see Β§D), and (b) hedged/refused because the values
"look like dependency paths rather than just the package name".
**Fix:** a benchmark-mode answer directive β lead with the bare
answer/identifier in the exact requested format, then optional detail.
### D. Wrong query semantics β confidently wrong values (2 tasks)
- **DEPS_DEV_V1/query2** β returned `react-component/picker`, `tailwindcss/typography`, β¦;
ground truth is `mui-org/material-ui`. The "marked as release" filter
+ fork-count join produced a different top-5.
- **music_brainz_20k/query3** β answered `"Groovey" by Rich Matteson,
$4,128.59` in a single `run_sql`; ground truth is
`"Zo gaat het leven aan je voor"`. Revenue was almost certainly
aggregated by the wrong entity (track title vs. recording, or not
summed across stores). The agent was overconfident β 4 steps, one
query, no cross-check.
**Fix:** these need the DAB `db_description` field-semantics to be
weighted more (e.g. how "latest release" / "revenue" are defined), and a
self-check step before finalizing on aggregation questions.
### E. Coded-value / data-semantics gaps (compounds B)
**stockmarket/query5, query3** β the agent filtered on
`Listing Exchange='Q' AND Market Category='QCM'`, got 0 rows, and
concluded the data didn't match. `Listing Exchange`/`Market Category`/
`Financial Status` are **coded** columns whose codes differ from the
agent's assumptions. It spent steps probing codes instead of answering,
which (with Β§B) guaranteed a timeout.
---
## Priorities
| Fix | Status | Impact |
|---|---|---|
| **A.** `_echo_args()` no longer cuts SQL mid-string | β
done | Removes false "truncated SQL" failures; helps any long-SQL task |
| **B.** `consolidate_tables` folds sharded families into one table | β
done | **+2** (stockmarket q4, q5); generic for any sharded datalake |
| **D/E.** Lean on `db_description` semantics + a pre-final self-check | open | DEPS/query2, music_brainz/query3, stockmarket q2/q3 SQL logic |
| **C.** Benchmark answer-format directive (lead with bare answer) | open | stockindex/query2 (+ partial DEPS/query1) |
**Net effect of A + B: 10/17.** A is a correctness floor (no more false
failures); B is the +2 (stockmarket q4, q5). The remaining levers are
**D/E** (analytical-SQL / coded-value semantics β the dominant failure
mode now that the structural blockers are gone) and **C** (output
format).
**Measure with `--iterations`.** Single-run pass@1 is noisy β a prompt
change re-rolls every multi-step task. Run `--iterations 3` (majority
vote) before trusting a future delta.
## Reproduce / inspect
```bash
# Noise-adjusted measurement run (majority vote per task):
python -m benchmark.dab.runner --all --llm lexsi --iterations 3 \
--log-dir artifacts/dab_runs/measure_v1
# Inspect one trajectory end-to-end (prompts, raw responses, SQL, payloads):
python -c "import json; d=json.load(open('artifacts/dab_runs/new_tool/stockmarket_query4_iter0.json')); \
print(d['reason']); [print(s['n'], s['tool'], (s['args'] or {}).get('sql','')[:80]) for s in d['run']['steps']]"
# Confirm the new tool fired on the stockmarket tasks:
grep -l consolidate_tables artifacts/dab_runs/new_tool/stockmarket_*.json
``` |