跳到正文
DEV Community· Shivam Dwivedi·· 3 小時前AI 評分57

如何用 Vercel 免費提供的 MiniMax M3.1 Flash 建立免 API key 的唯讀 SQL 報告應用

Free MiniMax, zero API keys: build a read-only SQL report app

AI 導讀

教學示範用 Vercel 免費提供至 10 月 22 日的 MiniMax M3.1 Flash 建立 SQL 報告應用,模型只產生查詢,由本地唯讀 SQLite 資料庫執行。

正文

Vercel is serving MiniMax M3.1 Flash for free until 22 October [2]. Free model, short window. So obviously we built something with it. 🛠️

The idea is simple. Let the model write SQL. Never let it run SQL. A small local app takes the query, runs it on read-only sample data, and shows you the report. If the query tries anything funny, SQLite says no.

No API key. No signup beyond your Vercel account. About ten minutes.

SQL Postcard showing a MiniMax-generated query for paid totals by category, with three result rows: Books 4300, Games 9000, Tools 10500.

The finished app running a query MiniMax actually wrote. Sample data is made up: twelve fake orders.

What we're building

Meet SQL Postcard. Two boxes:

  1. Generate: you copy a prompt into Vercel's MiniMax playground and get SQL back.
  2. Check & run: you paste that SQL into the app. It runs on a fresh in-memory SQLite database with twelve fake orders.

That copy-paste step looks old-school, and it's on purpose. The model never touches your data. It only sees the table's shape and the question.

Step 1: Run the app 🧪

You need Python 3 and nothing else. The app only uses the built-in sqlite3 module. We tested it on Python 3.14.7 on macOS.

Get SQL Postcard on GitHub. Clone it and open the project folder:

git clone https://github.com/panditshivam/sql-postcard.git
cd sql-postcard
python3 verify.py
python3 app.py --port 8775

verify.py checks the saved queries against a plain Python calculation. app.py starts the app at http://127.0.0.1:8775. Neither command calls a model.

Step 2: Get SQL from MiniMax for free

Open the MiniMax M3.1 Flash page on Vercel and click Playground [1]. Sign in with your own account.

Before you send anything, look at the Providers table. You want MiniMax with the green Free tag. That's the only route the promotion covers [2].

Vercel's MiniMax M3.1 Flash playground: the model's JSON answer with three SQL queries, and the Providers table showing MiniMax marked Free for input and output.

Our real playground run on 20 October, cropped. Top: the answer. Bottom: the provider row marked Free.

Now, in the app, open Show the exact generation prompt and copy it into the playground. It asks for three reports as JSON:

  1. Paid totals by category.
  2. Paid order count and total by region.
  3. Top two paid categories.

Here's one query MiniMax sent back:

SELECT category, SUM(total_cents) AS total_cents
FROM orders
WHERE status = 'paid'
GROUP BY category
ORDER BY category ASC

Paste one query at a time into the app's SQL box. Only the SQL, without the JSON quotes around it. Hit Run report locally. Done. ✅

The whole answer cost 362 input tokens and 338 output tokens, according to the Gateway log. Most of the output, 226 tokens, was the model thinking before it answered.

⚠️ Common mistake: assuming "free" means free on every route. Vercel can send a request to other providers, and the promotion only covers MiniMax serving it [2]. In code, pin the provider with only. The order setting is just a preference and can fall back to someone else [3].

Step 3: Try to break it

This is the fun part. Click Try a write query. The box fills with DELETE FROM orders. Run it.

Meme made from the real app screenshot. Top caption: ’Me: pastes DELETE FROM orders’. The app shows ’Query rejected · not authorized’. Bottom caption: ’SQLite authorizer: absolutely not’.

Original meme on our own screenshot. The rejection is real.

How does it say no? SQLite has a lesser-known feature called an authorizer [4]. It's a function SQLite calls for every action a query wants to do. You answer "allowed" or "denied". Ours allows reading the orders table plus a handful of math functions, and nothing else:

functions = {'sum', 'count', 'avg', 'min', 'max', 'round', 'coalesce'}

def authorize(action, first, second, *_):
    if action == sqlite3.SQLITE_SELECT:
        return sqlite3.SQLITE_OK
    if action == sqlite3.SQLITE_READ and first == 'orders':
        return sqlite3.SQLITE_OK
    if action == sqlite3.SQLITE_FUNCTION and (second or '').lower() in functions:
        return sqlite3.SQLITE_OK
    return sqlite3.SQLITE_DENY

db.set_authorizer(authorize)

On top of that: SQLite's query-only mode is on, the database is rebuilt fresh in memory every run, only one statement runs at a time, queries over 8,000 characters are refused, queries exceeding an instruction budget get stopped, and you see at most 100 rows.

We threw six bad queries at it: DELETE, DROP TABLE, a PRAGMA, reading SQLite's internal schema table, a function that isn't on the list, and two statements glued together. All six were rejected. 🛑

Original two-row reaction meme. Scared face: ’Letting the model run SQL straight on your data’. Sunglasses face: ’Model writes it. Read-only SQLite runs it.’

Original meme. Emoji: Twemoji, CC-BY 4.0.

⚠️ Common mistake: checking "does the text start with SELECT?" and calling it safe. It blocks good queries and misses bad ones. This perfectly harmless query starts with WITH:

WITH paid AS (SELECT region FROM orders WHERE status = 'paid') SELECT COUNT(*) AS paid_orders FROM paid

The authorizer looks at what the query does, so it allowed this one and returned 9. A text check would have thrown it out.

Did MiniMax get it right?

Yes, all three. We wrote the expected answers before asking the model, then checked each query against those answers and against a separate Python calculation.

  • By category: Books 4300, Games 9000, Tools 10500 (in cents).
  • By region: North 3 paid orders, South 2, West 4.
  • Top two: Tools, then Games.

The traps it avoided: it filtered to paid orders only, and it sorted the way we asked. Those are two easy mistakes a "looks right" query can hide.

Fine print

  • This is one model answer with three queries, on twelve fake rows. Nice demo, not a model ranking.
  • The guardrails fit this little app. A real database with real users needs proper permissions, timeouts and a separate read-only account, not just this callback.
  • The free window is temporary. Check the Providers table before you send anything.

The pattern is the takeaway: model writes, database decides, checker confirms. Try it with your own synthetic schema and questions: a starting point for a local report tool. The model route is free for a couple of days, at least. 😉

References

  1. Vercel AI Gateway: MiniMax M3.1 Flash model page and playground.
  2. Vercel changelog: MiniMax M3.1 Flash free on AI Gateway.
  3. Vercel docs: provider filtering and ordering.
  4. Python 3.14 docs: sqlite3 authorizers, progress handlers and execute.

Asset credits: screenshots are our own captures of the app and the Vercel playground. Memes are original. Emoji graphics: Twemoji, CC-BY 4.0.

AI disclosure

AI was used to draft the article.

來源:DEV Community · dev.to