InsuranceBot / docs /tech-stack-rationale.md
rohitsar567's picture
Deploy: Stack A (NIM brain + Maverick judge + Sarvam voice). D-019.
13779e8 verified
|
Raw
History Blame
13.9 kB

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.