A full-stack AI underwriting pipeline that replaces the bureau score with behavioural analysis, ingesting raw transaction data and producing a structured credit decision with product recommendations. Built in Python with a cascade of NLP models, a local LLM fallback, and a human review layer for edge cases.
This project started with a personal frustration and became a technical one. Traditional credit scoring reduces financial identity to a single number that cannot distinguish hardship from risk. This pipeline takes a different approach: raw bank transactions in, cleaned and classified behavioural data through, and a confidence-calibrated underwriting decision out, complete with Canadian product recommendations and a human override workflow for rejected applicants. The system was designed to function as a real prototype, not just a demo, with offline model fallbacks, PII-free audit logging, and a Streamlit interface built for an actual advisor workflow.
Process
How it got made.
Selected stills for the project, either a in-progress image or a reference.
A full-stack AI pipeline that ingests raw bank transaction data, cleans and classifies it through a cascade of NLP models, and produces a credit-style underwriting decision with product recommendations, without relying on a traditional bureau score.
The motivation was personal. In 2020, a serious medical condition left me unable to work for two years. My credit score collapsed, not because of irresponsible behaviour, but because of circumstance. Rebuilding it took years, even though my underlying financial habits were sound throughout. That experience made the gap in the system concrete: creditworthy people are routinely excluded by a metric that cannot distinguish hardship from risk. This project is an attempt to answer the question of what underwriting would look like if it were designed today.
The pipeline moves through several stages. Raw transaction data enters via CSV upload or Plaid API, is normalized into structured dataclasses, and passes through a three-tier memo cleaning cascade: a fast lookup path for common patterns, spaCy and BERT NER for entity extraction, and a local Qwen 3 8B LLM fallback for low-confidence results. Cleaned transactions are then categorized using zero-shot NLI inference across a two-level taxonomy before a financial summary is derived and passed to an LLM for scoring, decision, and product recommendations. Anthropic claude-sonnet-4-6 is the preferred provider, with OpenAI gpt-4o-mini as fallback.
A deliberate design choice runs through the whole system: AI handles the complexity that makes manual statement review impractical at scale, but a human retains authority over consequential outcomes. When an applicant is rejected, the Decision Review tab surfaces the model's reasoning, confidence breakdown, and data signals, and gives the advisor the ability to override with written justification. Context like recovering from illness or irregular but legitimate income is exactly the kind of judgment that should not be automated away.
Every pipeline run is logged to a local SQLite audit trail, storing a SHA-256 hash of the input, score, confidence, model provenance, and data completeness signals, with no PII stored directly. Product recommendations are drawn from a curated Canadian catalogue including Wealthsimple products, with eligibility rules enforced both in the system prompt and in the product catalogue itself.
The application is built in Python 3.11 with a Streamlit frontend, Altair and Plotly for visualizations, HuggingFace Transformers for the NLP stack, llama-cpp for local LLM inference, and Plaid for sandbox banking data.






