A voice career counsellor for tier-3/4 India
A student says “mujhe engineering karni hai.” Underneath that one sentence sits a fee ceiling, a parent who won’t allow a hostel, a two-hour travel limit, and a dream borrowed from a cousin. A form captures the answer. A counsellor discovers the reason.
Today that student decides from two cousins, a WhatsApp forward, and a commission agent who names the colleges he’s paid to name. They are phone-first, speak Hindi or Marathi code-mixed with English, and have no trustworthy adult to ask.
Voice wasn’t a feature. It was the only interface that made sense.
A voice counsellor that asks the questions nobody asked, opens avenues they’ve never heard of, and notices when the real problem is pressure — not marks.
Class 11–12 / fresh-pass student in a tier-3/4 town. Phone, no laptop. Speaks Hindi or Marathi, code-mixed.
Leave with 2–3 viable, affordable career avenues, a plan a parent can read — and if they’re struggling, a human counsellor alerted.
Spoken trade-offs grounded in a closed dataset · a written student + parent summary · a flag log and escalation card in a counsellor queue.
In most voice products the first hours vanish into plumbing — transcription, accents, language detection, synthetic voices that flatten emotion. The first loop worked early enough that the rest of the time went to the product’s judgment.
A student says “fees ka issue hai, hostel afford nahi kar payenge” without adapting to the machine — and a slip into Marathi mid-sentence survives. Runs on language="unknown" auto-detect. 22 Indian languages, code-mixed output.
Indian names sound right; English words inside Hindi don’t break the rhythm. When Disha slows down after a student names family pressure, the voice carries the change. 11 languages, 30+ natural voices.
The SD SEED handbook ships subsetted fonts with no Unicode map — pdftotext returns glyph soup. Sarvam Docs AI reads the rendered page instead, so both handbooks digitize cleanly into chunks the agent later cites by page. It runs offline, upstream of the call — the reason search_handbook can quote a real source instead of inventing one.
One tap in a browser. No app, no login.
Code-mixed Hindi/Marathi → usable context.
LiveKit worker. Elicit, ground, flag, remember.
A voice that belongs in the conversation.
search_careers · search_handbook · find_scholarships over a closed dataset — the advice can only be as wrong as the data.
Constraint tracker, flags and refusals stream over the LiveKit data channel to a Next.js client — no DB on the live path.
Web on Vercel · Python worker + case API on a Graviton box via Coolify. Case API has no public domain — it fails closed.
Cut Disha off mid-sentence and she stops in 1.2–1.4s — measured across four interruptions, no degradation over three consecutive cut-ins, and she never resumes the killed sentence.
Saaras runs on language="unknown" — it understands Hindi, Marathi, English and code-mixing without the student ever adapting to the machine. Comprehension is language-agnostic; the reply-language directive rebuilds the prompt without dropping other state.
Hindi and Marathi mark the speaker’s gender on the verb. Disha is a woman, so the prompt forces the feminine form everywhere — “main samjhaati hoon”, “mi sangte” — never the masculine.
Browsers suppress a fan easily; nearby talking lives in speech frequencies and syllable rhythm. Cancelling background voices, not just noise, kept the demo room from reading as an interruption.
Every number, class and institution name is repeated back to confirm (“gyarah-baarah class, theek?”); unclear proper nouns are re-asked, never guessed.
Five constraints surface through concrete life questions, never a form: travel · hostel · fee ceiling · family permission · scholarship dependence. Each saved the moment it becomes clear.
Rhythm rule enforced in the prompt: after each fact, give something back — name a real path from search_careers and its trade-off — before asking at most one new question. By turn 5 the student has heard 2–3 concrete paths.
finish_session persists a Hindi summary + a shortlist of exact tool-returned paths only — unverified paths are dropped, not spoken. A parent-facing version goes out translated.
Any wellbeing flag logs a verbatim quote and a timestamp into a counsellor escalation card — the job isn’t “a chat reply”, it’s a state change on a second surface.
Constraints surface through life questions, never a form. Advice a student brings (cousin, WhatsApp, agent) is acknowledged for its care, then checked against the list — never endorsed because someone trusted said it.
Every named career triggers search_careers first. No match → the reply must begin “meri list mein nahi hai”, then log_refusal, then the nearest listed option. No colleges, fees, cutoffs, or salaries — ever. Every refusal is auditable.
Told in plain words to stop the career script after a frightening moment, the model gave the helpline… then asked about travel distance one turn later. Instructions are a request; the tools are the rule. A self-harm flag now flips a safety lock that makes the career tools refuse for the rest of the session.
Within the call. The five constraints and the profile fill a live tracker on the student’s screen. The saved profile is re-injected into the system prompt after every save_profile, so a long call never asks a name twice.
Across sessions. Reopening the link resumes the case — distilled facts only. recall_memory lets Disha reach for why an option was ruled out. By design it stores no audio; flags keep the quote and timestamp, nothing more.
No audio stored. No transcripts kept. The memory boundary is a product decision, written down in MEMORY-DESIGN.md and enforced in the load path.
The alternative isn’t nothing — it’s a commission counsellor naming colleges he’s paid to name. The metric that matters: % of students reaching a constraint-fit shortlist vs. an agent-fed default.
The career tree descends from NaksheKadam, my SIH-2022-winning project on this exact problem — data reuse with disclosed lineage, zero code reuse.
When distress, family pressure or choice paralysis appears, Disha calls flag_wellbeing with the student’s exact words, then slows down, acknowledges, and drops the constraint questions for that turn. She never diagnoses, never labels — she flags and hands to a human.
For explicit self-harm language, the career conversation ends. She gives the Tele-MANAS helpline 14416 and stays with the student in short warm sentences. The parent summary that reaches home frames the student’s constraints with respect. Honest recovery, not cheerfulness.
Delight here is judgment under pressure — not a stock “I understand your concern.”
Coval and Hamming are built for English; on Marathi they score the failures that matter least reliably. So a persona bot speaks through Bulbul, the agent’s replies come back through Saaras, and every step is scored twice — assertions and an LLM judge — passing only if both agree. The agent under test is unmodified.
Five Marathi turns, five Hindi replies — STT auto-detected fine, but TTS was hardcoded to hi-IN. One line killed the whole Marathi path. A free-form call had already “passed” it.
A restarted worker read as a failed safety flow; a double-transcription bug blamed the agent for its own cut-off fragments. Before believing a bad score, check the thing measuring it was alive.
Because conversations and person-facts are stored separately, Disha recalls the student, not a transcript — so each visit starts deeper than the last, and the questions change as the person does.
From “no idea” to “these things interest you — this is worth trying.” A first constraint-fit shortlist.
vague → a directionAfter the spoken aptitude test, Disha pushes an emerging interest a level deeper. The questions are no longer “what stream?” but “how far into this?”
a direction → a planPost-12 → degree or diploma → first jobs → career moves. The same voice, carrying everything it learned, asking the questions the next stage needs.
a plan → a careerThe risk. Career paths and government scholarships change every year. A static tree quietly goes stale — and a confident, out-of-date answer is worse than a refusal.
The plan. Cron / loop-engineering agents that continuously discover new pathways and scholarships and fold them into the closed KB, with lineage disclosed — so the same three lookups keep returning current answers.
The dataset gets fresher, but the discipline is unchanged: Disha still speaks only what a tool returns, still says “meri list mein nahi hai” for anything absent, and still logs every refusal. Fresh data widens the list — it never loosens the rule.
| Dimension | Mult | Observable proof |
|---|---|---|
| Voice Experience | 2.5× | Auto-detected Hindi/Marathi/English code-mix input · barge-in 1.2–1.4s, no resume · feminine-verb grammar · background-voice cancellation. |
| JTBD completion | 2.5× | Five constraints elicited conversationally → closed-list shortlist → student + parent summary, no builder touch. |
| Creativity | 1.5× | Indirect elicitation · auditable “not in my list” refusals · safety stop enforced in the tools, not the prompt. |
| Impact | 1.5× | Commission-counsellor baseline · 327 pathways / 41 scholarships · NaksheKadam SIH-2022 lineage. |
| Memory & Context | 1× | Live constraint tracker · case resumes on reload · distilled facts only, no audio, no transcript. |
| Delight | 1× | Pressure moment handled with judgment — tone shift, verbatim flag, honest recovery without losing progress. |
No double-counting — in-call flow → Voice · persisted resume → Memory · refusal + flagging → Creativity · pressure handling → Delight · artifact → JTBD.
Sarvam let me build from the student outward instead of the model inward. The language could be mixed, the thought unfinished, the accent local — the product still listened. In four hours, that’s the difference between a demo and a counsellor.
Rushikesh Patade · Built with Sarvam Saaras v3 · Bulbul v3 · Docs AI