How to Build a claims processing Agent Using LangChain in Python for fintech
A claims processing agent in fintech reads incoming claim documents, extracts the relevant facts, checks them against policy rules, and routes the case to the right outcome: approve, reject, request more evidence, or escalate to a human. It matters because claims handling is high-volume, time-sensitive, and regulated; if you get the workflow wrong, you create fraud risk, compliance risk, and expensive manual review.
Architecture
- •
Document ingestion layer
- •Accept PDFs, emails, images, and structured claim forms.
- •Normalize everything into text plus metadata like claimant ID, policy number, jurisdiction, and timestamp.
- •
Extraction chain
- •Use an LLM to extract claim fields into a strict schema.
- •Keep outputs structured so downstream systems do not parse free-form text.
- •
Policy and rules engine
- •Apply deterministic checks for coverage limits, waiting periods, exclusions, and required attachments.
- •Do not let the model make final eligibility decisions on its own.
- •
Retrieval layer
- •Pull policy wording, product terms, internal SOPs, and regulatory guidance from a vector store.
- •Ground responses in approved sources only.
- •
Decision router
- •Classify cases into auto-approve, auto-reject, request-more-info, or escalate-to-human.
- •Add confidence thresholds and rule-based overrides.
- •
Audit logging
- •Persist prompts, retrieved documents, model outputs, decision reason codes, and timestamps.
- •This is mandatory for fintech reviewability and dispute handling.
Implementation
1) Define the claim schema
Use Pydantic models so the agent returns structured data. This makes validation explicit and keeps your pipeline deterministic.
from typing import List, Optional
from pydantic import BaseModel, Field
class ClaimExtraction(BaseModel):
claimant_name: str = Field(..., description="Full name of claimant")
policy_number: str = Field(..., description="Policy identifier")
claim_type: str = Field(..., description="Type of claim")
incident_date: str = Field(..., description="Date of incident in ISO format")
amount_requested: float = Field(..., description="Requested payout amount")
jurisdiction: str = Field(..., description="Country or state governing the claim")
supporting_docs: List[str] = Field(default_factory=list)
missing_info: List[str] = Field(default_factory=list)
2) Build an extraction chain with LangChain
This example uses ChatOpenAI, ChatPromptTemplate, JsonOutputParser, and RunnableLambda. The pattern is simple: extract first, then run deterministic validation.
import os
from datetime import date
from pydantic import ValidationError
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.runnables import RunnableLambda
llm = ChatOpenAI(
model="gpt-4o-mini",
temperature=0,
api_key=os.environ["OPENAI_API_KEY"],
)
parser = JsonOutputParser(pydantic_object=ClaimExtraction)
prompt = ChatPromptTemplate.from_messages([
("system", "Extract claim data from the document. Return only valid JSON."),
("human", """
Document:
{document}
Current date:
{current_date}
Use this schema:
{format_instructions}
"""),
])
extract_chain = (
prompt.partial(format_instructions=parser.get_format_instructions())
| llm
| parser
)
def validate_claim(claim: dict) -> dict:
extracted = ClaimExtraction(**claim)
# Deterministic business checks
if extracted.amount_requested <= 0:
raise ValueError("amount_requested must be positive")
if extracted.incident_date > date.today().isoformat():
raise ValueError("incident_date cannot be in the future")
return extracted.model_dump()
validation_chain = RunnableLambda(validate_claim)
claim_pipeline = extract_chain | validation_chain
result = claim_pipeline.invoke({
"document": """
Claimant: Sarah Khan
Policy No: FIN-88219
Claim Type: device theft
Incident Date: 2025-03-11
Amount Requested: 1200.00
Jurisdiction: Kenya
Supporting Docs: police report, receipt
""",
"current_date": date.today().isoformat(),
})
print(result)
3) Add retrieval for policy grounding
For fintech claims you need retrieval over approved policy docs. Use FAISS for local indexing or swap in your managed vector store later. The important part is that the model answers from retrieved context only.
from langchain_core.documents import Document
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
docs = [
Document(page_content="Device theft is covered only after a 30-day waiting period.", metadata={"source": "policy_1"}),
Document(page_content="Claims above $1,000 require manual review.", metadata={"source": "policy_2"}),
]
vectorstore = FAISS.from_documents(docs, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
context_docs = retriever.invoke("device theft waiting period manual review threshold")
for d in context_docs:
print(d.metadata["source"], d.page_content)
4) Route decisions with explicit thresholds
Do not bury business logic inside prompts. Use a small router that combines extraction output with retrieval results and applies hard rules.
def decide(claim: dict) -> dict:
reasons = []
if "missing_info" in claim and claim["missing_info"]:
return {"decision": "request_more_info", "reasons": claim["missing_info"]}
if claim["amount_requested"] > 1000:
reasons.append("amount_above_auto_approval_threshold")
if claim["jurisdiction"] not in {"Kenya", "South Africa"}:
reasons.append("jurisdiction_requires_review")
decision = "escalate_to_human" if reasons else "auto_process"
return {"decision": decision, "reasons": reasons}
decision_chain = RunnableLambda(decide)
final_pipeline = claim_pipeline | decision_chain
print(final_pipeline.invoke({
"document": "Claimant: Sarah Khan ...",
"current_date": date.today().isoformat(),
}))
Production Considerations
- •
Deploy with strict data controls
- •Keep PII inside approved regions if your regulator requires data residency.
- •Use private networking to your LLM provider or self-hosted models when policy demands it.
- •
Log everything needed for audit
- •Store input document hashes, retrieved source IDs, model version, prompt version, output JSON, and final decision.
- •Fintech audit teams will ask why a claim was routed a certain way.
- •
Add guardrails around final actions
- •The agent can recommend; your backend should execute.
- •Require human approval for high-value claims, suspicious patterns, or low-confidence extractions.
- •
Monitor drift and failure modes
- •Track extraction accuracy by field type.
- •Watch for spikes in missing-info rates by jurisdiction or product line.
Common Pitfalls
- •
Letting the LLM make final payout decisions
- •Avoid this by separating extraction from policy evaluation.
- •Use deterministic code for thresholds and coverage rules.
- •
Skipping schema validation
- •Free-form text breaks integrations fast.
- •Always validate with Pydantic before writing to your claims system.
- •
Retrieving unapproved sources
- •If the retriever pulls stale SOPs or public web pages, you create compliance risk.
- •Index only curated documents with source metadata and versioning.
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