How to Build a loan approval Agent Using LlamaIndex in Python for insurance
A loan approval agent for insurance reviews applicant data, policy context, and underwriting rules, then produces a recommendation with evidence. It matters because insurance decisions need consistency, auditability, and compliance; a good agent reduces manual review time without turning the process into an untraceable black box.
Architecture
- •Document ingestion layer
- •Pulls policy PDFs, underwriting guides, KYC notes, claim history, and product eligibility rules into a retrievable index.
- •Retrieval layer
- •Uses
VectorStoreIndexplus metadata filters to fetch only the relevant insurance documents for a given applicant.
- •Uses
- •Decision engine
- •Applies structured rules for hard stops like sanctions hits, missing KYC, or policy exclusions before any LLM reasoning.
- •LLM reasoning layer
- •Uses an LLM through LlamaIndex to summarize evidence and draft an approve/reject/manual-review recommendation.
- •Audit layer
- •Persists inputs, retrieved chunks, model output, and final decision for compliance review and model governance.
- •Guardrail layer
- •Prevents unsupported decisions by forcing citations and rejecting outputs that lack policy evidence.
Implementation
- •Load insurance documents into a retrievable index
Start with the underwriting material you actually use in production: product terms, eligibility rules, fraud indicators, and internal SOPs. In LlamaIndex, the common pattern is to build a VectorStoreIndex from Document objects.
from llama_index.core import Document, VectorStoreIndex
docs = [
Document(
text="""
Insurance loan approval policy:
- Reject if KYC is incomplete.
- Reject if applicant appears on sanctions list.
- Manual review if debt-to-income ratio > 0.45.
- Approve only if all mandatory disclosures are signed.
""",
metadata={"source": "underwriting_policy_v1", "type": "policy"}
),
Document(
text="""
Product eligibility:
- Minimum age 21
- Employment history >= 12 months
- No active fraud investigation
""",
metadata={"source": "product_rules_v3", "type": "product"}
),
]
index = VectorStoreIndex.from_documents(docs)
query_engine = index.as_query_engine(similarity_top_k=3)
- •Add a deterministic pre-check before the LLM
Do not ask the model to infer obvious compliance failures. Hard rules should short-circuit the workflow so your agent stays explainable and predictable.
def hard_rule_check(applicant: dict) -> tuple[bool, str]:
if not applicant.get("kyc_complete", False):
return False, "Reject: KYC incomplete"
if applicant.get("sanctions_hit", False):
return False, "Reject: sanctions match"
if applicant.get("mandatory_disclosures_signed", False) is False:
return False, "Reject: missing mandatory disclosures"
return True, "Passed hard checks"
applicant = {
"name": "Jane Doe",
"kyc_complete": True,
"sanctions_hit": False,
"mandatory_disclosures_signed": True,
"debt_to_income": 0.52,
}
passed, reason = hard_rule_check(applicant)
print(passed, reason)
- •Use LlamaIndex to retrieve evidence and generate a decision
This is where the agent becomes useful. Retrieve the relevant policy text, pass it alongside structured applicant data, and force the model to return a concise decision with rationale.
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)
def build_decision_prompt(applicant: dict) -> str:
return f"""
You are assisting an insurance underwriting team.
Use only the provided policy evidence to make a recommendation.
Applicant data:
- name: {applicant["name"]}
- debt_to_income: {applicant["debt_to_income"]}
- kyc_complete: {applicant["kyc_complete"]}
- sanctions_hit: {applicant["sanctions_hit"]}
- mandatory_disclosures_signed: {applicant["mandatory_disclosures_signed"]}
Return one of:
- APPROVE
- REJECT
- MANUAL_REVIEW
Include:
1) decision
2) short rationale
3) cited policy evidence from retrieval
"""
if passed:
response = query_engine.query(build_decision_prompt(applicant))
print(str(response))
- •Wrap it in an auditable service boundary
For production insurance workflows, store every step: raw applicant payload, rule-check result, retrieved nodes, final answer, timestamp, and model version. That gives you traceability during audits and disputes.
import json
from datetime import datetime
def approve_loan(applicant: dict):
passed, reason = hard_rule_check(applicant)
audit_record = {
"timestamp": datetime.utcnow().isoformat(),
"applicant": applicant,
"hard_check_result": {"passed": passed, "reason": reason},
}
if not passed:
audit_record["decision"] = reason.split(": ")[0]
return audit_record
response = query_engine.query(build_decision_prompt(applicant))
audit_record["decision"] = str(response)
return audit_record
result = approve_loan(applicant)
print(json.dumps(result, indent=2))
Production Considerations
- •Keep compliance rules outside the LLM
- •Sanctions screening, KYC completeness, consent checks, and mandatory disclosure validation should be deterministic code or upstream services.
- •Log retrieval context for audits
- •Store the exact chunks returned by
VectorStoreIndexqueries so reviewers can reconstruct why a decision was made.
- •Store the exact chunks returned by
- •Control data residency
- •If you handle regulated customer data in specific jurisdictions, keep embeddings and vector stores in-region and avoid sending raw PII to external systems unless your legal team has approved it.
- •Add guardrails around output format
- •Force structured outputs like
APPROVE,REJECT, orMANUAL_REVIEW, then validate them before downstream execution.
- •Force structured outputs like
Common Pitfalls
- •Letting the model decide on hard compliance failures
- •Fix this by checking KYC/sanctions/disclosure status before any retrieval or generation step.
- •Retrieving too much irrelevant policy text
- •Fix this by splitting documents cleanly and using metadata like
source,type,jurisdiction, andproduct_line.
- •Fix this by splitting documents cleanly and using metadata like
- •Skipping audit logging
- •Fix this by persisting applicant input, retrieved nodes, prompt text, model output, and final action in an immutable store.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit