How to Build a claims processing Agent Using LlamaIndex in TypeScript for insurance

By Cyprian AaronsUpdated 2026-04-21
claims-processingllamaindextypescriptinsurance

A claims processing agent takes a first notice of loss, reads supporting documents, extracts the key facts, checks policy context, and routes the claim to the right next step. For insurance teams, that matters because the bottleneck is rarely “writing an email”; it’s turning messy claimant input into a defensible, auditable decision path without leaking sensitive data or missing coverage rules.

Architecture

  • Claim intake layer

    • Accepts structured and unstructured inputs: FNOL forms, adjuster notes, PDFs, photos, emails.
    • Normalizes everything into a single claim case object.
  • Document ingestion and indexing

    • Uses SimpleDirectoryReader for internal docs and claim artifacts.
    • Builds a VectorStoreIndex over policy language, claims manuals, and SOPs.
  • Policy retrieval layer

    • Retrieves only relevant clauses: coverage limits, exclusions, waiting periods, deductibles.
    • Keeps answers grounded in source documents with citations.
  • Claims reasoning agent

    • Uses LLM-backed tools to extract fields, classify severity, detect missing info, and draft next actions.
    • Should not make final claim decisions without human review.
  • Audit and compliance log

    • Stores every prompt, retrieved chunk, model output, and tool call.
    • Needed for regulatory review, dispute handling, and internal QA.
  • Human handoff workflow

    • Routes low-confidence or high-risk claims to an adjuster.
    • Escalates fraud indicators, ambiguous coverage language, or jurisdiction-specific issues.

Implementation

1. Install dependencies and load claim documents

Use LlamaIndex TS with a local or approved model endpoint. For insurance workloads, keep policy docs and claim files in a controlled storage location and only index what you’re allowed to process.

npm install llamaindex dotenv
import "dotenv/config";
import { SimpleDirectoryReader } from "llamaindex";

async function loadClaimDocs() {
  const reader = new SimpleDirectoryReader({
    directoryPath: "./data/claims",
  });

  const documents = await reader.loadData();
  console.log(`Loaded ${documents.length} documents`);
  return documents;
}

loadClaimDocs().catch(console.error);

2. Build a policy index for grounded retrieval

This is the core pattern: index policy wording separately from claim evidence so the agent can retrieve the right clause before drafting an answer. Don’t mix internal SOPs with customer claim files unless you intentionally want both in the same retrieval space.

import { VectorStoreIndex } from "llamaindex";
import { SimpleDirectoryReader } from "llamaindex";

async function buildPolicyIndex() {
  const reader = new SimpleDirectoryReader({
    directoryPath: "./data/policies",
  });

  const policyDocs = await reader.loadData();
  const index = await VectorStoreIndex.fromDocuments(policyDocs);

  return index;
}

async function getRetrieverQueryEngine() {
  const index = await buildPolicyIndex();

  return index.asQueryEngine({
    similarityTopK: 3,
    responseMode: "compact",
  });
}

3. Create a claims assistant that extracts facts and checks coverage

For production insurance workflows, keep the agent narrow. It should extract fields like date of loss, peril type, location, policy number, and missing documents. Then it should query policy language to determine whether the claim needs manual review.

import {
  OpenAI,
  Settings,
} from "llamaindex";
import { FunctionTool } from "llamaindex";
import { VectorStoreIndex } from "llamaindex";

Settings.llm = new OpenAI({
  model: "gpt-4o-mini",
});

type ClaimInput = {
  policyNumber: string;
  lossDate: string;
  lossDescription: string;
};

async function buildClaimsAgent() {
  const policyDocs = await new (await import("llamaindex")).SimpleDirectoryReader({
    directoryPath: "./data/policies",
  }).loadData();

  const index = await VectorStoreIndex.fromDocuments(policyDocs);
  const queryEngine = index.asQueryEngine({ similarityTopK: 3 });

  const checkCoverageTool = FunctionTool.from(
    async ({ question }: { question: string }) => {
      const result = await queryEngine.query({ query: question });
      return result.toString();
    },
    {
      name: "check_coverage",
      description:
        "Searches policy documents for coverage terms, exclusions, deductibles, and waiting periods.",
    }
  );

  return {
    async assessClaim(input: ClaimInput) {
      const prompt = `
You are a claims triage assistant.
Extract whether this claim needs human review.
Return JSON with keys:
riskLevel, missingInfo[], recommendedNextStep.

Policy number: ${input.policyNumber}
Loss date: ${input.lossDate}
Loss description: ${input.lossDescription}
`;

      const response = await Settings.llm.complete(prompt);
      const coverage = await checkCoverageTool.call({
        question: `Does policy language cover this loss description? ${input.lossDescription}`,
      });

      return {
        triage: response.text,
        coverageEvidence: coverage,
      };
    },
  };
}

4. Wire in audit logging before you ship

In insurance, the output is not enough. You need traceability for what was asked, what was retrieved, and why the agent suggested escalation. Store these records in your logging system with immutable retention controls.

async function processClaim() {
  const agent = await buildClaimsAgent();

  const result = await agent.assessClaim({
    policyNumber: "POL-104992",
    lossDate: "2026-03-12",
    lossDescription:
      "Kitchen fire caused smoke damage to cabinets and appliances.",
  });

  console.log(JSON.stringify(result, null, 2));

  // Persist:
 // - input payload
 // - retrieved policy snippets
 // - model output
 // - final human decision
}

processClaim().catch(console.error);

Production Considerations

  • Keep data residency explicit

    Claims data often has jurisdictional constraints. If your policies require EU-only or country-specific storage, keep embeddings, logs, and raw documents inside that boundary.

  • Add hard guardrails for decisioning

    The agent should triage and summarize; it should not approve or deny claims autonomously. Route any denial recommendation through an adjuster or rules engine with documented rationale.

  • Monitor retrieval quality

    Track whether retrieved clauses actually match the claim type. If your top-k results are noisy, your agent will sound confident while being wrong.

  • Log for auditability

    Keep prompt versions, document versions, model version IDs, retrieval chunks, timestamps, and operator overrides. That’s what you need when a claimant disputes a handling decision.

Common Pitfalls

  • Using one giant index for everything

    Policy docs, SOPs, fraud rulesheets, and claimant evidence should not all live together by default. Separate indexes or namespaces so retrieval stays precise.

  • Letting the model invent missing facts

    If date of loss or cause of loss is absent from the file data set missingInfo instead of guessing. In claims work, hallucinated facts become compliance problems fast.

  • Skipping human review on edge cases

    Flood losses after catastrophe events are not normal claims. High severity amounts out-of-state residence issues or ambiguous exclusions should trigger escalation every time.


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