Ask your database questions in plain English
Type "top 3 customers by spend" and a local model writes the SQL, runs it against your own SQLite database, and shows you the answer. You will also watch it invent a column, wrap its SQL in markdown, and try to delete a table, and see each one caught before it runs. The point is not the clever part; it is the guardrails: the schema in the prompt, a SELECT-only allowlist, and a read-only connection. Free, offline, on your own PC.
- A local model running first: do Run AI on your own PC. That installs Ollama and pulls a small model. This mission uses
qwen2.5:3b(a 2GB download); pull it withollama pull qwen2.5:3b. - Level 0 helps: Install anything from GitHub, safely (for uv) and The terminal survival kit. Check uv with
uv --version. - A little Python and a willingness to read SQL. You don't need to write SQL; the model does that, and every query is explained.
- About 3GB of free disk space for the model, and a few minutes of patience per question on a CPU. No GPU needed.
Why text-to-SQL, and the danger in it
A database answers precise questions, but only in SQL. A model can write that SQL for you. The catch is that a model can also write SQL that deletes your data, so the whole lesson is about making that impossible.
A database stores your data in tables: rows and columns, like a spreadsheet with rules. You ask it questions in a language called SQL.
SELECT name, city FROM customersreads two columns from the customers table. Learning SQL well takes time, which is why text-to-SQL is appealing: you type a question in English, a model writes the SQL, and you get your answer.SQL commands fall into three groups, and the difference matters for safety:
- SELECT reads data. It never changes anything. This is the only group you want a model's SQL to use.
- DML (Data Manipulation Language:
INSERT,UPDATE,DELETE) changes the rows. A wrongDELETEcan empty a table in a split second. - DDL (Data Definition Language:
CREATE,DROP,ALTER) changes the structure.DROP TABLE customersdeletes the whole table, data and all.
Here is the risk, stated plainly. A model is a text predictor. Ask it for SQL and most of the time you get a sensible
SELECT. Some of the time you get a query against a column that doesn't exist, or one that quietly answers a different question from the one you asked. And if your tool runs whatever the model returns, a question like "clear out the old orders" can turn into a realDELETE.This is not classic SQL injection. In SQL injection, your query is fixed and an attacker smuggles something nasty through a value you paste into it; the fix is to pass values as parameters, never glue them into the text (the lesson Build your own API in Python shows that). Here the model writes the entire query, so there is no safe value to parameterise. The defence is different: decide what the model's SQL is allowed to do, check it before you run it, and run it on a connection that physically cannot write.
That is the plan for the rest of this mission:
- Ground the model by putting the real schema in the prompt, so it uses columns that exist.
- Show you the SQL before anything runs.
- Allowlist SELECT only: refuse any query that is not a single read-only statement.
- Run read-only, so even a query that slips past the checks cannot change a thing.
- Keep a human in the loop for anything that reads sensitive data or that you intend to act on.
TipA model writing SQL is a helper, not an oracle. Treat its query the way you would treat a SQL snippet from a stranger online: read it, understand it, and only then run it, read-only, on data you can afford to have read.