InsuranceBot / 70-docs /30-engineering /discovery-script.md
rohitsar567's picture
chore(cleanup): purge stale narrative/tombstones/dead code β€” codebase reads as the current standard
23b8fad
|
Raw
History Blame Contribute Delete
8.36 kB
# Discovery Conversation Script
> ⚠️ **Design intent, not the present-state map.** The turn-by-turn script
> and adaptive rules below capture the discovery *intent*; the implementation
> is now a single Gemini 2.5-flash call per turn with function-calling tools
> (`backend/single_brain.py` / `brain_tools.py`) β€” there is no scripted
> question renderer, no `orchestrator`, no `sales_brain` / `qa_brain` split,
> and no separate faithfulness judge. Present-state authority:
> [`README.md`](../../README.md) Β§4.
The 10-turn fact-find that turns a stranger into a profiled buyer.
**Design principles** (inspired by Even.in's tone + insurance-sector buyer-research norms):
1. **Plain language.** No "PED", no "UIN", no "sub-limit". We're talking to an adult who hasn't read a policy wording end-to-end.
2. **Every question explains WHY we're asking.** A form feels invasive; a conversation feels helpful. The one-line why-this-matters subtitle is non-optional.
3. **Chips, not text boxes.** Multi-choice + sliders + toggles. Free-text only when no chip set is honest.
4. **Honesty pre-commitment.** Right after the first turn, the bot tells the user: "Tell me the truth, even on hard things. Your honest answer protects your claim later β€” not just my recommendation."
5. **Optional, not gated.** The user can stop at any time. We surface what we can with partial profiles (insurer-level CSR / complaints) but ONLY personalize the scorecard once `profile_completeness >= 0.6`.
---
## Turn-by-turn script
### Turn 0 β€” Welcome (the bot starts)
> "Hi β€” I'm here to help you find a health policy that genuinely fits **you**, not the one that pays the highest commission to a broker. I'll ask about 8–10 short questions. Some will feel personal (your health, what you earn). **Be honest** β€” every answer is private to this chat, and being upfront about your medical history is the single biggest thing that protects you when you actually need to claim. Ready?"
[Chip: "Let's start" Β· "Tell me how this works first" Β· "Just let me browse"]
### Turn 1 β€” Age
> "What's your age?"
>
> *Why we ask: premium, eligibility, and renewability all hinge on this.*
[Slider 18–80, step 1]
### Turn 2 β€” Who's covered
> "Who else do you want to cover?"
>
> *Why we ask: covering parents or kids changes which policies make sense β€” some plans price family floaters very differently.*
[Multi-select chips: "Just me", "Spouse", "Children", "Parents", "Parents-in-law"]
### Turn 3 β€” Parents' health (CONDITIONAL β€” only if Turn 2 included parents)
> "If you're covering parents, what's the older one's age, and do they have any pre-existing conditions like diabetes, BP, or heart issues?"
>
> *Why we ask: parents-with-PED need policies with shorter PED waiting periods and lifelong renewability β€” that narrows the field a lot.*
[Slider for age + chips: "None", "Diabetes", "Hypertension/BP", "Heart", "Cancer", "Thyroid", "Multiple"]
### Turn 4 β€” Your own conditions
> "Any pre-existing conditions for yourself? Diabetes, BP, thyroid, asthma, anything chronic?"
>
> *Why we ask: this is where honesty matters most. Hiding it gets your premium β‚Ή500 cheaper today and a denied claim of β‚Ή8 lakh later. Insurers can and do find out at claim time.*
[Multi-select: "None", "Diabetes", "BP/Hypertension", "Thyroid", "Asthma", "Heart", "Cancer history", "Other"]
### Turn 5 β€” Existing cover
> "Do you already have any health insurance β€” through your employer or that you bought yourself?"
>
> *Why we ask: if you already have β‚Ή5L from work, you might need a top-up rather than a full base plan β€” different product, different price.*
[Chips: "None", "Employer only", "Personal policy", "Both" β†’ if any, ask sum insured slider]
### Turn 6 β€” City
> "Which city or town?"
>
> *Why we ask: cashless hospital network density varies massively. A "16,000-hospital network" means nothing if none are near you.*
[Free text + autocomplete] OR [Chips: "Metro", "Tier-1", "Tier-2", "Tier-3 / smaller town"]
### Turn 7 β€” Budget
> "Roughly what annual premium budget feels comfortable?"
>
> *Why we ask: helps us rank β€” but if a slightly higher budget materially improves your protection, we'll flag it.*
[Slider with 4 markers: <β‚Ή15k, β‚Ή15–30k, β‚Ή30–60k, β‚Ή60k+]
### Turn 8 β€” Maternity & near-term events (CONDITIONAL)
> "Anything planned in the next 12–24 months β€” pregnancy, a known surgery, anything you've discussed with a doctor recently?"
>
> *Why we ask: most policies have 30-day initial waits and 24–36-month maternity waits. If you need cover soon, that filters the list.*
[Multi-select: "Pregnancy planned", "Surgery planned", "Recent hospitalisation", "None of these"]
### Turn 9 β€” Risk preference
> "When it comes to surprises in your bill, what do you prefer?"
>
> *Why we ask: this single answer decides whether co-pay/deductible plans (cheaper premium, share-of-bill) or full-cover plans (higher premium, predictable bill) fit you.*
[Chips: "Lowest premium, I'll accept a 10–20% co-pay", "Balanced", "No surprises β€” full cover at higher premium"]
### Turn 10 β€” Income (optional, asked last)
> "One last optional question β€” your annual income band. We use it only to gauge how much sum insured fits your risk."
>
> *Why we ask: if you earn β‚Ή8L/yr, a β‚Ή50L cover is overkill; if you earn β‚Ή40L/yr, a β‚Ή5L cover leaves you exposed.*
[Chips: "Prefer not to say", "<β‚Ή5L", "β‚Ή5–10L", "β‚Ή10–25L", "β‚Ή25L+"]
### Wrap
> "That's all I needed. Here's what I heard: <readback_summary>. I'll now show you 3 policies that fit best, with the exact reasons they ranked well **for you specifically**."
β†’ Render scorecard cards (now personalised because `profile_completeness >= 0.6`).
---
## Honest disclosure β€” the trust contract
Right after Turn 0 and again before Turn 4 (own conditions), the bot surfaces a one-line contract:
> "Your answers stay in this conversation. They are NOT shared with any insurer until you choose to buy a policy through their channel. Being honest with me about your medical history is also what makes your claim defensible later β€” because insurers can match disclosed history against hospital records at claim time."
This is the customer-protection framing. It tells the user honesty is **self-protection**, not insurer-favoring.
---
## Adaptive rules
- If the user is in free-form mode (asks questions back to the bot), don't push the script β€” let them lead. Resume when they ask "what do you recommend?"
- If `profile_completeness >= 0.6` after some subset of questions, offer to skip the rest: "I have enough to recommend now. Want to keep going, or see what I'd suggest?"
- Never ask the same question twice. `Profile.asked` tracks this.
- A user who says "just show me policies" gets the marketplace with insurer-level metrics (CSR / complaints) visible but per-user scorecards GREYED with a "complete your profile to see how this ranks for you" CTA.
---
## Implementation notes
The 9-slot fact-find SCHEMA still lives in `backend/needs_finder.py::GRAPH` β€” used now as the schema source embedded in the single-LLM system prompt rather than as a scripted question list. Each entry's `id`, `field`, `is_core`, and `condition` are consumed by the LLM as a structured contract; the `prompt_en` / `prompt_hi` strings are no longer rendered to the user (the LLM owns voice + cadence end-to-end via its system prompt + the conversation so far, and records facts through the `save_profile_field` tool).
To add a new question:
1. Add a `Question(...)` entry with `id`, `field` (which Profile attribute it sets), `is_core` (boolean β€” counts toward completeness), optional `condition` callable, optional `parser`.
2. Surface the new slot in the single-brain system prompt's 9-slot schema (alongside accepted value shapes + examples) so the LLM knows to capture it. See the system prompt in `backend/single_brain.py`.
3. Wire any post-capture validation into the `save_profile_field` handler in `backend/brain_tools.py` (enum coercion, INR parsing, bounds).
4. Add a row in `70-docs/scorecard-knowledge-graph.md` Part B showing how the new input shifts weights.
5. Wire the shift into `_profile_tuned_weights()` in `backend/scorecard.py`.
Drift between these places breaks the transparency promise. Keep them in sync.