Local AI Workflow: Teach Once, Reuse Without Inference
See how Doze uses local AI to map payment columns once, validate the result, and reconcile future exports offline, with practical setup steps and clear limits.

Teach AI Once, Then Keep It Out of the Workflow
Most business workflows don't need a fresh AI judgment every time they run. What they usually need is a reliable way to handle the one uncertain part once, save the result, and then run the rest of the process the same way every time.
Doze is an open-source experiment built around that idea. It handles a common reconciliation task: match payment processor exports to bank exports, even when the two systems use different names for the same fields. A local Gemma model suggests how the columns correspond. A person reviews the suggestion. After approval, ordinary Python code checks references and amounts - without calling the model again.
That split matters. The model doesn't inspect transaction rows, calculate balances, or decide that a mismatch is "close enough." The arithmetic is deterministic, and a one-cent difference stays a mismatch. If the mapping doesn't change, the recurring run can proceed with inference disabled.
This article explains Doze's design, its checks, and its offline operation - and what the demo does and doesn't prove. The useful idea goes beyond payment reconciliation: use AI for a bounded translation step, then make the recurring workflow inspectable and independent of the model.
Why recurring workflows keep calling AI
A lot of AI automation starts with a tempting idea: give a model a recurring task and ask it to do the work on each run. That can make sense when every input genuinely requires fresh interpretation. It's a bad default when the hard part is learning a stable rule and the rest is routine.
Take weekly payment reconciliation. A processor export might label the same value as "Payout group," while a bank export calls it "Settlement reference." The processor reports gross payments and fees; the bank shows the net amount. Someone still has to figure out which fields match, then check whether the records agree.
The sums don't need interpretation. The column labels do. Once you've established what the fields mean, asking a model to repeat that interpretation - and to do arithmetic - adds a dependency without necessarily adding anything.
Separate uncertain translation from repeatable work
A useful way to think about this kind of workflow is to split it into two phases:
- Teach: Turn ambiguous labels or instructions into a proposed, reviewable rule.
- Reuse: Apply the approved rule to new inputs with predictable software and explicit checks.
The first phase may benefit from a language model. The second often does not. Keeping them separate reduces repeated inference, makes failures easier to trace, and answers a practical operational question: what happens if the model isn't available?
In theory, a model could take both exports every week and produce a reconciliation result. In practice, that bundles several responsibilities into one opaque output: schema understanding, record matching, value calculation, and the judgment about what counts as acceptable. When something is wrong, it's harder to tell which step failed.
Doze makes a narrower, more concrete claim. It uses local Gemma to propose a mapping based on approved explanations and headers, then saves that mapping as JSON. Humans review what the columns mean. Python performs the recurring reconciliation. After that, the model isn't needed again unless the export format changes.
This doesn't mean AI is always wasteful in repeated workflows. It just means you should ask whether the model is solving a new problem each time - or being asked to repeat a decision you already made. If the decision is stable, saving and reviewing the result is often more useful than keeping inference in the execution path.
How Doze separates AI from execution
Doze draws a clear boundary between what the model handles and what the reconciliation engine does. The model gets the two sets of column headers, the chosen decimal separator, and an approved explanation for ambiguous fields. It returns a proposed mapping - or it refuses to provide one.
For example, a user might explain that "Payout group" and "Settlement reference" hold the same payout identifier. The model can translate that explanation into a mapping like this:
{
"payments": { "batch": "Payout group" },
"bank": { "batch": "Settlement reference" }
}
That's just an excerpt. The full mapping also identifies unique record IDs, gross amounts, fees, bank amounts, and currencies. And it matters that this is a data contract - something you can inspect - not generated code, not a free-form formula, and not fuzzy "instructions" about what to do.
The model proposes; a person approves
AI isn't required to create the mapping. A user can fill it in manually. The model's job is to translate a human explanation into a reusable proposal that someone can inspect and correct before it's used.
That role is intentionally limited. A mapping can look structurally valid while still being wrong. If gross and fees are swapped, the JSON format can still be correct while its meaning isn't. Doze treats a valid output shape as a starting point, not proof that the interpretation is sound.
The project's development history also shows why a "structured output" constraint isn't enough on its own. Early attempts produced refusals, including after the shared reference had been explained. The eventual change included putting the complete successful schema in the model-visible prompt and constraining each role to real header names. The refusal path and the runtime checks stayed in place.
The combined change was evaluated with three inputs and no retries: the explained studio schema mapped correctly, a different header vocabulary mapped correctly, and unknown meanings still resulted in a refusal. One local call took 4.85 seconds, and the proposed mapping passed eight fixture tests. Those are bounded results for those cases - not proof of broad model accuracy, and not proof that a single prompt change caused the improvement.
Python handles the money
After approval, the reconciliation engine uses decimal arithmetic and exact shared settlement references. It doesn't ask the model to decide whether two amounts are "close enough." A one-cent discrepancy is a mismatch.
Other issues don't get quietly guessed. They're treated as explicit problems: duplicate IDs, ambiguous transfers, unsupported or conflicting currencies, malformed rows, and schema changes. That's part of what keeps things auditable - clean runs are distinguishable from runs that require investigation.
So the model stays away from the transaction rows and from the financial decision itself. This separation helps both auditability and reliability: you can inspect the saved mapping, the inputs, the report, and the deterministic checks without having to reconstruct what a model might have inferred during a particular run.
How the project tests mappings and reconciliation
A reusable mapping needs evidence that it means the same thing for known cases. Doze's studio workflow pairs the proposed mapping with synthetic CSV fixtures and fixed expected outcomes. The expectations are authored separately from the mapping, so the model doesn't get to decide whether its own output is "correct."
The eight fixed examples cover refunds, duplicate records, missing transfers, mixed currencies, and a one-cent discrepancy. They test whether the mapping supports the intended reconciliation behavior - not just whether the output parses as JSON. In the demonstration, swapping gross and fees changes the result from eight successful checks to one. It's a practical example of why schema validation alone isn't enough.
Recheck evidence instead of trusting a badge
When a workflow is imported, the application reruns the installed witness suite. It doesn't trust an exported "passed" label. If a mapping changes, a result is forged, or bundled expectations are rewritten, it shouldn't turn a failing workflow into a passing one.
There's also an important scope boundary. Those fixtures apply to the known studio schema. They're not a universal test suite for arbitrary payment providers. A plain, human-reviewed mapping exists separately and doesn't go through the same fixture gate. That distinction is worth keeping: a test suite for one known schema shouldn't be treated as validation for every possible export format.
Approval is tied to a specific report as well, not to an abstract idea of "a clean reconciliation." Doze binds the user's approval to the hash of the exact inputs and mapping. If the input changes, the previous approval no longer applies. Workflow reports also bind the identity of the witness suite used to check them.
The handoff ZIP can include a reconciliation CSV, audit JSON, mapping, source hashes, a read-me, and - when the tested workflow is used - the workflow itself. It doesn't bundle the selected source CSV contents, and it doesn't edit the source exports. Those choices are meant to keep the output easy to inspect, rather than presenting a generated packet as a shortcut around review.
Read the demo results in context
The project's walkthrough uses synthetic exports and a clearly labeled recorded Gemma result. It doesn't run a fresh teaching call during playback. The recorded result came from a real local inference run, but replaying it doesn't require a model.
With inference disabled, the same mapping was replayed across 52 generated weeks: 41 were clean, 11 were held for review, and 19 explicit exceptions were reported. The exception count isn't a separate set of weeks to add to the other totals; exceptions are issues surfaced during the replay. These are synthetic outcomes, not a year of customer history, and they don't by themselves show time saved or real-world accuracy.
The project also reports a latest local test suite of 120 tests: 119 passed and one Windows symlink-permission test was skipped. Its CI workflow covers Python 3.11 and 3.12 on Windows and Linux, including the offline proof. Those details are useful implementation evidence - but they shouldn't be mistaken for customer validation.
How to try Doze - and where its limits are
The recorded-result route is intentionally low-friction. Python 3.11 or later is enough; there's no account, package installation, or model download required for this path. Clone the project, enter its directory, and run:
python -m doze.server
Then open http://127.0.0.1:8741, choose Replay the verified Gemma lesson / recorded result, review the mapping, and run its tests. You can then reconcile the messy week, inspect an exception, try a clean week, and run the 52-Friday replay.
This is a replay, not a fresh model demonstration. The application uses a standard-library Python backend, a plain JavaScript interface, and local Ollama inference for the teaching step. The Gemma weights aren't distributed with the project and keep their own license terms. For current project files and instructions, see the original Doze submission.
The offline boundary is more than a UI switch
Doze also provides a standard-library command-line route:
python -m doze.close_cli --profile workflow.json --payments payments.csv --bank bank.csv --mapping-approved
This execution doesn't need a browser, a web server, or Ollama. Packet creation requires the exact report hash from a previous review and a new output filename. The developer tested this in fresh Python processes with socket creation blocked; 12 checks passed, including clean and bad-week verdicts, approved ZIP creation, rejection of stale approval, and preservation of existing output files.
That's stronger evidence of offline reuse than a "model asleep" indicator in a user interface. It checks whether the execution path can actually complete without opening a network connection. For a recurring workflow, that's the difference between a design intention and something you can verify.
Know what the tool does not establish
Matching two exports tells you that the records in those exports agree under the chosen mapping. It doesn't prove the exports are complete. If a transaction is missing from both sources, a comparison between them won't see it.
Doze doesn't connect directly to bank accounts, move money, convert currencies, resolve split transfers, or provide tax advice. The project hasn't reported a real customer trial, a measured reduction in human time, or an energy-use measurement. Those aren't minor footnotes if you're deciding whether to use it operationally - they're boundaries on what the demo supports.
The same caution applies to local AI. Running inference through Ollama on a local service means the teaching inputs go to that local loopback service rather than a hosted inference endpoint. The project also doesn't do an automatic cloud fallback or hidden model download. That's a real privacy and dependency choice, but it still doesn't prove every property of a deployment environment. You still have to understand the host, the installed model, and your own data-handling requirements.
The practical benefit shown here is specific: avoid re-explaining an unchanged export format, and avoid asking a model to repeat deterministic sums. Keep human review focused on the mapping and exceptions - the parts that still need judgment.
Conclusion
Doze is useful less as an argument for "put AI into payment reconciliation" and more as a concrete example of where to stop using it. Let the model help translate ambiguous column meanings into a reviewable mapping. Then save that decision, test it against known cases, and let deterministic code handle the recurring arithmetic.
This approach has trade-offs. It doesn't eliminate human review, it doesn't validate arbitrary schemas, and it doesn't prove a business outcome. What it does do is make the dependency boundary clearer - and give operators a way to repeat the workflow without repeating inference.
If you build a recurring AI workflow, start by figuring out which decision is genuinely uncertain and which steps should behave the same way every time. Save the first decision once it's been reviewed. Then keep the rest executable, testable, and safe to run without the model. For a closer look at this implementation, read the Doze project submission and review its recorded evidence before deciding whether the limits fit your use case.