AI evals framework for data & analytics engineering teams.
Project description
evaldata
The evaluation framework for AI-generated SQL.
pytest-native. CI-friendly. Built for data teams.
evaldata catches regressions on every prompt and model change, before they reach production.
Why evaldata
evaldata can prove two queries are equivalent without executing them or asking an LLM
to judge.
MLflow, Ragas, and DeepEval reach for an LLM even when the answer is exact and provable — a slow, costly guess at something you can settle for free.
- Semantic equivalence. Confirm two queries have the same meaning by comparing their
structure. No execution, no guessing — when it can't confirm, it returns
unknown. - Execution in your warehouse. Run the query on DuckDB, Postgres, or Databricks and compare the results, accounting for row order, NULLs, float tolerance, and types.
- It's just
pytest. Every eval is a test, run in your suite and your CI on every PR. No new runner, notebook, or dashboard. - An LLM judge when you need one. For ambiguous questions, missing reference answers, or an explanation to grade: the right tool for the job, fully supported.
evaldata reproduces dbt's own Semantic Layer benchmark locally on DuckDB — same dataset, questions,
and model — scoring 96.4% with gpt-5.3-codex, as pytest and with no dbt Cloud. See
Reproduce dbt's Semantic Layer benchmark.
Quickstart
uv add evaldata # core, includes the DuckDB adapter
An eval is a pytest test: a case (a question and its expected answer), a solver
(the system under test that writes the SQL), and a scorer (how the answer is judged).
Below, the AI's SQL is written differently from the reference query — reordered predicates,
different casing — but means the same thing. observed_equivalence() proves the match from
the query structure alone; no query runs.
from evaldata import CallableSolver, EvalCase, assert_eval, eval_case, observed_equivalence
from evaldata.platforms import duckdb_platform
platform = duckdb_platform(name="shop", path="shop.duckdb")
@eval_case(
input="Name the US customers with an id above 1.",
expected={"kind": "gold_query", "sql": "SELECT name FROM customers WHERE country = 'US' AND id > 1"},
platform=platform,
)
def test_us_customers(case: EvalCase) -> None:
solver = CallableSolver(lambda c: "select NAME from customers where id > 1 and country = 'US'")
assert_eval(case, solver, scorers=[observed_equivalence()])
uv run pytest
case result detail
──────────────────────────────────
test_us_customers PASS
1 passed, 0 failed
The full runnable version is in
examples/01_deterministic/test_showcase.py.
To test a real model instead of fixed SQL, swap the solver for
PromptSolver(model="openai/gpt-4o-mini") (needs the evaldata[litellm] extra). To judge
equivalence without a warehouse, swap the scorer for judged_equivalence(model).
Install
uv add evaldata # core (includes the DuckDB adapter)
uv add "evaldata[postgres]" # + Postgres adapter
uv add "evaldata[databricks]" # + Databricks adapter
uv add "evaldata[litellm]" # + litellm, to call a model as the AI under test
DuckDB, Postgres, and Databricks are the adapters available today. Snowflake and BigQuery are planned.
Documentation
Full documentation: monospaceai.github.io/evaldata
- Getting started — write and run your first eval.
- Concepts — cases, solvers, scorers, and platforms.
- Guides — semantic equivalence, LLM judge, local Ollama, hosted model, Databricks.
- API reference — the public API, generated from docstrings.
Examples
Runnable examples in examples/:
| Example | Shows |
|---|---|
| Showcase | Semantic equivalence with an execution fallback — no setup |
| Deterministic | Every expected-type and scorer, with fixed SQL |
| Local AI | A self-hosted Ollama model as the AI under test |
| Hosted AI | A hosted model, mocked so it runs without a key |
| Databricks | The same cases on a live Databricks SQL Warehouse |
| LLM judge | Judged equivalence, mocked so it runs without a key |
| Benchmark | Load a Spider/BIRD dataset and measure execution accuracy |
See examples/README.md for details.
Contributing
git clone https://github.com/monospaceai/evaldata.git
cd evaldata
uv sync # core + dev tooling
uv run pre-commit install
just check # lint + typecheck + tests with coverage (runs everything)
just check runs lint, typecheck, and tests with coverage (held at 100%). See the
justfile for the full set of commands.
Platform e2e tests
Adapter conformance for real platforms is marked e2e. CI provisions Postgres as a
service container and runs the suite on every push, so the Postgres adapter is exercised
against a real engine on every change.
Run it locally against Postgres with:
docker compose up -d # postgres:17 on localhost:5432
uv run --extra postgres pytest -m e2e # connection via POSTGRES_TEST_* env (defaults match compose)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file evaldata-0.4.0.tar.gz.
File metadata
- Download URL: evaldata-0.4.0.tar.gz
- Upload date:
- Size: 94.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
706b7da66932fac82eb576950ff9c258a9433b7de1c027c7f1e79a37d73d5c76
|
|
| MD5 |
dd33a512daca442e851f77546038b229
|
|
| BLAKE2b-256 |
453eb0d3453df866199313855132d6ffe2999bc7359511c85831c28a18b76f84
|
File details
Details for the file evaldata-0.4.0-py3-none-any.whl.
File metadata
- Download URL: evaldata-0.4.0-py3-none-any.whl
- Upload date:
- Size: 125.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0473a33cf8a0d938a07f06d01565d09495a1763839e95f970f738a03a64af88a
|
|
| MD5 |
da46454e8f4131c476071553fd9e9068
|
|
| BLAKE2b-256 |
fd1fb28f730973c41ecdb44656dcd8c4ac3a8e8308a1ceda59d7cb1ec891f419
|