CodePrism logoCodePrism Inc.
Back to Case Studies
Web Application (SaaS)

Building PrismAnalyst: A Privacy-First, Multi-Agent AI Analyst for Business Data

A conversational BI platform that lets business teams upload a spreadsheet and ask questions in plain English. Every answer is verified by a live SQL query, never guessed, and raw data never leaves the customer's environment.

Platform

Web (SSE Chat)

Duration

5 weeks

3Specialist agents behind one supervisor
2Tools power every analysis (SQL + chart)
94Automated tests covering safety, privacy, and routing

The Challenge

Business teams sit on more spreadsheet data than they can use, but getting a straight answer means waiting on an analyst, learning SQL, or trusting a general-purpose AI assistant that can state a wrong number with full confidence and needs to see raw, often sensitive rows to do it.

  • Getting a simple answer from business data meant waiting on an analyst or a BI ticket queue
  • Traditional BI tools require SQL, or a data team to write it, before anyone can ask a new question
  • Uploading spreadsheets to a general-purpose AI assistant sends raw rows, including anything sensitive in them, to a third-party model
  • General AI answers cannot be audited: there is no way to check which numbers were computed versus recalled from the model's memory
  • Real-world spreadsheets are messy (title rows, merged cells, footer totals) and break naive CSV ingestion before analysis can even start

Project Goals

Let a business user upload a spreadsheet and ask questions in plain English, with zero SQL required
Route each question to the right specialist automatically: sales/revenue, inventory/assortment, or deep analysis and forecasting
Make it architecturally impossible for an agent to answer without executing a real query: no hallucinated numbers
Keep raw data inside the customer's own environment: the LLM should only ever see schema and aggregated results
Handle real-world, messy Excel exports (title rows, merged cells, footer totals) without a manual cleanup step

How We Built It

01

Multi-Agent Supervisor Routing

A LangGraph StateGraph opens every conversation at a Supervisor node, which classifies the question against five labels (SALES, ASSORTMENT, ANALYST, BOTH, CLARIFY) using structured (Zod-validated) output from the LLM. If structured output fails, a regex-based fallback parser extracts the route from raw text, and if that fails too, the system defaults to SALES rather than going silent: a real question should never be dropped on a parsing error. BOTH triggers a chained hand-off: the Sales agent runs first and passes its findings as context into the Assortment agent, so a question like "what's driving the revenue drop, and which SKUs are at risk" gets a coordinated answer from two specialists instead of one shallow one.

Key DecisionStructured output with a text-parsing fallback and a safe default, rather than a single brittle parse path
ResultReliable routing across Sales, Assortment, and Analyst specialists, validated by a dedicated routing test suite covering malformed and edge-case responses
02

SQL-First, Zero-Hallucination Tooling

Every specialist agent (Sales, Assortment, and Analyst) is given exactly two tools: query_dataset_sql and generate_chart. There is no separate hardcoded statistics, forecasting, or recommendations engine; those existed in an earlier iteration and were deliberately removed once the team proved the LLM could write the SQL itself. Forecasting runs as a REGR_SLOPE/REGR_INTERCEPT regression, anomaly detection as an IQR calculation via PERCENTILE_CONT, correlation via CORR, and period comparisons via window functions (LAG/LEAD), all computed live against the uploaded data, not recalled from the model's memory.

Key DecisionTwo shared tools and SQL-first analysis over a library of specialized, hardcoded analysis tools
ResultAgents are structurally prevented from answering without a query result behind them; every number in every answer traces back to an executed SQL statement
03

Schema-Only Privacy Protocol

The analysis engine, DuckDB, runs in-process and never exposes raw rows to the LLM. The model only ever receives the dataset's column names and types, plus aggregated query results: sums, counts, averages, capped result sets. A strict-mode layer sits in front of every query result: it caps output to 50 rows and 5 columns by default, and auto-detects and redacts likely PII columns (email, phone, address, SSN, date of birth, and more) by name pattern before anything reaches the model.

Key DecisionEnforce the privacy boundary in code (a result-shaping layer), not just as a prompt instruction
ResultRaw customer rows and PII fields never reach the LLM, by construction rather than by policy
04

SQL Safety Guardrails

Because agents write their own SQL, that SQL has to be untrusted input. A validator requires every query to start with SELECT or WITH, rejects a blocklist of mutating keywords and file/network functions (INSERT, DROP, ATTACH, COPY, read_csv, httpfs, and others), and blocks multiple chained statements. A LIMIT is auto-injected on any query that lacks one, and an existing LIMIT is capped rather than trusted outright, with nesting-aware parsing so a LIMIT inside a subquery isn't mistaken for the outer one. Every query also runs under a hard timeout.

Key DecisionA dedicated, independently-tested SQL validator between the agent and the database, rather than trusting model-generated SQL directly
ResultThe largest single test file in the suite (24 cases) is dedicated to this validator, covering injection attempts, keyword bypasses, and LIMIT edge cases
05

LLM-Guided Excel Ingestion

Real spreadsheets exported from enterprise systems rarely start with a clean header row. The ingestion pipeline unmerges merged cells (propagating the top-left value across the range), then, for anything larger than 20 rows, asks the LLM to look at the first and last 20 rows and identify where the actual header row and any footer/summary rows are, so title rows, generated-on timestamps, and "Grand Total" rows get stripped before the data ever reaches DuckDB. Once ingested, a separate pass samples each text column and auto-casts it to a proper DATE type when 90%+ of sampled values parse cleanly, correcting for cases where DuckDB's own CSV auto-detection misses non-ISO date formats.

Key DecisionUse the LLM for structural cleanup of the file itself, not only for answering questions about it
ResultCSV, Excel (.xlsx/.xls), and JSON uploads all convert into a clean, correctly-typed DuckDB table without a manual data-prep step

The Outcome

A validated multi-agent, zero-hallucination architecture: three specialist agents, a two-tool SQL-first design, and a Schema-Only privacy protocol, now the basis for PrismAnalyst's production roadmap.

Impact & Results

3Specialist Agents
2Tools per Agent
94Automated Tests
0Raw Rows Sent to the LLM
5SQL-Computed Analysis Types

Key Takeaways

Constraining an agent to "always query, never recall" removes hallucination structurally: prompt instructions alone don't hold up under pressure, a tool-call requirement does

Privacy can be an architectural property, not just a policy statement: a schema-only boundary enforced in code is a stronger claim than "we promise not to look"

Real-world spreadsheets need an LLM in the ingestion path, not only the chat path: header/footer detection on messy enterprise exports is its own hard problem

A small, independently-tested SQL validator (blocklist, LIMIT injection, statement-count check) closes most of the risk of letting an LLM write live queries against a database

Removing code can be a milestone: retiring three hardcoded analysis tools in favor of SQL-first generation was a deliberate simplification, not a shortcut

Conclusion & Impact

"PrismAnalyst started as the generalized form of a conversational analytics interface first built inside an enterprise engagement, then rebuilt from the ground up as a standalone architecture: any team with a spreadsheet and a question, no analyst or SQL required, and no requirement to trust an AI vendor with raw business data to get there."

Technology Stack

TypeScriptNode.jsExpressLangGraphDuckDBZodSheetJSVitestClaude (Anthropic)Render
Background

Ready to achieve similar results?

Let our dedicated engineers bring your vision to life with cutting-edge technology and unparalleled expertise.