The rule we build by: code computes the numbers, and a language model describes them. Never the other way round.
Language models are good at reading a table and saying in plain English what stands out. They are bad at arithmetic they can't show, and they don't know when they've made something up. Those two facts decide where AI belongs in business software, and most of the work of adding it well is building the fence around it.
Good fits
- Summaries of data people already have. A dashboard with forty figures is a lot to read before the day starts. A paragraph that says which three moved, by how much, gets read.
- Morning briefs: a scheduled summary written from a dashboard's numbers, ready before anyone logs in.
- Explaining what changed and why, with the changes ranked by how much they matter in money.
- Drafting from structured data. A client update from a project's open items, the first draft of a report from the figures in it. A person edits it and decides whether it goes out.
Bad fits
Anything that has to be exact. Pay, prices, invoices, tax, compliance figures, anything a person signs. A model can't be trusted to compute those, and it can't be trusted to copy a computed figure perfectly either, so it shouldn't be the thing that writes the number an employee sees on a pay stub. A pay figure that's a few dollars wrong is an awkward conversation. A compliance figure that's wrong can be a lot worse.
It also doesn't belong where nobody reads the output critically, or where a plain rule would do. If "show a warning when stock drops below ten" covers it, write the rule.
The pattern
- Compute every number in code, on the same code path as the rest of the app, with tests.
- Verify the numbers before anything describes them. Check them against figures the client already trusts, and keep a debug view that shows which records produced each one.
- Decide what matters in code too. Ranking changes by dollar impact, and ignoring big percentages on tiny bases, are business rules. They shouldn't depend on a model's mood.
- Give the model only the verified, ranked figures, and ask it to describe them without adding any. Then check the output: a number in the text that isn't in the input is a reason to throw the text away and show the plain version instead.
- Keep it optional. The feature has to be useful with the AI layer switched off, because one day it will be: a timeout, an outage, a quota, a client who'd rather not.
- Log what went in and what came out, with the time and the model used. When someone asks "why did it say that?", the log answers. When you change models, the log lets you compare.
- Fall back quietly. If the model call fails, show the computed version without an error banner. The person still gets the facts.
- Send the minimum. Totals and changes, not raw records. Labels instead of names where the text doesn't need names. Nothing about health, and nothing that identifies a customer. Read the provider's data terms before the first call, not after.
Payroll analytics with an optional AI layer
One client runs a clinic, with a payroll and operations app we built on top of their scheduling platform. The owner didn't want another grid of figures. He asked for "a layer that reads the numbers and tells me the story: what moved, what matters, ranked by dollar impact".
The first phase has no AI in it at all. Every metric is recalculated from the raw data, using the client's existing reporting tool as the dictionary of what each figure means, and checked against the client's own figures for two months. Scheduled hours came within about 1.5 percent. Where figures didn't match, the client got plain-English questions instead of a quietly adjusted formula. Each card has a "more…" explainer and a debug view. The ranking of what changed, by dollars, is done by rules in code.
A written narrative from a language model is a separate, optional phase on top of that, and in the estimate it was the small part, about a fifth of the effort of the rules-based work. That proportion is typical. The model writes a paragraph; everything that makes the paragraph trustworthy is ordinary engineering underneath it. The owner's verdict on the analytics tab: "very cool".
Morning briefs from a dashboard
One of our own projects, a private dashboard fed by a desktop program, writes a brief several times each weekday morning. The brief is assembled in code from the dashboard's own data. An optional step passes those computed figures to a language model for a short written summary at the top.
The summary is the part people read first, and the part the system depends on least. The figures underneath are the same whether the summary is there or not, and they come from the same code as the dashboard, so the brief and the screen agree. If the summary ever says something the figures don't support, the figures are right there to show it.
Privacy is a design decision
Every call to a hosted model sends data to someone else's server. Decide what goes before writing the first prompt, and write it down. For most summaries the model needs aggregates, not records: a sentence about which service's revenue fell doesn't need a single customer's name. Where names matter in the output, send labels and swap the names back in code afterwards. The logs from step 6 hold the same data as the calls, so protect them like the database.
Done this way, the AI part of a feature is small, replaceable and easy to switch off, and the part that has to be right is still code you can test. If you have software full of numbers that nobody has time to read, tell us what it holds and we'll suggest where a summary would help and where it shouldn't go near.