Large language models are non-deterministic: the same prompt can return different answers. Financial operations are the opposite – a reconciliation is right or wrong, and every entry has to be auditable. TellMe, Embat’s treasury AI agent, is built around that tension. The design principle we keep coming back to is simple: let the model interpret intent, and let deterministic code do the work.
This post is about how we hold those two things together in production – the architecture, the trade-offs we made, and the guardrails that let an unpredictable model operate safely on top of a very predictable general ledger.
Why financial software can’t just trust an LLM
When a treasurer asks “reconcile last week’s bank statements” or an invoice lands that needs to be matched to a payment, there is exactly one correct outcome. The amounts have to tie out to the cent. The ledger account has to be the right one. And six months later, an auditor has to be able to ask why a given entry was booked and get a real answer.
An LLM is fantastic at the first half of that problem – understanding a messy transaction description, mapping “the Iberia flights” to a supplier, reading a PDF invoice – and structurally unsuited to the second half. It will happily invent a plausible-looking ledger account code, or return a slightly different answer on a retry. So the question we started from wasn’t “how do we make the model more accurate?” It was: how do we use the model only for the part it’s good at, and never let its output be the thing that moves money?
TellMe’s shape: one agent core, many vertical domains
TellMe has two runtimes that reflect two different jobs.
The first is a real-time conversational agent. A single agent core powers every way a user talks to TellMe – the in-app chat, Slack, Microsoft Teams, and an MCP server for external agents all share the same graph and the same streamed event format. Adding a channel means adapting transport and identity, not rewriting the agent.
The second runtime is a set of event-driven domain pipelines, each owning one vertical: data enrichment, categorisation, accounting and reconciliation, treasury forecasting, accounts receivable forecast date prediction, etc. These run as independent serverless functions that react to events. When new bank data arrives, each domain reacts to it in turn and does its own narrow job. Keeping the domains separate means each one can pick the right technique for its problem instead of forcing everything through a single “AI” box.
The stack underneath is deliberately boring where it can be: a managed cloud runtime for the agent, event-triggered serverless functions for the pipelines, a document store as the system of record, a vector index for similarity search, and a leading general-purpose model as the default LLM. Boring infrastructure is easier to reason about when the interesting part is already unpredictable.
The core split: interpretation to the model, execution to deterministic code
The pattern that repeats across every domain is a hybrid one: a cheap, deterministic method runs first, and the LLM is only invoked when determinism isn’t enough – and even then its answer is treated as a proposal, not a fact.
Categorisation is the clearest example. A new transaction is first compared against the company’s own history of already-categorised transactions. When that history points clearly to a single answer, the category is applied directly – no LLM involved, and the result is fully reproducible. Only when the match is ambiguous do we fall back to the model, and its answer is then treated differently.
That difference in handling is the whole point. A deterministic match against the company’s own history can be applied automatically, because it’s traceable and repeatable. A category the LLM reasoned its way to is never written straight to the ledger – it becomes a pending suggestion a person reviews. The model widens what TellMe can understand; it never gets the final say on what gets booked.
Ask mode: turning a plain-language request into a safe action
Everything so far runs in the background. Ask mode is where a user meets TellMe head-on – and it’s the clearest illustration of this article’s thesis, because it puts a free-form, non-deterministic conversation directly against operations that have to stay exact.
Ask mode is one of TellMe’s three interaction modes, alongside Guided (copilot) and Silent (autopilot). It pairs a conversational chat with a set of predefined workflows, so a treasurer can either type “why hasn’t the Iberia invoice been reconciled?” or pick a ready-made workflow and let TellMe run it. Behind that single text box is an agent graph, not a single prompt.
The graph has two layers. A top-level orchestrator agent does one job: work out what the user actually wants and route it. It never touches financial data itself. Underneath sit domain agents that mirror the verticals – categorisation, reconciliation and accounting, enrichment, treasury and forecasting. Each domain agent is an expert in a narrow slice of the product and can only act through a small, bounded set of deterministic actions. The model chooses which action fits the request; the action itself is ordinary, well-tested code with a fixed contract and a predictable result.
That is the same split as everywhere else in TellMe, made conversational. Language – vague, ambiguous, phrased a hundred ways – is the model’s job. Execution – turning “the Iberia invoice” into a specific operation, running a match, proposing a booking – belongs to the tool. Breaking the agent into domain specialists rather than one all-knowing agent also keeps each one’s context and toolset small, which makes its behaviour far more predictable and far easier to reason about.
Guardrails: no suggestion touches the ledger without approval
This is what makes Ask mode safe to expose. When the conversational agent decides to act, it doesn’t execute anything irreversibly – it produces the very same objects the background pipelines do. A chat request and an automatic run converge on one approval-and-audit path.
Everything the model contributes lands in one place: a suggestion. Each suggestion keeps the model’s original proposal alongside anything a user later changes, a plain-language summary, and a record of how it was reached – so every action carries its own audit trail. Nothing is applied until a person accepts it, and an accepted action can still be undone. Nothing the model does is ever final or irreversible.
Suggestions also come in modes. Some are surfaced for explicit review, some run silently as an audit log of what was done autonomously under deterministic rules, and some ask for a one-tap confirmation. The treasury team always supervises and decides; TellMe executes and suggests.
Access is scoped at every layer. A user’s permissions decide exactly which companies and which parts of TellMe they can reach, and those limits are enforced on the server – not just hidden in the UI. The same scope travels into everything the Ask-mode agent does, so however the model phrases a plan, it can only ever read or act on data the person is already allowed to touch.
Evaluating a system that never gives the same answer twice
You can’t unit-test your way to confidence in an LLM pipeline, so evaluation is a first-class part of TellMe rather than an afterthought.
Before any new version reaches a customer, we run it in shadow mode – side by side with the live one, on real data, without affecting anything the customer sees – so we can compare the two before switching over. Roll-outs happen gradually.
Ask mode is the hardest thing to evaluate, because a conversation is open-ended. Pushing determinism into the tools helps here too: because the tools are ordinary code we can unit-test, the genuinely non-deterministic surface shrinks to two questions – did the orchestrator route to the right domain agent, and did it extract the right arguments? Those are what we benchmark, replaying real conversations against new agent-graph versions in shadow before any rollout.
The second half of evaluation is the human feedback loop the guardrails give us for free. Because every model-driven decision – whether from a background pipeline or an Ask-mode conversation – becomes a suggestion that is accepted, edited, or rejected, we get a continuous signal of quality. Acceptance rate is our north-star quality metric, tracked per domain across live customer usage. A drop in acceptance for one agent is a far more honest quality alarm than any offline benchmark – it’s real users telling us the model got it wrong.
What determinism buys a treasury team
The point of all this isn’t to use as much AI as possible. It’s the opposite: to use the model in exactly the places where language and ambiguity live, and to keep everything downstream of it deterministic, reversible, and auditable. A treasurer gets an agent that understands a vague request and a pile of messy bank data – and a ledger where every entry can still be traced back to a rule, a match, or a human click.
Non-determinism and financial operations don’t actually have to fight. You just have to be disciplined about which one is allowed to touch the money.












