InsuranceBot / docs /05-needs-analysis-flow.md
rohitsar567's picture
Deploy v1 โ€” single-Docker FastAPI + Next.js + RAG + voice + faithfulness
5dbdf6e verified
|
Raw
History Blame
8.81 kB

05 โ€” Needs Analysis Flow (Fact-Find)

Field Value
Project Insurance Sales Portfolio Expert
Version 0.1
Date 2026-05-13
Implementation backend/needs_finder.py

0. Why an explicit graph (not "let the LLM figure it out")

A good Independent Financial Advisor opens with a stable, repeatable set of questions โ€” and conditionally deep-dives based on the buyer's signal. We replicate this with an explicit question graph, not an LLM that improvises every session.

Why:

  1. Auditable behavior. A reviewer can see the graph, trace any session, and check why a question was (or wasn't) asked.
  2. Testable. Pure functions of Profile โ†’ Question. Every branch can be unit-tested.
  3. Fail-soft. Even if the LLM brain degrades, the question flow still works.
  4. Bilingual by construction. Each node has English + Hindi prompts side by side.

1. The graph

                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  Q1: age (core)             โ”‚
                    โ”‚  "What is your age?"        โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  Q2: dependents (core)      โ”‚
                    โ”‚  "Who else do you cover?"   โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  Q3: income_band (core)     โ”‚
                    โ”‚  "Annual income?"           โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  Q4: existing_cover (core)  โ”‚
                    โ”‚  "Already have health ins?" โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  Q5: primary_goal (core)    โ”‚
                    โ”‚  "Why are you here?"        โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  Q6: location (core)        โ”‚
                    โ”‚  "Which city / tier?"       โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
                         (conditional branches)
                                 โ–ผ
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ–ผ                                                  โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Q7: parents_age (cond)       โ”‚         โ”‚ Q8: health_conditions (always) โ”‚
โ”‚ asked IF dependents include  โ”‚         โ”‚ "Any pre-existing condition    โ”‚
โ”‚ 'parent'                     โ”‚         โ”‚  on your side?"                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ–ผ                                            โ–ผ
                                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                โ”‚  Q9: budget_band (core)              โ”‚
                                โ”‚  "Premium budget?"                   โ”‚
                                โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                               โ–ผ
                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                          โ”‚  Profile complete โ†’ readback +      โ”‚
                          โ”‚  policy recommendation              โ”‚
                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

2. Termination criteria

The graph emits next_question = None (i.e., ready to recommend) when all of:

  1. All 6 core questions answered (age, dependents, income, existing_cover, primary_goal, location)
  2. All applicable conditional questions answered (parents_age if dependents include parents)
  3. health_conditions and budget_band answered

Or when the user sets profile.free_form_session = True โ€” the orchestrator skips fact-find and answers free questions directly.

3. Bilingual prompts

Every node has both prompt_en and prompt_hi. The orchestrator picks based on the user's detected language. Example:

Node English Hindi
age "To start, what's your age?" "เคถเฅเคฐเฅ‚ เค•เคฐเคคเฅ‡ เคนเฅˆเค‚ โ€” เค†เคชเค•เฅ€ เค‰เคฎเฅเคฐ เค•เฅเคฏเคพ เคนเฅˆ?"
dependents "Who else do you want to coverโ€ฆ" "เค†เคชเค•เฅ‡ เค…เคฒเคพเคตเคพ เค•เคฟเคธ-เค•เคฟเคธ เค•เฅ‹ cover เค•เคฐเคจเคพ เคนเฅˆโ€ฆ"
budget "What annual premium budgetโ€ฆ" "Premium เค•เฅ‡ เคฒเคฟเค เคธเคพเคฒเคพเคจเคพ เค•เคฟเคคเคจเคพ เค–เคฐเฅเคšโ€ฆ"

This is what "Indic-native, not translated" (Doc 01 ยง5.3) looks like in practice โ€” the question is authored in both languages, not machine-translated at runtime.

4. Parsing user answers

Each node has a parser callable that normalizes the user's natural-language answer into a typed Profile field:

  • age: lambda s: int("".join(c for c in s if c.isdigit())[:3] or 0) or None
  • dependents: free-form string (will be normalized via LLM in v1.1)
  • income_band: bucketed via keyword match ("5 lakh" โ†’ "under_5L")

When the parser returns None, we treat the question as unanswered and re-ask (v1 simply leaves the field as None and moves on โ€” re-ask is v1.1).

5. How the orchestrator uses this

profile = Profile.from_session(session_id)
q = next_question(profile, language=detected_language)
if q is not None:
    # Still in fact-find phase โ€” ask the next question
    reply = q.prompt_hi if language == "indic" else q.prompt_en
    profile.asked.append(q.id)
else:
    # Profile complete โ€” proceed to retrieval + recommendation
    chunks = retrieve(user_query, top_k=5)
    reply = brain.generate(...)

The orchestrator can also let the user drive the conversation freely โ€” if the user immediately asks a specific question like "compare Star and HDFC ERGO," we set free_form_session = True and skip the fact-find.

6. What the user sees

Bot: "Hi, I'm your AI insurance advisor. To start, what's your age?"
User: "I'm 32"
Bot: "Got it. Who else do you want to cover โ€” just yourself, spouse, kids, or parents?"
User: "self + spouse, kids later"
Bot: "Roughly what's your annual income โ€” under 5 lakh, 5-10, 10-25, or 25+ lakh?"
User: "around 18 lakhs"
... [continues through the core 6] ...
Bot: "Here's what I've understood: 32 years old; covering self+spouse; income 10L-25L;
      no existing cover; goal: first health policy; in a metro; budget 15K-30K.
      Did I get that right?"
User: "yes"
Bot: "Based on that, three policies stand out: [...] โ€” let me explain why."

7. v2 enhancements

# Enhancement Why
1 LLM-parser for free-form answers ("I'm in my early 30s with 2 kids") Handles natural-language replies instead of rigid bucket-matching
2 Re-ask on None parse Robust to user confusion
3 Skip-confirm flow ("you can skip this โ€” say 'skip'") Buyer autonomy
4 Save profile across sessions Returning user picks up where they left off
5 Tone-match the user's energy (formal vs casual) Conversation feels human