What AI Actually Does in Loan Underwriting
(Part 1): The Architecture

A walk through the AI loan underwriting stack we rebuilt with a mid-size NBFC over 14 months: what each model really does, what the rules engine decides, and what still lands on a human underwriter’s screen.

AI loan underwriting architecture featured image showing loan department, investor desk and gold loan with automated approval process

A walk through the AI loan underwriting stack we rebuilt with a mid-size NBFC over 14 months: what each model really does, what the rules engine decides, and what still lands on a human underwriter’s screen.

Marketing decks describe AI loan underwriting as one black box that decides loans. The stack I helped rebuild at a mid-size NBFC looks nothing like that. It has about 14 components, five scoring models in the serving path, one rules engine, and a pile of data plumbing that took us 14 months to get right. In this article I walk through that stack one component at a time, in the order a loan application touches it. Half of it is plumbing. The other half is statistics that predate the marketing by decades.

Key Takeaways

  • AI does not approve your loan. A policy written by the risk team decides which threshold the model’s score has to clear.
  • Our stack uses about 1,200 features and five scoring models (XGBoost, LightGBM, GraphSAGE, LSTM, logistic regression) held together by code and rules, not one giant model.
  • Auto-approved loans finish in under a minute. The ambiguous 12% still go to a senior underwriter, who often picks up the phone.
  • Models took weeks. Data plumbing that keeps features identical between training and serving took 14 months, and that is where the money went.

What Is Inside

The Misconception That Got Us Here

A borrower in a tier-2 Indian city applies for a personal loan on their phone and gets approved in 47 seconds. The next week, the NBFC’s marketing team puts “AI approved your loan in under a minute” on a billboard. I have argued about that sentence with three different marketing teams now. It packs three claims into one line, and only the last one is true.

AI did not approve the loan. A policy did. The policy on our project said: if the risk score is below 0.18, the fraud score is below 0.05, and the applicant has no active default at any bureau, route to auto-approval. The models produced the two scores. A human wrote the policy. A different human, the Chief Risk Officer, signs off on those thresholds every quarter and takes the heat if defaults climb past 4.2%. Once I started seeing it that way, the whole architecture stopped feeling mystical.

The CRO told me something in our first week that held up for the entire engagement. We were not replacing underwriters with anything. We were replacing the parts of their job that were mechanical. The judgement part stayed with them. The paperwork part went to the models. I did not fully believe it at the time, because the vendor pitches we had sat through said the opposite. Fourteen months later it was the most accurate summary of what we had built.

What the NBFC Had Before the Rebuild

When we started in early 2023, the NBFC (a non-banking financial company, which is a lender licensed by the RBI but not a deposit-taking bank) ran its underwriting like this. An applicant filled out a form on the app. The form produced a PDF. The PDF landed in a queue. A junior underwriter opened it, pulled a CIBIL report (CIBIL is India’s oldest consumer credit bureau) in a browser tab, and worked out FOIR on a calculator. FOIR is the fixed obligation to income ratio, the share of monthly income already committed to EMIs. Then they read three months of bank statements the applicant had emailed in and stamped one of four decisions on the file.

Simple cases took about 40 minutes. Contested cases went to a senior underwriter. The senior queue sat at 11 days during festival season, and I watched it happen in October 2023 while we were still in discovery.

The old process looked at roughly 18 variables per applicant. CIBIL score, FOIR, employer name, salary credits, last-six-months EMI outgo, self-declared obligations, age, city, loan amount, tenure, product code, and a handful of KYC fields. That was it. Everything else inside the bank statements, the UPI history, the device, or the employer’s stability was invisible to the decision. Not ignored. Invisible, because nobody had the time to read 800 transaction lines by hand.

Below is the legacy flow as we mapped it in the first month. Stops marked red are where the NBFC was losing money, time, or consistency.

Free to use, share it in your presentations, blogs, or learning materials.
AI loan underwriting legacy manual system block diagram showing eight pain points
Legacy underwriting line at the NBFC before the rebuild. Red stops mark where money, time, or judgement leaked.

Each red stop had a failure pattern behind it, and the NBFC’s own internal audit had already surfaced most of them before we arrived. At stop 2, about 9% of salaried applicants were getting rejected as “thin file” because their CIBIL history was under 24 months old. Their bank statements, meanwhile, showed three years of steady salary credits from the same employer. At stop 4, the underwriter had no way to see that an applicant was putting 40% of take-home into Dream11, because the only data surface was a PDF nobody had time to read line by line.

Stop 6 was the one that got the CRO’s attention. Decisions were getting overturned on appeal at 7.2% per quarter, which told the risk team the first-pass judgement varied a lot between underwriters. All of this was survivable at 40,000 applications a month. By the time volume crossed 180,000, the queue hit 11 days and the business was losing roughly ₹3.4 crore a month to applicants who walked off to faster competitors. That number is what funded the rebuild.

What Changed On Paper Versus Underneath

The on-paper change is easy to describe. Median cycle time went from 3.4 days to 47 seconds for 62% of applications. Auto-approval climbed from 41% of volume to 88%. Bad debt fell from 5.1% of book to 3.9%. Cost to originate dropped from ₹1,840 per loan to ₹310. Those are the four numbers that went into the board deck.

The change underneath is harder to describe, and it is the whole point of this article. We did not buy a product that “does AI loan underwriting.” We built a stack. The stack has about 14 distinct components, and each one does a single job. Some of those components are machine learning models. Most are not. The ones that are not hold the ML parts together.

Here is the thing I would tell anyone starting a similar project. The models are the small part. The hard work was never training a risk model. Our data science team had a working XGBoost scorer in about two weeks, and it was decent. The 14 months went into making sure that when an application comes in at 3:14 AM, the right 1,200 features land in front of that model within 800 milliseconds. And that those features mean the same thing they meant when the model was trained six weeks earlier. Without that plumbing the model sees garbage and scores garbage, and it does so with total confidence.

Anatomy of the Underwriting Engine

The diagram below is a simplified version of the architecture drawing that ended up on the wall of the NBFC’s engineering bay. The wall version has about 80 boxes. This one keeps the five horizontal lanes. Each lane is one stage in the life of a loan application, and the lanes run left to right because that is how the data flows.

Free to use, share it in your presentations, blogs, or learning materials.
AI loan underwriting architecture block diagram with ingestion feature store model serving decision and feedback lanes
The five lanes of the underwriting stack. Each lane is one stage in a loan’s life.

I will take each lane in turn, in the order the data touches it.

Lane 1: Ingestion

This is the border crossing. Everything the system will ever know about the applicant enters here. When an application hits submit, we pull from seven sources in parallel. The app sends the form payload. An account aggregator fetches six months of bank transactions; in India that runs on the Sahamati AA framework, which is the regulator’s answer to Plaid. CIBIL, Experian, and CRIF get hit at the same time for credit history. The NSDL endpoint confirms the PAN is valid. The device SDK inside the app ships up a fingerprint: OS version, SIM metadata, device model, location drift over the last week, and whether we have ever seen this device against a different PAN in our own history.

All of that lands in an orchestration service we wrote in Go. Its job is to fire the seven calls in parallel, time each one out at 4 seconds, and fan the results into the next lane. If one source is slow, the orchestrator does not wait. It records “bureau_experian: timeout” as a feature and moves on. We argued about that timeout for two weeks. The risk team wanted 8 seconds so fewer bureau pulls would be lost. The product team wanted 2 seconds. We settled on 4 after measuring that Experian’s p95 was 3.1 seconds and its p99 was north of 9, so waiting longer bought almost nothing. That missing-bureau feature matters later, and Part 2 comes back to it.

Lane 2: Feature Engineering and the Feature Store

This is the lane where a PDF bank statement turns into 1,247 numbers. We built the feature store on Feast, the open source project, with Redis as the online cache and a Postgres-backed offline store for training data. A feature store has one specific, important job: every feature the model was trained on has to exist, in the same form, at serving time. If the model learned on a feature called avg_monthly_salary_credit_last_3m, that number has to be computable live from whatever the account aggregator returns. It also has to be computed the exact same way the training pipeline computed it.

That second half bit us early. In month four, the training pipeline computed that feature on calendar months while the serving path used a rolling 90-day window. Same name, different number. The model had been scoring slightly wrong for 11 days before a data engineer caught it while chasing an unrelated bug. Nobody outside the team noticed, because the error was small and the policy thresholds absorbed it. It was still the moment we stopped treating the feature store as optional. A typical feature definition in Feast looks like this:

YAMLfeast/features/salary_stability.yaml
 1# Feast feature view for salary stability signals
 2feature_view:
 3  name: applicant_salary_stability
 4  entities: [applicant_id]
 5  ttl: 90d
 6  schema:
 7    - name: avg_monthly_salary_credit_last_3m
 8      dtype: Float32
 9    - name: salary_credit_date_stddev_days
10      dtype: Float32
11    - name: employer_tenure_months
12      dtype: Int32
13    - name: salary_dip_count_last_6m
14      dtype: Int32
15  source: postgres_account_aggregator

The file above registers four features under one view. The training pipeline reads them from Postgres. The serving path reads the same four features from Redis. Both go through the same definition, so the calendar-month versus rolling-window mismatch we hit in month four cannot happen again by construction. That is the entire value of a feature store, and it is worth more than any model choice we made.

The feature store now has about 1,200 features registered. They break down roughly like this. Bureau features, about 180. Bank-statement derived features, around 620. Device and behavioural features, about 140. UPI-derived features (merchant categories, counterparty stability, gambling and gaming merchant flags), around 180. Employer stability features from EPFO UAN lookups, about 60. Self-declared form features, around 30. The model does not use all of them on every application. It uses whatever signals are present, and we trained it to tolerate missing inputs instead of failing on them.

Behind the feature store sits a transaction categorisation engine. When 847 UPI transactions land, something has to tell the system that “ZOMATO-BL-274829” is food, “DREAM11” is gaming, and “RENT PAYMENT OCT” is rent. We use a fastText classifier with a rule-based overlay for the long tail. It is not glamorous work. However, it is fast, and after two years of corrections from the underwriters it sits at about 96.1% accuracy on Indian merchant strings. The first version was closer to 88%, and most of the gap was regional grocery chains and petrol pumps with creative spellings.

Lane 3: Model Serving

Here is where the inference happens, and where most of the confusion about “AI” lives. We run five scoring models at this stage. There is no single big model. Each one has a narrow job and a narrow output, and I will go through them in the order the decision engine reads them.

The primary risk scorer is an XGBoost model. It takes roughly 380 features and produces a probability of default within the next 12 months. We trained it on about 4.6 million historical loans, including defaults, pre-payments, and normal closures, and it retrains monthly on a rolling window. It sits behind FastAPI, responds in about 24 milliseconds, and returns both a score and the top 15 SHAP values that drove it. SHAP stands for Shapley additive explanations, which are per-feature contributions to a single prediction. Those top features feed the adverse action notice later, which Part 2 covers in detail.

The second model is a fraud scorer. It uses LightGBM on a different feature set and looks for synthetic identities, manipulated documents, and duplicate device-PAN combinations. A separate Graph Neural Network (GraphSAGE) runs on top of the NBFC’s historical application graph. It flags cases where an applicant sits within two hops of five known defaulters who share a device or an address. This one matters more than it sounds. On our book, about 1.4% of applications trigger the graph model, and that 1.4% accounts for 11% of the rupee value of prevented fraud. I would not have predicted that ratio before we had the data.

The third is an income verification model, an LSTM over the salary credit time series. It predicts whether the self-declared income on the form is within 15% of the salary pattern visible in the bank statement. If someone declares ₹85,000 a month and the credits suggest ₹52,000, it flags the file. This is not fraud detection, it is plausibility checking, and it catches honest over-declaration just as often as dishonest.

The fourth is a Large Language Model, and we placed it very carefully. Its only job is to summarise the applicant’s bank statement into a paragraph a human underwriter can read in 30 seconds. It does not decide anything, and it does not score. What it writes is something like “Applicant shows steady salary credits of ₹48,200 on the 28th of every month for nine months, with discretionary spending concentrated in food delivery and fuel, and no gambling or lending-app activity.” That paragraph appears on the underwriter’s screen when a case goes to manual review. The decision stays with the human. We had one vendor push hard to let the LLM score applications directly. We said no, and Part 2 explains why that was the right call.

The fifth is a plain logistic regression, and the CRO insisted on it. It runs in parallel with XGBoost and its job is to be the regulator-friendly baseline. If the RBI (the Reserve Bank of India, the central banking regulator) asks how a decision was made, we can point at the logistic regression, show every coefficient, and explain the arithmetic on a whiteboard. XGBoost is more accurate. The logistic regression is more defensible. We keep both because two different audiences need them.

Lane 4: Decision Engine

The five model outputs, the feature vector, and a set of hard rules all land in the decision engine. The hard rules are the boring ones: no loans to anyone on the OFAC or RBI wilful defaulter lists, no loans to anyone under 21, nothing above ₹8 lakh without manual review. The decision engine is a rules engine, not a model. We run Drools, and we have a lighter Go replacement in prototype because Drools has become the slowest hop in the chain.

The engine produces one of four routes. Auto-approve. Approve with modified terms (lower amount, higher rate, or shorter tenure). Route to a human underwriter. Auto-decline with reason codes.

The thresholds separating those routes are not machine-learned. The CRO and the risk team set them every quarter based on the portfolio’s actual default performance, market conditions, and regulatory guidance. When the rupee weakened in Q3 2024, the CRO tightened the auto-approve threshold from 0.22 to 0.18 probability of default. The model did not change that week. The policy did. This is the single most underrated fact about AI loan underwriting, and it took me a while to appreciate how much of the risk posture lives in that one YAML file. The model gives you a number. A human decides what to do with that number, and that decision is where the real risk sits.

Lane 5: Feedback and Retraining

Every decision, plus every outcome (paid on time, paid late, defaulted, prepaid), flows back into the offline feature store. MLflow records which model version decided which loan. When we train a new version, it shadow-scores live traffic against the production model for two weeks before promotion. If the new model’s default prediction accuracy is within 0.3% of production and its calibration on the most recent month is better, it becomes champion. Otherwise it stays as a challenger or gets thrown away. About a third of our candidates get thrown away.

This is the lane vendors hide. It is unglamorous, it is where drift detection lives, and it is where every production incident we have had originated. Part 2 is mostly about what goes wrong here.

Which Model Does Which Job

The model-to-job map below is the cleaned-up version of the whiteboard we kept redrawing during the build. Five of these models sit in the scoring lane. The other three (document extraction, transaction categorisation, and the LLM summary) sit around it. If you remember one image from this article, make it this one.

Free to use, share it in your presentations, blogs, or learning materials.
AI loan underwriting model function map showing XGBoost LightGBM GraphSAGE LSTM logistic regression and LLM mapped to specific jobs
Eight jobs, eight model choices. Each model was picked for the shape of the problem, not because it was fashionable that quarter.

The table spells out the “why” for each pairing. These are the reasons we put in writing when the CRO asked us to justify every model choice, one row at a time.

FunctionModelWhy this one
Primary risk score (PD)XGBoostTabular data champion, handles missing values, fast, SHAP-explainable for adverse action
Fraud scoringLightGBMFaster than XGBoost on wide sparse feature sets, similar accuracy, lower memory
Synthetic identity and ring fraudGraphSAGE (GNN)Operates on the applicant-device-address graph; tabular models cannot see relationships
Income stabilityLSTMSalary credits are a time series; LSTM captures cadence, seasonality, and dips
Document field extractionLayoutLMv3Reads structure of pay slips and ITR forms, not just text
Transaction categorisationfastText + rulesMillions of merchant strings per day, needs to be cheap and fast, rules cover long-tail edge cases
Bank statement summary for humanLLM (Llama-3 class)Only model that produces readable prose; kept out of the decision path deliberately
Regulator-facing baselineLogistic regressionEvery coefficient is explainable, satisfies RBI audit expectations, calibrates deviations from XGBoost

Look at what is missing from that table. There is no giant foundation model that does everything, and no single neural network that takes the application and spits out a decision. Each model has one job, and code and policy stitch the jobs together. This is what a working AI loan underwriting stack looks like once you scrape the marketing off.

One Application, Step By Step

The best way to feel how this holds together is to follow one real application end to end. The example below comes from our anonymised production logs, with the name and PAN changed. It is a real approval from a Tuesday in February 2026.

The applicant is a 29-year-old software engineer earning ₹87,000 a month, asking for a ₹3,50,000 personal loan over 36 months. She taps submit at 11:42:18 AM.

  • T+0.0s: The app fires the application payload at the ingestion orchestrator. Seven parallel calls go out (three bureaus, account aggregator, PAN, EPFO UAN, device fingerprint lookup).
  • T+0.2s: CIBIL returns first with a score of 782 and a thin-but-clean credit history.
  • T+1.1s: The account aggregator returns 184 days of bank statements from HDFC. 847 transactions.
  • T+1.4s: The categorisation engine labels all 847 transactions. Food 18%, rent 23%, fuel 4%, investments 11%, zero gambling, zero lending-app activity.
  • T+2.1s: Feature engineering produces 1,194 features for the applicant. Some are null because she has no credit card history; the feature store records those as nulls and the model handles them.
  • T+2.3s: XGBoost scores: probability of default within 12 months = 0.071. LightGBM fraud score = 0.009. GraphSAGE flag = none. LSTM income stability = 0.94. Logistic regression PD = 0.082.
  • T+2.4s: Decision engine: PD < 0.18 threshold, fraud < 0.05 threshold, no ring flag, declared income (₹87,000) within 6% of the LSTM estimate (₹82,400). Route: auto-approve.
  • T+2.5s: KYC and agreement generation triggered in parallel.
  • T+47s: eNACH mandate signed, agreement eSigned via Aadhaar OTP, funds queued for the next NEFT cycle.
Free to use, share it in your presentations, blogs, or learning materials.
AI loan underwriting timeline walkthrough 47 second approval from tap submit to eNACH signed, including bureau pulls, account aggregator, categorisation, feature engineering, model scoring, decision engine, and disbursal
A single loan application, station by station, from tap-submit to funds queued. The model decision lands at 2.4 seconds. The rest of the 47 seconds is eSign and Aadhaar OTP, which the lender does not own.

47 seconds from tap to approval. Most of that was eSign and Aadhaar OTP, which we do not control. The AI decision itself took 2.4 seconds, and most of that was waiting on bureaus. The inference was 24 milliseconds. When people ask me why we cannot make it faster, the honest answer is that the 45 seconds we do not own are the ones the borrower feels.

Now compare a case from the same day that did not auto-approve. A 34-year-old self-employed restaurant owner wants ₹6,00,000. CIBIL is 701. The bank statements show seasonal cash deposits that look nothing like a salaried pattern. Declared income is ₹1,40,000 a month; the LSTM estimates ₹78,000. XGBoost PD comes in at 0.21. So the decision engine routes the file to a human underwriter with the one-paragraph LLM summary on screen. Our underwriter spends 11 minutes on it, approves ₹3,00,000 over 24 months at a higher rate, and writes a note explaining why. Fourteen minutes after tapping submit, the applicant has an answer. No model approved this loan. A person did, with the model’s help.

Those are the two modes the whole architecture is built around. A fast lane for cases where the signals are clean, and a human lane for everything else. On our book the split sits at 88% fast, 12% human, and it has stayed within two points of that for a year.

What Comes Next

Everything above is the part that works. The architecture is mostly boring engineering once you see it drawn out. Most of the models came off the shelf. Fourteen months of data plumbing is where the real investment went. Decision boundaries are set by people, not algorithms, and they get revisited every quarter.

What I have not covered is where all of this breaks. It does break, and we have the incident reports to prove it. Thin-file borrowers were the first casualty. Then the model drifted, because festival-season spending looks nothing like regular spending. Later a proxy feature learned to discriminate on pincode, and compliance only caught it at audit. And in a quieter way, it broke when a declined borrower asked why and the reason codes we produced were not reasons a person could act on.

If this walkthrough made sense, the interesting half of the story is the part where it goes wrong. Part 2 covers the real numbers from Upstart and J.P. Morgan, the three failure modes our risk team now monitors every week, the adverse action notice problem, and what the senior underwriter does now that 88% of loans never reach their desk. Part 2 is here.

Related Reading


References


Frequently Asked Questions

Does AI actually approve my loan?

No. AI produces a risk score and a fraud score. A policy written by the risk team and signed off by the Chief Risk Officer decides the threshold below which a score gets auto-approved. If you were approved in 47 seconds, a policy approved you, not a model.

Is XGBoost better than deep learning for credit scoring?

For tabular bureau and bank-statement data, yes. Deep learning only wins when the inputs include unstructured data such as document images or time series.

Which machine learning model is used for loan underwriting?

Most AI lenders, including the one in this article, use XGBoost or LightGBM as the primary risk scorer. These are gradient-boosted tree models, not neural networks, and they work well on tabular financial data. A Graph Neural Network runs separately for fraud ring detection, and a logistic regression runs alongside as a regulator-facing baseline.

How many data points does an AI loan system look at?

Between 800 and 1,500 features per application is typical. Our feature store holds about 1,200, covering bureau data, bank statement patterns, UPI merchant categories, device fingerprint signals, and employer stability. A traditional underwriter looked at roughly 18 variables.

What is SHAP in loan underwriting?

SHAP values show which features pushed the risk score up or down on a specific application. Lenders use them to produce adverse-action reason codes that a borrower can act on.

Why does a loan application get routed to a human if AI is doing the work?

About 12% of applications land in ambiguous territory: the risk score is neither clearly low nor clearly high, or the applicant’s profile has contradictions the model was not trained on. These go to a senior underwriter who reviews the model’s output plus a generated summary of the file, and often makes a phone call.

Does an AI lender still need my Aadhaar?

Yes, for KYC and for eSigning the eNACH mandate and loan agreement. That step is driven by the regulator, not by the AI model.

How long does an AI underwriting decision actually take?

The model inference takes 20 to 50 milliseconds. The full decision, including bureau pulls and account aggregator calls, takes 2 to 5 seconds. The end-to-end customer experience, including KYC, eSign, and eNACH, takes 30 seconds to 2 minutes for an auto-approved case.