All case studies FMCG distribution · ERP · 2026

AI analyst agents inside a distributor ERP

Two LLM roles wired into a sales-management platform: an analyst on the management dashboard, a sales assistant on the B2B portal. Both answer only from the KPI API - the model never writes a number it did not fetch.

agent roles
2
alert triggers
5
merged PRs
24
Control Tower management dashboard “margin by region, June?” B2B portal distributor clients “what should I reorder?” AI Analyst LLM + tool calling summary → numbers → action AI Salesperson history · balance · upsell blocked on overdue debt KPI API gross_sales(period, region)margin(period, branch)receivables(overdue_days)top_sku(limit, segment)distributor_rating() Guardrails shipped with it · call the API before answering· never invent a number· raw tool payload never leaves the API Alert triggers that fire on their own plan < 80%  ·  receivables > 60 days  ·  order anomaly > 40%  ·  VIP candidate  ·  no orders in 14 days
Both agent roles read the same KPI tool API. Nothing else leaves the boundary.

The problem

A distributor runs on numbers that live in several systems at once: the ERP, the 1C accounting side, and the field reports the sales agents file. Management asked the same handful of questions every week - how is the plan tracking, who is overdue, which SKUs moved - and every answer meant somebody exporting a report.

The ask was an assistant that could answer those questions directly. The risk was obvious: a language model that talks about revenue will happily produce a number that looks right and is not.

How it works

Two agent roles sit on top of one KPI API. The analyst answers on the management dashboard; the sales assistant answers on the B2B portal, where distributors place their own orders.

Neither role has access to the raw database. Both are given tools - gross_sales, margin, receivables, top_sku, distributor_rating - and both are instructed to call a tool before answering. Every response is shaped the same way: a one-line summary, the figures the tool returned, then a recommended action.

The B2B assistant carries one extra rule: it does not push an upsell at an account whose balance is overdue.

Keeping it honest

The interesting engineering here is not the prompt, it is the boundary. Tool responses are rich - they carry the query shape, the intermediate rows, the raw aggregates - and the first version passed all of it back through the endpoint.

Two pull requests fixed that: the insight report response and the AI endpoints both stopped returning the raw tool payload. What leaves the API is the answer and the figures it cites, nothing else.

On top of the request path, five triggers fire on their own: plan under 80 per cent, receivables overdue past 60 days, an order that deviates more than 40 per cent from the account average, a VIP candidate, and an account that has gone 14 days without an order.

The rest of the platform

The agents sit on a system that had to exist first: role-based access control and tenancy, webhook sync with 1C for counterparties, nomenclature, debts, operations, warehouse stock and business regions, tour-plan reporting for the sales agents, a management dashboard with downloadable PDF reports, and a React 19 SPA in front of all of it.