How to Build a loan approval Agent Using LlamaIndex in TypeScript for insurance

By Cyprian AaronsUpdated 2026-04-21
loan-approvalllamaindextypescriptinsurance

A loan approval agent for insurance reviews an applicant’s policy, claims history, premium payment behavior, and underwriting rules, then returns a decision recommendation with a traceable rationale. It matters because insurance lending decisions need to be fast, consistent, and auditable without turning every case into a manual review queue.

Architecture

  • Policy and underwriting document loader

    • Ingests product rules, eligibility matrices, exclusions, and internal lending policies.
    • Usually backed by PDFs, SharePoint exports, or a document store.
  • Vector index over policy knowledge

    • Stores embeddings for retrieval of relevant clauses.
    • Lets the agent cite the exact underwriting rule behind a recommendation.
  • Applicant data adapter

    • Pulls structured data from CRM, claims systems, billing systems, and KYC/AML checks.
    • Normalizes fields like claim frequency, lapse history, and outstanding balances.
  • Decision engine

    • Combines retrieved policy context with applicant facts.
    • Produces one of: approve, reject, or manual review.
  • Audit trail logger

    • Persists prompt inputs, retrieved chunks, model output, and final decision.
    • Required for compliance reviews and dispute handling.
  • Guardrail layer

    • Blocks unsafe outputs, missing evidence, and decisions outside policy thresholds.
    • Enforces human review on edge cases.

Implementation

1) Install dependencies and load policy documents

Use LlamaIndex in TypeScript with a local or hosted LLM. For insurance workloads, keep your policy corpus clean and versioned before indexing it.

npm install llamaindex
import {
  Document,
  SimpleDirectoryReader,
  VectorStoreIndex,
} from "llamaindex";

async function loadPolicyDocs() {
  const reader = new SimpleDirectoryReader();
  const docs = await reader.loadData({
    directoryPath: "./insurance-policy-docs",
  });

  return docs.map(
    (d) =>
      new Document({
        text: d.text,
        metadata: {
          source: d.metadata?.file_name ?? "unknown",
          docType: "underwriting_policy",
        },
      }),
  );
}

2) Build the retriever-backed index

This gives the agent grounded access to underwriting rules instead of relying on model memory. That matters when you need to explain why one applicant was approved and another was not.

import { Settings } from "llamaindex";

async function buildIndex() {
  const docs = await loadPolicyDocs();

  // Configure your LLM/embedding providers in your app bootstrap.
  // Keep this aligned with your residency requirements.
  Settings.chunkSize = 1024;

  const index = await VectorStoreIndex.fromDocuments(docs);
  return index;
}

3) Create the approval workflow

For a production system, don’t let the model directly “decide” from free-form text alone. Pull relevant policy context first, then pass structured applicant facts into the reasoning step.

import { QueryEngineTool } from "llamaindex";

type Applicant = {
  applicantId: string;
  claimCount24M: number;
  latePayments12M: number;
  activePolicyYears: number;
  requestedAmount: number;
};

async function approveLoan(applicant: Applicant) {
  const index = await buildIndex();
  const queryEngine = index.asQueryEngine({ similarityTopK: 4 });

    const policyTool = QueryEngineTool.fromDefaults({
      queryEngine,
      name: "underwriting_policy_search",
      description:
        "Searches insurance underwriting and lending policy documents for approval criteria.",
    });

    const prompt = `
You are an insurance loan approval assistant.
Use only the retrieved policy context.
Return JSON with fields:
decision: APPROVE | REJECT | MANUAL_REVIEW
reason: string
policy_citations: string[]
applicant_id: string

Applicant facts:
${JSON.stringify(applicant, null, 2)}

Rules:
- If claimCount24M > 3 => MANUAL_REVIEW unless policy explicitly allows exception.
- If latePayments12M >= 2 => REJECT unless policy says otherwise.
- If activePolicyYears < 1 => MANUAL_REVIEW.
`;

    const response = await queryEngine.query({
      query: prompt,
    });

    return {
      applicantId: applicant.applicantId,
      rawResponse: response.response,
      sourceNodes: response.sourceNodes?.map((n) => ({
        text: n.node.getContent(),
        source: n.node.metadata?.source,
      })),
    };
}

approveLoan({
  applicantId: "A-10021",
  claimCount24M: 1,
  latePayments12M: 0,
  activePolicyYears: 4,
  requestedAmount: 25000,
}).then(console.log);

Why this pattern works

  • The index keeps your policy retrieval grounded in current documents.
  • The structured applicant object prevents the model from inventing missing fields.
  • The sourceNodes give you evidence for audit logs and reviewer escalation.

Production Considerations

  • Deploy in-region

    • Keep document storage, embeddings, and inference inside approved regions if your insurer has residency constraints.
    • Don’t send customer PII to an external endpoint without a data processing agreement and security review.
  • Log every decision artifact

    Persist:

    • input payload
    • retrieved chunks
    • model output
    • final decision
    • policy version hash

    This is what makes adverse-action review possible later.

  • Add human review thresholds

    Force manual review when:

    • claims exceed a threshold
    • payment history is incomplete
    • confidence is low
    • retrieved evidence conflicts with applicant data
  • Monitor drift

    Track:

    • approval rate by product line
    • manual review rate
    • override rate by underwriters
    • retrieval quality after policy updates

    Insurance rules change often; stale indexes create bad decisions fast.

Common Pitfalls

  • Using unstructured prompts as the source of truth

    Don’t ask the model to “decide based on common sense.” Always retrieve underwriting rules first and bind the answer to specific clauses.

  • Ignoring versioned policies

    If your index mixes old and new lending rules, you’ll get inconsistent approvals. Rebuild indexes per policy release and store the effective date in metadata.

  • Skipping compliance controls

    Loan approval for insurance touches regulated data. Encrypt PII at rest, restrict access by role, redact sensitive fields before logging, and keep an audit trail that ties every decision back to a specific policy version.


Keep learning

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

Related Guides