BIRD Mini-Dev on EKOS
Text-to-SQL on the BIRD Mini-Dev benchmark (release “Mini-Dev 1024”, SQLite, 500 questions over 11 databases), answered by Claude Haiku 5.5 through OpenCode Zen, with and without the knowledge EKOS compiles from each database. Every number below is read from the saved run reports and the model router’s billing log.
COMMENT ON on quoted identifiers. It is fixed in v1.2.0, and a run with descriptions has not been made yet (section 1). Mini-Dev 1024 is 92% “challenging” questions, so its numbers are not comparable with older Mini-Dev releases.1 · Source databases and what EKOS compiled from them
Each database is its own EKOS project, built by ekos eval bench prepare. The pipeline reads the database’s catalogue and its dictionary (database_description/*.csv): one generated schema.sql per project, holding CREATE TABLE statements plus one COMMENT ON COLUMN per dictionary row. That file goes through the normal pipeline (build → recover → resolve → compile → commit). Question files and gold SQL never leave the archive. After the build, every ledger is scanned for the text of all 500 questions, gold statements and evidence hints; the scan was clean (1,349 texts, no hit).
| Database | Tables | Columns | Rows | MB | Dictionary rows | Ledger objects / edges | Ledger fingerprint | Questions | Hold-out |
|---|---|---|---|---|---|---|---|---|---|
| california_schools | 3 | 89 | 29,941 | 11.1 | 82 | 4 / 2 | 35495712d6ca | 49 | 30 |
| card_games | 6 | 115 | 803,445 | 261.8 | 108 | 7 / 4 | 43c6b940e58d | 69 | 41 |
| codebase_community | 8 | 71 | 740,646 | 481.4 | 71 | 9 / 11 | c063ce1abe1f | 31 | 19 |
| debit_card_specializing | 5 | 21 | 423,050 | 34.6 | 20 | 6 / 1 | c0523524574a | 14 | 8 |
| european_football_2 | 7 | 199 | 222,796 | 597.8 | 103 | 8 / 7 | 503457f2e927 | 31 | 19 |
| financial | 8 | 55 | 1,079,680 | 71.3 | 52 | 9 / 8 | 29f17c9a0751 | 46 | 28 |
| formula_1 | 13 | 94 | 493,257 | 22.4 | 94 | 14 / 19 | 5e0d7f2c4bb8 | 55 | 33 |
| student_club | 8 | 48 | 42,511 | 2.6 | 48 | 9 / 8 | 13e0be5f92cf | 37 | 23 |
| superhero | 10 | 31 | 10,614 | 0.2 | 31 | 11 / 9 | 8e3bf8c45391 | 50 | 30 |
| thrombosis_prediction | 3 | 64 | 15,252 | 7.3 | 61 | 4 / 2 | c7b307cdc172 | 86 | 52 |
| toxicology | 4 | 11 | 36,922 | 2.7 | 11 | 5 / 4 | b39fe42d8780 | 32 | 19 |
The schema text below is exactly what a cell showed the model, printed by ekos eval bench context. Three views per database: the EKOS pack as the measured G2 runs saw it (tables, keys and join paths from the ledger, plus column profiles: rows, nulls, empty strings, distinct values, examples, list columns); the same pack after the v1.2.0 analyzer fix, now carrying the dictionary’s descriptions; and the raw DDL that cells A and A-4k got.
2 · Every hold-out question, the query EKOS generated, and its result
302 hold-out questions. The SQL is cell G2’s answer; ✓ means its result set equals the gold result set (execution accuracy, as BIRD’s official scorer computes it). The A-4k and G columns show whether those cells got the same question right. Each prompt was the template below, with the database’s schema text from section 1, the matched values, and the question. No cell here used BIRD’s evidence hint.
Prompt template used by G and G2 (ekos-v1)
Task Overview:
You are a data science expert. Below, you are provided with a database schema and a natural language question. Your task is to understand the schema and generate a valid SQL query to answer the question.
Database Engine:
{engine}
Database Schema:
{schema}This schema describes the database's structure, including tables, columns, primary keys, foreign keys, and any relevant relationships or constraints. Column comments give each column's meaning, its null and distinct counts, and example values.
Question:
{question_block}
Instructions:
- Return exactly the columns the question asks for, in the order it asks for them, and nothing else.
- The generated query should return all of the information asked in the question without any missing or extra information.
- Before counting or averaging, check the grain of each table from its row and distinct counts: when an entity appears in several rows (e.g. one row per printing or per year), count DISTINCT entities if the question is about entities.
- Use the exact spelling of values shown in the schema comments; a comma-separated list column is matched with LIKE '%value%'.
- Keep computations in the form the question states (e.g. a rate as a count divided by a count).
Output Format:
Give the SQL query first, in one code block:
```sql
-- Your SQL query
```
Then explain it in at most three sentences.
| ID | Database | Difficulty | Question | Generated SQL (G2) | G2 | Soft-F1 | A-4k | G | Tokens in / out | Seconds |
|---|
3 · Tokens and money
All metered calls went to Claude Haiku 5.5 through OpenCode Zen ($0.10 per million input tokens, $0.50 per million output tokens). The billing log (data/llm/llm-usage.jsonl) records each call that reached the provider. Repeated identical prompts were served from EKOS’s LLM cache and are not billed, so a report’s processed tokens can exceed its billed tokens.
| Model | Billed calls | Input tokens | Output tokens | Cost | Mean latency |
|---|---|---|---|---|---|
| Claude Haiku 5.5 (Zen) | 2,865 | 10,182,225 | 2,737,094 | $2.3868 | 4.6 s |
| qwen2.5-coder:3b (local Ollama) | 668 | 889,540 | 254,521 | $0 (local GPU) | 17.9 s |
Every run
Cost covers billed calls only. “$ per 1k” is the cost of 1,000 questions at that run’s rate. Runs before the cache accounting was added (the first five) show processed tokens only.
| Model | Cell | Split | n | EX % | 95% CI | Soft-F1 | R-VES | Calls | Cached | Processed in / out | Billed in / out | Cost | $ per 1k | Duration | Latency mean / P95 s | Note |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Haiku 5.5 | A | hold | 100 | 52.0 | 42–62 | 53.1 | 48.8 | 145 | — | 285,414 / 125,511 | — | $0.0913 | 0.913 | 11m 49s | 6.4 / 10.3 | 100-question sample |
| Haiku 5.5 | C | hold | 100 | 48.0 | 39–58 | 51.2 | 45.0 | 146 | — | 286,097 / 124,654 | — | $0.0909 | 0.909 | 11m 36s | 6.4 / 10.6 | 100-question sample |
| Haiku 5.5 | B | hold | 100 | 47.0 | 38–57 | 47.8 | 43.5 | 141 | — | 285,066 / 122,310 | — | $0.0897 | 0.897 | 8m 28s | 4.7 / 10.4 | 100-question sample |
| Haiku 5.5 | D | hold | 100 | 46.0 | 36–56 | 47.5 | 42.1 | 149 | — | 299,123 / 127,218 | — | $0.0935 | 0.935 | 8m 54s | 5.1 / 10.7 | 100-question sample |
| Haiku 5.5 | C-prime | hold | 100 | 53.0 | 44–63 | 55.6 | 50.3 | 143 | — | 269,832 / 122,912 | — | $0.0884 | 0.884 | 8m 53s | 4.5 / 10.4 | 100-question sample |
| Haiku 5.5 | E | tune | 198 | 56.6 | 50–64 | 63.6 | 53.1 | 199 | 0 | 895,989 / 222,821 | 895,989 / 222,821 | $0.2010 | 1.015 | 19m 19s | 5.4 / 9.4 | |
| Haiku 5.5 | F | tune | 198 | 54.0 | 47–61 | 61.8 | 50.7 | 199 | 88 | 904,682 / 223,835 | 575,753 / 121,260 | $0.1182 | 0.597 | 13m 26s | 3.3 / 9.1 | |
| Haiku 5.5 | G | tune | 198 | 65.7 | 59–72 | 70.3 | 61.5 | 205 | 0 | 964,193 / 189,196 | 964,193 / 189,196 | $0.1910 | 0.965 | 19m 50s | 5.0 / 9.4 | |
| Haiku 5.5 | A | tune | 198 | 45.5 | 39–52 | 48.3 | 41.8 | 288 | 0 | 564,266 / 257,706 | 564,266 / 257,706 | $0.1853 | 0.936 | 24m 21s | 6.8 / 10.7 | |
| Haiku 5.5 | H | tune | 198 | 64.1 | 58–71 | 69.9 | 58.4 | 616 | 205 | 2,672,408 / 569,972 | 1,708,215 / 380,776 | $0.3612 | 1.824 | 37m 35s | 10.6 / 20.1 | |
| Haiku 5.5 | G-nv | tune | 198 | 63.6 | 57–70 | 68.9 | 59.1 | 208 | 90 | 971,271 / 188,991 | 621,690 / 104,480 | $0.1144 | 0.578 | 13m 36s | 3.2 / 9.5 | |
| Haiku 5.5 | G | hold | 302 | 63.9 | 59–69 | 67.7 | 59.7 | 320 | 0 | 1,509,241 / 295,405 | 1,509,241 / 295,405 | $0.2986 | 0.989 | 27m 53s | 5.1 / 9.4 | |
| Haiku 5.5 | A-4k | hold | 302 | 53.3 | 48–59 | 57.6 | 49.5 | 304 | 55 | 572,686 / 350,683 | 468,612 / 308,078 | $0.2009 | 0.665 | 28m 54s | 5.3 / 10.4 | |
| Haiku 5.5 | G2 | tune | 198 | 67.7 | 61–74 | 73.8 | 62.9 | 205 | 67 | 978,518 / 188,935 | 648,344 / 123,659 | $0.1267 | 0.640 | 14m 21s | 3.4 / 7.9 | |
| Haiku 5.5 | G2 | hold | 302 | 66.9 | 62–72 | 70.2 | 62.0 | 318 | 108 | 1,525,399 / 300,615 | 985,856 / 200,425 | $0.1988 | 0.658 | 21m 11s | 3.7 / 8.7 | after the formula_1 analysis |
| qwen2.5-coder:3b | A | hold | 100 | 5.0 | 1–9 | 7.1 | 4.7 | 150 | — | 194,591 / 56,457 | — | $0.0000 | 0.000 | 43m 57s | 25.8 / 40.6 | 100-question sample |
| qwen2.5-coder:3b | C | hold | 100 | 2.0 | 0–5 | 3.5 | 1.9 | 159 | — | 207,604 / 60,289 | — | $0.0000 | 0.000 | 47m 02s | 28.1 / 45.6 | 100-question sample |
| qwen2.5-coder:3b | B | hold | 100 | 4.0 | 1–8 | 6.9 | 4.1 | 152 | — | 202,315 / 57,918 | — | $0.0000 | 0.000 | 34m 39s | 20.2 / 42.0 | 100-question sample |
| qwen2.5-coder:3b | D | hold | 100 | 3.0 | 0–6 | 4.6 | 3.0 | 159 | — | 211,132 / 59,949 | — | $0.0000 | 0.000 | 42m 13s | 25.0 / 64.7 | 100-question sample |
| qwen2.5-coder:3b | C-prime | hold | 100 | 3.0 | 0–6 | 5.5 | 3.0 | 155 | — | 196,148 / 58,589 | — | $0.0000 | 0.000 | 29m 52s | 17.6 / 38.6 | 100-question sample |
4 · Average price per question
The EKOS prompt is about three times longer on input (1,509,241 against 572,686 input tokens for 302 questions), because the profiles describe every column. Output is the same size, and output carries five times the per-token price, so the EKOS cell costs about 1.5× as much per question: about one tenth of a cent.
5 · Accuracy and speed on the hold-out split
Execution accuracy, 302 questions
Bars are execution accuracy; whiskers are the bootstrap 95% interval (2,000 resamples).
Averages
| A-4k | G | G2 | |
|---|---|---|---|
| Execution accuracy | 53.3% | 63.9% | 66.9% |
| Soft-F1 | 57.6 | 67.7 | 70.2 |
| R-VES (3 timed runs) | 49.5 | 59.7 | 62.0 |
| Answers that executed | 100% | 100% | 100% |
| Mean latency per question | 5.3 s | 5.1 s | 3.7 s |
| P95 latency | 10.4 s | 9.4 s | 8.7 s |
| Wall-clock for 302 questions | 28m 54s | 27m 53s | 21m 11s |
By database
| Database | n | A-4k | G | G2 |
|---|---|---|---|---|
| california_schools | 30 | 37% | 53% | 53% |
| card_games | 41 | 46% | 61% | 66% |
| codebase_community | 19 | 53% | 47% | 42% |
| debit_card_specializing | 8 | 100% | 100% | 100% |
| european_football_2 | 19 | 74% | 84% | 84% |
| financial | 28 | 57% | 57% | 57% |
| formula_1 | 33 | 79% | 55% | 79% |
| student_club | 23 | 43% | 78% | 78% |
| superhero | 30 | 57% | 50% | 47% |
| thrombosis_prediction | 52 | 33% | 65% | 67% |
| toxicology | 19 | 68% | 95% | 95% |
By difficulty
| Difficulty | n | A-4k | G | G2 |
|---|---|---|---|---|
| challenging | 275 | 52.4% | 63.6% | 67.6% |
| moderate | 21 | 61.9% | 66.7% | 57.1% |
| simple | 6 | 66.7% | 66.7% | 66.7% |
How answers failed
| Outcome | A-4k | G | G2 |
|---|---|---|---|
| correct | 161 | 193 | 202 |
| wrong values | 99 | 84 | 79 |
| wrong rows | 41 | 24 | 20 |
| wrong columns | 1 | 1 | 1 |
| exec error | 0 | 0 | 0 |
| no sql | 0 | 0 | 0 |
How the EKOS cell was chosen (tune split, 198 questions)
Everything was tuned on a separate tune split (40% of each database × difficulty stratum, fixed seed). The hold-out split was used once per cell.
| Cell | EX % | 95% CI | Cost |
|---|---|---|---|
| A | 45.5 | 39–52 | $0.185 |
| F | 54.0 | 47–61 | $0.118 |
| E | 56.6 | 50–64 | $0.201 |
| G-nv | 63.6 | 57–70 | $0.114 |
| H | 64.1 | 58–71 | $0.361 |
| G | 65.7 | 59–72 | $0.191 |
| G2 | 67.7 | 61–74 | $0.127 |
A = raw DDL with a 1,024-token output limit · E = EKOS pack + column profiles · F = E + value lookup · G = F + the ekos-v1 prompt + result checks · G-nv = G without value lookup · H = G with three varied-context candidates (voting) · G2 = G + empty-string profiles.
6 · Code added to run the benchmark
6,927 lines in 32 files, all in the public EKOS repository (alexeyban/EKOS, v1.2.0). Nothing outside EKOS is needed to run a benchmark. The official BIRD scorer is used only by the parity test, from a separate checkout, and is never copied into the repository.
| File | Lines |
|---|---|
| ekos/crates/cli/src/commands/eval_bench.rs | 663 |
| ekos/crates/cli/tests/bench.rs | 246 |
| ekos/crates/evals/src/bench/bird.rs | 1,191 |
| ekos/crates/evals/src/bench/context.rs | 1,107 |
| ekos/crates/evals/src/bench/fixture.rs | 389 |
| ekos/crates/evals/src/bench/leakage.rs | 265 |
| ekos/crates/evals/src/bench/mod.rs | 499 |
| ekos/crates/evals/src/bench/report.rs | 608 |
| ekos/crates/evals/src/bench/split.rs | 124 |
| ekos/crates/evals/src/bench/sqlexec.rs | 496 |
| ekos/crates/evals/src/bench/stats.rs | 137 |
| ekos/crates/evals/src/bench/suite.rs | 232 |
| ekos/crates/evals/tests/bench_fixture.rs | 427 |
| ekos/crates/evals/tests/bird_parity.rs | 170 |
| evals/bench/bird-mini-dev/configs/a.toml | 17 |
| evals/bench/bird-mini-dev/configs/b.toml | 17 |
| evals/bench/bird-mini-dev/configs/c-prime.toml | 17 |
| evals/bench/bird-mini-dev/configs/c.toml | 17 |
| evals/bench/bird-mini-dev/configs/d.toml | 17 |
| evals/bench/bird-mini-dev/configs/zen-haiku/a-4k.toml | 19 |
| evals/bench/bird-mini-dev/configs/zen-haiku/a.toml | 19 |
| evals/bench/bird-mini-dev/configs/zen-haiku/b.toml | 19 |
| evals/bench/bird-mini-dev/configs/zen-haiku/c-prime.toml | 19 |
| evals/bench/bird-mini-dev/configs/zen-haiku/c.toml | 19 |
| evals/bench/bird-mini-dev/configs/zen-haiku/d.toml | 19 |
| evals/bench/bird-mini-dev/configs/zen-haiku/e.toml | 24 |
| evals/bench/bird-mini-dev/configs/zen-haiku/f.toml | 24 |
| evals/bench/bird-mini-dev/configs/zen-haiku/g-nv.toml | 24 |
| evals/bench/bird-mini-dev/configs/zen-haiku/g.toml | 24 |
| evals/bench/bird-mini-dev/configs/zen-haiku/g2.toml | 25 |
| evals/bench/bird-mini-dev/configs/zen-haiku/h.toml | 24 |
| evals/bench/bird-mini-dev/suite.toml | 29 |
bench/mod.rs: theBenchAdaptertrait, the experiment cell (ExperimentConfig), the run loop with its budget stop, the ledger fingerprint.bench/bird.rs: the BIRD adapter. It extracts files from the archive by allowlist, generates the project schema, builds the prompt, runs repair rounds and result checks, votes between candidates, scores, and exports BIRD’s prediction format.bench/context.rs: raw DDL, the EKOS pack from a ledger, column profiles, value lookup, and the SQL shape measures (schema-linking and join-path recall).bench/sqlexec.rs: read-only SQLite under a deadline; EX, Soft-F1 and R-VES as the official scorer computes them; SQLite’s math functions.bench/leakage.rs,split.rs,stats.rs,report.rs,suite.rs: the leakage guards, the fixed-seed split, bootstrap and McNemar, reports with the contamination check, and suite files with pinned checksums.cli/commands/eval_bench.rs:ekos eval bench list | prepare | run | context | compare | export.- Tests: a two-database, ten-question fixture with a scripted model (
bench_fixture.rs); the real binary end to end against a stand-in Ollama server (cli/tests/bench.rs); parity with the official scorer (bird_parity.rs).
One fix outside the benchmark code was needed: recovery/src/sql_analyzer.rs (COMMENT ON on quoted identifiers).
7 · Configuration
The suite pins its downloads by SHA-256. A cell is one TOML file: what the model is shown, the prompt, the generation strategy and the model route.
evals/bench/bird-mini-dev/suite.toml
# RFC 0240 — BIRD Mini-Dev, SQLite, the "Mini-Dev 1024" release (2026-10-28 update).
#
# Questions come from the Hugging Face dataset at a pinned revision; the databases from the
# original Mini-Dev package (the SQLite databases did not change in the update — the README says
# the original dev databases serve the SQLite version). `ekos eval bench prepare` downloads both,
# checks these checksums and extracts only <db>/<db>.sqlite and <db>/database_description/*.csv:
# the package's own question and gold files never leave the archive.
name = "bird-mini-dev"
adapter = "bird"
version = "Mini-Dev 1024"
dialect = "sqlite"
new-dev = false
notes = "birdsql/bird_mini_dev @ 5b256b5a (data/manifest.json revision colleague_review_fixes_20261025)"
[questions]
file = "mini_dev_sqlite.jsonl"
url = "https://huggingface.co/datasets/birdsql/bird_mini_dev/resolve/5b256b5a9c17478f06ed6912612e9a14d17065c8/data/mini_dev_sqlite.jsonl"
sha256 = "926af2a0d1b47e5d0d15a7aa8a34d4721007f4550a881555b6a89496b54a2606"
[databases]
file = "minidev.zip"
url = "https://bird-bench.oss-cn-beijing.aliyuncs.com/minidev.zip"
sha256 = "cc48ba16838204e4e214512030cb572eeb5f7bcdd999bae4b9b6ff12ec13b92f"
prefix = "minidev/MINIDEV/dev_databases/"
# Fixed seed, stratified by database and difficulty: 40% tune / 60% hold-out (RFC 0240 §6).
[split]
seed = 240
tune-fraction = 0.4
evals/bench/bird-mini-dev/configs/zen-haiku/g2.toml
# RFC 0241 — G with profile v2. Motivated by the formula_1 hold-out analysis; validate on the tune split.
name = "G2"
description = "G with profile v2: empty-string counts, and that '' means missing"
context = "ekos-pack"
evidence = false
value-lookup = true
few-shot = 0
n = 1
r = 1
max-tokens = 4096
ves-iterations = 3
timeout-seconds = 30
profiles = true
profile-version = 2
value-lookup-version = 2
prompt = "ekos-v1"
result-checks = true
vary-context = false
[llm]
# OpenCode Zen, Claude Haiku 5.5 ($0.10 / $0.50 per million tokens). Metered: needs --allow-metered.
provider = "zen"
model = "claude-haiku-5-5"
api-key-env = "OPENCODE_API_KEY"
budget-usd = 0.6
evals/bench/bird-mini-dev/configs/zen-haiku/a-4k.toml
# RFC 0241 — the baseline for the final comparison: cell A with max-tokens 4096, so the difference to G/H is EKOS alone.
name = "A-4k"
description = "Cell A (raw DDL, baseline prompt, no evidence, no lookup) with the output allowance of the RFC 0241 cells"
context = "raw-ddl"
evidence = false
value-lookup = false
few-shot = 0
n = 1
r = 1
max-tokens = 4096
ves-iterations = 3
timeout-seconds = 30
[llm]
# OpenCode Zen, Claude Haiku 5.5 ($0.10 / $0.50 per million tokens). Metered: needs --allow-metered.
provider = "zen"
model = "claude-haiku-5-5"
api-key-env = "OPENCODE_API_KEY"
budget-usd = 1.0
Commands, from the repository root
ekos eval bench prepare --suite bird-mini-dev # download, verify, extract, build 11 projects, leakage scan
ekos eval bench context --suite bird-mini-dev --cell g2 --db formula_1 # print what the model is shown
ekos eval bench run --suite bird-mini-dev --cell evals/bench/bird-mini-dev/configs/zen-haiku/g2.toml \
--split hold --allow-metered # needs OPENCODE_API_KEY
ekos eval bench compare <report-g2.json> <report-a-4k.json>
ekos eval bench export <report.json> --target bird-submission
ekos eval history # every run, newest last
8 · How it works, and what it costs to run
Pipeline
- Prepare. Check the archive checksums. Extract only
<db>.sqliteand its dictionary CSVs. Write oneschema.sqlper database, from SQLite’s own catalogue and the dictionary. Build one EKOS project per database through the standard pipeline (child processes, with API keys removed, so preparing never calls a model). Record each ledger’s fingerprint, and scan every ledger for leaked benchmark text. Build a column profile and a distinct-value index from the database file; these are kept beside the project, never in a ledger. - Context. For an EKOS cell, the schema text is rendered from the project’s compiled ledger:
Tableobjects with columns, types, keys and descriptions, plusForeignKeyedges as join paths. The column profile is added, and the values the question mentions are looked up. - Generate. One model call with the cell’s prompt. If the SQL does not run, the error goes back once. If it returns no rows or a single NULL (result checks), that fact goes back once. The model is never shown anything about the gold answer.
- Score. The predicted and gold SQL run against the same read-only database with a 30-second limit. Result sets are compared with Python’s equality, as the official scorer does (
1 == 1.0). Each answer gets an outcome category. Three timed runs feed R-VES. - Report. Each report stores the cell’s configuration and its hash, the prompt hash, ledger fingerprints, the split and a hash of its question ids, and n with a bootstrap interval. It also stores tokens (billed and cached), cost, latency, and every question’s SQL and verdict.
comparepairs two runs question by question.
Machine and resources
| Step | Wall clock | Peak memory (RSS) | Notes |
|---|---|---|---|
prepare --force, all 11 projects | 1 min 32 s | 48 MB | 35 s user + 36 s system CPU; 1.4 GB of SQLite databases read; value index and profiles rebuilt |
run, 30 questions, all model calls cached | 39 s | 45 MB | The harness alone: SQL execution, gold execution, 3 timed runs per correct answer |
run, cell G2, 302 questions | 21m 11s | ≈ 45 MB | 3.7 s mean per question, mostly waiting on the model |
| All Zen runs (15) | 4h 30m | 16,394,949 tokens processed | |
| All local qwen2.5-coder:3b runs (5 × 100) | 3h 17m | GTX 1650 4 GB; about 30 s per question; 2–5% accuracy |
The machine was a 12-core Linux workstation with 62 GB RAM and a 4 GB GTX 1650. The model calls run remotely (Zen) or on the local GPU (Ollama). The harness itself is single-threaded and light.
What the results say
- EKOS’s compiled pack beats raw DDL by 10–14 points with the same model, prompt and output limit: G 63.9% (a clean hold-out) and G2 66.9%, against 53.3%. Both differences are significant on 302 paired questions.
- What moved the score (on the tune split): column profiles +11 points; the
ekos-v1prompt with result checks another +12. Raising the output limit from 1,024 to 4,096 tokens removed answers with no SQL at all (9% of the baseline). Voting between three candidates did not pay; value lookup is neutral. - formula_1 was worse under the pack (G 18/33 against 26/33) until the profile also counted empty strings. Its lap-time columns record “no time” as both NULL and
''. A profile that reported only the NULLs made the model drop the<> ''filter it writes when it sees raw DDL. G2 fixed it: 26/33. - The scorer matches BIRD’s official one. 704 recorded predictions gave identical verdicts from
bird-bench/mini_dev’s scorer (Python 3.10, SQLite 3.37.2). One Soft-F1 value differed because SQLite before 3.45 cannot parse 16 nestedreplace()calls. - Not yet measured: the pack with BIRD’s column and value descriptions (fixed in v1.2.0), few-shot examples from BIRD’s train split, a stronger model.