How to Build a document extraction Agent Using LangChain in Python for retail banking
A document extraction agent for retail banking takes scanned PDFs, images, and uploaded forms, then pulls out structured fields like customer name, account number, income, address, and signatures. It matters because onboarding, KYC, loan processing, and dispute handling are still document-heavy workflows, and every manual review step adds cost, latency, and operational risk.
Architecture
A production-ready retail banking extraction agent needs these components:
- •
Document ingestion layer
- •Accept PDFs, images, and multi-page scans from channels like branch upload, mobile app, or back-office queues.
- •Normalize files before extraction.
- •
OCR / text extraction layer
- •Convert scanned pages into text with layout hints.
- •Preserve page boundaries for traceability.
- •
LangChain extraction chain
- •Use
ChatPromptTemplate,JsonOutputParser, and a structured model call to extract fields into a strict schema. - •Keep the output machine-readable for downstream systems.
- •Use
- •
Validation and policy layer
- •Validate required fields, format rules, and confidence thresholds.
- •Reject or route incomplete cases to human review.
- •
Audit and observability layer
- •Store source document IDs, extracted JSON, model version, timestamps, and reviewer actions.
- •Support compliance review and incident investigation.
- •
Human-in-the-loop fallback
- •Send low-confidence or ambiguous documents to an operations queue.
- •Never auto-approve regulated decisions from raw extraction alone.
Implementation
1) Define the extraction schema
For retail banking, keep the schema tight. Don’t ask the model to infer business logic; extract only what is visible in the document.
from pydantic import BaseModel, Field
from typing import Optional
class RetailBankingDocument(BaseModel):
full_name: str = Field(description="Customer full legal name")
date_of_birth: Optional[str] = Field(default=None, description="DOB in YYYY-MM-DD if present")
account_number: Optional[str] = Field(default=None, description="Masked or full account number if present")
address: Optional[str] = Field(default=None, description="Customer address")
document_type: str = Field(description="Type of document such as utility_bill, bank_statement, payslip")
issue_date: Optional[str] = Field(default=None, description="Document issue date in YYYY-MM-DD if present")
2) Load the document text with LangChain loaders
If you already have OCR output from your scanning stack, feed that into LangChain. If not, use a loader that matches your file type. For PDFs with embedded text:
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("customer_statement.pdf")
documents = loader.load()
text = "\n\n".join(doc.page_content for doc in documents)
print(text[:1000])
For scanned documents in production, OCR usually happens before this step. LangChain should receive normalized text plus metadata like page numbers and source file IDs.
3) Build the extraction chain with ChatPromptTemplate and JsonOutputParser
This pattern uses a structured prompt and a parser that forces JSON output. It’s simple to test and easy to extend.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
parser = JsonOutputParser(pydantic_object=RetailBankingDocument)
prompt = ChatPromptTemplate.from_messages([
("system",
"You extract fields from retail banking documents. "
"Return only valid JSON that matches the schema. "
"Do not guess missing values."),
("user",
"Extract the required fields from this document:\n\n{document_text}\n\n"
"{format_instructions}")
])
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
chain = prompt | llm | parser
result = chain.invoke({
"document_text": text,
"format_instructions": parser.get_format_instructions()
})
print(result)
This gives you a clean Python dictionary-like object. In practice, wrap it in Pydantic validation again before persisting it.
4) Add validation and human review routing
Retail banking cannot rely on “best effort” extraction. If a required field is missing or suspiciously malformed, route it out of automation.
from pydantic import ValidationError
def validate_extraction(payload: dict):
try:
doc = RetailBankingDocument(**payload)
return {"status": "approved_for_processing", "data": doc.model_dump()}
except ValidationError as e:
return {
"status": "send_to_human_review",
"errors": e.errors(),
"raw_payload": payload,
}
decision = validate_extraction(result)
print(decision)
You can also add deterministic checks outside the model:
- •Date formats must match
YYYY-MM-DD - •Account numbers must match your internal mask rules
- •Document type must be one of an approved list
- •Required fields for KYC must be present before downstream submission
Production Considerations
- •
Data residency
- •Keep document processing inside approved regions.
- •If you use hosted LLMs, verify where prompts and outputs are stored or logged.
- •For regulated workloads, isolate tenant data by environment and geography.
- •
Auditability
- •Persist the original file hash, OCR text hash, prompt version, model name, response payload, and validation result.
- •This is what compliance teams will ask for when a customer disputes an onboarding decision.
- •
Monitoring
- •Track extraction accuracy by document type.
- •Monitor fallback rate to human review, parser failure rate, token usage per page, and average processing time.
- •Alert on spikes by branch or channel; those often indicate scan quality issues or upstream fraud patterns.
- •
Guardrails
- •Never let the agent invent missing identity data.
- •Block high-risk actions unless a separate policy engine approves them.
- •Mask sensitive fields in logs; treat PAN-like strings and account numbers as regulated data.
Common Pitfalls
- •
Using free-form generation instead of strict structured output
- •Problem: The model returns prose or inconsistent keys.
- •Fix: Use
JsonOutputParserwith a Pydantic schema and reject invalid payloads immediately.
- •
Skipping OCR quality checks
- •Problem: Garbage input produces garbage extraction.
- •Fix: Measure OCR confidence before calling LangChain. Route blurry scans or low-confidence pages to manual review first.
- •
Treating extraction as decisioning
- •Problem: Teams start auto-approving loans or onboarding based on extracted text alone.
- •Fix: Separate extraction from policy decisions. Extraction populates fields; rules engines and compliance workflows make approvals.
- •
Ignoring traceability requirements
- •Problem: You can’t explain why a field was extracted or why a case was escalated.
- •Fix: Store source document references, page numbers when available from loaders like
PyPDFLoader, plus model/version metadata for every run.
A good retail banking extraction agent is not just an LLM wrapper. It is a controlled pipeline that turns messy documents into validated data while preserving audit trails and keeping humans in charge of exceptions.
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