How to Build a claims processing Agent Using LangChain in TypeScript for insurance
A claims processing agent takes a FNOL or inbound claim packet, extracts the key facts, checks policy context, routes the case, and drafts the next action for a human adjuster. For insurance teams, that matters because claims are where cost, cycle time, leakage, and customer trust all collide.
Architecture
- •
Ingress layer
- •Receives email, web form, PDF, or API payloads.
- •Normalizes raw claim data into a single internal schema.
- •
LLM extraction chain
- •Uses LangChain to turn unstructured claim text into structured fields.
- •Extracts claimant identity, loss date, location, peril, damage summary, and urgency.
- •
Policy context retrieval
- •Pulls relevant policy clauses, deductibles, coverage limits, and exclusions from a vector store or document store.
- •Keeps the model grounded in approved policy language.
- •
Decision/routing layer
- •Classifies the claim into straight-through processing, manual review, SIU review, or request-more-info.
- •Applies deterministic business rules before any automated action.
- •
Audit and persistence layer
- •Stores prompts, outputs, timestamps, model version, and retrieved sources.
- •Supports compliance review and claim file traceability.
- •
Human handoff layer
- •Generates an adjuster-ready summary with citations.
- •Escalates uncertain or high-risk claims to a human queue.
Implementation
1) Define the claim schema and build the LLM extractor
Use zod for structure and StructuredOutputParser so the model returns predictable fields. In insurance workflows, free-form text is not enough; you need typed output that downstream systems can validate.
import { ChatOpenAI } from "@langchain/openai";
import { StructuredOutputParser } from "@langchain/core/output_parsers";
import { PromptTemplate } from "@langchain/core/prompts";
import { z } from "zod";
const ClaimSchema = z.object({
claimantName: z.string(),
policyNumber: z.string(),
lossDate: z.string(),
lossType: z.enum(["property", "auto", "liability", "health", "other"]),
lossDescription: z.string(),
location: z.string(),
urgency: z.enum(["low", "medium", "high"]),
});
const parser = StructuredOutputParser.fromZodSchema(ClaimSchema);
const prompt = PromptTemplate.fromTemplate(`
Extract claim details from the input below.
Return only data that matches the format instructions:
{format_instructions}
Claim text:
{claimText}
`);
const llm = new ChatOpenAI({
model: "gpt-4o-mini",
temperature: 0,
});
export async function extractClaim(claimText: string) {
const chain = prompt.pipe(llm).pipe(parser);
return chain.invoke({
claimText,
format_instructions: parser.getFormatInstructions(),
});
}
2) Add retrieval for policy grounding
For claims work, you should not ask the model to “know” coverage. Retrieve policy excerpts first and pass only approved text into the prompt. That keeps answers tied to policy documents and gives you an audit trail.
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";
import { Document } from "@langchain/core/documents";
const docs = [
new Document({
pageContent: "Section 4.2 Water Damage Exclusion applies to gradual seepage.",
metadata: { policyId: "POL-123" },
}),
new Document({
pageContent: "Deductible for wind damage is $1,000.",
metadata: { policyId: "POL-123" },
}),
];
const vectorStore = await MemoryVectorStore.fromDocuments(
docs,
new OpenAIEmbeddings()
);
export async function retrievePolicyContext(query: string) {
const retriever = vectorStore.asRetriever(3);
return retriever.invoke(query);
}
3) Combine extraction + policy context + decisioning
This is the pattern you actually want in production: extract facts first, retrieve context second, then classify with explicit routing rules. Keep the final decision step narrow so it is easier to test and govern.
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { RunnableLambda } from "@langchain/core/runnables";
const decisionPrompt = ChatPromptTemplate.fromMessages([
["system", "You are a claims triage assistant for an insurance carrier."],
["user", `
Claim data:
{claim}
Policy context:
{policyContext}
Classify this claim into one of:
- straight_through
- manual_review
- siu_review
- request_more_info
Return JSON with keys:
decision, rationale, missing_information
`],
]);
const triageChain = decisionPrompt.pipe(llm);
export async function triageClaim(claimText: string) {
const claim = await extractClaim(claimText);
const policyDocs = await retrievePolicyContext(
`${claim.lossType} ${claim.lossDescription} ${claim.policyNumber}`
);
const policyContext = policyDocs.map(d => d.pageContent).join("\n");
const result = await triageChain.invoke({
claim: JSON.stringify(claim),
policyContext,
});
return result;
}
4) Wrap it with audit logging
Insurance teams need replayable decisions. Log input hashes, retrieved documents, model name, and outputs so compliance can reconstruct why a claim was routed a certain way.
import crypto from "crypto";
function sha256(value: string) {
return crypto.createHash("sha256").update(value).digest("hex");
}
export async function processClaim(claimText: string) {
const inputHash = sha256(claimText);
const extracted = await extractClaim(claimText);
const auditRecord = {
inputHash,
model: "gpt-4o-mini",
extracted,
timestamp: new Date().toISOString(),
sourceSystem: "fnol-api",
};
// persist auditRecord to your DB / SIEM here
return auditRecord;
}
Production Considerations
- •
Compliance
- •Keep every automated decision traceable.
Store prompt versions, retrieved policy excerpts, and final outputs.
If your jurisdiction requires it,
make sure adverse decisions are explainable in plain language.
- •
Data residency
Claims data often contains PII/PHI.
Use region-specific deployment for embeddings,
vector stores,
and logs.
Do not send regulated data across unsupported regions.
- •
Monitoring
Track extraction accuracy,
manual override rate,
false SIU escalations,
and average time-to-triage.
Alert when confidence drops or when output schema validation starts failing.
- •
Guardrails
Hard-block medical advice,
settlement promises,
or coverage determinations outside approved rules.
Require human approval for low-confidence claims,
high-value losses,
litigation indicators,
or suspected fraud.
Common Pitfalls
- •
Letting the LLM make coverage decisions directly
The model should summarize and route; it should not be your source of truth for coverage. Put deterministic rules after retrieval and before any customer-facing action.
- •
Skipping structured output validation
If you accept raw text from the model, downstream systems will break on malformed dates or missing fields. Use
StructuredOutputParser, validate with Zod, and reject anything that does not match schema. - •
Ignoring audit requirements
In claims operations you will eventually need to explain why a case was routed or delayed. Persist inputs, outputs, retrieved documents IDs, model version, timestamps, and rule outcomes for every run.
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