Supply-Chain & Logistics Agents

9 min read

Y23
Playbook · Domain Playbooks

Supply-chain & logistics agents.

In logistics your agent's failure mode is not hallucination — it is acting confidently on a fact that was true four hours ago. Every system it reads is a photograph of an already-moved world: carrier status events arrive in batches, inventory counts are accurate as of the last cycle count, ETAs are model output with error bars nobody attached. Build freshness into the tool contract, scope the agent to exception triage rather than planning, and the whole domain becomes tractable.

STEP 1

Four jobs wear this name, and only one of them is yours.

"Logistics agent" is used for four products with almost no shared engineering. Say which one you are building before anything else, because two of them are actively wrong for a language model.

  • Network planning and optimisation — routing, load-building, slotting, inventory placement. This is operations research with decades of solvers behind it, and the objective function is explicit. An LLM choosing a route is strictly worse than a solver choosing a route, and it cannot prove feasibility. Do not build this.
  • Exception triage and resolution — a shipment missed its connection, a dock appointment slipped, a supplier confirmed short, a container is sitting at a terminal. This is the job. It is judgement under incomplete information across systems that do not talk, which is exactly what the technology is good at and exactly what nobody has ever had enough staff to do well.
  • Document and message processing — bills of lading, packing lists, commercial invoices, EDI transactions that arrived malformed. Real value, largely an extraction problem, and it benefits from being built as a separate deterministic pipeline rather than folded into the agent loop.
  • Status answering — internal and customer-facing "where is my order". Genuinely useful, but it is a support agent over logistics data, and it inherits that playbook rather than this one.

The split that matters: let the solver decide what the optimal answer is, and let the agent decide which of the thousand daily deviations is worth a human's attention and what to say about it. Teams that invert this ship an agent that produces plausible routes nobody can defend to a carrier.

STEP 2

Every fact carries a shutter time, and the tool contract must say so.

This is the design decision the domain turns on. In most agent applications the retrieved document is as true now as when it was written. In logistics, nothing is. The physical world moves continuously and the data about it arrives in discrete, delayed, sometimes out-of-order batches — so a tool result without a timestamp is not a fact, it is a rumour with a confident schema.

Give every read tool a mandatory as_of and source on the response, and sort your data into three staleness classes with different rules:

  • Seconds to minutes — telematics pings, yard scans, WMS transactions as they post. Safe to reason from directly.
  • Hours — carrier status events, terminal gate moves, partner confirmations. These arrive batched and frequently out of order, so "no event" means "no event reported", never "nothing happened". An agent that concludes a shipment is stuck because the last scan is six hours old will raise a false exception on every carrier whose feed runs on a four-hour cycle.
  • Days — inventory on hand, lead times, master data, cost tables. Treat as an estimate. Never let an agent promise availability from a stock figure alone; that is a commitment against a number whose error bar you did not read.

Then enforce it in the harness rather than requesting it in the prompt: a per-field maximum age, checked in code, that turns an over-age read into a refusal to act with a named reason. Models are poor at spontaneously noticing that a timestamp disqualifies an otherwise perfect answer, and this is the single highest-value guardrail in the domain. The general form of the problem is in knowledge cutoffs and time; here it is not an edge case, it is the main case.

The tell that a team has not internalised this: their demo works beautifully on a replayed dataset, where every record is simultaneously final and consistent. Production is a stream in which the ETA you read at 09:00 was superseded at 09:02 by an event that will reach you at 11:30. Test on a replay that preserves original arrival times, out-of-order delivery included, or you are testing a world you will never operate in.

STEP 3

The exception taxonomy is the product.

An agent turned loose on an event stream with "find problems" will find a different set of problems every day, none of them countable. What makes this shippable is a closed, named list of exception types — eight to fifteen is the realistic range — each with four things attached before a single one goes live:

  • A detection rule, deterministic where possible. "Promised date at risk" is a date comparison, not a judgement call; the model's job starts after the trigger fires.
  • A severity that maps to a real consequence — a stockout at a production line, a missed customer commitment, a demurrage clock that started. Severity derived from the money or the promise at stake, never from how alarming the event sounds.
  • A named owner. Every exception type routes to a role that can actually resolve it. An exception with no owner is a notification, and notifications with no owner get muted.
  • An explicit no-action branch. Most deviations self-resolve — a truck that is ninety minutes late arrives. The agent must be able to conclude "this will resolve, watch it until 14:00" and record that as a decision, not silence.

Keep the taxonomy closed and force the agent to classify into it with a structured output, including an explicit unclassified bucket. The unclassified rate is your best single health metric: rising, it means the world changed and your taxonomy did not, and the queue of unclassified events is the specification for your next release.

STEP 4

Every write is a contract with somebody who can say no.

Logistics write actions are not database updates. Rebooking a container, expediting a shipment, changing a delivery appointment, releasing a purchase order — each spends money, moves a promise, or consumes capacity that a counterparty may have already sold to someone else. Three rules follow, and the third is the one teams learn the hard way.

  • Sort actions by reversibility and cost, and gate accordingly. Free and reversible — adding a note, flagging a shipment for watch, drafting a message — runs unattended. Reversible with a cost, like moving a dock appointment inside the same window, runs unattended with a cap and a daily report. Anything that spends money, changes a customer-facing date, or notifies an external party is proposed to a human with the evidence attached; the approval surface is the whole design, and approval and confirmation UX covers how to make it fast enough to survive contact with a control tower at 07:00.
  • Re-read at commit. Between the agent forming an intent and the write landing, minutes passed and the world moved — often because of the same disruption. Re-fetch the record immediately before the write and abort on a changed state rather than overwriting it. This is the same discipline the booking playbook applies to a fare quote, and the reason is identical: the thing you priced is not the thing you are about to buy.
  • Never retry a logistics write blindly. Partner APIs and EDI paths time out constantly while succeeding, so a retry books the second container. Every write carries an idempotency key and every ambiguous outcome resolves by reconciliation — read back and confirm — not by trying again. The full argument is in idempotency and retries; in this domain the duplicate is not a bad row, it is a physical container on a physical ship.
STEP 5

The integration layer is most of the build, and it does not belong in the prompt.

Everyone underestimates this and it is where the schedule goes. You are joining a WMS, a TMS, an ERP, a handful of carrier APIs, and EDI feeds from partners who each interpret the standard slightly differently — and the joins are dirty in ways that are invisible until an agent reasons across them.

  • Identity resolution. The same location is a DC code in the WMS, a ship-to in the ERP, a SCAC-plus-facility string from the carrier and a free-text address on the ASN. Resolve these in deterministic code with a mapping table you can audit. An agent that resolves entities by inference will silently merge two facilities in the same city, and you will find out from a delivery.
  • Units and quantities. Eaches, cases, pallets, layers; kilograms and pounds; gross and net weight. Normalise at the tool boundary and return one canonical unit with the original alongside. Do not ask a model to keep unit conversions straight across forty steps — it will mostly succeed, and mostly is the wrong bar for a quantity that becomes a shipment.
  • Partner dialect drift. Carriers change status-code semantics and add fields without telling you, and an EDI segment that starts arriving differently is a behaviour change with no commit and no error. Snapshot the contract, stamp its version on every trace, and absorb changes in a facade layer — the pattern in third-party tool drift.
  • Tool granularity beats tool count. Resist a tool per endpoint per system; you will end up with sixty overlapping tools and selection errors that look like reasoning failures. Build a small set of domain-shaped tools — get_shipment_status, get_inventory_position, propose_appointment_change — each fanning out across systems underneath. See tool design for agents.
STEP 6

Measure the exception it did not raise.

Precision on raised exceptions is easy to measure, easy to make look good, and nearly irrelevant. The failures that cost you are the ones the agent never surfaced: the shortage that reached a production line, the demurrage that accrued for three days, the customer who found out before you did. Those never appear in a review queue, because there is nothing in the queue to review.

  • Backtest against resolved history. Take last quarter's genuine disruptions — the ones with a cost attached in somebody's ledger — replay the event stream as it actually arrived, and ask whether the agent would have raised each one, and how many hours before the human did. Hours-of-lead-time is the metric that means something commercially, and it is the number to put in front of an operations director.
  • Sample the silence. Take a random weekly sample of shipments the agent classified as no-action and have a planner review them. This is the only mechanism that finds systematic blind spots, and it needs to be a standing ritual rather than an investigation opened after an incident.
  • Track the unclassified rate and the override rate together. Rising unclassified means the taxonomy is stale. Rising overrides on a specific exception type means that type's playbook is wrong, and it names the fix precisely.
  • Grade the trajectory on the hard cases. A correct call reached by reading a stale record is a coin flip that landed well, and it will land badly at scale — which is why the freshness discipline needs trajectory evaluation, not just outcome scoring.

Ship the narrowest version first: one exception type, detected deterministically, where the agent only drafts and a planner sends. Instrument two numbers from day one — hours of lead time versus the human baseline, and the weekly no-action sample's miss rate — and do not add a second exception type until the first one beats the baseline on both. Meanwhile put the real engineering into the boring half: as_of on every tool response with a code-enforced maximum age, canonical units, an audited location mapping, and an idempotency key on every write. That layer is what makes the second exception type take a week instead of a quarter.

Related: procurement and sourcing agents for the upstream half of the same network, data analysis agents for the reporting layer this sits beside, and human in the loop for where the planner goes.