InsuranceBot / rag /SCHEMA.md
rohitsar567's picture
fix(voice+chat+llm+docs): KI-155 + KI-156 + KI-157 + KI-158 + KI-159 + KI-160 bundle
1c5baae
|
Raw
History Blame Contribute Delete
8.19 kB

HealthPolicy Schema β€” design notes

Canonical record for one Indian health insurance policy variant. One row = one (insurer, policy_name, variant) tuple. Schema lives in rag/schema.py.

The shape is grounded in the IRDAI Customer Information Sheet (CIS) β€” the regulator-mandated one-page disclosure every insurer must publish for every product β€” supplemented by the comparison dimensions used by PolicyBazaar / InsuranceDekho / Acko so that extracted records support both regulator-grade and consumer-grade filtering.

Field groupings

# Group Fields Purpose
1 Identity & metadata policy_id, insurer_name, insurer_slug, policy_name, policy_type, uin_code Primary key + IRDAI cross-reference.
2 Eligibility min_entry_age_years, max_entry_age_years, max_renewal_age_years, min_child_entry_age_days, family_composition_allowed, residency_requirement First-cut filter: "can this person even buy it?"
3 Sum insured & premium sum_insured_options_inr, premium_payment_modes, premium_range_indicative_inr, premium_payment_term_years, grace_period_days, free_look_period_days Affordability + billing flexibility.
4 Waiting periods initial_waiting_period_days, pre_existing_disease_waiting_months, specific_disease_waiting_months, specific_diseases_listed, maternity_waiting_months, sub_limits_waiting_notes The single biggest source of claim disputes β€” buyer must understand these before signing.
5 Coverage scope inpatient_hospitalization, pre/post_hospitalization_days, day_care_treatments, domiciliary_treatment, ayush_coverage, maternity_coverage, newborn_coverage, organ_donor_expenses, ambulance_cover, critical_illness_cover, restoration_benefit, no_claim_bonus_pct, no_claim_bonus_cap_pct, preventive_health_checkup What's covered. Each benefit uses the reusable CoverageItem shape (covered, limit_inr, limit_text, notes) so the verbatim CIS wording stays available for citation.
6 Sub-limits & caps room_rent_capping, icu_capping, copayment_pct, copayment_trigger_notes, disease_wise_sub_limits, deductible_amount_inr What's not fully covered β€” the hidden gotchas.
7 Geography & network geographic_coverage, worldwide_emergency_cover, network_hospital_count, cashless_treatment_supported Where the policy works.
8 Exclusions permanent_exclusions, temporary_exclusions, notable_exclusions_summary IRDAI standardised the permanent-exclusion list in 2020 β€” relatively easy to extract.
9 Claim & service claim_settlement_ratio_pct, claim_process_summary, tat_cashless_authorization_hours Trust signals.
10 Riders available_riders, top_rider_examples, rider_premium_indicative_inr Up-sell surface.
11 Source metadata source_pdf_path, source_pdf_url, last_updated_date, extraction_confidence_pct Provenance & quality gating.

Field count: ~48, mostly Optional[...] because PDF extraction is lossy.

Critical vs nice-to-have

Critical for side-by-side comparison β€” these drive almost every buyer decision and must be extracted reliably:

  • sum_insured_options_inr, policy_type
  • pre_existing_disease_waiting_months, initial_waiting_period_days, specific_disease_waiting_months, maternity_waiting_months
  • room_rent_capping, icu_capping, copayment_pct, deductible_amount_inr
  • pre_hospitalization_days, post_hospitalization_days
  • no_claim_bonus_pct, restoration_benefit
  • ayush_coverage, maternity_coverage, critical_illness_cover
  • network_hospital_count, cashless_treatment_supported

Nice-to-have β€” useful for narrative / pitch but not deal-breakers:

  • top_rider_examples, rider_premium_indicative_inr
  • preventive_health_checkup, domiciliary_treatment
  • worldwide_emergency_cover
  • disease_wise_sub_limits (the dict can stay sparse)

Likely-hard-to-extract fields (and why)

Field Why it's hard Where to actually get it
claim_settlement_ratio_pct Not in the policy wordings PDF at all. Insurer-level, not policy-level. IRDAI Annual Report (Statement 11) β€” separate scrape, joined on insurer_slug.
network_hospital_count Quoted in marketing pages, rarely in wordings. Changes weekly. Insurer's hospital-locator API or the IRDAI "Network Hospital" portal.
premium_range_indicative_inr Wordings never contain pricing. Public quote engines (PolicyBazaar etc.) for a fixed benchmark profile.
disease_wise_sub_limits Usually buried in an annexure with inconsistent table layouts. Targeted second-pass extraction with table-aware models (Camelot / pdfplumber).
tat_cashless_authorization_hours IRDAI mandated 1 hour in 2024, but older PDFs still say "as per regulations". Default to 1.0 if absent and policy is post-2024; flag otherwise.
uin_code Present but easy to confuse with similar product codes; same insurer reuses prefixes. Regex [A-Z]{4,6}HLIP\d{5}V\d{6} with cross-check against IRDAI's product master.
specific_diseases_listed Listed in an annexure, often with sub-bullets; needs structure-preserving extraction. LLM extraction with a clear schema example shot.

extraction_confidence_pct is the gating signal β€” records below ~70 should be flagged for human review before being served to users.

v2 expansion: Life / Motor / Travel

The schema is forward-compatible without breaking changes:

  1. Shared header. policy_id, insurer_name, insurer_slug, policy_name, policy_type, uin_code, plus the entire Source metadata group, apply to every line of business. Move them into a shared PolicyBase mixin when the second LOB lands.
  2. Sibling models. Create LifePolicy, MotorPolicy, TravelPolicy alongside HealthPolicy. Each inherits the shared header and adds its own category-specific groups (e.g. LifePolicy adds policy_term_years, death_benefit_inr, maturity_benefit_inr, surrender_value_table).
  3. Discriminator field. Add line_of_business: Literal["health","life","motor","travel"] at the base. Storage and retrieval layers route by this field.
  4. Backward compatibility. HealthPolicy keeps Config.extra = "allow", so any v2 keys that briefly leak into a health record (during migration) are preserved rather than dropped. Never remove or rename existing fields β€” downstream extractors and the RAG vector store key off them.

Storage & embedding notes

  • One record per JSON file under rag/extracted/. The policy_id is the filename.
  • For the vector store, embed two views of each record:
    • The full prose of notable_exclusions_summary + claim_process_summary (high-signal narrative chunks for semantic queries).
    • A flattened key-value string for every populated field (so structured queries like "policies with PED waiting < 24 months" can still match).
  • The original policy wordings PDF stays in rag/corpus/ for citation fallback. The schema's source_pdf_path field is the link back.

Chroma chunk metadata

Each chunk persisted in Chroma carries the following metadata keys (set by rag/ingest.py):

Key Type Notes
policy_id str e.g. aditya-birla__activ-one. Primary filter for per-policy retrieval.
insurer_slug str e.g. aditya-birla. Secondary filter.
source_pdf str Relative path under rag/corpus/.
page int 1-indexed PDF page number.
chunk_index int Position within the policy's chunk sequence.
doc_type str 'wordings' / 'brochure' / 'cis' / 'prospectus' / 'curated'. 'curated' (KI-137) marks chunks ingested from hand-curated 40-data/policy_facts/<id>.json rather than raw PDF text.
legacy_issuer str (optional) KI-144. Present on indusind-general__* chunks whose source PDFs carry the previous reliance-general issuer branding. Value: 'reliance-general'. Lets retrieval surface legacy citations without breaking the canonical slug.