How to Build a claims processing Agent Using LangChain in Python for insurance
A claims processing agent takes a first notice of loss, extracts the relevant facts, checks policy context, classifies the claim, and drafts a structured outcome for human review. For insurance teams, this matters because claims are high-volume, document-heavy, and expensive to process manually; the agent reduces handling time while keeping compliance, auditability, and escalation controls intact.
Architecture
- •
Input layer
- •Accepts claim emails, FNOL forms, adjuster notes, PDFs, or OCR text.
- •Normalizes raw content into a consistent claim payload.
- •
Extraction chain
- •Uses an LLM to pull out policy number, date of loss, loss type, location, parties involved, and supporting evidence.
- •Returns structured JSON instead of free-form text.
- •
Policy retrieval
- •Pulls relevant policy language from a vector store or document index.
- •Grounds decisions in actual coverage terms and exclusions.
- •
Decision workflow
- •Classifies the claim as straight-through eligible, needs human review, or likely denied.
- •Applies business rules before any final response is produced.
- •
Audit trail
- •Stores prompt inputs, model outputs, retrieved policy snippets, and final decision metadata.
- •Supports internal audit and regulator review.
- •
Human escalation path
- •Routes ambiguous claims to an adjuster with a concise summary and evidence bundle.
- •Prevents unsupported automation on edge cases.
Implementation
1. Install the LangChain pieces you actually need
For this pattern, keep dependencies narrow. Use langchain, langchain-openai, and pydantic for typed extraction.
pip install langchain langchain-openai pydantic
Set your model key in the environment:
export OPENAI_API_KEY="your-key"
2. Define the claim schema and extraction chain
Use PydanticOutputParser so the agent returns structured fields that downstream systems can trust. This is better than parsing raw markdown or hoping the model formats JSON correctly.
from typing import Literal
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
class ClaimExtract(BaseModel):
policy_number: str = Field(description="Insurance policy number")
date_of_loss: str = Field(description="Date of loss in ISO format if possible")
loss_type: Literal["auto", "property", "health", "liability", "other"]
claimant_name: str
summary: str
severity: Literal["low", "medium", "high"]
parser = PydanticOutputParser(pydantic_object=ClaimExtract)
prompt = ChatPromptTemplate.from_messages([
("system", """
You extract insurance claim data from incoming claim descriptions.
Return only data that is explicitly supported by the input.
If a field is missing, infer conservatively and mark it as 'other' or leave it blank when allowed.
{format_instructions}
"""),
("human", "{claim_text}")
]).partial(format_instructions=parser.get_format_instructions())
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
extract_chain = prompt | llm | parser
claim_text = """
Policy: POL-88321. On 2025-03-14 the insured reported water damage after a burst pipe.
Claimant: Maria Chen. The kitchen floor and cabinets were damaged.
"""
result = extract_chain.invoke({"claim_text": claim_text})
print(result.model_dump())
3. Add policy retrieval so decisions are grounded in contract language
In production you would back this with a vector store like FAISS or pgvector. The important part is that the agent does not decide coverage from memory; it retrieves policy text first.
from langchain_core.documents import Document
policy_docs = [
Document(
page_content="Water damage caused by sudden pipe burst is covered unless due to neglect.",
metadata={"policy_id": "POL-88321", "section": "property.coverage"}
),
Document(
page_content="Gradual seepage and wear-and-tear are excluded.",
metadata={"policy_id": "POL-88321", "section": "property.exclusions"}
)
]
def retrieve_policy_snippets(policy_number: str):
# Replace with vector search in production
return [doc.page_content for doc in policy_docs if doc.metadata["policy_id"] == policy_number]
4. Generate a triage decision with guardrails
Use a second prompt to combine extracted facts and retrieved policy snippets into a recommendation. Keep it explicit: recommend review status, not final payment authority.
decision_prompt = ChatPromptTemplate.from_messages([
("system", """
You are a claims triage assistant for an insurer.
Use only the provided claim facts and policy excerpts.
Do not make unsupported legal conclusions.
Return:
1) triage_status: one of APPROVE_FOR_REVIEW, NEEDS_HUMAN_REVIEW, DENY_RECOMMENDATION
2) rationale: short explanation
3) missing_info: list of missing facts needed for final handling
"""),
("human", """
Claim facts:
{claim_facts}
Policy excerpts:
{policy_excerpts}
""")
])
decision_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
decision_chain = decision_prompt | decision_llm
claim = extract_chain.invoke({"claim_text": claim_text})
snippets = retrieve_policy_snippets(claim.policy_number)
decision = decision_chain.invoke({
"claim_facts": claim.model_dump_json(indent=2),
"policy_excerpts": "\n".join(snippets)
})
print(decision.content)
Production Considerations
- •
Keep humans in the loop for adverse decisions
- •Do not let the agent issue denials autonomously.
- •Route low-confidence or exclusion-based outcomes to an adjuster for sign-off.
- •
Log every decision input
- •Store extracted fields, retrieved policy sections, model version, prompt template version, timestamp, and reviewer ID.
- •This is non-negotiable for auditability and dispute handling.
- •
Control data residency
- •Claims data often contains PII/PHI and jurisdiction-specific records retention requirements.
- •Use region-bound deployments and avoid sending sensitive content to unapproved model endpoints.
- •
Add deterministic guardrails before generation
- •Validate required fields like policy number and date of loss with Python rules before invoking downstream steps.
- •If critical fields are missing, stop early and request more information instead of letting the model guess.
Common Pitfalls
- •
Letting the model invent coverage conclusions
- •Fix this by separating extraction from recommendation.
- •The LLM can summarize evidence; final coverage determination should be rule-based or human-approved.
- •
Skipping structured output
- •Free-form responses break integrations with claims platforms.
- •Use
PydanticOutputParser,StructuredOutputParser, or tool calling so every field has a schema.
- •
Ignoring jurisdictional constraints
- •Insurance workflows vary by state and country on notices, disclosures, retention periods, and denial language.
- •Build jurisdiction metadata into prompts and routing logic so one generic workflow does not handle every market.
- •
No traceability across retrieval and generation
- •If you cannot show which policy clauses influenced a recommendation, you will struggle during audits or complaints.
- •Persist retrieved documents alongside the generated output for each case.
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