What If You Could Just... Ask Your Data a Question? 🤔
Most people who need insights from a data file are blocked by one simple thing: they don't know SQL. Even technically strong users often don't want to stop, inspect schema manually, write queries, debug syntax, and format results just to answer a quick question like "Which category has the highest revenue?" or "Show me null rates by column."
This project removes that friction entirely. Upload your file, type your question in plain English, and let a Gemma 4-powered agentic backend inspect the schema, generate DuckDB SQL, execute it, and return the results — right inside a clean chat interface. 🎯
👉 Try it live here: is an open-source framework for orchestrating autonomous AI agents in structured multi-agent workflows. Instead of a single giant prompt doing everything, CrewAI lets you break a problem into specialized, coordinated responsibilities.
Three building blocks to understand:
🧑💼 Agents
Specialized workers, each with a defined role. Think of them as employees on your AI team — one might be a "Schema Inspector," another a "SQL Writer," another a "Result Formatter."
📋 Tasks
Units of work assigned to agents. A task has a clear description, expected output, and the agent responsible for it. Examples:
- "Analyze the uploaded file and return its schema"
- "Given this schema and user intent, write a valid DuckDB SQL query"
- "Execute the SQL and format the result for the user"
🔧 Tools
Capabilities agents can invoke to act on the world — file inspection utilities, DuckDB query executors, schema extractors, etc.
This model is powerful because it creates transparent, inspectable pipelines instead of black-box AI magic. Every step has a purpose, and every output is traceable.
🏗️ How the Tool Is Built — End to End
Step 1 — The Next.js Frontend
The portfolio app at
💡 The LLM Settings panel (visible by scrolling right on the chat panel) lets you switch between
Gemma 4 31B InstructandGemma 4 26B A4B Instructmid-session.
🟢 Query 1 — "Show me the top 10 rows"
What Gemma 4 generated:
SELECT * FROM data LIMIT 10
Result: Processed 49 CSV rows, returned 10 of 10 matching rows. Clean tabular output showing order_id, customer_id, customer_name, customer_email, customer_segment and more.
🟡 Query 4 — "Show me monthly revenue trend with total orders count and average order value grouped by month"
What Gemma 4 generated:
SELECT
date_trunc('month', order_date) AS month,
SUM(sales) AS total_revenue,
COUNT(order_id) AS total_orders,
AVG(sales) AS avg_order_value
FROM data
GROUP BY date_trunc('month', order_date)
ORDER BY month
Result:
| month | total_revenue | total_orders | avg_order_value |
|---|---|---|---|
| 2024-01-01 | 6471.26 | 30 | 215.71 |
| 2024-02-01 | 3114.65 | 19 | 163.93 |
Gemma 4 correctly used DuckDB's native date_trunc('month', ...) function — not a workaround, not a SUBSTR hack — real DuckDB date intelligence applied from natural language.
🔴 Query 6 — "Find all returned orders, show total profit loss by category and ship mode, sorted by biggest loss first"
What Gemma 4 generated:
SELECT
category,
ship_mode,
SUM(profit) AS total_profit_loss
FROM data
WHERE returned = 'Yes'
GROUP BY category, ship_mode
ORDER BY total_profit_loss ASC
Result:
| category | ship_mode | total_profit_loss |
|---|---|---|
| Furniture | Second Class | -200 🚨 |
| Furniture | Standard Class | -155 ⚠️ |
| Furniture | First Class | -20 |
Every single return came from Furniture. Second Class shipping returns caused the most financial damage. This is exactly the kind of insight a business analyst would spend hours finding — delivered in under 30 seconds via plain English.
💡 Why This Is Genuinely Useful — No SQL Expertise Needed
Look at what just happened across those 6 queries:
| What the user typed | What DuckDB actually executed |
|---|---|
| "Show me the top 10 rows" | SELECT * FROM data LIMIT 10 |
| "What are the key columns and null rates?" | 18-column null rate audit with (count(*) - count(col)) * 100.0 / count(*) |
| "Top categories by sales and profit margin" | SUM + division for margin %, GROUP BY, ORDER BY |
| "Monthly revenue trend" | date_trunc('month', order_date) + AVG + COUNT |
| "Customers with multiple orders" | COUNT(DISTINCT ...) + HAVING clause |
| "Returned orders profit loss by category" | WHERE returned = 'Yes' + GROUP BY + ORDER BY ASC |
SOCIAL SHARE CARD GENERATOR