AI Agents · Ai

AI Agent for Supplier Risk Scoring

AI Agent for Supplier Risk Scoring is the work that defines the next phase of enterprise software. ERP systems hold the most valuable business data in the company — customers,.

John Kihiu12 min read

Supplier risk scoring is usually pitched as a model problem — feed in features, get out a number. In practice the useful version is closer to a research assistant: an agent that pulls the structured signals ERP systems already track, adds whatever unstructured context is worth checking (a news search, a filing, a shipping delay report), and writes a brief a procurement lead can act on in five minutes. The number matters less than the reasoning behind it, because the number is what gets challenged when a purchase order gets held.

What actually predicts supplier risk

Most of the useful signal already sits in the ERP, underused. Payment terms drift — a supplier who was Net 30 and is now insisting on prepayment or Net 10 — is one of the strongest leading indicators of their own cash strain, and it shows up in the vendor terms history if anyone bothers to track changes over time instead of just the current value. On-time delivery percentage, computed from promised-date versus receipt-date on POs, catches operational decline before it becomes a shortage. AP aging concentration — how much of your payables sits with one vendor, and how much of one vendor's revenue is plausibly you — flags exposure in both directions. Price volatility on repeat SKUs, especially step changes outside of a stated contract escalation clause, is worth flagging even when it's not yet a problem.

None of these require a model. They're SQL against tables Acumatica already maintains: POOrder, APInvoice, APPayment, vendor terms on Vendor. The agent's job is not to invent these metrics — it's to assemble them consistently and explain what changed.

A brief, not a verdict

The pattern that holds up is "human decides, agent assembles a brief," not "agent scores, human rubber-stamps." A single risk score collapses too much context — a supplier can look risky on paper because of a one-off dispute that's already resolved, or look safe because the metrics haven't caught up to a bankruptcy filing from last week. Procurement decisions get audited, sometimes years later, and "the model said 72" is not a defensible answer to "why did we keep buying from a supplier that went insolvent." A brief with cited numbers and a plain-language summary of what an LLM found in public sources is defensible, because a person can point to the specific evidence and say why they acted or didn't.

Two different failure costs

False positives (flagging a healthy supplier) cost you a wasted review. False negatives (missing a supplier that's about to fail) cost you a stockout or a scramble for an alternate source. Because the costs are asymmetric, the agent should be tuned to over-flag and let a human triage, not to stay quiet until it's confident.

Vendor master data is worse than you think

Before any of this works, someone has to confront how bad the underlying data usually is. Vendor names get entered inconsistently across subsidiaries — "Acme Supply Ltd" and "Acme Supply Limited" as two separate vendor records with no relationship between them, which silently splits concentration risk in half. Terms fields get set once at onboarding and never updated even when a supplier renegotiates informally. Country and tax ID fields are frequently stale after a supplier changes legal entity or gets acquired. An agent that queries this data as ground truth without checking for duplicates or staleness will produce confident, wrong output — which is worse than no output, because it looks authoritative.

A cheap mitigation: before scoring, run a fuzzy match pass on vendor name plus tax ID (or registration number) to catch likely duplicates, and surface a "data confidence" note in the brief when key fields — terms, primary contact, last verified date — haven't been touched in over a year.

Combining structured queries with LLM synthesis without hallucinating numbers

The failure mode to design against is the model inventing or misremembering a number that came from the ERP. The fix is boring but effective: compute every metric in code, pass the computed values into the prompt as already-formatted facts, and instruct the model to cite only those values verbatim rather than perform arithmetic itself. The model's job is synthesis and narrative — turning "on-time delivery dropped from 94% to 81% over two quarters, AP terms shifted from Net 30 to Net 10 in March, and a Reuters piece from last week mentions a factory closure" into three coherent sentences a buyer can scan — not calculation.

PYTHON · RISK BRIEF ASSEMBLY
def build_supplier_brief(vendor_id: str) -> dict:
    # 1. Structured facts computed in code, not by the model
    metrics = {
        "on_time_pct_90d": on_time_delivery_pct(vendor_id, days=90),
        "on_time_pct_prior_90d": on_time_delivery_pct(vendor_id, days=90, offset=90),
        "terms_current": current_payment_terms(vendor_id),
        "terms_12mo_ago": payment_terms_as_of(vendor_id, months_ago=12),
        "ap_concentration_pct": ap_balance_share(vendor_id),
        "price_change_pct_90d": avg_unit_price_change(vendor_id, days=90),
        "data_last_verified": vendor_last_verified_date(vendor_id),
    }

    # 2. Unstructured signal, fetched separately, kept distinct from ERP facts
    news = search_recent_news(vendor_name(vendor_id), days=30)

    # 3. Model only narrates the pre-computed facts — no math, no invented figures
    brief = llm_summarize(
        instructions="Cite only the numeric values provided. Do not calculate "
                      "or estimate any figure not present in `metrics`. Flag if "
                      "data_last_verified is over 365 days old.",
        metrics=metrics,
        news=news,
    )
    return {"metrics": metrics, "news": news, "narrative": brief}

Audit and explainability requirements

A risk brief that influences a purchasing decision needs to be reproducible after the fact. Store the raw metric values and the query timestamp alongside the generated narrative — not just the final text — so that six months later someone can answer "what exactly did we know when we approved this PO." Log which news sources the agent pulled from, since LLM web synthesis is the part most likely to be wrong or outdated, and treat it as supporting context rather than a citable fact on its own. Keep a clear boundary in the UI between "computed from ERP data" and "summarized from external sources" — mixing them in one paragraph makes it hard for a reviewer to know what to trust.

SignalSourceUpdate cadence
On-time delivery %PO promised vs. receipt dateRolling 90-day, recomputed daily
Payment terms driftVendor terms historyOn change, diffed against 12mo prior
AP concentrationAP aging by vendorWeekly
Price volatilityPO line price vs. contractRolling 90-day
External news/filingsLLM web searchOn-demand, timestamped, never cached silently

Wrapping up

The agent earns its keep by doing the tedious assembly work — pulling terms history, computing delivery trends, checking recent news — faster than a person would, not by replacing the judgment call. Keep the arithmetic in code, keep the narrative clearly separated from the source data, and log enough to reconstruct the brief later. That's what makes a risk score something procurement will actually trust instead of a number they route around.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.