Small Open Models for Finance
A lot of the work at a bank, a broker or a fund is checking. Onboarding teams check who a new customer is before an account opens, AML teams watch transactions for money laundering, credit teams decide on a loan and then keep an eye on the borrower for years, fraud teams sort through alerts and customer reports, and research and reporting teams read filings and turn them into numbers. AI is being tried in all of it. The rules for most of this are written down in a policy or a credit manual, while the evidence arrives as scans, statements and news stories nobody tagged, and an analyst sits in the middle deciding whether a case passes, needs another document, or goes up to someone more senior.
In this post I’ll go through why those checks are hard to keep up with, what banks and funds are already doing with open models, and the way I break a finance check into steps that go to code, a small model, an agent or the analyst. Then I’ll show how that works on two examples from the SIE cookbook, a KYC check and a check of the morning news for bad news about a borrower. The KYC check is a workflow, with separate agent jobs for the odd requests it was never built for, and the news check is a hybrid, where the workflow hands the stories it can’t settle to an agent. Fraud only comes up briefly, because sorting customer messages for fraud reports is a job a plain classifier trained on your labels already does well. If you want the longer version of how to choose between a workflow and an agent, that’s in When to Use a Workflow and When to Use an Agent, which uses the same two recipes.
Why KYC Files and Borrower News Slip Through
Take the documents first. Most big banks hand that part of KYC to an identity-verification vendor, but a smaller bank, broker or credit union often doesn’t. Documents arrive by upload or post, a branch scans paper, and a remediation team goes back through old files that are scans nobody ever extracted anything from. Most cases are fine, which is what makes a case with the wrong flat number easy to miss on a Friday afternoon. An account opened without the evidence the policy requires is a finding at the next audit, whether or not the customer turns out to be fine.
The news has its own version of the problem. Vendor feeds tag listed companies with tickers, but a private borrower like “Halden Cold Storage” usually isn’t on the vendor’s list, so the stories that matter most come through untagged. Skimming for them is the job that gets dropped first in a busy week. And a bank has to be able to explain every model it relies on and every vendor it sends customer data to; the finance page has what the regulators ask for.
What Banks and Funds Already Do With Open Models
The financial firms furthest along already mix model sizes and run open models, most of them tuned on their own data:
- Bloomberg: “Our products are built on a combination of models. We have some commercial models, some open-weight LLMs, some smaller, custom language models that we build ourselves,” Wayne Barlow, its Global Head of Terminal Products, told A-Team Insight (April 2026).
- Bridgewater Associates fine-tuned Qwen3-235B to replicate its experts’ judgment on financial tasks, and by its own measurements reached 84.7% average accuracy against 78.2% for the best frontier model it evaluated, with “a 13.8x reduction in inference costs per task”.
- Capital One built Chat Concierge, the assistant on participating car dealers’ websites, on Meta’s open Llama model, customized with its own data “to meet our high performance, risk, and governance thresholds”.
- PayPal is building its agentic commerce services on NVIDIA Nemotron open models, and credits “our ability to directly fine-tune models rather than relying on less efficient prompt engineering approaches”.
In finance that makes sense to me, because a model has to fit your risk and governance rules, and that’s easier when you hold the weights and can say exactly which model produced each answer.
How I Break a Finance Check Into Steps
I start by writing down the steps of the check as an analyst does it today, and first decide whether it runs as a workflow, an agent or a hybrid of the two (I’ve written up how I decide separately, on the same two recipes). Then, for each step, I try the cheapest thing that can do it and move up only when it can’t.
Code does everything that’s a lookup or a rule: the application form from the onboarding system, the policy as rules in a file, the list of issuers the policy accepts, and the counterparty list from the loan system with the names people actually write (“Halden”, “Halden Cold Store”). If you have labels, and finance usually has years of tickets and dispositions with a human decision on each, a plain classifier comes next; in Superlinked’s study on BANKING77, a TF-IDF classifier trained on the labels reached 92.1% recall at 95% precision at spotting possible fraud, and the bank’s model risk team can review a model that simple in an afternoon. Steps that read something (turn a scan into text, point at a field, find the company names, score a story) go to a small model that returns text, a span or a score code can check. A large model writes anything that needs writing, quoting its sources, and the decision itself stays with a rule the bank signed off or with the analyst. Whether to tune a small model on your own labels is a separate question, and I wrote that up in off the shelf or fine-tuned.
Two Finance Examples, Worked Through
Both recipes are examples with synthetic data, picked because each is mostly rules the bank already wrote with a few steps in between that read a scan or a story, and both have an agent.py next to the workflow for the jobs it wasn’t built for.
Checking a KYC Case Against the Bank’s Policy
As a first example, consider a KYC analyst at a smaller bank. The analyst opens a new case: the form came from the onboarding system, the ID and the utility bill came in as scans, and the policy’s checklist sits in another window. Is the form complete, with the right kinds of documents? Does the ID give the name and date of birth on the form, and does a recent bill in that name show that address? The policy writes every one of those steps down, so the daily check in the KYC recipe is a workflow.

Python checks the form and the document types before any page is read, so a blank occupation never needs a model to notice it. Then LightOnOCR-3-4B reads each scan, including the machine-readable lines at the bottom of an ID, and gliner2-large-v1 points at each field. Every rule after that is Python, and each one compares what the models read against something they didn’t write: the check digits the issuer printed on the ID, the form, the bank’s list of who issues what, today’s date. That’s how a bill at “Flat 114, 2 Harbour Road” for a customer at flat 2, 114 Harbour Road came out for review, and how a perfectly good bill from Larkspur Mobile, uploaded as a utility bill, failed: the customer called it a utility bill, but the bank’s list says Larkspur Mobile issues phone bills, and the policy doesn’t accept those as proof of address. Each case comes out checks_passed or review with a list of what to ask the customer for, and neither one is an approval.
The weak spot is the OCR step. On one ID card it dropped a check digit on every run, so a good ID failed its check and the case went to review. The check did its job, since the issuer printed those digits and the model didn’t, but the analyst got one more thing to look at for nothing.
Pro-tip: test the OCR model on your own scans before you test anything else, because every check downstream reads what the OCR model wrote.
A few times a week the analyst gets a job the workflow was never built for, like a customer who has just moved and has no bill at the new address yet. Those are agent jobs, and the agent uses the workflow as one of its tools. The one I’ll walk through here is rarer: a letter from the regulator, which comes once or twice a year, asking for every personal account opened in 2025 on a mobile phone bill, and what was done about each. Nobody has written those steps down, because each account goes a different way (one opened on an exception a team lead approved in a note, one sent a water bill five weeks later, one was closed in August, and one is another Larkspur Mobile bill uploaded as a utility bill, with nothing recorded). So the agent works through the bank’s register of accounts, the scans and the case notes, and writes a table with one row per account and what was done about it. Code then checks that table: every quote has to be in its source, an account it calls fixed by a later document has to pass the KYC check on that document, and code reads every 2025 address scan itself to make sure no account is missing. That last check earned its keep. In all five runs the agent missed the Larkspur Mobile account, because it was reading every scan in order and ran out of its 10 tool calls first. Code found the account each time and sent it back, and after that the final table had the right four accounts with the right outcomes in every run. The money laundering reporting officer still reads and signs it. The workflow-vs-agent post walks through the letter and the customer who moved.
Spotting Bad News About a Borrower
For a second example, take a credit analyst at a commercial bank. Every morning the analyst skims the news for stories about the bank’s borrowers, most of them private companies no news vendor tags. The counterparty news recipe asks two questions per article: which borrower is it about, and is it the kind of news a credit officer has to act on. “Halden opens a new depot” and “Halden misses supplier payments” contain the same name, and only one of them is a warning. Both questions repeat every morning, so this is a workflow too.

NuNER_Zero tags companies, tickers and places, and Python links each name to one borrower on the counterparty list. GLiNER2.5-Decide then gives a probability for each of seven kinds of warning event plus none, and thresholds in a rules file decide between an alert, filed and review. Adding an event is one more line in that file, with no training.
The decision that mattered most was which text to give the event model. In one test story, a borrower’s competitor enters administration. Given the whole article, the model said insolvency at 0.84 for a dairy that’s doing fine and picking up its rival’s orders; given the borrower’s own two sentences, it said none at 0.93. The model read whatever it was given, very literally.

The workflow refuses to guess when a name belongs to two borrowers (“Northwind”) or a ticker belongs to someone else, because a guess sends a missed-payment story to the wrong credit officer. Working out which borrower those stories are about takes different digging each time, so the workflow doesn’t try. That’s what makes this a hybrid: the workflow hands just those stories to an agent that works overnight, reads the candidates’ credit files and suggests a link (for Northwind, the one whose largest customer is the parcel carrier in the story). Code checks every quote and that every candidate’s file was read. On Northwind it can’t check the pick itself, because the event model scores the story the same whichever Northwind it’s about, so the analyst confirms the pick in the morning. Sending one story to the agent costs about 400 times what the workflow spends on a story, which is fine because only a few stories a day end up there.
Run It Yourself
If you’d like to try this, start on SIE Serverless with the cookbook’s synthetic data. You need uv and an SIE API key, plus an ANTHROPIC_API_KEY if you want to run the agents:
git clone https://github.com/superlinked/cookbook && cd cookbookcp .env.example .env # then set SIE_API_KEY (and ANTHROPIC_API_KEY for the agents)cd finance/check_kyc_documents_against_policyuv run recipe.py # the daily KYC checkuv run --group agent agent.py # the odd jobsThe first calls can wait a few minutes while SIE Serverless starts the models. The news recipe in finance/alert_on_counterparty_news runs the same way, and the cookbook’s self-hosting guide covers running the models on your own GPUs once you want the scans to stay inside your network. That keeps the task-model calls in your environment, but the agents still call the Anthropic API, so run them only with data approved for that service.
Conclusion
Most finance checks are a policy someone already wrote, applied to evidence that arrives as scans and stories. You can look at your own checks the same way: let the steps the policy writes down run as a workflow, with code for the rules and a small model for each step that reads a scan or a story, give the cases the workflow can’t settle to an agent with code checking its work, and keep the decision with the analyst.
I’d like to hear which rule in your policy breaks it first. Until next time.