Current state. Public repository and docs describe a cited sales-intelligence API over cleaned structured data and redacted business notes; this portfolio presents the documented architecture, benchmarks, and lessons learned without claiming a live deployment or production adoption.
Context
“Why did SparkClean 1kg sales spike in Mumbai in Sep 2025?”
That is the kind of question this agent answers. It turns a messy sample FMCG sales export — 8 CSV tables across 52 weeks, 5 product categories, and 12 territories, plus 30 business-note documents — into a question-answering API. WHAT questions are answered from the structured data; WHY questions must back their causal claims with citations retrieved from the notes.
Problem
The hard part was never just wiring an LLM to a database. The system needed to separate three different contracts:
- WHAT questions should return factual answers from the structured dataset.
- WHY questions should return causal analysis only when citations are available.
- WHAT_TO_DO questions should remain recommendations with
PENDING_APPROVAL, never decisions presented as fact.
That contract had to survive bad source data. The cleaning pass found 10,972 mixed-format dates, 9,416 non-numeric sales-value strings, 771 9999 sentinel volumes, 734 negative-unit rows, 23 duplicate primary-sales pairs, and 12 PII redactions in the unstructured notes. Later audit work also found that the dataset’s value column is mostly synthetic: 53,849 of 58,262 valid rows match 0.75 × MRP × units exactly, with another 4,385 within ₹1 rounding.
Approach
The architecture follows the repo’s accepted decisions:
- Clean first, then reason. The pipeline normalizes dates and value strings, deduplicates rows, redacts PII from business notes, and preserves bad-unit rows via null-with-flag handling, keeping the audit trail inspectable.
- One agent, three tools. A single LangGraph loop calls
query_database,search_docs, anddescribe_database— no multi-agent supervisor. The repo ADRs make the trade-off explicit: lower latency, less state complexity, fewer moving parts. - Structured data + retrieval together. The structured side uses a SQLAlchemy star schema; the unstructured side indexes the 30 business notes in ChromaDB with Gemini embeddings so WHY answers can cite qualitative evidence.
- Serverless-safe async path.
POST /askenqueues via QStash, the signed webhook processes the request, and Upstash-backed Redis stores intermediate and semantic-cache state./ask-directremains available for synchronous runs. - Validation as a product boundary. The agent uses a two-pass output flow and enforces response contracts in code: WHY needs citations, WHAT_TO_DO must stay
PENDING_APPROVAL, and tool failures map to an explicit error status.
Tech stack / architecture
- API layer: FastAPI endpoints for
/ask,/ask-direct,/webhook/process, and cache invalidation. - Agent runtime: LangGraph single-agent tool loop with
deepseek-v4-flashas the default model. - Structured analytics layer: SQLAlchemy over a star schema spanning facts, dimensions, promotions, and stockouts; local SQLite with PostgreSQL as the production target.
- Retrieval layer: ChromaDB vector search over 30 cleaned business-note documents using Gemini embeddings (
gemini-embedding-2, 1536 dimensions). - Caching: Redis semantic cache with cosine similarity threshold
0.97and 600-second TTL. - Async processing: QStash queue plus signed webhook flow; Upstash Redis for serverless-compatible state.
- Observability: optional Langfuse tracing for LLM calls, chains, and tool invocations.
- Evaluation: 14-question golden set with policy checks, runnable in fake or live mode.
Evidence
The repo ships unusually complete public evidence:
README.mddocuments the architecture, API surface, and tech stack.APPROACH.mdrecords the data-cleaning ledger, tool design, queue flow, cache behavior, and major limitations.docs/adr/README.mdindexes six accepted ADRs covering the agent loop, star schema, QStash choice, semantic cache, PII redaction, and model selection.docs/DATA_QUALITY.mddeepens the anomaly catalogue, including the synthetic value finding and unresolved edge cases.docs/LESSONS_LEARNED.mdpreserves the failed RQ-first plan and the serverless pivot to QStash/Upstash.
Evidence boundary
This entry is a repository-backed case study, not proof of a live system:
- no deployed badge, live URL, or production-adoption claim;
- no invented business metrics beyond what the repository already documents;
- no claim that sparse promotions and stockouts coverage explains every sales movement;
- the synthetic value column is not presented as an independent source of pricing truth.
Outcomes
The reconciliation and audit trail preserve 38,630,596 validated units across 52 weeks: problematic rows are kept annotated, not deleted. The eval harness turned model choice into a measurement: the 14-question golden set kept deepseek-v4-flash over kimi-k2.6 on both pass rate and wall time. The hardening pass expanded verification from 70 to 98 passing tests and added benchmark, ADR, and data-quality docs.
Read this as an in-development, public-safe architecture case study — evidence-backed, but not proof of a live customer deployment, production adoption, or business ownership.
Next
If the public evidence set expands later, the strongest follow-up angles are already clear from the repo: selective cache invalidation, richer promo/stockout evidence for causal answers, and further benchmark/eval work. Until then, the most honest value is the current one: a fully inspectable record of how the system was built, where the data lied, and which engineering decisions held up under measurement.