sans_schema — a Semantic Query Gateway
Open it now — you'll use it during the talk.
author_name. Theirs says writer.
The next API says author.full_name.POST /query
{
"want": ["book name", "writer", "cost"],
"where": "science fiction under 25 dollars"
}
{
"rows": [
{ "book name": "Vingt mille lieues sous les mers",
"writer": "Jules Verne",
"cost": 15.5 } ],
"interpreted": {
"want": { "writer": {
"field": "books_view.author_name",
"confidence": 0.95 } },
"where": { "ast": { "op": "and", … },
"confidence": 0.9 } }
}
want: fields in your vocabulary ·
where: a plain-language filter ·
the answer comes back in your keys, with an inspectable
interpreted echo.
Natural-language easy on the outside, a deterministic contract on the inside — stable enough for a traditional application to build against.
want + where
against.The schema block sits behind a prompt-cache boundary — after the first request it costs ~0.1× tokens per query.
NL → validated predicate AST → execute. Never NL → SQL.
The shape is an hourglass: many protocols on top, many data sources at the bottom — one narrow waist everything must squeeze through.
A hijacked model can at worst mis-resolve inside the allowed schema — it can never emit SQL. You'll see the proof live: the playground echoes the exact SQL it ran, values as bound parameters.
The one risky bet — can a model resolve fields + compile filters reliably? — was measured before any gateway code existed.
want): 100% · filter compilation
(where): 98%want
99–100% · where
80–100% — the spread is why the model sits
behind a swappable interface.The spike harness is frozen and re-runnable — every resolver change re-takes the same exam.
sans-schema-playground.vercel.app
Made-up field names → real answers. Every run shows its work:
what the gateway understood (resolved fields, confidence, cache hits, the
AST), the exact SQL with bound parameters, and a copy-paste
curl of the whole request.
git clone + docker builddocker run with your DATABASE_URL + your LLM keycurl it in your own wordsStated limits are how you know the numbers are honest.
Plus symbolic dates (bind_today) — compile
“published over 20 years ago” date-independent, bind today
at execute time, so the cache survives midnight.