Skip to main content

Head of AI, Air & LCL Forwarding at Maersk · Amsterdam

I build AI into operations that can’t afford to be wrong.

I write the agents, the data underneath them, and the gates in front of them. When something doesn’t work, I want to know why before I make the model smarter.

44%of bookings through a touchless channel18% to ~4%override rate, in one sprint45 to 4 minquote turnaround32%cut from my own business case

What actually changed

The numbers I use to decide whether something worked.

44%
Booking channel share

44% of the unit's bookings now come through the booking automation I built

Up from ~13%. It is now the unit's #1 digital channel, ahead of the company website, its system integrations, and Alibaba's marketplace.

80%
Adoption rate

Auto-rating adoption scaled from 14% to a peak of 80%

Automated pricing across the air & LCL freight unit, phased by confidence band and gated on override rate. This is the line that returned $11M EBIT.

45 → 4 min
Quote turnaround

Pricing agents cut quote turnaround from 45 minutes to 4

The agents sit on the live quoting path. A quote leaves without a person touching it only inside the confidence band the override rate has already cleared. Everything outside the band still goes to a person.

137%
Revenue growth

Drove platform growth at Blibli

A travel SaaS platform for corporate, agency and retail clients. Over the same period users went from 135K to 165K.

Customer names and internal system names are withheld.

How AI gets adopted, or doesn’t

How automated pricing went from 14% to a peak of 80% adoption.

The situation

We'd shipped automated pricing across Maersk's air and LCL freight business. It cut quote time from 45 minutes to 4. And almost nobody wanted to use it. Adoption stalled at 14%. Worse, operations teams were overriding 18% of the quotes we were calling high confidence. So before we touched the model, I wanted to know why.

What I found

The consensus was that the model was hallucinating and we needed a better one. It wasn't. The same physical lane existed three different ways across our source systems. There was no canonical lane-and-commodity entity, and no controlled vocabulary connecting commodity codes to surcharge rules. So it retrieved the wrong surcharge and reasoned flawlessly over it.

The obvious fix

The obvious move was to swap in a newer model, tune the prompts and train the users. I stopped that. If the model was reasoning correctly over bad data, a smarter model would just be wrong faster, and more training would only teach people to distrust it more efficiently.

What worked

I halted the rollout and fixed the knowledge layer first. I defined a canonical lane-plus-commodity entity with a controlled vocabulary, and reconciled the master data behind the rate lookup. Then I put an eval gate in front of it: shadow-mode replay against known-good quotes, and nothing went live until accuracy cleared the floor. Override on high-confidence quotes fell from 18% to ~4% in one sprint. After that I widened the rollout region by region, through super-users their own teams already trusted.

What I learned

Adoption reached a peak of 80%, worth ~$11M EBIT on the pricing line. Same model, same features. The model was not the problem. The representation underneath it was. I have now seen that failure with lanes, with customers, with commodities and with flight milestones. Different entity, same problem. So I look for it before I change the model: where do two systems describe the same thing differently?

The biggest thing I shipped

Touchless Booking Platform

Maersk Email-to-Booking Automation

Most LCL bookings used to arrive as an email with attachments and get keyed in by hand. I built the pipeline that reads the email, extracts the documents, resolves the customer, lane and commodity, and creates the booking in the system of record.

Why I built it

~94% of LCL bookings were keyed in by hand from emails and attachments. The plan on the table was to move that typing to a cheaper keying centre. Whoever automates booking entry owns the data it creates.

What I built

Intent classifier over email + attachments as one intent object
Document extraction, commercial invoice & packing list
Canonical party/lane entity resolution + controlled vocabulary
Deterministic booking workflow into the system of record

Outcome

#1 digital booking channel | 44% of bookings (from ~13%)

LLMEntity ResolutionLogistics0→1

Code I wrote

Public projects and production code. The numbers are there because I don’t expect you to take my word for it.

Ladder

Let an agent show its work before it changes anything.

Ladder runs the agent's real tool against a copy of the application's state. You see the proposed changes as a diff, remove anything you do not want, and then the same tool runs for real against what remains. The agent gets back an account of what landed and why the rest did not.

Tests
394
Authors
1
Launch film
2:53
Public since
2 Sep 2026
Nothing real moves. What the tool would do becomes a diff: how many records, how much money, how much of it cannot be undone.

FreightBench

Not all AI errors cost the same.

I wanted a benchmark that counted a missing value and a confident wrong value separately, so I wrote one. It generates its own corpus, and each document carries one named fault, so a failure reports by cause: a seaport confused with the airport of the same city, a weight given in pounds, a correction buried in a forwarded thread. No model has been run through it yet. The harness, the corpus generator and 40 tests are public.

Pathologies
10
Tests
40
Python
3.10 to 3.13
Dependencies
0
A null routes the booking to a person. A confident wrong value goes straight through and surfaces when somebody is invoiced for it.

Airline Milestone Agent

Maersk internal

Catches impossible flight milestones before customers do.

Production code at Maersk that grades carrier milestone updates before they reach the shipment record. An adapter per carrier, a guard that rejects any milestone contradicting one already recorded, and a golden set that measures each carrier's accuracy in probe mode before anyone switches it on. It also settled a long-running argument about whether the system of record stores local time or UTC.

Internal code, so there is nothing to open.

Merged PRs
10
Flight legs graded
399
Impossible legs caught
21
Fields matching local time
23 of 23
Physics alone could not settle it, and I tried first. Only a carrier publishing both readings decides it.

Where the number was mine

Three corrections I filed on my own work, each before anyone else found it.

01

The 32% cut

Three agent business cases were heading into a Friday sign-off. All three rested on one time study, and all three assumed that every activity happens on every shipment. Nobody had written that assumption down, so nobody had tested it.

I queried the production system of record: 12,005 air shipments from one month, checked across two databases. The lowest real occurrence rate was 1.0%. The highest was 94.2%.

Then I built the correction to run against my own case. Where the log understated work that physically happened, I applied a floor. One pickup-side step was logged on 40.9% of shipments. It had physically happened on 68.2% of them. Four activities I could not measure I left at 100%, so the bias stayed against me.

My agent's entitlement per shipment came back a third lower. I sent it to the study's owner before the number went to sign-off.

Shipments queried
12,005
Minutes per file, before
49.8
Minutes per file, after
33.5
Cut to my own case
32%

The study was not wrong. I was using its number too casually.

02

The gate that passed itself

A customer's live performance dashboard refreshes on a schedule with nobody watching. I built a gate in front of the publish step so a bad payload could not reach the customer. On its first real test, coverage had fallen to 78.7%. The gate tripped and refused to publish. Correct.

Then the retry passed. The script overwrote the local payload before the gate ran, so the second attempt compared the new payload against itself. The fix was ordering: a tripped gate now restores the previous payload before anything else happens.

Coverage, previous run
96.0%
Coverage, the run that tripped it
78.7%
Refresh cadence
Twice daily
Blockers fixed to get it green
5
The first publish went out with the gate effectively neutralised.
03

The eleven-day write

An agent I wrote reads flight milestones from carriers we do not control and records them against the shipment. One consignment matched on every identity signal: airwaybill, route and pieces. It scored high confidence and wrote an arrival eleven days before the departure already on file.

The reason it got through was my own design. Temporal sanity only ever compared a proposal against estimates, never against an actual already recorded, and eleven days sat inside the tolerance. I found it, blocked auto-apply on any proposal contradicting a recorded actual, and wrote the reason into the pull request.

Days the arrival preceded departure
11
Tolerance window that hid it
14 days
Identity signals that matched
All
Confidence it scored
0.9
This is the part that is easy to get wrong, and I got it wrong first.

High confidence and a wrong write are not opposites.

About

Harsh Puri

In 2021 we put an early GPT assistant in front of real customers at Navan. It was accurate, and users still escalated to humans. They didn’t ask “is it right?”. They asked “why should I believe it?”. That question has stuck with me.

Most of what I have built since is about the gap between a system being capable and someone trusting it enough to let it touch production. That is why I care about gates, evaluation sets, rollback and slow rollouts. The model is one part of the system, and usually not the part that decides whether it gets used.

The same booking automation that reached near-universal adoption in Sweden sat near zero in Hong Kong until local super-users made the case themselves. Trust does not globalize.

There are two things I am not satisfied with yet. The model under my agents is somebody else’s and I do not retrain it; I harvest failures into a golden set and move the thresholds and guards around it. And my entity resolution is code, not an ontology a domain expert can edit without a deploy. I know how I would like to change the second one. I just have not built it.

Outside the day job I write code, with Claude Code as my pair programmer. This site, Ladder and FreightBench were all built that way. At work the habit became The Build Log, a weekly AI newsletter for 100+ PMs. The point of it is not to teach people about AI. It is to get them building with it.

Experience

Where I have worked, and what I changed there.

Current RoleMay 2023

Head of AI, Forwarding (Air & LCL)

A.P. Moller Maersk

May 2023 - PresentAmsterdam, NL
  • Built a touchless booking platform instead of moving the manual keying offshore. It now creates 44% of the unit's bookings, up from ~13%, and is the unit's #1 digital channel
  • Scaled automated pricing on an eval-gated rollout from 14% to a peak of 80% adoption, worth $11M EBIT
  • Shipped a file-compliance agent that reads the invoice and packing list and writes the reference numbers into the system of record. It inserted the right commercial-invoice reference on 98% of shipments in the June 2026 window
  • Put pricing and quoting agents on the live quoting path. Quote turnaround went from 45 minutes to 4
  • Retained a ~$15M ARR account at renewal: ETA accuracy at the final port went from 1% to 92%, and milestone timeliness from 47.7% to 70%
  • Run six AI product lines with five product managers and ~40 cross-functional colleagues. Their work delivered $22M gross profit in Air and $4M EBIT in LCL
Global operations
Jul 2021

Senior Product Manager - Experience

Navan (formerly TripActions)

Jul 2021 - Apr 2023Amsterdam, NL
  • Launched a GPT-powered customer assistant that resolved queries without a human agent. It saved $1.2M a year, and CSAT went up
  • Redesigned the agent workflows around it. Handling time fell 10%, worth $1M a year
  • Folded 4 legacy communication systems into one CX platform. That cut $2.64M a year in infrastructure cost
  • Grew the product organisation from 1 to 3 scrum teams
3 scrum teamsGlobal CX operations
Apr 2020

Senior Product Manager - Travel SaaS

Blibli (via Coviam)

Apr 2020 - Jul 2021Bangalore, IN
  • Delivered a SaaS travel platform with 137% revenue growth
  • Grew the user base from 135K to 165K, up 22%
  • Packaged one platform for retail, corporate and agency demand on supply from 101 airline APIs and 3.6M+ accommodations
Cross-functional platform teamIndonesia & Southeast Asia
Nov 2016

Senior Product Manager - Core Platform

Wipro Technologies

Nov 2016 - Apr 2020Bangalore, IN
  • Built Way2Go, an enterprise SaaS travel and expense platform, from nothing to 50K active users and 600+ trips a day
  • Ran a 24-person product and engineering group through engineering managers and a UX lead who were my direct reports
  • Set the architecture direction and sat on the hiring panel for the engineers, the product manager and the designer
24 people, through leadsEnterprise clients
Apr 2014

Technical Product / Program Manager

SITA

Apr 2014 - Nov 2016New Delhi, IN
  • Delivered IATA-regulated Passenger Name Record migrations at a 0.02% rejection rate. Regulated data, fixed external deadlines, no silent failures
Global airline systems

Get in touch

Email me about the builds above, AI in operations, or something you're trying to ship.

Harsh Puri

Harsh Puri

Head of AI, Forwarding (Air & LCL) at Maersk

I put software into operations that run on other people’s hands. Pickup vans and airlines we do not employ, and a system of record that has to end up correct or the money does not move.