Skip to content

Plain-English questions to SQL: the model runs in 2 of 10 steps

Justin Ahinon

A box where users ask a question about their data and get an answer sounds like an AI project. On my own product, the model is 2 steps out of 10. The other 8 are application code.

The product is WhatMedicaidPays, which I build and run. On its /ask page, you type a question like "What does Medicaid pay for an office visit in California?" and get stats, a table, or a US map. One model call writes a SQL query against the production database. A second call turns the rows into the answer you read. This is my own product, not client work.

The short answer

The question is validated, rate-limited, and checked against a cache. A model writes the SQL. A short validator inspects the SQL, and the query runs on the database. A second model call writes the answer, and the result gets its own URL. The model is in steps 6 and 9.

The ten steps

  1. The form receives the question.

  2. A schema checks it: not empty, at most 500 characters.

  3. A rate limit blocks more than ten requests in sixty seconds from one IP address.

  4. A pattern check rejects a few known prompt-injection phrases.

  5. If someone already asked this exact question, a cache check sends the user to the existing answer.

  6. Model call 1 writes SQL. The database schema is in its prompt.

  7. A short, hand-written validator inspects the SQL before it runs.

  8. The query runs on the database, and reads can go to replicas.

  9. Model call 2 turns the rows into an answer: text, stats, a table, a chart, or a map.

  10. The answer is saved with a slug, and the user goes to its shareable URL.

Everything except steps 6 and 9 is code I can inspect and test without the model.

Three choices that kept it simple

  • The whole schema goes in the prompt. The interface has five tables, small enough to paste in full. There is no retrieval step that could miss a table.

  • Two model calls, not one. The first call writes code that runs against the database. The second writes text that people read. They have different rules, and the split gives one clean place to check the SQL between them.

  • The cache doubles as pages. Every answered question gets its own URL, like /ask/r/what-does-medicaid-pay-for-an-office-visit-in-california, so the answers become pages that can rank in search.

The rate limit is mostly a cost defense. Every request is two model calls and a database query.

What this means for your product

Generating the SQL was the easy part. For a team that wants this feature, most of the work is the code between the SQL the model writes and what your database runs.

One example scope of my AI integration sprint is "Questions in plain English": a model writes the SQL, and the answer comes back as a chart, a table, or a map.

The technical long version, with the prompt, the SQL check, and the Cloudflare D1 details, is on my personal site: Building a text-to-SQL feature with Cloudflare D1.