laloop

Client work · March–April 2026 · Agricultural machinery

Who buys parts next month, and which invoice is a fraud

For a global agricultural machinery manufacturer's Brazilian dealer network: a weekly ranked list of the customers most likely to buy parts and lubricants in the next 30 days, the best product to offer each one, and a fraud check that holds incentive points until an invoice is trusted.

5
signals blended into one propensity score
1.4M
code-level cross-sell pairs in the affinity model
1.0
recall on confirmed fraud cases (precision 0.59)
1
indexed lookup at insert time to hold a suspicious invoice

The problem

Dealers sell parts and lubricants to farmers who buy a few times a year. Sales teams called whoever they remembered. The manufacturer wanted each dealer to start the week with a short list: who is about to buy, what to offer, and a ready WhatsApp message.

The same data fed an incentive programme where sellers and customers earn points per invoice. Some sellers registered invoices, collected the points and then cancelled them. Checking every invoice with the tax authority is slow and rate-limited, so the answer had to be preventive.

How it works

Propensity and next best offer

  1. IngestInvoices mirrored from MySQL into BigQuery, no transforms
  2. StageDealer hierarchy and brand resolved per branch, including single-store dealers
  3. SignalsExponential smoothing (α 0.2), RFM, basket affinity, seasonality, churn health
  4. ScoreWeighted blend 0–100, tiers HOT / WARM / COLD
  5. OfferBest cross-sell per customer; NeuMF model for customers with no history
  6. DeliverTop 50 per dealer every week, with WhatsApp templates

Preventive fraud scoring

  1. BaselineNightly profile per seller: rolling 90 days, threshold at mean + 2.5σ
  2. SignalsSeller spike, customer spike, quantity anomaly, new seller–customer pair, invoice density
  3. ExportPersonalised thresholds synced to MySQL
  4. GateAt insert, one SELECT decides: credit points now or hold for review
  5. LearnXGBoost + SHAP trained on confirmed cases; cancellations at the tax authority become labels
  6. ExplainA local LLM writes a per-seller report: pattern, likely mechanism, recommended action, confidence

Decisions that mattered

Weights move, they don't vanish

61–77% of customers had too little history for the smoothing signal. Instead of scoring them zero, the missing weight moves to RFM, so the score always sums to one and new customers are not punished for missing data.

Revenue-weighted churn, not the maximum

Taking the worst category flagged a healthy customer as churning when one of five product lines paused. Weighting by revenue flipped the signal's correlation with purchases from −0.32 to +0.49.

Fix the denominator before the model

The same-invoice share was above 100% because numerator and denominator were deduplicated on different keys. After the fix the affinity model went from 15 category pairs to 1.4M part-number pairs.

BigQuery computes, MySQL blocks

No model runs on the transactional path. Thresholds are computed overnight per seller and per customer, so the insert stays a single indexed lookup.

Prevent rather than chase

Points are held until an invoice passes the risk check. The rate-limited tax-authority lookups are spent on labelling training data, not on policing every invoice.

Explainable to an auditor

Every flag carries a plain-language reason, the top SHAP features and a recommended action. People decide; the system prioritises.

Stack

LayerChoiceWhy
WarehouseBigQuery · SQL, BQML, JS UDFRecursive smoothing without recursive CTEs; matrix factorisation in place
Cold startTensorFlow NeuMF on Vertex AIGMF + MLP with side features; split by machine to avoid leakage
ServingFastAPI on Cloud RunThree-tier fallback: NeuMF, BQML, standard basket
Fraud modelXGBoost + SHAP, SMOTEImbalanced labels, explanations per invoice
GateMySQLPersonalised thresholds, one lookup at insert
ReportsLocal LLM via OllamaInvestigation write-ups without sending data out

Where it stands

Built March to April 2026. The fraud model was trained on the first 35 confirmed cases and catches all of them; precision is 0.59, so the plan is to retrain at around 200 confirmed cases.

Open items are documented in the repository: smoothing coverage, unmatched part numbers and a move from weekly full refresh to change data capture.

Client name, dealer names and all personal data are withheld.

More work

Have an AI project stuck at the prototype stage?

Tell us the problem, the data and where it needs to run. We'll come back with an architecture and scope proposal.

Email contato@laloop.ai