5 min read

I Taught an LLM to Query Data in English. The Hard Part Was Trust.


There’s a wall between most researchers and their own data, and the wall is SQL. The data is right there — tables, columns, years of it — and the question is right there too, in their head, in plain English. In between sits a query language they don’t write. The obvious dream is to knock the wall down: ask in English, get an answer.

I built a proof-of-concept for exactly that. The setting mattered: the data was patient data, and the organization was — rightly — being very careful about how AI got used at the time. Both of those facts turned out to be central, because the POC taught me the two things that still decide whether “chat with your data” is a genuine tool or a quiet liability. One is what makes it work at all. The other is what keeps it from hurting you.

The semantic layer is the unlock

The first thing I learned is that an LLM cannot understand your schema from the schema. Real database columns are cryptic — dx_cd, enc_dt, pt_id, a table named enc. Those names mean something to the people who built them and nothing to anyone else, including a model. Hand an LLM the raw schema and ask it to write a query, and it guesses, because guessing is all the names give it room to do.

What changed everything was a second layer: metadata that described what each table and column actually meant. Not the names — the meaning. This table is clinical encounters. enc_dt is the date of the encounter. This column relates to that one through this key. This code set means these things. When I packed that semantic layer into the model’s context alongside the schema, the behaviour flipped. It stopped guessing at gibberish and started reasoning about a domain it now understood — which table to touch, how to join, what a question was really asking for.

That was the whole unlock, and it’s the part people underestimate. The model was only ever as good as the meaning I gave it. Context — a real semantic layer describing the data, not just its column names — is what turns “generate SQL over these opaque tables” into “answer a question about a domain you’ve been taught.” Without it you have a party trick. With it you have something that genuinely works.

And then it hallucinated

Something that genuinely works is exactly where the danger starts, because the model, well-fed with context, produces confident, fluent, plausible queries — and sometimes they are subtly wrong. It invents a column that sounds like it should exist. It joins on a key that looks right and isn’t. It reads a definition slightly off and filters on the wrong thing. Every one of those mistakes comes out looking just as assured as a correct query, because fluency is what the model is built for and fluency is not correctness.

Here is why that’s not a small problem. A wrong query usually doesn’t error. It runs, and it returns a number. On a research question over patient data, a wrong number that looks right is the worst possible output there is — worse than a crash, worse than “I don’t know” — because it’s an answer, and someone will believe it, and they may act on it. Plausibility, the model’s great strength, is precisely the thing you cannot afford to trust when the answer is about patients.

The verification boundary

The resolution is the suggest-versus-decide split, and this project is where it stopped being a slogan for me. The LLM is genuinely excellent at the drafting: turning a question plus a semantic layer into a candidate query. It cannot be trusted with the deciding: whether that query is correct, whether it’s safe to run, whether the result should be believed. Those are exactly the tasks that need a deterministic check the model can’t sail past.

So the only architecture I’d trust looks like this: the model drafts at the edge; the candidate query is surfaced — here is the SQL, here are the definitions it used, here are the columns it touched — so it’s inspectable rather than a black box; and it is checked, by a person and, wherever possible, by a deterministic rule, before it runs and before anyone believes the answer. The model proposes. It never gets to conclude — an optimistic edge that drafts fast, an authoritative core that owns the truth, and patient data raising the stakes to where the boundary is non-negotiable.

Raw schema plus a semantic layer feed an LLM as context; the LLM drafts a candidate query; a verification step of human and deterministic checks reviews it; only if it holds does it run and return a trusted answer.

The model drafts. It never gets to conclude — no query runs, and no number is believed, until it’s checked.

The caution was the right instinct

It would be easy, from a builder’s chair, to read an organization’s carefulness about AI as friction. This POC convinced me of the opposite. The caution was correct, and the POC is why it was correct: the technology was genuinely useful and genuinely unreliable at the same moment, and the only responsible way to put something like that near patient data is with the verification boundary firmly in place and a human who owns the answer.

Capability and caution aren’t opposed forces to be balanced against each other. On data that matters, the caution is the thing that makes the capability usable at all. A “chat with your data” system that will confidently hand a researcher a wrong number about patients isn’t an asset you’re being too slow to adopt. It’s a liability you haven’t finished building yet.

It’s a whole category now

Years later, this is an entire product category — text-to-SQL, semantic layers, “chat with your warehouse,” an assistant on top of every analytics tool. And the two truths from that early POC have only hardened. The semantic layer is still the unlock: no amount of model quality substitutes for actually telling it what your data means. And verifiability is still the moat: the differentiator was never smarter chat, it’s showing your work.

A tool that returns just an answer is a liability wearing a chat interface. A tool that returns the answer plus the query, plus the definitions it used, plus a way to check it is something a serious person can actually put in front of a decision. The semantic layer taught the model to speak the domain. The verification boundary kept it from being trusted with the conclusion. On data that matters, you need both — and, in the end, the second one more than the first.


Companion code: ramwise-examples/semantic-sql — a semantic layer plus a verification gate that blocks a hallucinated query before it runs (synthetic data).