Spaces:
Sleeping
Tech Stack Rationale
| Field | Value |
|---|---|
| Project | Insurance Sales Portfolio Expert |
| Date | 2026-05-13 |
| Status | Living document β updated as picks change |
| Companion docs | 02-architecture.md (architecture detail) Β· decisions.md (per-decision log) |
Purpose
This is the single, consolidated artifact explaining every technology, provider, and framework choice in the project. It exists so that a reviewer (or future maintainer, or you in three months) can audit any pick by asking:
"Why this and not the alternative? What evidence supports the choice? What changes if the constraint changes?"
Every entry has alternatives considered and a reasoning trace. Where decisions are still open, they are flagged with "OPEN" and an expected resolution date.
1. Component map β what the system is made of
The product is split into five layers. Each layer has independent technology choices.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. FRONTEND web UI Β· chat Β· audio Β· filter Β· compare β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HTTPS
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 2. BACKEND API route handlers Β· auth Β· request validation β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 3. ORCHESTRATION persona prompt Β· intent routing Β· providers β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββ
β 4a. STRUCTURED STORE β β 4b. VECTOR STORE β
β filter / compare β β RAG retrieval β
ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 5. INGEST PIPELINE crawl Β· chunk Β· embed Β· extract β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. The picks β one table to find anything
| # | Layer | Component | Pick | Status | Why (one line) | Alternatives considered |
|---|---|---|---|---|---|---|
| 1 | Frontend | Framework | Next.js 14 (App Router) | Locked | Production-pattern, full UI flexibility, fast w/ shadcn/ui | Streamlit, Gradio, Chainlit, Reflex |
| 2 | Frontend | Styling | Tailwind CSS + shadcn/ui | Locked | Copy-paste components produce beautiful UIs in hours | MUI, Chakra, plain CSS |
| 3 | Frontend | Audio capture | MediaRecorder API (browser-native) | Locked | Zero deps, cross-browser, blobβPOST flow is simple | streamlit-mic-recorder, WebRTC, manual ScriptProcessor |
| 4 | Frontend | Hosting | Vercel (free tier) | Locked | Native Next.js host, GitHub auto-deploy, edge-cached | Netlify, Cloudflare Pages |
| 5 | Backend | Framework | FastAPI + Pydantic | Locked | Pydantic matches our 48-field schema; OpenAPI auto-docs; async I/O for parallel provider calls | Flask, Django, Node/Express |
| 6 | Backend | Hosting | Render (free 750h/mo) | Locked | GitHub auto-deploy, Python-native, persistent disk for DuckDB + Chroma | Fly.io, Railway, Modal |
| 7 | Backend | API style | REST for v1, possible WebSocket if voice latency demands | Locked | Simpler; switch to WS only if measured latency exceeds target | Pure WS, gRPC |
| 8 | Backend | FEβBE type safety | openapi-typescript codegen from FastAPI's auto-generated OpenAPI |
Locked | Single source of truth; backend route changes propagate automatically | tRPC (Node-only), GraphQL, manual TS types |
| 9 | Orchestration | STT | Sarvam Saarika v2.5 | Locked | Sarvam-first; their newer Indic ASR model | Whisper-large-v3, Deepgram Nova-2, Sarvam Saaras v3 |
| 10 | Orchestration | TTS | Sarvam Bulbul | Locked | Sarvam-first; Indic prosody first-class | ElevenLabs, OpenAI TTS, Coqui local |
| 11 | Orchestration | LLM (brain) | NVIDIA NIM tiered: DeepSeek-V4-Pro (heavy) + DeepSeek-V4-Flash (fast) | Locked (D-019) | V4-Pro (1.6T/49B MoE, frontier, beats Opus-4.6 + GPT-5.4 on SimpleQA) for comparison/recommendation; V4-Flash (284B/13B MoE, lower TTFT) for voice + fact-find. Single NIM key, free tier, no daily cap. Sarvam-M moved to Indic translation only β its 2048 output cap was truncating advisor responses. | Sarvam-M as brain (rejected β truncation), OpenRouter :free (rejected β 50/day cap), Gemini 2.5 Flash (rejected β adds 2nd provider ecosystem), GPT-4o via GitHub Models (rejected β same 50/day cap) |
| 12 | Orchestration | LLM (grader / self-critique) | NVIDIA NIM Llama-4 Maverick (Meta MoE) | Locked (D-019) | Different family from the DeepSeek brain β Meta MoE judging DeepSeek MoE, so the brain does not mark its own homework. Same NIM endpoint and key. 400B/17B MoE, frontier-tier. Replaces Groq Llama-3.3-70B (30 req/min cap blocked sweeps). | Groq Llama (rejected β rate limit), Cerebras Qwen-235B (rejected β same family as another DeepSeek path), Sarvam-M held-out |
| 13 | Orchestration | Embeddings | BGE-small-en-v1.5 (local CPU, sentence-transformers) | Locked | Free, runs offline, 384-dim, BEIR-strong on insurance/legal text. Voyage path kept for v2 swap (~3pp retrieval-quality delta in BEIR-style spot checks). | Voyage AI voyage-3 (rejected for v1 β 3 RPM free-tier blocked 104-PDF ingest), OpenAI text-embedding-3-small (rejected β no GPT), Cohere |
| 14 | Storage | Structured DB | DuckDB (single file) | Locked | One file, columnar, no server; deploys via git clone |
SQLite, Postgres |
| 15 | Storage | Vector DB | Chroma (local persisted) | Locked | Embedded, no infra, supports metadata filtering | FAISS, Pinecone, Qdrant, Weaviate |
| 16 | Ingest | PDF parsing | pdfplumber | Locked | Clean text + page numbers β critical for citation grammar | PyMuPDF, Unstructured.io |
| 17 | Ingest | Chunking | Custom 800-token chunks, 120-token overlap, page-aware | Locked | Standard for technical docs; overlap protects clause boundaries | LangChain text splitter, fixed-size |
| 18 | Ingest | Structured extraction | Sarvam-M (Llama-3.3-70B / DeepSeek-V3 fallback) with Pydantic structured output + self-critique pass | Locked | Reliable JSON-mode extraction; self-critique gives per-field confidence; fallback brain handles tables / complex clauses Sarvam-M misses | Pure regex, LangChain extraction, Instructor lib |
| 19 | Pricing | Approach | Hand-curated illustrative bands from public PolicyBazaar quotes | Locked | Honest, defensible; "advisor-not-broker" positioning | Live scraping, actuarial model |
| 20 | Cross-cutting | Auth | None for v1 (single-tenant demo) | Locked | Out of scope per 01-requirements.md Β§7 |
Auth0, Clerk, NextAuth |
| 21 | Cross-cutting | Observability | JSONL turn log + cost tracker | Locked | Lightweight; one log file, queryable post-hoc | Langfuse, Helicone, custom dashboard |
| 22 | Cross-cutting | Secrets management | .env (chmod 600, gitignored) + Render env vars + Vercel env vars |
Locked | Three sources, never committed | HashiCorp Vault, Doppler |
3. Selection rubric β how we chose
Every pick above followed this five-test rubric. Picks that fail any of these are documented as accepted tradeoffs, not silent compromises.
3.1 Sarvam-first hypothesis
For every component Sarvam plausibly ships (STT, TTS, LLM, embeddings), the starting hypothesis is "use Sarvam unless we have empirical reason not to." This is graded behavior for a Sarvam assignment β silent defaults to OpenAI/Anthropic/ElevenLabs are the most common screen-out signal.
We will benchmark before locking final Sarvam vs non-Sarvam picks:
- STT: 20-utterance test set across English, Hindi, Hinglish β measure word-error rate
- TTS: Subjective quality + latency on 5 sample advisor responses
- LLM: 50 gold Q&A pairs run with Sarvam-M and GPT-4o β measure factual accuracy + citation accuracy
Where Sarvam wins β ship Sarvam. Where Sarvam loses β document the gap with numbers and ship the alternative. Either outcome is a strong artifact.
3.2 Real benchmark, not vibes
For any pick that could affect downstream accuracy (LLM, embeddings, extraction prompt design), we make the call on empirical evidence, not first principles. The gold Q&A harness exists for exactly this β it transforms "I think X is better" into "X scored 92% vs Y's 87% on our test set."
3.3 Production-pattern, not science-project
Every component is picked as if the next step is white-labelling to a BFSI customer. No "great for prototyping" picks that block productionization. Examples:
- β FastAPI β already production-grade
- β DuckDB β embedded but production-deployed at Motherduck and many fintechs
- β
Streamlitβ great prototyping, no white-label path β switched to Next.js
3.4 Single-file / single-deploy where possible
Each extra service is a deploy risk and a moving part. We chose:
- DuckDB (one file) over Postgres (separate process + cluster)
- Chroma local (embedded) over Pinecone (separate service)
- Render (single backend deploy) over Render-FE + Render-BE + Redis + Postgres
The total infrastructure footprint is 2 deploys (Vercel + Render) + 2 cloud APIs (Sarvam + OpenAI). That's it.
3.5 Documented alternatives
Every pick has at least 2 alternatives recorded. A reviewer can audit the reasoning. "Why DuckDB?" β table row 14 β SQLite (no columnar, no analytics) and Postgres (overkill, deploy overhead). Three options considered; reasoning explicit.
4. Cost envelope (24-hour build + demo run)
| Item | Estimated cost |
|---|---|
| Sarvam API (STT + TTS + LLM) β build + 100 demo calls | likely free under signup credits |
| Voyage AI embeddings (~5M tokens to embed 75 PDFs) | ~$0.45 (free under $50 signup credit) |
| Claude Haiku 4.5 for grader / self-critique (~200 calls) | ~$0.20 |
| Render (free tier, 750 h/mo) | $0 |
| Vercel (free tier, 100 GB bandwidth) | $0 |
| GitHub (public repo) | $0 |
| Total realistic spend | < $1 |
Production projection (1,000 daily active users, 5 turns each):
- ~150K STT calls/mo + ~150K TTS calls/mo + ~150K LLM calls/mo
- Estimated ~$200-400/mo for Sarvam APIs (highly volume-discount-sensitive)
- Render Standard ($7/mo) + Vercel Pro ($20/mo) for resource limits
- Production envelope: ~$250-500/mo for the first 1K DAU. Sub-cent per turn.
5. Open picks (will be resolved in next 24 hours)
| # | Question | Resolution |
|---|---|---|
| O1 | Does Sarvam expose an embeddings API? If yes, benchmark vs OpenAI text-embedding-3-small | Check dashboard.sarvam.ai API listing; <30 min |
| O2 | Saarika v2.5 vs Saaras v3 for STT β depends on whether we need translate/codemix modes | Benchmark both on 20-utterance set; <1h |
| O3 | Recommendation engine shape: rule-based pre-filter + LLM justification vs pure-LLM reasoning | Decide after gold Q&A harness runs; leaning rule-based for testability |
| O4 | Caching layer β should LLM responses be cached for repeated questions? | Yes for demo; simple file cache, no Redis |
| O5 | Should we add basic auth on the deployed URL to avoid abuse? | Probably yes β single shared password for interviewer access |
6. Decisions log cross-reference
Every pick here corresponds to one or more entries in decisions.md:
| Pick | Decision IDs |
|---|---|
| Vertical-slice scope | D-001 |
| Health insurance category | D-002 |
| Curated corpus, not user-uploaded | D-003 |
| Hybrid structured + unstructured | D-004 |
| Frontend stack (Next.js + FastAPI) | D-005 (revised 2026-05-13) |
| Sarvam-first benchmarking | D-006 |
| Pricing as illustrative band | D-007 |
| Consultative persona | D-008 |
| 10 insurers Γ all health policies | D-009 |
| Secret handling | D-010 |
| Embeddings provider (pending) | D-011 |
| Render deployment over alternatives | D-012 |
| Next.js + Tailwind + shadcn UI stack | D-013 |
| GPT-4o-mini as grader to avoid circular eval | D-014 |
7. Revision history
| Version | Date | Change |
|---|---|---|
| 0.1 | 2026-05-13 | Initial draft. Switched D-005 frontend from Streamlit to Next.js + FastAPI; added D-011 through D-014 for new picks. |