mirror of
https://github.com/Shubhamsaboo/awesome-llm-apps.git
synced 2026-08-28 19:11:53 +08:00
Improve insurance claim intake follow-up logic
This commit is contained in:
@@ -261,40 +261,6 @@ def _events(
|
||||
return events
|
||||
|
||||
|
||||
def _next_question(
|
||||
validation: dict[str, Any],
|
||||
coverage: dict[str, Any],
|
||||
fraud_gate: dict[str, Any],
|
||||
) -> str:
|
||||
route = fraud_gate.get("final_routing_decision", coverage.get("routing_decision"))
|
||||
signals = fraud_gate.get("signals", [])
|
||||
if route == "emergency_escalation" and any(
|
||||
signal.get("route_to_emergency") for signal in signals
|
||||
):
|
||||
return (
|
||||
"Because you mentioned an injury or safety concern, are you and everyone "
|
||||
"else currently safe, and has anyone needed emergency medical care?"
|
||||
)
|
||||
|
||||
missing = validation.get("missing_fields", [])
|
||||
question_map = {
|
||||
"policyholder_name": "What is your full name as it appears on the policy?",
|
||||
"contact_method": "What is the best phone number or email for the adjuster to reach you?",
|
||||
"date_of_loss": "When did the loss happen?",
|
||||
"loss_location": "Where did the loss happen?",
|
||||
"loss_description": "Can you briefly describe what happened?",
|
||||
}
|
||||
for field_name in missing:
|
||||
if field_name in question_map:
|
||||
return question_map[field_name]
|
||||
|
||||
required_docs = coverage.get("required_documents", [])
|
||||
if required_docs:
|
||||
return f"Do you already have this document or evidence available: {required_docs[0]}?"
|
||||
|
||||
return "I have enough for the initial intake packet. Is there anything important the adjuster should know before handoff?"
|
||||
|
||||
|
||||
def _ui_state(
|
||||
session: IntakeSession,
|
||||
validation: dict[str, Any],
|
||||
@@ -383,7 +349,7 @@ def _ui_state(
|
||||
"Priority": f"{classification.severity.title()} - {classification.severity_rationale}",
|
||||
"Required actions": _join(required_doc_names, "No additional documents identified by current rules."),
|
||||
"Attachments": evidence_text,
|
||||
"Next best action": _next_question(validation, coverage, fraud_gate),
|
||||
"Next best action": packet["claimant_next_message"],
|
||||
},
|
||||
"packet_markdown": packet["markdown"],
|
||||
"model": MODEL,
|
||||
@@ -542,10 +508,14 @@ async def live_voice(websocket: WebSocket) -> None:
|
||||
response_modalities=["AUDIO"],
|
||||
system_instruction=(
|
||||
"You are a voice insurance FNOL intake agent. Speak naturally and briefly. "
|
||||
"Collect claim facts one step at a time. If injury, unsafe housing, or immediate "
|
||||
"danger is mentioned, prioritize safety and human escalation. Do not promise "
|
||||
"coverage, payment, liability, benefits, or approval. Ask only one or two focused "
|
||||
"follow-up questions at a time."
|
||||
"Your job is to collect enough blocking intake facts for a smooth adjuster handoff, "
|
||||
"not to end the call after the claimant's first narrative. If injury, unsafe housing, "
|
||||
"or immediate danger is mentioned, prioritize safety and human escalation. Otherwise, "
|
||||
"keep asking for missing blockers one step at a time: claimant name, contact method, "
|
||||
"policy number if available, date and location of loss, what happened, safety/injury "
|
||||
"status, evidence, documents, reports, tow details, or other involved parties. Do not "
|
||||
"promise coverage, payment, liability, benefits, or approval. Ask only one or two "
|
||||
"focused follow-up questions at a time."
|
||||
),
|
||||
speech_config=types.SpeechConfig(
|
||||
voice_config=types.VoiceConfig(
|
||||
|
||||
@@ -74,6 +74,15 @@ TYPE_REQUIRED_DOCS: dict[str, list[tuple[str, str]]] = {
|
||||
],
|
||||
}
|
||||
|
||||
BLOCKING_FIELD_QUESTIONS = {
|
||||
"policyholder_name": "What is your full name as it appears on the policy?",
|
||||
"policy_number": "What is the policy number, if you have it available?",
|
||||
"contact_method": "What is the best phone number or email for the adjuster to reach you?",
|
||||
"date_of_loss": "When did the loss happen?",
|
||||
"loss_location": "Where did the loss happen?",
|
||||
"loss_description": "Can you briefly describe what happened?",
|
||||
}
|
||||
|
||||
|
||||
def _as_model(model_type, value):
|
||||
if isinstance(value, model_type):
|
||||
@@ -186,6 +195,39 @@ def _parse_date(value: str) -> datetime | None:
|
||||
return None
|
||||
|
||||
|
||||
def _next_claimant_message(
|
||||
route: str,
|
||||
missing: list[str],
|
||||
required_documents: list[str],
|
||||
) -> str:
|
||||
if route == "emergency_escalation":
|
||||
return (
|
||||
"Your claim mentions injury, safety, or habitability concerns. A human representative "
|
||||
"should review this immediately. If anyone is in danger, contact local emergency services first."
|
||||
)
|
||||
|
||||
for field_name in missing:
|
||||
if field_name in BLOCKING_FIELD_QUESTIONS:
|
||||
return BLOCKING_FIELD_QUESTIONS[field_name]
|
||||
|
||||
if missing:
|
||||
return f"Can you clarify this missing detail so the adjuster can process the claim smoothly: {missing[0]}?"
|
||||
|
||||
if required_documents:
|
||||
return f"Do you have this document or evidence available now: {required_documents[0]}?"
|
||||
|
||||
if route == "special_investigation":
|
||||
return (
|
||||
"A human reviewer should look at this file, but the core intake packet is started. "
|
||||
"Please keep originals of any receipts, reports, photos, or messages related to the loss."
|
||||
)
|
||||
|
||||
return (
|
||||
"Your intake packet has the core information needed for adjuster assignment. Keep copies of "
|
||||
"all receipts, photos, reports, and communications related to the loss."
|
||||
)
|
||||
|
||||
|
||||
def validate_required_claim_fields(claim_value: Any) -> dict[str, Any]:
|
||||
"""Validate minimum intake facts before coverage and evidence rules run."""
|
||||
|
||||
@@ -195,6 +237,7 @@ def validate_required_claim_fields(claim_value: Any) -> dict[str, Any]:
|
||||
|
||||
required_fields = {
|
||||
"policyholder_name": claim.policyholder_name,
|
||||
"policy_number": claim.policy_number,
|
||||
"contact_method": claim.contact_method,
|
||||
"date_of_loss": claim.date_of_loss,
|
||||
"loss_location": claim.loss_location,
|
||||
@@ -204,8 +247,6 @@ def validate_required_claim_fields(claim_value: Any) -> dict[str, Any]:
|
||||
if _blank(value):
|
||||
missing.append(field_name)
|
||||
|
||||
if _blank(claim.policy_number):
|
||||
warnings.append("Policy number was not supplied; adjuster may need identity verification.")
|
||||
if claim.estimated_loss_usd is None:
|
||||
warnings.append("Estimated loss amount was not supplied.")
|
||||
|
||||
@@ -585,26 +626,7 @@ def build_claim_intake_packet(
|
||||
f"Estimated loss: {claim.estimated_loss_usd if claim.estimated_loss_usd is not None else 'not supplied'}."
|
||||
)
|
||||
|
||||
if route == "emergency_escalation":
|
||||
claimant_next = (
|
||||
"Your claim mentions injury, safety, or habitability concerns. A human representative "
|
||||
"should review this immediately. If anyone is in danger, contact local emergency services first."
|
||||
)
|
||||
elif route == "special_investigation":
|
||||
claimant_next = (
|
||||
"We can open the intake packet, but some timing or evidence details require specialized "
|
||||
"human review. Please provide the requested documents and keep originals available."
|
||||
)
|
||||
elif route == "needs_docs":
|
||||
claimant_next = (
|
||||
"Your intake packet is started. Please provide the missing information and checklist items "
|
||||
"so an adjuster can evaluate the claim without delay."
|
||||
)
|
||||
else:
|
||||
claimant_next = (
|
||||
"Your intake packet has the core information needed for adjuster assignment. Keep copies of "
|
||||
"all receipts, photos, reports, and communications related to the loss."
|
||||
)
|
||||
claimant_next = _next_claimant_message(route, missing, evidence_decision.required_documents)
|
||||
|
||||
audit_lines = [f"{idx}. {entry}" for idx, entry in enumerate(fraud_gate.audit_trail, start=1)]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user