Inspiration

Loan fraud rarely comes one deal at a time. A ring files several applications that each look clean on their own: plausible financials, a real-looking guarantor, a bank statement that passes every check. What gives them away is what they share: the same bookkeeper, the same payment account, the same document software. Banks review deals one at a time, so that pattern is easy to miss until the money is gone.

We wanted a lending desk that looks across deals, catches the ring before disbursement, and leaves honest borrowers alone, including the ones whose files are just messy.

What it does

Prism runs a commercial lending desk end to end on a simulated clock:

  • Reads the bank's shared loan folder as files arrive: it identifies each document by its content, extracts the deal facts with their source, and flags missing or mismatched information.
  • Moves each deal through six stages (Intake, Credit, Committee, Product, Committed, Closed), enforces each stage's exit requirements, routes every sign-off to the right person (or their backup), and raises alerts and escalations in plain English when a deal is stuck.
  • Stops fraud rings by building an entity graph of deals and the parties, documents and accounts they share, and holding a suspicious deal before it reaches Closed, with the linked deals and earlier funded ring members named.
  • Explains itself: an interactive fraud graph shows the ring connecting as files arrive, each piece of evidence in words, and an advisory Nemotron investigation.

How we built it

A deterministic engine makes every scored decision. It is Python behind FastAPI. Given the same inputs it produces a byte-identical output file, with Nemotron on or off.

Fraud detection is unsupervised anomaly detection, measured in bits of surprise. For every observation we estimate how likely it is under the bank's own clean loan history and score it as

$$ b(x) = -\log_2 \hat{P}(x) $$

with smoothing so nothing is ever infinitely surprising. A bookkeeper used by 1 in 200 honest deals carries about \( \log_2 200 \approx 7.6 \) bits; an address shared by many deals that repaid carries almost none.

Shared entities link deals. Two deals \( i, j \) score

$$ s(i,j) = \sum_{e \,\in\, E_i \cap E_j} w_{k(e)} \cdot \omega_e \cdot b(e) $$

where \( w_k \) weights the entity type (a payment account or preparer is strong, a bank or address is weak) and \( \omega_e \) discounts entities whose past deals mostly repaid.

Evidence falls into six families: shared rare entity, sudden new activity, lookalike counterparty, document fingerprint, deposit pattern, and loan terms (shown, never votes). The hold rule requires a shared rare entity plus two other families, or plus one when the deals are tied by two independent parties (a phone and its bookkeeper count as one fact).

Thresholds come from clean data only, never from fraud examples. Each family's threshold is the 95th percentile of its score on clean, repaid history, with a floor so a thin history cannot make it trigger-happy:

$$ \tau_f = \max\left( Q_{0.95}\big(b_f \mid \text{clean}\big),\; -\log_2(1 - 0.95) \right), \qquad -\log_2(0.05) \approx 4.32 \text{ bits} $$

The config stores percentiles, not values, so every threshold recomputes from whatever history ships with a new data set.

Nemotron works around the engine, not inside the score. A Nemotron investigator runs a multi-step tool loop (up to 8 steps, 5 read-only tools over the deal graph, the deals' documents and the loan history) and writes a cited, advisory case for each held ring. A Nemotron vision model reads documents the parser cannot, and its output is checked before it can fill a field. Every call is recorded, so the demo replays offline.

The UI is React, Vite and Tailwind with a force-directed fraud graph that replays the ring forming over time, plus an Upload & run page that runs the frozen engine on a new zipped data set.

Challenges we ran into

  • Testing generalization when the real trick is hidden. Once we had studied the sample's fraud, it was no longer a fair test. We built a synthetic bench of fraud tricks, each paired with an honest lookalike twin (a family bookkeeper, a genuine sister company), so we could measure both catches and false flags.
  • Strange is not fake. Many honest small businesses look odd: round deposits, young entities, a shared accountant. Holding them would be costly, so the rule asks several independent kinds of evidence to agree.
  • Thresholds that silently switched off. Our first calibration used a fixed date window. When we shifted the history by a year, two signal families found no data to learn from and stopped firing, without any error. We now calibrate on all clean history and added a floor; that test went from \( 0\% \) to \( 100\% \) of rings held.
  • Time. Files only become visible when they arrive, the clock can jump hours at once, and every alert in between must still be raised with the right timestamp.

Accomplishments that we're proud of

  • On fraud tricks the engine was never tuned on, it holds about 95% of ring deals; on our main synthetic bench it holds 80% of ring deals while wrongly holding only 0.1% of honest lookalike twins and none of the ordinary background deals.
  • Holds happen at Intake, the earliest stage, before any money moves.
  • No sample-specific values anywhere in the detector: no names, account numbers or software strings.
  • Every scored field is deterministic and reproducible, and every hold comes with a plain-English reason a fraud analyst can check.
  • The engine survives damaged inputs (corrupt PDFs, missing files, duplicate or malformed arrivals) and still produces a valid submission.

What we learned

  • Fraud rings are cheap to build because they reuse resources, and reuse is exactly what a graph of shared entities exposes.
  • Measuring the false-alarm rate matters as much as the catch rate. A fraud model earns trust when it can say how often it is wrong on good deals.
  • Keep the AI advisory where money and audits are involved: the agent explains and investigates, and the rule engine decides.
  • Test the thing you can't see: shifting dates, thinning the history and corrupting files found real bugs that the sample never would.

What's next for Prism

  • Signals that need no shared entity, such as timing and writing-style fingerprints, to catch a ring that shares nothing visible, without loosening the hold rule.
  • Faster runs on large books so the engine scales well beyond a weekly folder.
  • Connecting every screen to the live engine (today the board, inbox and graph screens run on demo data; the Upload & run page runs the real engine).
  • A feedback loop where Fraud Ops decisions on held deals sharpen the model.

Built With

Share this project:

Updates

Submission history